感谢无名大佬提供的思路,使用了下unicorn,编写idapython脚本去掉控制流混淆,unicorn一个字,好使,推荐大家可以用用,
1、ccfK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6G2j5X3k6#2M7$3y4S2N6r3!0J5i4K6u0V1L8r3I4$3L8g2)9J5c8X3!0T1k6Y4g2K6j5$3q4@1L8%4u0Q4c8e0c8Q4b7U0S2Q4z5p5u0Q4c8e0S2Q4b7V1c8Q4b7V1c8Q4c8e0k6Q4z5f1y4Q4z5o6m8Q4c8e0k6Q4z5e0k6Q4b7U0m8Q4c8e0N6Q4z5f1q4Q4z5o6c8G2L8r3I4$3L8g2!0q4y4g2)9^5z5q4)9^5y4W2!0q4y4W2)9&6y4q4!0m8c8W2!0q4y4#2!0n7b7#2)9&6y4W2!0q4z5q4!0m8c8W2)9&6x3g2)9J5b7#2!0q4y4g2)9^5y4W2)9^5c8r3u0#2K9h3I4V1i4K6u0r3j5X3W2F1i4@1f1@1i4@1t1^5i4K6S2n7i4@1f1%4i4K6V1@1i4K6W2r3i4@1f1$3i4K6R3^5i4K6V1H3j5$3I4S2L8X3N6Q4c8e0y4Q4z5o6m8Q4z5o6t1`.
1)、 在llvm目录下创建build文件。
2)、 在build目录下行 cmake -DCMAKE_BUILD_TYPE=Release-DLLVM_INCLUDE_TESTS=OFF ../
3)、 make -j4
4)、 build目录下会生成clang的可执行文件bin、lib目录
2、将Lib\Transforms\Obfuscation\Flattening.cpp移植出来单独编译,方便测试,否则修改了源文件还得放到整个ollvm源码中编译,费时不方便测试。编译生成 libflatten.so

3、编写一个简单的llvm-test.cpp,只有一个测试函数。

4、使用clang分别进行编译,一个加载控制流混淆pass,一个不加载,在ida中进行对比下看看效果

未加控制流混淆pass:
除了入口块,还剩余4个真实块

添加控制流混淆pass:
可以看到添加了好多用来寻找真实块的无用块,统一从0xDB0块出发,找到真实块,最后统一从块0xDC0回到块0xDB0,跳转到入口块的指令都是有很明显的
特征的,后边会提到

以上是llvm生成的最终的机器指令控制流程图
llvm 通过Function.viewCFG()提供生成的中间IR指令的控制流图
在控制流混淆Pass的runOnFunction函数的前后调用f.viewCFG(),可以清晰的看到
混淆前后中间IR指令控制流图对比
对比下IR控制流图,
混淆前:

混淆后:
看下源码, 429K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6G2j5X3k6#2M7$3y4S2N6r3!0J5i4K6u0V1L8r3I4$3L8g2)9J5c8X3!0T1k6Y4g2K6j5$3q4@1L8%4u0Q4x3U0k6F1j5Y4y4H3i4K6y4n7Lib\Transforms\Obfuscation\Flattening.cpp中的flatten函数
1、 第一个块 :添加 AllocaInst、StoreInst、BranchInst指令,alloca分配switchVar变量空间,store填充switchVar为随机值,bl跳转到loopEntry块
2、 loopEntry块 :添加 LoadInst、SwitchInst指令,load获取switchVar变量地址,switch根据获取的switchVar值,查表跳转
3、 loopEnd块 :添加 BranchInst指令,跳转到loopEntry块
4、 真实块 :如果是无条件分支指令,去掉终止指令br,添加StoreInst、BranchInst指令,根据真实块后继对应的switchNum用store更新
switchVar值,跳转到loopEnd块如果是条件分支指令,去掉终止指令br,添加SelectInst、StoreInst、BranchInst指令,根据SelectInst 指令选择的真实块后继对应的switchNum用store更新switchVar值,跳转到loopEnd块
5、 switchDefault块 :添加 BranchInst指令,跳转到loopEnd块
引用网上的一张图

总结控制流混淆的原理:
搭建一个switch代码框架,将真实块塞到框架case中,根据switchVar变量的值,通过switch指令寻找到真实的代码块,跟前边开启了混淆编译,中间生成
IR 流程就能匹配起来了。
控制流混淆生成的中间IR控制流图和源码是完全能对应起来的,都是通过switch指令,随机值串联起来的,但是和生成的汇编控制流图还不太一样,反汇编生 成的控制流图是通过多个块中的比较指令,最终找到真实块
Hook app输出日志函数pBA425510043BB3BE41A7E30AA69623BE
反混淆之前控制流图:

F5伪代码:外层一个大的while循环,内部通过switch case的方式寻找到真实块

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课