4 ms·
You can convert an irreducible CFG to a reducible CFG with a loop and a switch case(/match in case of rust): In pseudocode Goto = Start; While(Goto!=End)
by legulere 8y ago
You can convert an irreducible CFG to a reducible CFG with a loop and a switch case(/match in case of rust):
In pseudocode
Goto = Start;
While(Goto!=End) {
Match(Goto) {
...
}
}
It’s a pretty basic obfuscation technique.
Compilers will happily unroll this leaving you with an irreducible CFG.
- edflsafoiewq 8y agoYou have more faith in the compiler than I do. Here's a stupid test I made. * In C++, using goto: https://godbolt.org/z/YqCMbU https://godbolt.org/z/YqCMbU * In Rust, with relooped CFG: https://godbolt.org/z/IIXtKo https://godbolt.org/z/IIXtKo The compiler was obviously not able to unroll the relooped code into the original CFG. A specific example: in principle, the compiler could see the exact target of every continue in the Rust code, so the continue on line 34 could go directly to line 27 (or, better, as in C++ the basic blocks could just be laid out adjacently), but the compiler does not actually do this and there are a bunch of unnecessary tests on the path between those two lines.
- dbaupp 8y agoIt's unfortunate that the enum-based solution doesn't work, but that particular example can be made "optimal" (at least, as good control flow as LLVM can get this code: the same as clang, not GCC), by using a rather unpleasant series of loops and labelled breaks: https://godbolt.org/z/sQ1nH8 https://godbolt.org/z/sQ1nH8 (rustfmt'd version: https://play.rust-lang.org/?gist=b1091e0c583b88f27bf1eaeae3a670f0&version=stable&mode=debug&edition=2015 https://play.rust-lang.org/?gist=b1091e0c583b88f27bf1eaeae3a...). This doesn't work in general, and is ... impossible to maintain, but it's not an unreasonable approach for generated code.