waffle/copying/
fcopy.rs

1use alloc::collections::{BTreeMap, BTreeSet};
2use alloc::string::String;
3use hashbrown::{HashMap};
4
5// use libc::key_t;
6
7use 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            // eprintln!("l={ls:?};o={o}");
64            for v in ls.iter_mut() {
65                // eprintln!("l={v}");
66                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::Trace(_, l) => {
77        //     let mut ls = ba.arg_pool[*l].to_vec();
78        //     for v in ls.iter_mut() {
79        //         m(v)
80        //     }
81        //     *l = f.arg_pool.from_iter(ls.into_iter());
82        // }
83        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        // if c.len() == 1 {
170        //HACK: fix
171        let (v, d) = obf.obf(a, f, *b, &d, &c, module)?;
172        *b = d;
173        return Ok(v);
174        // }
175    }
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 ValueDef::BlockParam(_, p, _) = basis.values[*v]{
200    //     *v = f.blocks[b].params[p as usize].1;
201    //     return *v;
202    // }
203    // loop {
204    if let Some(n) = m.get(&*v) {
205        // *v = *n;
206        return Ok(*v);
207    }
208    // let n = f.add_value(ValueDef::None);
209    let g = f as *mut FunctionBody;
210    // let mut r = vec![];
211    let n = clone_value(
212        basis,
213        f,
214        |a| {
215            *a = match m.get(a) {
216                None => {
217                    // if basis.value_blocks[*a] == Block::invalid() {
218                    //     *a = n;
219                    //     return;
220                    // }
221                    // clone_value_in(basis, unsafe { &mut *g }, m, a, b, o, depth - 1);
222                    // eprintln!("{}", basis.display("", None));
223                    // eprintln!("{}; {}", o, b);
224                    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                    // r.push(*a);
235                    // *a
236                    *a
237                }
238                Some(b) => b.clone(),
239            }
240        },
241        v.clone(),
242        b,
243        obf,
244        module,
245    )?;
246    // eprintln!("{v} => {n}");
247    m.insert((*v).clone(), n.clone());
248    *v = n;
249    // f.append_to_block(*b, n);
250    return Ok(n);
251    // }
252}
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    // eprintln!("insts={:?}",d.insts);
273    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        // eprintln!("b={b},v={v}");
282        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    // let mut c = f.blocks.get_mut(r).unwrap();
299    // for a in d.insts.clone(){
300    //     f.append_to_block(r, a);
301    // }
302    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 = m.funcs[f].sig();
361    // if let Some(b) = m.funcs[f].body() {
362    // let b = b.clone();
363    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    // crate::td::fi(&mut n, m)?;
374    *b = n;
375    //     *m.funcs[f].body_mut().unwrap() = n;
376    // }
377    return Ok(());
378}
379pub fn obf_fn(m: &mut Module, f: Func, obf: &mut impl Obfuscate) -> anyhow::Result<()> {
380    // let s = m.funcs[f].sig();
381    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}