看到了GhHei大佬的文章OLLVM扁平化还原—更优雅的解法:IDA Hex-Rays Microcode,迫不及待得尝试了一下,然后想对一些变种的OLLVM进行处理,由于大佬使用的方法没法添加新的分支,所以自己琢磨了一周,发现网上关于ida microcode的文章极少。这里查阅了D810插件和hrtng插件的源码才找到添加新分支的办法,最后也是写出了处理OLLVM的脚本。通过find_widget 函数查找Pseudocode-A 界面,这里拿到的是TWidget再使用get_widget_vdui拿到vdui_t,从vdui_t中可以拿到 mba。这种方法拿到的 mba.maturity(成熟度) 是 8,已经是经过了所有优化之后的情况,没有办法添加新的块和删除块。ida python 里面有个Hexrays_Hooks 类,这个类里面可以拦截优化过程进度。根据类中的函数分别有以下进度:
● stkpnts:SP change points have been calculated.(SP 变化点已计算。)(mba maturity: 0)
● prolog:Prolog analysis has been finished.(前缀分析已完成。)(mba maturity: 0)
● microcode:Microcode has been generated.(微码已生成。)(mba maturity: 0)
● preoptimized:Microcode has been preoptimized.(微码已预先优化。)(mba maturity: 1)
● locopt:Basic block level optimization has been finished.(基本块级优化已完成。)(mba maturity: 2)
● calls_done:All calls have been analyzed.(所有调用都已分析。)(mba maturity: 3)
● prealloc:Local variables: preallocation step begins.(局部变量:预分配步骤开始。)(mba maturity: 5、6)
● glbopt:Global optimization has been finished. If microcode is modified, MERR_LOOP must be returned. It will cause a complete restart of the optimization.(全局优化已完成。如果微代码被修改,必须返回 MERR_LOOP。这将导致优化完全重启。)(mba maturity: 6)使用 hook 会在 F5 的时候都会执行,需要注意多个 hook 同一个优化进度可能会导致冲突。在 ida mblock 中的指令是以双向链表进行连接的,mblock.head和 mblock.tail分别指向第一条指令和最后一条指令,指令使用的类型为minsn_t,以下为分析:
● minsn_t.opcode:操作码,如 goto、mov、jz 等
● minsn_t.d:目标操作数,可能是变量或寄存器
● minsn_t.l:左操作数,可能是变量、寄存器、常数、目标块
● minsn_t.r:右操作数,可能是变量或寄存器
这些操作数使用的类是mop_t:
● mop_t.t:操作数类型,是个 int,后面会有说明
● mop_t.size:操作数大小,一般是 1、2、4、8 或者NOSIZE
● mop_t.r:微码寄存器,类型为 mreg_t
● mop_t.nnn:一个整数常量,类型为 mnumber_t
● mop_t.s:栈上变量的引用,类型为stkvar_ref_t
● mop_t.b:一般用于 goto 之后的 block_id
● mop_t.l:局部变量的引用,类型为lvar_ref_t
这里的操作数类型的宏定义如下:
● mop_r:寄存器,在 maturity 为MMAT_LVARS 之前使用,也就是说在MMAT_LVARS 之前使用的是mop_t.r,在其之后使用mop_t.l
● mop_n:立即数,对应mop_t.nnn
● mop_b:基本块(mblock),对应mop_t.b
● mop_l:局部变量,对应mop_t.l
● mop_S:局部栈变量,对应mop_t.s举个例子:这是第 2 个块(成熟度为 MMAT_GLBOPT3),可以通过 mba.get_mblock(2)拿到该块的数据,假如我要修改#0x24279280.4 这个立即数,首先使用 mblock.head 拿到第一条指令数据,然后这个立即数是左操作数那他对应的就是 minsn.l.nnn,在mnumber_t 里面成员 value 可以拿到具体数值,也就是说minsn.l.nnn.value 就是0x24279280,此时可以直接给minsn.l.nnn.value 赋值即可改变。代码如下:改变前的反编译效果:
加载脚本后,改变后的反编译效果
同样使用上面的例子,现在目标是在两行指令之间添加一行指令对w9.4 里面的值再次处理,新增一个减法指令,代码如下:mblock 打印出来的内容如下:再查看反编译后的内容:
修改或者新增跳转指令,不仅是对指令操作,还有对 mblock 的处理,包括 mblock 的上下文关系还有 mblock 的属性等。重新观察一下上面的例子:在第一行里有1WAY-BLOCK、INBOUNDS: 1、OUTBOUNDS: 4 这三个项是我们需要注意的,其中INBOUNDS 代表会有什么块跳转到本块,OUTBOUNDS 代表本块会跳转到什么块。那么 1WAY-BLOCK 是什么呢?我们来看下一个例子:可以发现,当OUTBOUNDS 有 2 个的时候他是2WAY-BLOCK,这里代表两个分支。从简单一点的入手,我们可以修改 mblock2 的 goto 让他直接跳转到结尾,代码如下:mblock.succset 是后继块,mblock.predset 是前驱块,这个关联需要手动处理。
改完之后,这个 if else 直接到最后了。
这会还是使用mblock2,把 goto 改成 jz 跳转,这里注意需要添加一个分支和修改1WAY-BLOCK,代码如下:mblock.type 实际上就是1WAY-BLOCK,这里设置为BLT_2WAY 也就是 2WAY-BLOCK
特别需要注意的是,OUTBOUNDS 是有顺序的,例如 jz 的话第一个 id 是下一个 mblock,第二个才是 jz 跳转过去的 mblock观察 ida 的微码可以发现,每个块的结尾都是一个跳转指令,那么如果我们想要添加一个分支判断也就是 jz 加 goto,那么我们需要新增一个块给 goto 使用。那么刚刚已经修改了 mblock2 的 goto 为 jz,这次新增一个 mblock3 写一个 goto 作为一个分支。代码如下:新增块有几个需要注意的点:def find_pseudocode_view ( fu
...(已截断)
---
来源: 看雪论坛
原文链接: https://bbs.kanxue.com/thread-288865.htm
教你玩转ida反编译(修改ida microcode)
362 浏览
9 回复
感谢分享
感谢分享
感谢分享
这个讨论对我很有帮助,谢谢!
谢谢分享
最后于 2025-10-21 09:24
被huangjw编辑
,原因:
被huangjw编辑
,原因:
感谢分享
tql
爸爸