1use alloc::collections::{BTreeMap, BTreeSet};
2use alloc::string::String;
3use hashbrown::{HashMap};
4
5use crate::{
8 cfg::CFGInfo, entity::EntityRef, pool::ListRef, Block, BlockTarget, FrontendOptions, Func,
9 FunctionBody, Memory, MemoryArg, Module, Operator, Signature, SignatureData, Terminator, Type,
10 Value, ValueDef,
11};
12
13use crate::util::new_sig;
14use alloc::vec::Vec;
15use alloc::vec;
16pub trait Obfuscate {
17 fn boot(&mut self, b: Block, f: &mut FunctionBody) -> anyhow::Result<Block> {
18 return Ok(b);
19 }
20 fn sig(&mut self, a: SignatureData) -> anyhow::Result<SignatureData> {
21 return Ok(a);
22 }
23 fn obf(
24 &mut self,
25 o: Operator,
26 f: &mut FunctionBody,
27 b: Block,
28 args: &[Value],
29 types: &[Type],
30 module: &mut Module,
31 ) -> anyhow::Result<(Value, Block)>;
32 fn obf_term(&mut self, t: Terminator, b: Block, f: &mut FunctionBody) -> anyhow::Result<()> {
33 f.set_terminator(b, t);
34 return Ok(());
35 }
36}
37pub struct DontObf {}
38impl Obfuscate for DontObf {
39 fn obf(
40 &mut self,
41 o: Operator,
42 f: &mut FunctionBody,
43 b: Block,
44 args: &[Value],
45 types: &[Type],
46 module: &mut Module,
47 ) -> anyhow::Result<(Value, Block)> {
48 let v = f.add_op(b, o, args, types);
49 return Ok((v, b));
50 }
51}
52pub fn tweak_value(
53 f: &mut FunctionBody,
54 ba: &FunctionBody,
55 x: &mut ValueDef,
56 mut m: impl FnMut(&mut Value),
57 b: Block,
58) {
59 match x {
60 ValueDef::BlockParam(a, _, _) => *a = b,
61 ValueDef::Operator(o, l, t) => {
62 let mut ls = ba.arg_pool[*l].to_vec();
63 for v in ls.iter_mut() {
65 m(v)
67 }
68 *l = f.arg_pool.from_iter(ls.into_iter());
69 *t = f
70 .type_pool
71 .from_iter(ba.type_pool[*t].iter().map(|a| a.clone()));
72 }
73 ValueDef::PickOutput(v, _, _) => m(v),
74 ValueDef::Alias(v) => m(v),
75 ValueDef::Placeholder(_) => todo!(),
76 ValueDef::None => {}
84 }
85}
86pub fn tweak_target(
87 f: &mut FunctionBody,
88 x: &mut BlockTarget,
89 mut m: impl FnMut(&mut Value),
90 mut k: impl FnMut(&mut Block),
91) {
92 k(&mut x.block);
93 for a in &mut x.args {
94 m(a)
95 }
96}
97pub fn tweak_terminator(
98 f: &mut FunctionBody,
99 x: &mut Terminator,
100 mut m: impl FnMut(&mut Value),
101 mut k: impl FnMut(&mut Block),
102) {
103 match x {
104 Terminator::Br { target } => tweak_target(f, target, m, k),
105 Terminator::CondBr {
106 cond,
107 if_true,
108 if_false,
109 } => {
110 m(cond);
111 tweak_target(f, if_true, &mut m, &mut k);
112 tweak_target(f, if_false, m, k);
113 }
114 Terminator::Select {
115 value,
116 targets,
117 default,
118 } => {
119 m(value);
120 for target in targets {
121 tweak_target(f, target, &mut m, &mut k)
122 }
123 tweak_target(f, default, m, k)
124 }
125 Terminator::Return { values } => {
126 for a in values {
127 m(a)
128 }
129 }
130 Terminator::Unreachable => {}
131 Terminator::None => {}
132 Terminator::ReturnCall { func, args } => {
133 for a in args {
134 m(a)
135 }
136 }
137 Terminator::ReturnCallIndirect { sig, table, args } => {
138 for a in args {
139 m(a)
140 }
141 }
142 Terminator::ReturnCallRef { sig, args } => {
143 for a in args {
144 m(a)
145 }
146 }
147 }
148}
149pub fn clone_value(
150 basis: &FunctionBody,
151 f: &mut FunctionBody,
152 mut m: impl FnMut(&mut Value),
153 v: Value,
154 b: &mut Block,
155 obf: &mut impl Obfuscate,
156 module: &mut Module,
157) -> anyhow::Result<Value> {
158 let mut w = basis.values.get(v).map(|b| b.clone()).unwrap();
159 if let ValueDef::Operator(a, d, c) = w {
160 let d = basis.arg_pool[d]
161 .iter()
162 .map(|a| {
163 let mut a = *a;
164 m(&mut a);
165 return a;
166 })
167 .collect::<Vec<_>>();
168 let c = basis.type_pool[c].to_vec();
169 let (v, d) = obf.obf(a, f, *b, &d, &c, module)?;
172 *b = d;
173 return Ok(v);
174 }
176 tweak_value(f, basis, &mut w, m, *b);
177 let w = f.add_value(w);
178 f.append_to_block(*b, w);
179 Ok(w)
180}
181pub fn clone_value_in(
182 basis: &FunctionBody,
183 f: &mut FunctionBody,
184 m: &mut HashMap<Value, Value>,
185 v: &mut Value,
186 b: &mut Block,
187 o: Block,
188 depth: usize,
189 obf: &mut impl Obfuscate,
190 module: &mut Module,
191) -> anyhow::Result<Value> {
192 if depth == 0 {
193 let mut p = String::new();
194 if let ValueDef::Operator(a, b, c) = basis.values[*v] {
195 p = format!("{p};params={:?}", &basis.arg_pool[b])
196 }
197 panic!("exceeded depth: {} ({:?} {p})", *v, basis.values[*v]);
198 }
199 if let Some(n) = m.get(&*v) {
205 return Ok(*v);
207 }
208 let g = f as *mut FunctionBody;
210 let n = clone_value(
212 basis,
213 f,
214 |a| {
215 *a = match m.get(a) {
216 None => {
217 let mut p = format!(
225 "block={};m={:?};in={}",
226 basis.value_blocks[*a],
227 m.clone(),
228 *v
229 );
230 if let ValueDef::Operator(a, b, c) = basis.values[*a] {
231 p = format!("{p};params={:?}", &basis.arg_pool[b])
232 }
233 panic!("value not found: {a} ({:?} {p})", basis.values[*a]);
234 *a
237 }
238 Some(b) => b.clone(),
239 }
240 },
241 v.clone(),
242 b,
243 obf,
244 module,
245 )?;
246 m.insert((*v).clone(), n.clone());
248 *v = n;
249 return Ok(n);
251 }
253pub fn clone_block(
254 f: &mut FunctionBody,
255 basis: &FunctionBody,
256 b: Block,
257 new: Block,
258 mut k: impl FnMut(&mut Block),
259 obf: &mut impl Obfuscate,
260 modu: &mut Module,
261) -> anyhow::Result<()> {
262 let mut d = basis.blocks.get(b).unwrap().clone();
263 let mut m: HashMap<Value, Value> = HashMap::new();
264 let mut c = BTreeSet::new();
265 let mut r = new;
266 for (pt, pv) in d.params.iter_mut() {
267 let npv = f.add_blockparam(r, *pt);
268 m.insert(*pv, npv);
269 *pv = npv;
270 }
271 r = obf.boot(r, f)?;
272 for v in &mut d.insts {
274 if let Some(_) = m.get(v) {
275 continue;
276 }
277 if c.contains(v) {
278 continue;
279 }
280 c.insert(*v);
281 if basis.value_blocks[*v] != b {
283 panic!("inconsistent block value: {}", *v);
284 }
285 clone_value_in(basis, f, &mut m, v, &mut r, b, 100, obf, modu)?;
286 }
287 tweak_terminator(
288 f,
289 &mut d.terminator,
290 |a| {
291 *a = match m.get(a) {
292 None => a.clone(),
293 Some(b) => b.clone(),
294 }
295 },
296 k,
297 );
298 obf.obf_term(d.terminator.clone(), r, f)?;
303 return Ok(());
304}
305pub struct FunCloneRes {
306 pub all: BTreeMap<Block, Block>,
307}
308pub fn sanity(body: &FunctionBody) {
309 let mut uses = BTreeSet::default();
310 for block in body.blocks.iter() {
311 for &inst in &body.blocks[block].insts {
312 match &body.values[inst] {
313 &ValueDef::Operator(_, args, _) => {
314 for &arg in &body.arg_pool[args] {
315 let arg = body.resolve_alias(arg);
316 uses.insert(arg);
317 }
318 }
319 &ValueDef::PickOutput(value, ..) => {
320 let value = body.resolve_alias(value);
321 uses.insert(value);
322 }
323 _ => {}
324 }
325 }
326 body.blocks[block].terminator.visit_uses(|u| {
327 let u = body.resolve_alias(u);
328 uses.insert(u);
329 });
330 }
331 for (v, w) in body.values.entries() {
332 if w.ty(&body.type_pool).is_none() && uses.contains(&v) {
333 panic!("invalid type: {v} in {}", body.display("", None));
334 }
335 }
336}
337pub fn clone_fn(
338 f: &mut FunctionBody,
339 basis: &FunctionBody,
340 obf: &mut impl Obfuscate,
341 m: &mut Module,
342) -> anyhow::Result<FunCloneRes> {
343 let mut basis = basis.clone();
344 sanity(&basis);
345 basis.convert_to_max_ssa(None);
346 let mut all = BTreeMap::new();
347 for k in basis.blocks.entries().map(|a| a.0) {
348 all.insert(k, f.add_block());
349 }
350 for (a, b) in all.clone() {
351 clone_block(f, &basis, a, b, |k| *k = *all.get(k).unwrap(), obf, m)?;
352 }
353 return Ok(FunCloneRes { all });
354}
355pub fn obf_fn_body(
356 m: &mut Module,
357 b: &mut FunctionBody,
358 obf: &mut impl Obfuscate,
359) -> anyhow::Result<()> {
360 let s = new_sig(
364 m,
365 obf.sig(SignatureData::Func {
366 params: b.blocks[b.entry].params.iter().map(|a| a.0).collect(),
367 returns: b.rets.clone(),
368 })?,
369 );
370 let mut n = FunctionBody::new(&m, s);
371 let r = clone_fn(&mut n, &b, obf, m)?;
372 n.entry = *r.all.get(&b.entry).unwrap();
373 *b = n;
375 return Ok(());
378}
379pub fn obf_fn(m: &mut Module, f: Func, obf: &mut impl Obfuscate) -> anyhow::Result<()> {
380 if let Some(b) = m.funcs[f].body() {
382 let mut b = b.clone();
383 obf_fn_body(m, &mut b, obf)?;
384 *m.funcs[f].body_mut().unwrap() = b;
385 }
386 return Ok(());
387}
388pub fn obf_mod(m: &mut Module, obf: &mut impl Obfuscate) -> anyhow::Result<()> {
389 for f in m.funcs.iter().map(|a| a).collect::<Vec<_>>() {
390 obf_fn(m, f, obf)?;
391 }
392 return Ok(());
393}