之前写过了混淆pass和去除案例,但多为windows上的一些样本,所以这篇文章写了三个安卓去混淆案例
应用为小*书,版本是目前最新(936084)
目标去除函数是sub_81CC4函数,这是sheid生成算法中比较关键的一个函数,但被大量复杂混淆,无法分析其中逻辑。我们以它为例,演示如何去除这种混淆
在之前的文章中使用idc脚本自动断点的方式来处理间接跳转,安卓逆向中可以使用firda来代替。
先用idc脚本搜集想要hook的跳转地址和寄存器
再写firda脚本hook值即可
部分输出如下
这个表同时也是执行跳转的顺序,对接下来的恢复很有帮助。
得到跳转表之后,因为循环比较多,所以对跳转表进行一个去重,最后只剩下100条跳转地址
从第一个跳转地址开始看起,
0x831e8对应的跳转地址是0x831F4
但是观察去重后的跳转表,0x831F4会跳到多个不同地址。这样无法找出唯一对应的地址。而这处跳转的计算和寄存器x27有关

返回0x81d88处观察x27

x27是定值,最终跳转的肯定也是一个唯一固定的地址。再观察顺序跳转表
由此可以得到最终跳转关系为:0x81d88 -> 0x831e8 -> 0x831f8
0x831e8这个块只是一个分发块,没有实际作用,所以这其实是一种控制流平坦化 + 间接跳转混淆
接下来继续找类似这种结构的跳转关系
跳入分发块:
跳出分发块:
实际执行顺序
这样就可以得到最终的执行顺序:
写一个脚本批量重复这个过程即可得到真实跳转关系
不过在这个过程中我们可以发现神奇的一点

最终跳转的地址就是上面赋值用来计算的地址。这样的话都不需要根据trace表来分析, 直接根据特征写脚本patch就可以了(谜底就在谜面上这一块)
搞定了这种fla + idr的A -> 分发块 -> B跳转关系,还有多目标块A -> B -> C / A -> B -> D需要修复,这种是因为条件跳转导致的

上面的两个函数是要跳转的目标,条件是NE,但是我们很难确定哪个是满足条件后的跳转目标,这个时候可以再trace一遍。因为这个混淆中所有的条件跳转结尾都是
hook打印这个地方的值
w8和w30相同,说明不满足NE
观察顺序跳转表
不满足NE条件时最终会跳到0x82080这个函数
可知B.NE 0x84058 B 0x82080
这样两种混淆就全部解决了。
去混淆后的部分代码如下

逻辑清晰,可识别出算法
应用为*幸咖啡,版本是网上找的一个旧版
以md5算法的外层函数为示例。
观察cfg图,可以看出明显是控制流平坦化

去除控制流平坦化只有三步
1.计算基本块下一跳转块的case值
2.遍历分发块找到对应地址
3.patch
先来看一下基本块和分发块的特征
基本块
单后继
双后继
分发块
或
如果用同一种LLVM Pass来混淆函数的话,汇编层面往往指令相同。
简单观察特征之后就可以发现,这个函数基本块单后继都是mov + stur + movk的这种结构,多后继块都是cesl + b的结构(多后继的典型特征就是csel / cmov 汇编),所以根据特征不难定位后继块,可以写一个脚本提取出case值和跳转地址
输出:
这样就提取出了函数中所有单后继基本块跳转地址和下一个基本块的case值
稍微修改一下得到多后继的
输出:
分发块全部以mov w9,imm + cmp w8,w9这样的结构开头。不过有一种分发块需要注意
如果case值和这里的0xF8D34334相等,那么最后会跳转到loc_43C34,这是什么地方呢

是开始分发的地方。所以这里的逻辑其实是basicBlock -> dispatchBlock -> dispatchBlock -> basicBlock,而不是经典的basicBlock -> dispatchBlock -> basicBlock。多分发了一次。
写出idc脚本提取值
输出:
现在我们有了这两张表,应该怎么使用呢,以具体的例子观察一下
所以 0x43CC4 -> 0x44338
再具体的观察一下,可以发现所有的case值对应的条件都是B.EQ / B.NE,条件跳转完全是吓唬人的,没有起到实际作用。之前我文章中提到的那种魔改控制流平坦化混淆才是真的使用大于小于来分发case值。
使用python脚本批量处理这两个表
我python水平一般,写的脚本比较丑陋,大家见谅(≧﹏ ≦)
输出跳转关系表如下
根据这张表patch代码即可。效果如下

恢复后的cfg图

这是MD5函数的外层函数,内层算法混淆和这种是一样的,这里就不再展示了
目标为鹅的反作弊so文件,被间接跳转和控制流平坦化保护。由于不好动态,所以我们纯静态的去除这两种混淆
间接跳转
先观察是如何进行间接跳转混淆的
X23是函数表,根据计算出的偏移对其进行查找
偏移的计算公式为 (imm + num) ^ imm。除了加法外还有其他计算,sub、or等
每个函数只对函数表赋一次值,如果看到附近其它块也以X23为基址寻找跳转函数,大概率都是21094C这个函数的

计算的值不一定是常数,还有可能是通过寄存器计算。
通过观察我们可以发现,不是所有的块都对函数表进行了赋值,被间接跳转切割的块全部使用同一个寄存器作为跳转表,因此,同一个函数的块都是相连在一起的。

[招生]科锐逆向工程师培训(2026年7月3日实地,远程教学同时开班, 第56期)!
最后于 1天前
被mb_wckjnnha编辑
,原因: