许多年之后,面对IDA的F5,奋飞将会想起,老李老板甩给他一本80x86汇编的那个遥远的下午。git
那时的App的名字还叫exe、com。Asm程序员最后的荣光,就是面对黑洞洞的屏幕敲下DEBUG的那个不眠之夜。程序员
后来App更名叫pe、elf了。IDA F5一下就是C程序员的狂欢,Asm程序员只能黯淡落幕了。默默的抱起小李老板新买的《C语言程序设计》。github
时代的车轮呼啸而过,瑞士的同行给咱们上了一课,ollvm一下,你妈都认不出来你了。json
ollvm纪元都已经10年了,如今的混淆只有更狠,没有最狠。api
谁来还我源代码?还得是 IDA F5 ,当年横空出世的时候喊人家小甜甜,如今赶上ollvm了,就喊人家牛夫人了。牛夫人也有变身的时候。缓存
是的,我知道你在用 7.5。安全
git clone https://gitlab.com/eshard/d810.git
复制代码
把d810文件夹和D810.py文件一块儿放到 C:\fenfei\IDAPro7_5\plugins 目录下面。微信
而后做者强烈建议安装 z3markdown
pip3 install z3-solver
复制代码
打开心爱的IDA,载入样本 blog_instruction_obfuscation_sub1.bin, 而后 File->Script File... 选中 D810.py 跑一下,最后 Ctrl-Shift-D ,神器出现了。函数
Current file loaded 中选择配置文件 default_instruction_only.json
而后点击 ”Start“ 按钮,再 F5一下, 见证奇迹的时刻来了。
虽然看上去还不是很帅,可是起码他妈应该能认出他来了。
为啥有的小伙伴即便都配置好了D810,可是F5以后仍是没有变化?
那是由于IDA F5有缓存,你以前已经F5过了,再来一次不会走D810插件,还会走原来的缓存。
那怎么删除这个F5的缓存呢? 这个,我也不知道。
可是飞哥找到了一个等效的方法。
这下再F5就会从新生成,走D810的加强结果了。
完美收工……
李老板: 奋飞呀,你就这么结束也太水了吧。这种文章我都很差意思 转发,严重影响我大佬的人设。
奋飞:老板说的有道理,使用开源工具,不读他的源码是对做者的不尊重。
咱们先来聊聊 IDA Microcode, 他是一种中间语言,从反汇编出来的汇编代码到F5生成漂亮的C代码,中间要通过屡次的Microcode转换。
举个例子,生米煮成熟饭(说你呢,别想歪了),在萌新看来,就是大米 biu~~ 一下就成米饭了。可是立志成为老鸟的小伙伴就要分析一下了, 大米加水后会膨胀,成熟度1度的时候,大米刚刚有点发白,成熟度2度的时候,大米表皮变软,成熟度n度的时候,才是香喷喷的米饭。
若是咱们在成熟度2度的时候,给锅里加点葡萄干,那么最后出来的米饭会不会更帅?
Microcode把 ASM -> C 的过程分红了多个成熟度,每一个成熟度提供api给你hook,你能够本身加点料。这样最后出来的C代码就更可口了。
此次的新朋友是 github.com/gaasedelen/…
明明白白的查看各个成熟度的微码,方便你夹私货。
Microcode聊完了,咱们再聊聊D810小甜甜的原理。
D810主要作了两步,一步是指令替换
混淆后的代码里面有大量这种模式的代码,只要用点小学数学知识,咱们就能换算出
而后把对应的代码替换掉不就好了?
在 d810/ast.py 中用 AstNode 对象来表示一个算式
好比 x+y 用 AstNode表示就是
# x+y
AstNode(m_add,
AstLeaf("x_0"),
AstLeaf("x_1"))
# (x + y) - 2 * (x & y)
AstNode(m_sub,
AstNode(m_add,
AstLeaf("x_0"),
AstLeaf("x_1")),
AstNode(m_mul,
AstConstant("2", 2),
AstNode(m_and,
AstLeaf("x_0"),
AstLeaf("x_1"))))
复制代码
这样抽象出来以后,你从 d810/optimizers/instructions/pattern_matching 下面就能够翻到一堆指令替换的代码了。
D810作的第二步,是流程重组,相似咱们以前 91fans.com.cn/post/disoll… 分析的那样,找到 主分发器和真实块,而后重组正确的流程。
这一步的实如今 d810/optimizers/flow 里面
说那那么多,咱们来动手给d810再加点料。
刚才分析的 obfucated_full_example 还不是很帅,
while ( ((v3 | 0xFFFFFFFA) & ~(((v3 - 5) | v3 ^ 0xFFFFFFFA) & (v3 ^ (v3 - 5) ^ 5)) & 0x80000000) == 0 )
复制代码
这行代码看上去应该也是能够优化的
在 \d810_logs\pattern_guess.log 的日志里面,他有提示咱们 (~((x_0 - 5)) | (x_0 ^ 5)) 这一步是能够优化的。
小学数学登场
(~((x_0 - 5)) | (x_0 ^ 5)) == 1
复制代码
飞哥,我小学数学是体育老师教的,你会不会骗我?
说好的信任呢? 来吧, 介绍一位新朋友 github.com/quarkslab/a…
专治小学数学不服
那就开始写代码吧
class FFRule0(PatternMatchingRule):
PATTERN = AstNode(m_or,
AstNode(m_bnot,
AstNode(m_sub,
AstLeaf('x_0'),
AstConstant('5', 5))),
AstNode(m_xor,
AstLeaf('x_0'),
AstConstant('5', 5)))
REPLACEMENT_PATTERN = AstNode(m_mov, AstConstant("val_1"))
def check_candidate(self, candidate):
candidate.add_constant_leaf("val_1", 1, candidate.size)
return True
复制代码
而后配置上咱们新的规则
再看看加强plus的结果:
欧耶,漂亮多了。
小学数学很重要。
通常状况下做者推荐用 default_instruction_only.json ,等你搞明白了,能够本身搭配配置,小孩子才作选择,成年人全都要。是不行的,全部配置都加上慢的一比不说,还会增长崩溃的概率。
没有一劳永逸直接F5就出来漂亮源码的办法,IDA的F5已经作了不少的工做,攻防老是在不断升级的,武器是战争的重要因素,但不是决定因素,决定的因素是人不是物。
参考连接:
D810:为 IDA Pro 建立一个可扩展的反混淆插件
若是把出类拔萃定义为成功,那么大多数人注定无所建树;若是把比昨天进步一点点当成目标,那么咱们天天都有机会宣布本身得到了一次小胜利
TIP: 本文的目的只有一个就是学习更多的逆向技巧和思路,若是有人利用本文技术去进行非法商业获取利益带来的法律责任都是操做者本身承担,和本文以及做者不要紧,本文涉及到的代码项目能够去 奋飞的朋友们 知识星球自取,欢迎加入知识星球一块儿学习探讨技术。有问题能够加我wx: fenfei331 讨论下。
关注微信公众号:奋飞安全,最新技术干货实时推送