OLLVM 是一种代码混淆技术,旨在通过增加二进制代码的复杂度,显著提升逆向工程的难度
本文首先梳理 OLLVM 常见的混淆效果,接着编译部署 一个 OLLVM 项目 ,然后使用该项目混淆一段 C 代码,最后探讨相应的反混淆策略
OLLVM 的核心混淆功能有:
-sub) :将简单的算术或逻辑指令替换为语义等价但形式复杂的指令序列。例如使用 MBA(Mixed Boolean-Arithmetic,混合布尔算术) 表达式来实现-bcf) :插入永远为假或永远为真的条件判断,从而引入大量不可达的代码块(死代码)和虚假跳转路径。-fla) :将清晰的树状或网状控制流重构为一个基于状态机的单一大循环。所有基本块都被放入一个巨大的 switch 结构中,通过一个不透明的状态变量来控制执行流程的跳转。对于安卓逆向人员而言,OLLVM 已成为 native 层(SO 文件)保护的“标配”。在分析加固壳的so 文件、或者大厂的 so 文件经常会遇到 OLLVM 混淆的代码
例如:x度加固免费版中,这个函数将原有的执行流程分为32个 case 块。用 IDA 生成的函数块图就十分复杂
这是某数字壳企业版的一段汇编程序:代码最后执行 BR X17,而不是 B 或 BL 指令,所以ida无法计算出程序跳转至哪里。
这段代码使用了间接跳转混淆,原版 OLLVM 并没有实现

下面的 OLLVM 实现了间接跳转混淆
本文只涉及原版 OLLVM 的三个混淆方法:虚假控制流、指令替换以及控制流平坦化
下图还是某数字壳的一段代码,&qword_B8 是一个函数指针数组,off_E5FC0 充当数组索引。程序通过动态计算具体的函数指针,来完成函数的间接调用
通过上面的例子,我们直观地体会到 OLLVM 是一个很流行的编译器层级的代码混淆方法。根据名字就可以知道 OLLVM 基于 LLVM 架构。那么 LLVM又是什么?
LLVM 是一个编译器,编译指的是将一种高级语言转换成另一种低级语言,之后再运行。例如运行 C 语言,编译器会将 C 代码编译成汇编代码,然后汇编成机器码,最后运行
GCC介绍: https://zh.wikipedia.org/wiki/GCC
在 GCC 编译器里,每一种语言的编译器都是一种独立的程序。GCC 编译器的架构分为前端、中介端和后端。前端接受各种语言的源代码,生成语法分析树 AST 。中介端负责将源代码转化为可执行语言 GIMPLE ,并进行优化。后端用于生成最终的汇编代码。下图是GCC编译器的架构:
LLVM 的架构又是什么呢? 前端:获取源代码并将其转换为中间表示 IR。中间端: 将中间表示(IR)转换为另一种 IR。通常这些 pass 用于优化代码——输出的 IR 程序与输入的 IR 功能相同,但运行更快。后端生成实际的机器代码
emmm,这看起来好像和 GCC 架构一样啊。实际上,现代编译器基本都使用上面的三层架构
LLVM的特别之处,在于:
用户通过修改Pass,可以自由干预代码编译流程。也就是说,想实现代码优化或者代码混淆,只需要编写相应的 Pass 代码
OLLVM 的思想变来源于此
C++ 源码 ─┐Rust 源码 ─┼→ 各自前端 → 统一的 LLVM IR → OLLVM Pass → 生成混淆后的代码Swift 源码 ─┘接下来便是做实验,大概会完成以下几步:
现存的 OLLVM 项目汇总 https://lich4.github.io/cpp_posts/20240826_ollvm/#%E7%8E%B0%E5%AD%98ollvm%E9%A1%B9%E7%9B%AE%E6%B1%87%E6%80%BB
由于 OLLVM 的编译可能有环境上的问题,有人将编译 OLLVM 的环境封装成 Docker 容器
以下是编译原版 OLLVM 的步骤
git clone -b llvm-4.0 --depth=1 https://github.com/obfuscator-llvm/obfuscator.gitsudo apt install docker.iosudo docker pull nickdiego/ollvm-build# 也可以使用国内镜像sudo docker pull docker.1ms.run/nickdiego/ollvm-build:latestollvm-build, 打开ollvm-build.sh# 找到这一行,在末尾添加 -DLLVM_INCLUDE_TESTS=OFFDOCKER_CMD="/scripts/ollvm-build.sh --docker ${FWD_ARGS[*]}${CMAKE_ARGS:+-- ${CMAKE_ARGS[*]}} -- -DLLVM_INCLUDE_TESTS=OFF"然后运行 ollvm-build.sh , 运行参数是OLLVM 代码下载的位置
sudo ./ollvm-build.sh /home/xiaoy/obfuscator/运行结束,输出
Build finished successfully. Output directory: /home/xiaoy/obfuscator/build_release文章很多思路、代码来源于:https://oacia.dev/ollvm-study/
这是一段 RC4 加密和解密的代码
//test.c#include<stdio.h>/*RC4 初始化函数*/voidrc4_init(unsignedchar* s, unsignedchar* key, unsignedlong Len_k){int i = 0, j = 0;char k[256] = { 0 };unsignedchar tmp = 0;for (i = 0; i < 256; i++) { s[i] = i; k[i] = key[i % Len_k]; }for (i = 0; i < 256; i++) { j = (j + s[i] + k[i]) % 256; tmp = s[i]; s[i] = s[j]; s[j] = tmp; }}/*RC4 加解密函数unsigned char* Data 加解密的数据unsigned long Len_D 加解密数据的长度unsigned char* key 密钥unsigned long Len_k 密钥长度*/voidRC4(unsignedchar* Data, unsignedlong Len_D, unsignedchar* key, unsignedlong Len_k)// 加解密{unsignedchar s[256]; rc4_init(s, key, Len_k);int i = 0, j = 0, t = 0;unsignedlong k = 0;unsignedchar tmp;for (k = 0; k < Len_D; k++) { i = (i + 1) % 256; j = (j + s[i]) % 256; tmp = s[i]; s[i] = s[j]; s[j] = tmp; t = (s[i] + s[j]) % 256; Data[k] = Data[k] ^ s[t]; }}voidRC4encrypt(unsignedchar* Data, unsignedlong Len_D, unsignedchar* key, unsignedlong Len_k){ RC4(Data, Len_D, key, Len_k);}voidRC4decrypt(unsignedchar* Data, unsignedlong Len_D, unsignedchar* key, unsignedlong Len_k){ RC4(Data, Len_D, key, Len_k);}intmain(){// 字符串密钥unsignedchar key[] = "secret";unsignedlong key_len = sizeof(key) - 1;// 字符串最后还有一个 '/0' 所以需要 - 1// 数组密钥//unsigned char key[] = {'s','e','c','r','e','t'};//unsigned long key_len = sizeof(key);unsignedchar data[] = {104, 101, 108, 108, 111, 32, 120, 105, 97, 48, 121};// 对明文进行加密 RC4encrypt(data, sizeof(data), key, key_len);printf("加密结果:");for (int i = 0; i < sizeof(data); i++) {printf("%d, ", data[i]); }printf("\n");// 对密文进行解密 RC4encrypt(data, sizeof(data), key, key_len);printf("解密结果:");for (int i = 0; i < sizeof(data); i++) {printf("%c", data[i]); }printf("\n");return0;}/*加密结果:133, 83, 190, 112, 237, 132, 174, 207, 83, 251, 194, 解密结果:hello xia0y*/用 GCC 编译test
gcc ./test.c -o test未混淆的代码
int __fastcall main(int argc, constchar **argv, constchar **envp){unsignedint i; // [rsp+0h] [rbp-30h]unsignedint j; // [rsp+4h] [rbp-2Ch]char v6[7]; // [rsp+16h] [rbp-1Ah] BYREF _BYTE v7[19]; // [rsp+1Dh] [rbp-13h] BYREF *(_QWORD *)&v7[11] = __readfsqword(0x28u);strcpy(v6, "secret"); qmemcpy(v7, "hello xia0y", 11); RC4encrypt(v7, 11, v6, 6);for ( i = 0; i <= 0xA; ++i )printf("%d, ", (unsigned __int8)v7[i]);putchar(10); RC4encrypt(v7, 11, v6, 6);for ( j = 0; j <= 0xA; ++j )putchar((unsigned __int8)v7[j]);putchar(10);return0;}
虚假控制流的原理是:插入永远为假或永远为真的条件判断,从而引入大量不可达的代码块(死代码)和虚假跳转路径,使 IDA 无法正确判断程序执行流程
使用以下命令对代码进行虚假控制流编译:
../obfuscator/build_release/bin/clang test.c -mllvm -bcf -mllvm -bcf_loop=3 -mllvm -bcf_prob=40 -o test_bcf混淆结果如下图,增加了许多无用的控制流
这是加密后的main函数代码,感觉其实能看懂,是 CTF 题目的话,直接赛博厨子梭哈就好了
这个混淆添加了许多while循环,while循环的表达式y_12 >= 10 && (((x_11 - 1) * x_11) & 1) != 0 反复出现。 ((x_11 - 1) * x_11) & 1用于判断最低位的数是0还是1,而(x_11 -1 ) * x_11 一定是偶数,所以 ((x_11 - 1) * x_11) & 1一定为0。 又因为参与&&运算的两个数,如果其中一个为假,整个结果一定是假。 整个表达式可以化简为0!=0,所以while循环不会进行
如何去除 bcf 混淆?有三种方法:
第一种: 由于 IDA 无法获取x_11 , y_12全局变量的值,导致 IDA 无法计算出表达式的结果。 我们可以在 IDA 里手动指定全局变量的值,IDA 计算发现代码不可达后,便会删除死代码
第二种:使用 D-810 插件,删除代码里的不透明谓词(也就是程序执行前已确定值,但是静态分析器难以推断的逻辑表达式)
第三种:直接修改汇编代码,将使用全局变量的地方修改成使用常数
.text:00000000004039EA mov eax, ds:x_11.text:00000000004039F1 mov ecx, ds:y_12上面的 mov eax, ds:x_11 , 修改成mov eax, 0。由于需要修改的位置比较多,需要使用 IDAPython 完成批量修改
演示一下如何使用D-810吧,我下载的 IDA9 自带了D-810插件,按照下面的位置打开
点击 Start,等待一段时间
回到代码页面,按下F5,发现混淆已成功去除

指令替换的原理是:将简单的算术或逻辑指令替换为语义等价但形式复杂的指令序列
使用以下命令对代码进行指令替换编译:
../obfuscator/build_release/bin/clang test.c -mllvm -sub -mllvm -sub_loop=3 -o test-sub
开启指令替换之后, 就连简单的++ 运算都被i = i - 0x4B88BBDCA8AF4960LL + 0x4B88BBDCA8AF4961LL 代替
我们依然可以使用D-810 去混淆,结果如下图,一些复杂的表达式没有去掉混淆。
如果进行算法逆向,到这一步可以直接根据算法规律盲猜加密算法是 RC4
使用解析 MBA 的开源工具
我选择使用 GAMBA ,一是参考文章里使用这个项目,二是其他项目需要编译 C 代码... 真不想编译了
试试解这段代码的混淆
v5 = *(v17 + i) & ((v13[v10] & 0xB5 | ~v13[v10] & 0xA) ^ (~v13[v10] & 0x40 | 0xA) ^ 0xBF); v6 = ~(v13[v10] & ~((*(v17 + i) & 4 | ((*(v17 + i) & 2 | ~*(v17 + i) & 0xA0) ^ 2 | (*(v17 + i) & 9 | ~*(v17 + i) & 0x50) ^ 0x50) ^ 0x59) ^ v13[v10] ^ 4)); v7 = v13[v10] & ~((*(v17 + i) & 4 | ((*(v17 + i) & 2 | ~*(v17 + i) & 0xA0) ^ 2 | (*(v17 + i) & 9 | ~*(v17 + i) & 0x50) ^ 0x50) ^ 0x59) ^ v13[v10] ^ 4) & 0xA8; *(v17 + i) = ~(~v5 | v6) | v5 & 0xA8 ^ 0x13 ^ (~v5 & 0x44 | v5 & 0x13) ^ (v7 & v6 & 0x57 | ~((v6 & 0x52 | ~v6 & 5 | 0x80) ^ v7 ^ 0x7A));由于工具无法识别数组,所以我使用变量ab代替算法里的数组。a表示v13[v10] , b表示v17 +i
C:\Users\24526\Desktop\桌面图标\逆向\GAMBA-main\src>python3 simplify_general.py -v 3 "a & ((b & 0xB5 | ~b & 0xA) ^ (~b & 0x40 | 0xA) ^ 0xBF)"*** Expression a & ((b & 0xB5 | ~b & 0xA) ^ (~b & 0x40 | 0xA) ^ 0xBF)*** ... verify via evaluation ... [====================] 100%*** ... verification successful!*** ... simplified to 255&a&~bC:\Users\24526\Desktop\桌面图标\逆向\GAMBA-main\src>python3 simplify_general.py "~(a & ~((b & 4 | ((b & 2 | ~b & 0xA0) ^ 2 | (b & 9 | ~b & 0x50) ^ 0x50) ^ 0x59) ^ a ^ 4))"*** Expression ~(a & ~((b & 4 | ((b & 2 | ~b & 0xA0) ^ 2 | (b & 9 | ~b & 0x50) ^ 0x50) ^ 0x59) ^ a ^ 4))*** ... simplified to -256|~a|bC:\Users\24526\Desktop\桌面图标\逆向\GAMBA-main\src>python3 simplify_general.py "a & ~((b & 4 | ((b & 2 | ~b & 0xA0) ^ 2 | (b & 9 | ~b & 0x50) ^ 0x50) ^ 0x59) ^ a ^ 4) & 0xA8 "*** Expression a & ~((b & 4 | ((b & 2 | ~b & 0xA0) ^ 2 | (b & 9 | ~b & 0x50) ^ 0x50) ^ 0x59) ^ a ^ 4) & 0xA8*** ... simplified to 168&a&~bC:\Users\24526\Desktop\桌面图标\逆向\GAMBA-main\src>python3 simplify_general.py "~(~(255&~a&b) | (-256|~a|b)) | (255&~a&b) & 0xA8 ^ 0x13 ^ (~(255&~a&b) & 0x44 | (255&~a&b) & 0x13) ^ ((168&a&~b) & (-256|~a|b) & 0x57 | ~(((-256|~a|b) & 0x52 | ~(-256|~a|b) & 5 | 0x80) ^ (168&a&~b) ^ 0x7A))"*** Expression ~(~(255&~a&b) | (-256|~a|b)) | (255&~a&b) & 0xA8 ^ 0x13 ^ (~(255&~a&b) & 0x44 | (255&~a&b) & 0x13) ^ ((168&a&~b) & (-256|~a|b) & 0x57 | ~(((-256|~a|b) & 0x52 | ~(-256|~a|b) & 5 | 0x80) ^ (168&a&~b) ^ 0x7A))*** ... simplified to 105^~(128|82&(-256|~a|b)|5&a&~b)^168&(a^b)^(68&(-256|a|~b)|19&~a&b)emmm,看起来并没有完全去除混淆
用simplify.py 进行处理,效果好很多
C:\Users\24526\Desktop\桌面图标\逆向\GAMBA-main\src>python3 simplify.py -v 3 "b& ((a & 0xB5 | ~a & 0xA) ^ (~a & 0x40 | 0xA) ^ 0xBF)"*** Expression b& ((a & 0xB5 | ~a & 0xA) ^ (~a & 0x40 | 0xA) ^ 0xBF)*** ... input is not considered linear*** ... verify via evaluation ... [====================] 100%*** ... verification successful!*** ... simplified to ~a&bC:\Users\24526\Desktop\桌面图标\逆向\GAMBA-main\src>python3 simplify.py -v 3 "~(a & ~((b & 4 | ((b & 2 | ~b & 0xA0) ^ 2 | (b & 9 | ~b & 0x50) ^ 0x50) ^ 0x59) ^ a ^ 4))"*** Expression ~(a & ~((b & 4 | ((b & 2 | ~b & 0xA0) ^ 2 | (b & 9 | ~b & 0x50) ^ 0x50) ^ 0x59) ^ a ^ 4))*** ... input is not considered linear*** ... verify via evaluation ... [====================] 100%*** ... verification successful!*** ... simplified to ~(a&~b)C:\Users\24526\Desktop\桌面图标\逆向\GAMBA-main\src>python3 simplify.py -v 3 "a & ~((b & 4 | ((b & 2 | ~b & 0xA0) ^ 2 | (b & 9 | ~b & 0x50) ^ 0x50) ^ 0x59) ^ a ^ 4) & 0xA8 "*** Expression a & ~((b & 4 | ((b & 2 | ~b & 0xA0) ^ 2 | (b & 9 | ~b & 0x50) ^ 0x50) ^ 0x59) ^ a ^ 4) & 0xA8*** ... input is not considered linear*** ... verify via evaluation ... [====================] 100%*** ... verification successful!*** ... simplified to 0C:\Users\24526\Desktop\桌面图标\逆向\GAMBA-main\src>python3 simplify.py -v 3 "~(~(~a&b) | (~(a&~b))) |(~a&b) & 0xA8 ^ 0x13 ^ (~(~a&b) & 0x44 | (~a&b) & 0x13) ^ (0 & (~(a&~b)) & 0x57 | ~(((~(a&~b)) & 0x52 | ~(~(a&~b)) & 5 | 0x80) ^ 0^ 0x7A))"*** Expression ~(~(~a&b) | (~(a&~b))) |(~a&b) & 0xA8 ^ 0x13 ^ (~(~a&b) & 0x44 | (~a&b) & 0x13) ^ (0 & (~(a&~b)) & 0x57 | ~(((~(a&~b)) & 0x52 | ~(~(a&~b)) & 5 | 0x80) ^ 0^ 0x7A))*** ... input is not considered linear*** ... verify via evaluation ... [====================] 100%*** ... verification successful!*** ... simplified to -256+(a^b)化简结果是 -256+(a^b) , 在八位无符号运算中, -256+(a^b)与 a ^ b是等价的。上面的代码可以转化为v17[i] ^= v13[v10] ,是标准 RC4 算法的一部分
控制流平坦化原理:将清晰的树状或网状控制流重构为一个基于状态机的单一大循环。所有基本块都被放入一个巨大的 switch 结构中,通过一个不透明的状态变量来控制执行流程的跳转。
下面的伪代码展示了控制流平坦化的基本原理:flag 变量用于控制程序在 switch 块中的执行流程
# 伪代码flag = 0while(1){ switch(flag){ case 0: { flag = 2; print("1")break; } case 1: { print("3")return; } case 2 :{ flag = 1; print("2")break; } }}使用以下命令对代码进行控制流平坦化编译:
../obfuscator/build_release/bin/clang test.c -mllvm -fla -mllvm -split -mllvm -split_num=3 -o test_fla混淆后的 CFG 图(Control Flow Graph , 控制流图 ),还挺好看的
下图来自 :利用符号执行去除控制流平坦化 - 安全动态 - 腾讯安全应急响应中心 https://security.tencent.com/index.php/blog/msg/112
这是一张经典的介绍控制流平坦化的图片
执行流程是 序言——>主分发器 -> 子分发器 -> 真实块 -> 预处理器 ->主分发器 --> ......
主分发器、子分发器、预处理器用来决定真实块的执行顺序
解混淆步骤
接下来我将使用 IDAPython 脚本解混淆
首先需要获取所有真实块的地址。预处理器的前驱是真实块
import idaapiimport idcmain_func = 0x401EC0# main 函数地址preprocessor_block = 0x4026A4# 预处理器地址true_blocks = []fake_blocks = []# f_blocks是控制流中的所有块信息f_block = idaapi.FlowChart(idaapi.get_func(main_func), flags=idaapi.FC_PREDS)for block in f_block:if block.start_ea==preprocessor_block:# 将预处理器存在虚假块中 fake_blocks.append((block.start_ea,idc.prev_head(block.end_ea))) print("find ture block!")# 预处理器的前驱,也就是真实块 tbs = block.preds()for tb in tbs: true_blocks.append((tb.start_ea,idc.prev_head(tb.end_ea)))# 如果这个块没有后继块,表示这个块是return块elifnot [x for x in block.succs()]: print("find ret block!") true_blocks.append((block.start_ea,idc.prev_head(block.end_ea)))elif block.start_ea!=main_func: fake_blocks.append((block.start_ea,idc.prev_head(block.end_ea)))print('true block:')print('tbs =',true_blocks)print('fake block:')print('fbs =',fake_blocks)运行结果
true block:tbs = [(4204185, 4204195), (4203137, 4203137), (4203142, 4203195), (4203200, 4203221), (4203226, 4203340), (4203345, 4203364), (4203369, 4203389), (4203394, 4203421), (4203426, 4203451), (4203456, 4203487), (4203492, 4203511), (4203516, 4203535), (4203540, 4203576), (4203581, 4203600), (4203605, 4203624), (4203629, 4203648), (4203653, 4203663), (4203668, 4203720), (4203725, 4203762), (4203767, 4203810), (4203815, 4203825), (4203830, 4203849), (4203854, 4203874), (4203879, 4203906), (4203911, 4203936), (4203941, 4203960), (4203965, 4203995), (4204000, 4204040), (4204045, 4204055), (4204060, 4204079), (4204084, 4204103), (4204108, 4204127), (4204132, 4204142), (4204147, 4204180)]fake block:fbs = [(4202204, 4202230), (4202236, 4202236), (4202241, 4202258), (4202264, 4202264), (4202269, 4202286), (4202292, 4202292), (4202297, 4202314), (4202320, 4202320), (4202325, 4202342), (4202348, 4202348), (4202353, 4202370), (4202376, 4202376), (4202381, 4202398), (4202404, 4202404), (4202409, 4202426), (4202432, 4202432), (4202437, 4202454), (4202460, 4202460), (4202465, 4202482), (4202488, 4202488), (4202493, 4202510), (4202516, 4202516), (4202521, 4202538), (4202544, 4202544), (4202549, 4202566), (4202572, 4202572), (4202577, 4202594), (4202600, 4202600), (4202605, 4202622), (4202628, 4202628), (4202633, 4202650), (4202656, 4202656), (4202661, 4202678), (4202684, 4202684), (4202689, 4202706), (4202712, 4202712), (4202717, 4202734), (4202740, 4202740), (4202745, 4202762), (4202768, 4202768), (4202773, 4202790), (4202796, 4202796), (4202801, 4202818), (4202824, 4202824), (4202829, 4202846), (4202852, 4202852), (4202857, 4202874), (4202880, 4202880), (4202885, 4202902), (4202908, 4202908), (4202913, 4202930), (4202936, 4202936), (4202941, 4202958), (4202964, 4202964), (4202969, 4202986), (4202992, 4202992), (4202997, 4203014), (4203020, 4203020), (4203025, 4203042), (4203048, 4203048), (4203053, 4203070), (4203076, 4203076), (4203081, 4203098), (4203104, 4203104), (4203109, 4203126), (4203132, 4203132), (4203137, 4203137), (4203142, 4203195), (4203200, 4203221), (4203226, 4203340), (4203345, 4203364), (4203369, 4203389), (4203394, 4203421), (4203426, 4203451), (4203456, 4203487), (4203492, 4203511), (4203516, 4203535), (4203540, 4203576), (4203581, 4203600), (4203605, 4203624), (4203629, 4203648), (4203653, 4203663), (4203668, 4203720), (4203725, 4203762), (4203767, 4203810), (4203815, 4203825), (4203830, 4203849), (4203854, 4203874), (4203879, 4203906), (4203911, 4203936), (4203941, 4203960), (4203965, 4203995), (4204000, 4204040), (4204045, 4204055), (4204060, 4204079), (4204084, 4204103), (4204108, 4204127), (4204132, 4204142), (4204147, 4204180), (4204196, 4204196)]接着通过 unicorn 模拟执行,得到真实块跳转到下一个真实块的地址。hook_code是一个回调函数。在第一个for循环中提取当前指令的机器码,如果当前执行的汇编代码是call,那么通过修改RIP寄存器的值,直接跳过该代码。如果是ret,表示main函数已执行完毕,此时停止模拟执行。 第二个for循环中,遍历所有的真实块,如果某一个真实块的最后一个地址tb[1]与address相同,表示该真实块刚刚执行完毕。记录下当前零标志位ZF,用于进行跳转判断
import networkx from unicorn import * from unicorn.x86_const import * from keystone import * # pip install keystone-engine from capstone import * # pip install capstone BASE = 0x400000CODE = BASE + 0x0CODE_SIZE = 0x100000STACK = 0x7F00000000STACK_SIZE = 0x100000FS = 0x7FF0000000FS_SIZE = 0x100000ks = Ks(KS_ARCH_X86, KS_MODE_64) # 汇编引擎 uc = Uc(UC_ARCH_X86, UC_MODE_64) # 模拟执行引擎 cs = Cs(CS_ARCH_X86, CS_MODE_64) # 反汇编引擎 # 上一步得到的真实块 tbs = [(4204185, 4204195), (4203137, 4203137), (4203142, 4203195), (4203200, 4203221), (4203226, 4203340), (4203345, 4203364), (4203369, 4203389), (4203394, 4203421), (4203426, 4203451), (4203456, 4203487), (4203492, 4203511), (4203516, 4203535), (4203540, 4203576), (4203581, 4203600), (4203605, 4203624), (4203629, 4203648), (4203653, 4203663), (4203668, 4203720), (4203725, 4203762), (4203767, 4203810), (4203815, 4203825), (4203830, 4203849), (4203854, 4203874), (4203879, 4203906), (4203911, 4203936), (4203941, 4203960), (4203965, 4203995), (4204000, 4204040), (4204045, 4204055), (4204060, 4204079), (4204084, 4204103), (4204108, 4204127), (4204132, 4204142), (4204147, 4204180)] tb_call = [] main_addr = 0x00000000000401EC0main_end = 0x000000000004026A9# 创建模拟器definituc(uc): uc.mem_map(CODE, CODE_SIZE, UC_PROT_ALL) uc.mem_map(STACK, STACK_SIZE, UC_PROT_ALL) uc.mem_write(CODE, CODE_DATA) uc.reg_write(UC_X86_REG_RSP, STACK + 0x1000) uc.hook_add(UC_HOOK_CODE, hook_code) uc.hook_add(UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED | UC_HOOK_MEM_FETCH_UNMAPPED, hook_mem_access) # -----------------------初始化结束---------------------------- defhook_code(uc: unicorn.Uc, address, size, user_data):for i in cs.disasm(CODE_DATA[address - BASE:address - BASE + size], address): if i.mnemonic == "call": print(f"find call at {hex(address)}, jump...") uc.reg_write(UC_X86_REG_RIP, address + size) elif i.mnemonic == "ret": print("find ret block, emu stop~") uc.emu_stop() print("block emu path↓↓↓↓") print(tb_call) for tb in tbs: if address == tb[1]: ZF_flag = (uc.reg_read(UC_X86_REG_FLAGS) & 0b1000000) >> 6 tb_call.append((tb, ZF_flag)) breakdefhook_mem_access(uc, access, address, size, value, user_data):"""Hook for memory access violations""" pc = uc.reg_read(UC_X86_REG_RIP) # 修正:用 RIP 而不是 RSP print(f'PC:{pc:x} Access:{access} Addr:{address:x} Size:{size:x} Value:{value:x}') returnTrue# 返回 True 继续执行 #----------------代码执行--------------------------------- with open(r"C:\Users\24526\Desktop\网安\安卓逆向\ollvm\test_fla", 'rb') as f: CODE_DATA = f.read() inituc(uc) try: uc.emu_start(main_addr, main_end) except Exception as e: print(e)运行结果
[((4203142, 4203195), 1), ((4203200, 4203221), 1), ((4203226, 4203340), 1), ((4203345, 4203364), 1), ((4203369, 4203389), 1), ((4203394, 4203421), 0), ((4203426, 4203451), 0), ((4203456, 4203487), 0), ((4203492, 4203511), 1), ((4203516, 4203535), 1), ((4203540, 4203576), 1), ((4203581, 4203600), 1), ((4203605, 4203624), 0), ((4203629, 4203648), 1), ((4203653, 4203663), 1), ((4203345, 4203364), 1), ((4203369, 4203389), 1), ((4203394, 4203421), 0), ((4203426, 4203451), 0), ((4203456, 4203487), 0), ((4203492, 4203511), 1), ((4203516, 4203535), 1), ((4203540, 4203576), 1), ((4203581, 4203600), 1), ((4203605, 4203624), 0), ((4203629, 4203648), 1), ((4203653, 4203663), 1), ((4203345, 4203364), 1), ((4203369, 4203389), 1), ((4203394, 4203421), 0), ((4203426, 4203451), 0), ((4203456, 4203487), 0), ((4203492, 4203511), 1), ((4203516, 4203535), 1), ((4203540, 4203576), 1), ((4203581, 4203600), 1), ((4203605, 4203624), 0), ((4203629, 4203648), 1), ((4203653, 4203663), 1), ((4203345, 4203364), 1), ((4203369, 4203389), 1), ((4203394, 4203421), 0), ((4203426, 4203451), 0), ((4203456, 4203487), 0), ((4203492, 4203511), 1), ((4203516, 4203535), 1), ((4203540, 4203576), 1), ((4203581, 4203600), 1), ((4203605, 4203624), 0), ((4203629, 4203648), 1), ((4203653, 4203663), 1), ((4203345, 4203364), 1), ((4203369, 4203389), 1), ((4203394, 4203421), 0), ((4203426, 4203451), 0), ((4203456, 4203487), 0), ((4203492, 4203511), 1), ((4203516, 4203535), 1), ((4203540, 4203576), 1), ((4203581, 4203600), 1), ((4203605, 4203624), 0), ((4203629, 4203648), 1), ((4203653, 4203663), 1), ((4203345, 4203364), 1), ((4203369, 4203389), 1), ((4203394, 4203421), 0), ((4203426, 4203451), 0), ((4203456, 4203487), 0), ((4203492, 4203511), 1), ((4203516, 4203535), 1), ((4203540, 4203576), 1), ((4203581, 4203600), 1), ((4203605, 4203624), 0), ((4203629, 4203648), 1), ((4203653, 4203663), 1), ((4203345, 4203364), 1), ((4203369, 4203389), 1), ((4203394, 4203421), 0), ((4203426, 4203451), 0), ((4203456, 4203487), 0), ((4203492, 4203511), 1), ((4203516, 4203535), 1), ((4203540, 4203576), 1), ((4203581, 4203600), 1), ((4203605, 4203624), 0), ((4203629, 4203648), 1), ((4203653, 4203663), 1), ((4203345, 4203364), 1), ((4203369, 4203389), 1), ((4203394, 4203421), 0), ((4203426, 4203451), 0), ((4203456, 4203487), 0), ((4203492, 4203511), 1), ((4203516, 4203535), 1), ((4203540, 4203576), 1), ((4203581, 4203600), 1), ((4203605, 4203624), 0), ((4203629, 4203648), 1), ((4203653, 4203663), 1), ((4203345, 4203364), 1), ((4203369, 4203389), 1), ((4203394, 4203421), 0), ((4203426, 4203451), 0), ((4203456, 4203487), 0), ((4203492, 4203511), 1), ((4203516, 4203535), 1), ((4203540, 4203576), 1), ((4203581, 4203600), 1), ((4203605, 4203624), 0), ((4203629, 4203648), 1), ((4203653, 4203663), 1), ((4203345, 4203364), 1), ((4203369, 4203389), 1), ((4203394, 4203421), 0), ((4203426, 4203451), 0), ((4203456, 4203487), 0), ((4203492, 4203511), 1), ((4203516, 4203535), 1), ((4203540, 4203576), 1), ((4203581, 4203600), 1), ((4203605, 4203624), 0), ((4203629, 4203648), 1), ((4203653, 4203663), 1), ((4203345, 4203364), 1), ((4203369, 4203389), 1), ((4203394, 4203421), 0), ((4203426, 4203451), 0), ((4203456, 4203487), 0), ((4203492, 4203511), 1), ((4203516, 4203535), 1), ((4203540, 4203576), 1), ((4203581, 4203600), 1), ((4203605, 4203624), 0), ((4203629, 4203648), 1), ((4203653, 4203663), 1), ((4203345, 4203364), 1), ((4203369, 4203389), 1), ((4203394, 4203421), 1), ((4203426, 4203451), 1), ((4203668, 4203720), 1), ((4203725, 4203762), 1), ((4203767, 4203810), 1), ((4203815, 4203825), 1), ((4203830, 4203849), 1), ((4203854, 4203874), 1), ((4203879, 4203906), 0), ((4203911, 4203936), 0), ((4203941, 4203960), 1), ((4203965, 4203995), 0), ((4204000, 4204040), 1), ((4204045, 4204055), 1), ((4204060, 4204079), 1), ((4204084, 4204103), 0), ((4204108, 4204127), 1), ((4204132, 4204142), 1), ((4203830, 4203849), 1), ((4203854, 4203874), 1), ((4203879, 4203906), 0), ((4203911, 4203936), 0), ((4203941, 4203960), 1), ((4203965, 4203995), 0), ((4204000, 4204040), 1), ((4204045, 4204055), 1), ((4204060, 4204079), 1), ((4204084, 4204103), 0), ((4204108, 4204127), 1), ((4204132, 4204142), 1), ((4203830, 4203849), 1), ((4203854, 4203874), 1), ((4203879, 4203906), 0), ((4203911, 4203936), 0), ((4203941, 4203960), 1), ((4203965, 4203995), 0), ((4204000, 4204040), 1), ((4204045, 4204055), 1), ((4204060, 4204079), 1), ((4204084, 4204103), 0), ((4204108, 4204127), 1), ((4204132, 4204142), 1), ((4203830, 4203849), 1), ((4203854, 4203874), 1), ((4203879, 4203906), 0), ((4203911, 4203936), 0), ((4203941, 4203960), 1), ((4203965, 4203995), 0), ((4204000, 4204040), 1), ((4204045, 4204055), 1), ((4204060, 4204079), 1), ((4204084, 4204103), 0), ((4204108, 4204127), 1), ((4204132, 4204142), 1), ((4203830, 4203849), 1), ((4203854, 4203874), 1), ((4203879, 4203906), 0), ((4203911, 4203936), 0), ((4203941, 4203960), 1), ((4203965, 4203995), 0), ((4204000, 4204040), 1), ((4204045, 4204055), 1), ((4204060, 4204079), 1), ((4204084, 4204103), 0), ((4204108, 4204127), 1), ((4204132, 4204142), 1), ((4203830, 4203849), 1), ((4203854, 4203874), 1), ((4203879, 4203906), 0), ((4203911, 4203936), 0), ((4203941, 4203960), 1), ((4203965, 4203995), 0), ((4204000, 4204040), 1), ((4204045, 4204055), 1), ((4204060, 4204079), 1), ((4204084, 4204103), 0), ((4204108, 4204127), 1), ((4204132, 4204142), 1), ((4203830, 4203849), 1), ((4203854, 4203874), 1), ((4203879, 4203906), 0), ((4203911, 4203936), 0), ((4203941, 4203960), 1), ((4203965, 4203995), 0), ((4204000, 4204040), 1), ((4204045, 4204055), 1), ((4204060, 4204079), 1), ((4204084, 4204103), 0), ((4204108, 4204127), 1), ((4204132, 4204142), 1), ((4203830, 4203849), 1), ((4203854, 4203874), 1), ((4203879, 4203906), 0), ((4203911, 4203936), 0), ((4203941, 4203960), 1), ((4203965, 4203995), 0), ((4204000, 4204040), 1), ((4204045, 4204055), 1), ((4204060, 4204079), 1), ((4204084, 4204103), 0), ((4204108, 4204127), 1), ((4204132, 4204142), 1), ((4203830, 4203849), 1), ((4203854, 4203874), 1), ((4203879, 4203906), 0), ((4203911, 4203936), 0), ((4203941, 4203960), 1), ((4203965, 4203995), 0), ((4204000, 4204040), 1), ((4204045, 4204055), 1), ((4204060, 4204079), 1), ((4204084, 4204103), 0), ((4204108, 4204127), 1), ((4204132, 4204142), 1), ((4203830, 4203849), 1), ((4203854, 4203874), 1), ((4203879, 4203906), 0), ((4203911, 4203936), 0), ((4203941, 4203960), 1), ((4203965, 4203995), 0), ((4204000, 4204040), 1), ((4204045, 4204055), 1), ((4204060, 4204079), 1), ((4204084, 4204103), 0), ((4204108, 4204127), 1), ((4204132, 4204142), 1), ((4203830, 4203849), 1), ((4203854, 4203874), 1), ((4203879, 4203906), 0), ((4203911, 4203936), 0), ((4203941, 4203960), 1), ((4203965, 4203995), 0), ((4204000, 4204040), 1), ((4204045, 4204055), 1), ((4204060, 4204079), 1), ((4204084, 4204103), 0), ((4204108, 4204127), 1), ((4204132, 4204142), 1), ((4203830, 4203849), 1), ((4203854, 4203874), 1), ((4203879, 4203906), 1), ((4203911, 4203936), 1), ((4204147, 4204180), 1)]最后需要 patch IDA 中的代码
添加系统路径,让 IDA 可以使用 pip 安装的库
Python>import sysPython>sys.path.append(r'D:\practice_code\PythonReverse\.venv\Lib\site-packages')在 IDAPython 中运行代码
import idaapiimport ida_bytesimport idcfrom keystone import *ks = Ks(KS_ARCH_X86, KS_MODE_64) defjmp_patch(start, target, j_code="jmp"):global debug patch_byte, count = ks.asm(f"{j_code}{hex(target)}", addr=start) patch_byte = bytes(patch_byte) + b'\x00' * (idc.get_item_size(start) - len(patch_byte)) print(hex(start), f"{j_code}{hex(target)}", patch_byte) ida_bytes.patch_bytes(start, patch_byte)defpatch_nop(addr, endaddr):#print(f"Patching from {addr} to {endaddr}")while addr < endaddr: ida_bytes.patch_byte(addr, 0x90) addr += 1defpatch_nop_line(addr): patch_nop(addr,addr+idc.get_item_size(addr))preamble_block = 0x401EDC# 主分发器的起始地址internal_reg = '[rbp+var_A0]'#中间变量的名称tb_path = [((4203142, 4203195), 1), ((4203200, 4203221), 1), ((4203226, 4203340), 1), ((4203345, 4203364), 1), ((4203369, 4203389), 1), ((4203394, 4203421), 0), ((4203426, 4203451), 0), ((4203456, 4203487), 0), ((4203492, 4203511), 1), ((4203516, 4203535), 1), ((4203540, 4203576), 1), ((4203581, 4203600), 1), ((4203605, 4203624), 0), ((4203629, 4203648), 1), ((4203653, 4203663), 1), ((4203345, 4203364), 1), ((4203369, 4203389), 1), ((4203394, 4203421), 0), ((4203426, 4203451), 0), ((4203456, 4203487), 0), ((4203492, 4203511), 1), ((4203516, 4203535), 1), ((4203540, 4203576), 1), ((4203581, 4203600), 1), ((4203605, 4203624), 0), ((4203629, 4203648), 1), ((4203653, 4203663), 1), ((4203345, 4203364), 1), ((4203369, 4203389), 1), ((4203394, 4203421), 0), ((4203426, 4203451), 0), ((4203456, 4203487), 0), ((4203492, 4203511), 1), ((4203516, 4203535), 1), ((4203540, 4203576), 1), ((4203581, 4203600), 1), ((4203605, 4203624), 0), ((4203629, 4203648), 1), ((4203653, 4203663), 1), ((4203345, 4203364), 1), ((4203369, 4203389), 1), ((4203394, 4203421), 0), ((4203426, 4203451), 0), ((4203456, 4203487), 0), ((4203492, 4203511), 1), ((4203516, 4203535), 1), ((4203540, 4203576), 1), ((4203581, 4203600), 1), ((4203605, 4203624), 0), ((4203629, 4203648), 1), ((4203653, 4203663), 1), ((4203345, 4203364), 1), ((4203369, 4203389), 1), ((4203394, 4203421), 0), ((4203426, 4203451), 0), ((4203456, 4203487), 0), ((4203492, 4203511), 1), ((4203516, 4203535), 1), ((4203540, 4203576), 1), ((4203581, 4203600), 1), ((4203605, 4203624), 0), ((4203629, 4203648), 1), ((4203653, 4203663), 1), ((4203345, 4203364), 1), ((4203369, 4203389), 1), ((4203394, 4203421), 0), ((4203426, 4203451), 0), ((4203456, 4203487), 0), ((4203492, 4203511), 1), ((4203516, 4203535), 1), ((4203540, 4203576), 1), ((4203581, 4203600), 1), ((4203605, 4203624), 0), ((4203629, 4203648), 1), ((4203653, 4203663), 1), ((4203345, 4203364), 1), ((4203369, 4203389), 1), ((4203394, 4203421), 0), ((4203426, 4203451), 0), ((4203456, 4203487), 0), ((4203492, 4203511), 1), ((4203516, 4203535), 1), ((4203540, 4203576), 1), ((4203581, 4203600), 1), ((4203605, 4203624), 0), ((4203629, 4203648), 1), ((4203653, 4203663), 1), ((4203345, 4203364), 1), ((4203369, 4203389), 1), ((4203394, 4203421), 0), ((4203426, 4203451), 0), ((4203456, 4203487), 0), ((4203492, 4203511), 1), ((4203516, 4203535), 1), ((4203540, 4203576), 1), ((4203581, 4203600), 1), ((4203605, 4203624), 0), ((4203629, 4203648), 1), ((4203653, 4203663), 1), ((4203345, 4203364), 1), ((4203369, 4203389), 1), ((4203394, 4203421), 0), ((4203426, 4203451), 0), ((4203456, 4203487), 0), ((4203492, 4203511), 1), ((4203516, 4203535), 1), ((4203540, 4203576), 1), ((4203581, 4203600), 1), ((4203605, 4203624), 0), ((4203629, 4203648), 1), ((4203653, 4203663), 1), ((4203345, 4203364), 1), ((4203369, 4203389), 1), ((4203394, 4203421), 0), ((4203426, 4203451), 0), ((4203456, 4203487), 0), ((4203492, 4203511), 1), ((4203516, 4203535), 1), ((4203540, 4203576), 1), ((4203581, 4203600), 1), ((4203605, 4203624), 0), ((4203629, 4203648), 1), ((4203653, 4203663), 1), ((4203345, 4203364), 1), ((4203369, 4203389), 1), ((4203394, 4203421), 0), ((4203426, 4203451), 0), ((4203456, 4203487), 0), ((4203492, 4203511), 1), ((4203516, 4203535), 1), ((4203540, 4203576), 1), ((4203581, 4203600), 1), ((4203605, 4203624), 0), ((4203629, 4203648), 1), ((4203653, 4203663), 1), ((4203345, 4203364), 1), ((4203369, 4203389), 1), ((4203394, 4203421), 1), ((4203426, 4203451), 1), ((4203668, 4203720), 1), ((4203725, 4203762), 1), ((4203767, 4203810), 1), ((4203815, 4203825), 1), ((4203830, 4203849), 1), ((4203854, 4203874), 1), ((4203879, 4203906), 0), ((4203911, 4203936), 0), ((4203941, 4203960), 1), ((4203965, 4203995), 0), ((4204000, 4204040), 1), ((4204045, 4204055), 1), ((4204060, 4204079), 1), ((4204084, 4204103), 0), ((4204108, 4204127), 1), ((4204132, 4204142), 1), ((4203830, 4203849), 1), ((4203854, 4203874), 1), ((4203879, 4203906), 0), ((4203911, 4203936), 0), ((4203941, 4203960), 1), ((4203965, 4203995), 0), ((4204000, 4204040), 1), ((4204045, 4204055), 1), ((4204060, 4204079), 1), ((4204084, 4204103), 0), ((4204108, 4204127), 1), ((4204132, 4204142), 1), ((4203830, 4203849), 1), ((4203854, 4203874), 1), ((4203879, 4203906), 0), ((4203911, 4203936), 0), ((4203941, 4203960), 1), ((4203965, 4203995), 0), ((4204000, 4204040), 1), ((4204045, 4204055), 1), ((4204060, 4204079), 1), ((4204084, 4204103), 0), ((4204108, 4204127), 1), ((4204132, 4204142), 1), ((4203830, 4203849), 1), ((4203854, 4203874), 1), ((4203879, 4203906), 0), ((4203911, 4203936), 0), ((4203941, 4203960), 1), ((4203965, 4203995), 0), ((4204000, 4204040), 1), ((4204045, 4204055), 1), ((4204060, 4204079), 1), ((4204084, 4204103), 0), ((4204108, 4204127), 1), ((4204132, 4204142), 1), ((4203830, 4203849), 1), ((4203854, 4203874), 1), ((4203879, 4203906), 0), ((4203911, 4203936), 0), ((4203941, 4203960), 1), ((4203965, 4203995), 0), ((4204000, 4204040), 1), ((4204045, 4204055), 1), ((4204060, 4204079), 1), ((4204084, 4204103), 0), ((4204108, 4204127), 1), ((4204132, 4204142), 1), ((4203830, 4203849), 1), ((4203854, 4203874), 1), ((4203879, 4203906), 0), ((4203911, 4203936), 0), ((4203941, 4203960), 1), ((4203965, 4203995), 0), ((4204000, 4204040), 1), ((4204045, 4204055), 1), ((4204060, 4204079), 1), ((4204084, 4204103), 0), ((4204108, 4204127), 1), ((4204132, 4204142), 1), ((4203830, 4203849), 1), ((4203854, 4203874), 1), ((4203879, 4203906), 0), ((4203911, 4203936), 0), ((4203941, 4203960), 1), ((4203965, 4203995), 0), ((4204000, 4204040), 1), ((4204045, 4204055), 1), ((4204060, 4204079), 1), ((4204084, 4204103), 0), ((4204108, 4204127), 1), ((4204132, 4204142), 1), ((4203830, 4203849), 1), ((4203854, 4203874), 1), ((4203879, 4203906), 0), ((4203911, 4203936), 0), ((4203941, 4203960), 1), ((4203965, 4203995), 0), ((4204000, 4204040), 1), ((4204045, 4204055), 1), ((4204060, 4204079), 1), ((4204084, 4204103), 0), ((4204108, 4204127), 1), ((4204132, 4204142), 1), ((4203830, 4203849), 1), ((4203854, 4203874), 1), ((4203879, 4203906), 0), ((4203911, 4203936), 0), ((4203941, 4203960), 1), ((4203965, 4203995), 0), ((4204000, 4204040), 1), ((4204045, 4204055), 1), ((4204060, 4204079), 1), ((4204084, 4204103), 0), ((4204108, 4204127), 1), ((4204132, 4204142), 1), ((4203830, 4203849), 1), ((4203854, 4203874), 1), ((4203879, 4203906), 0), ((4203911, 4203936), 0), ((4203941, 4203960), 1), ((4203965, 4203995), 0), ((4204000, 4204040), 1), ((4204045, 4204055), 1), ((4204060, 4204079), 1), ((4204084, 4204103), 0), ((4204108, 4204127), 1), ((4204132, 4204142), 1), ((4203830, 4203849), 1), ((4203854, 4203874), 1), ((4203879, 4203906), 0), ((4203911, 4203936), 0), ((4203941, 4203960), 1), ((4203965, 4203995), 0), ((4204000, 4204040), 1), ((4204045, 4204055), 1), ((4204060, 4204079), 1), ((4204084, 4204103), 0), ((4204108, 4204127), 1), ((4204132, 4204142), 1), ((4203830, 4203849), 1), ((4203854, 4203874), 1), ((4203879, 4203906), 1), ((4203911, 4203936), 1), ((4204147, 4204180), 1)]tbs = [(4204185, 4204195), (4203137, 4203137), (4203142, 4203195), (4203200, 4203221), (4203226, 4203340), (4203345, 4203364), (4203369, 4203389), (4203394, 4203421), (4203426, 4203451), (4203456, 4203487), (4203492, 4203511), (4203516, 4203535), (4203540, 4203576), (4203581, 4203600), (4203605, 4203624), (4203629, 4203648), (4203653, 4203663), (4203668, 4203720), (4203725, 4203762), (4203767, 4203810), (4203815, 4203825), (4203830, 4203849), (4203854, 4203874), (4203879, 4203906), (4203911, 4203936), (4203941, 4203960), (4203965, 4203995), (4204000, 4204040), (4204045, 4204055), (4204060, 4204079), (4204084, 4204103), (4204108, 4204127), (4204132, 4204142), (4204147, 4204180)]fbs = [(4202204, 4202230), (4202236, 4202236), (4202241, 4202258), (4202264, 4202264), (4202269, 4202286), (4202292, 4202292), (4202297, 4202314), (4202320, 4202320), (4202325, 4202342), (4202348, 4202348), (4202353, 4202370), (4202376, 4202376), (4202381, 4202398), (4202404, 4202404), (4202409, 4202426), (4202432, 4202432), (4202437, 4202454), (4202460, 4202460), (4202465, 4202482), (4202488, 4202488), (4202493, 4202510), (4202516, 4202516), (4202521, 4202538), (4202544, 4202544), (4202549, 4202566), (4202572, 4202572), (4202577, 4202594), (4202600, 4202600), (4202605, 4202622), (4202628, 4202628), (4202633, 4202650), (4202656, 4202656), (4202661, 4202678), (4202684, 4202684), (4202689, 4202706), (4202712, 4202712), (4202717, 4202734), (4202740, 4202740), (4202745, 4202762), (4202768, 4202768), (4202773, 4202790), (4202796, 4202796), (4202801, 4202818), (4202824, 4202824), (4202829, 4202846), (4202852, 4202852), (4202857, 4202874), (4202880, 4202880), (4202885, 4202902), (4202908, 4202908), (4202913, 4202930), (4202936, 4202936), (4202941, 4202958), (4202964, 4202964), (4202969, 4202986), (4202992, 4202992), (4202997, 4203014), (4203020, 4203020), (4203025, 4203042), (4203048, 4203048), (4203053, 4203070), (4203076, 4203076), (4203081, 4203098), (4203104, 4203104), (4203109, 4203126), (4203132, 4203132), (4203137, 4203137), (4203142, 4203195), (4203200, 4203221), (4203226, 4203340), (4203345, 4203364), (4203369, 4203389), (4203394, 4203421), (4203426, 4203451), (4203456, 4203487), (4203492, 4203511), (4203516, 4203535), (4203540, 4203576), (4203581, 4203600), (4203605, 4203624), (4203629, 4203648), (4203653, 4203663), (4203668, 4203720), (4203725, 4203762), (4203767, 4203810), (4203815, 4203825), (4203830, 4203849), (4203854, 4203874), (4203879, 4203906), (4203911, 4203936), (4203941, 4203960), (4203965, 4203995), (4204000, 4204040), (4204045, 4204055), (4204060, 4204079), (4204084, 4204103), (4204108, 4204127), (4204132, 4204142), (4204147, 4204180), (4204196, 4204196)]block_info = {} #判断有没有 patch 结束for i in range(len(tbs)): block_info[tbs[i][0]] = {'finish': 0,'ret':0}#nop 掉所有无用块for fb in fbs: patch_nop(fb[1], fb[1] + idc.get_item_size(fb[1]))# 遍历所有真实块for tb in tbs: dont_patch = False current_addr = tb[0]# nop真实块的cmov指令和状态变量while current_addr <= tb[1]:# print(hex(current_addr),idc.GetDisasm(current_addr))if"cmov"in idc.print_insn_mnem(current_addr):#cmov 指令会影响分支跳转,所以这里直接 patch 掉 patch_nop_line(current_addr) dont_patch = True# print(hex(current_addr),hex(tb_path[i][0]))elif internal_reg in idc.print_operand(current_addr, 0): print('find internal_reg!') patch_nop_line(current_addr)elif'ret'in idc.print_insn_mnem(current_addr): block_info[tb[0]]['ret'] = 1 dont_patch = True current_addr = idc.next_head(current_addr)ifnot dont_patch: patch_nop_line(tb[1]) block_info[tb[0]]['finish'] = 1# 将主选择器的开头替换成第一个真实块jmp_patch(preamble_block, tb_path[0][0][0])for i in range(len(tb_path) - 1):# 不是返回块,也未完成 patch, 剩下的指令都是有分支跳转的.if block_info[tb_path[i][0][0]]['finish'] == 0andnot block_info[tb_path[i][0][0]]['ret']: ZF = tb_path[i][1]#当要跳转的块和当前块不连续时,这个分支跳转才修复完成ifnot idc.next_head(tb_path[i][0][1]) == tb_path[i + 1][0][0]: block_info[tb_path[i][0][0]]['finish'] = 1 j_code = ('jnz', 'jz') jmp_patch(tb_path[i][0][1], tb_path[i + 1][0][0], j_code[ZF])成功去混淆:)