首页
社区
课程
招聘
教你玩转ida反编译(修改ida microcode)
发表于: 2025-10-20 18:41 3815

教你玩转ida反编译(修改ida microcode)

2025-10-20 18:41
3815

看到了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:右操作数,可能是变量或寄存器
举个例子:

mov 是 opcode,#1.8 是左操作数,x8.8 是右操作数

goto 是 opcode,@34 是左操作数(块编号)

sub 是 opcode,x0.8{34}是左操作数,%var_90.8{3}是右操作数,x8.8 是目标操作数
这些操作数使用的类是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 ( func_ea, auto_open=False ):
    widget  = idaapi.find_widget( "Pseudocode-A" )
    if widget and idaapi.get_widget_type( widget ) == idaapi.BWN_PSEUDOCODE :
        vu  = idaapi.get_widget_vdui( widget )
        if vu and vu.cfunc.entry_ea == func_ea :
            return vu
 
    if auto_open :
        idaapi.open_pseudocode( func_ea, idaapi.OPF_REUSE )
        return find_pseudocode_view( func_ea, False )
 
    return None
 
vu: ida_hexrays.vdui_t= find_pseudocode_view(0x113CC, True)
mba: ida_hexrays.mba_t = vu.cfunc.mba
def find_pseudocode_view ( func_ea, auto_open=False ):
    widget  = idaapi.find_widget( "Pseudocode-A" )
    if widget and idaapi.get_widget_type( widget ) == idaapi.BWN_PSEUDOCODE :
        vu  = idaapi.get_widget_vdui( widget )
        if vu and vu.cfunc.entry_ea == func_ea :
            return vu
 
    if auto_open :
        idaapi.open_pseudocode( func_ea, idaapi.OPF_REUSE )
        return find_pseudocode_view( func_ea, False )
 
    return None
 
vu: ida_hexrays.vdui_t= find_pseudocode_view(0x113CC, True)
mba: ida_hexrays.mba_t = vu.cfunc.mba
class HexraysDecompilationHook(Hexrays_Hooks):
    def __init__(self):
        super().__init__()
 
    def prolog(self, mba: mbl_array_t, fc, reachable_blocks, decomp_flags) -> "int":
        print(f"prolog mba maturity: {mba.maturity}")
        return 0
 
    def glbopt(self, mba: mbl_array_t) -> "int":
        print(f"glbopt mba maturity: {mba.maturity}")
        return MERR_OK
     
    def locopt(self, mba: mba_t) -> int:
        print(f"locopt mba maturity: {mba.maturity}")
        return 0
 
    def prealloc(self, mba: mba_t) -> int:
        print(f"prealloc mba maturity: {mba.maturity}")
        return 0
    def calls_done(self, mba: mba_t):
        print(f"calls_done mba maturity: {mba.maturity}")
        return 0
     
    def microcode(self, mba: mba_t):
        print(f"microcode mba maturity: {mba.maturity}")
        return 0
 
    def stkpnts(self, mba: mba_t, _sps:ida_frame.stkpnts_t):
        print(f"stkpnts mba maturity: {mba.maturity}")
        return 0
 
    def preoptimized(self, mba: mba_t):
        print(f"preoptimized mba maturity: {mba.maturity}")
        return 0
     
testHook = HexraysDecompilationHook()
print(testHook.hook())
class HexraysDecompilationHook(Hexrays_Hooks):
    def __init__(self):
        super().__init__()
 
    def prolog(self, mba: mbl_array_t, fc, reachable_blocks, decomp_flags) -> "int":
        print(f"prolog mba maturity: {mba.maturity}")
        return 0
 
    def glbopt(self, mba: mbl_array_t) -> "int":
        print(f"glbopt mba maturity: {mba.maturity}")
        return MERR_OK
     
    def locopt(self, mba: mba_t) -> int:
        print(f"locopt mba maturity: {mba.maturity}")
        return 0
 
    def prealloc(self, mba: mba_t) -> int:
        print(f"prealloc mba maturity: {mba.maturity}")
        return 0
    def calls_done(self, mba: mba_t):
        print(f"calls_done mba maturity: {mba.maturity}")
        return 0
     
    def microcode(self, mba: mba_t):
        print(f"microcode mba maturity: {mba.maturity}")
        return 0
 
    def stkpnts(self, mba: mba_t, _sps:ida_frame.stkpnts_t):
        print(f"stkpnts mba maturity: {mba.maturity}")
        return 0
 
    def preoptimized(self, mba: mba_t):
        print(f"preoptimized mba maturity: {mba.maturity}")
        return 0
     
testHook = HexraysDecompilationHook()
print(testHook.hook())
mov    #1.8, x8.8
mov    #1.8, x8.8
goto   @34
goto   @34
sub    x0.8{34}, %var_90.8{3}, x8.8
sub    x0.8{34}, %var_90.8{3}, x8.8
2.0 ; 1WAY-BLOCK 2 FAKE INBOUNDS: 1 OUTBOUNDS: 4 [START=1143C END=11440] MINREFS: STK=C0/ARG=2C0, MAXBSP: 0
2.0 ; DEF: w9.4
2.0 ; DNU: w9.4
2.0 ; VALRANGES: x20.8:==0
2.0 mov    #0x24279280.4, w9.4     ; 1143C split4 u=           d=w9.4
2.1 goto   @4                      ; 1143C u=
2.1
2.0 ; 1WAY-BLOCK 2 FAKE INBOUNDS: 1 OUTBOUNDS: 4 [START=1143C END=11440] MINREFS: STK=C0/ARG=2C0, MAXBSP: 0
2.0 ; DEF: w9.4
2.0 ; DNU: w9.4
2.0 ; VALRANGES: x20.8:==0
2.0 mov    #0x24279280.4, w9.4     ; 1143C split4 u=           d=w9.4
2.1 goto   @4                      ; 1143C u=
2.1
from ida_hexrays import *
def change_minsn(mba: mba_t):
    mblock:mblock_t = mba.get_mblock(2)
    minsn:minsn_t = mblock.head
    minsn.l.nnn.value = 1
    mba.verify(True)
 
class HexraysDecompilationHook(Hexrays_Hooks):
    def __init__(self):
        super().__init__()
 
    def glbopt(self, mba: mbl_array_t) -> "int":
        print(f"glbopt mba maturity: {mba.maturity}")
        change_minsn(mba)
        return MERR_OK
         
testHook = HexraysDecompilationHook()
print(testHook.hook())
from ida_hexrays import *
def change_minsn(mba: mba_t):
    mblock:mblock_t = mba.get_mblock(2)
    minsn:minsn_t = mblock.head
    minsn.l.nnn.value = 1
    mba.verify(True)
 
class HexraysDecompilationHook(Hexrays_Hooks):
    def __init__(self):
        super().__init__()
 
    def glbopt(self, mba: mbl_array_t) -> "int":
        print(f"glbopt mba maturity: {mba.maturity}")
        change_minsn(mba)
        return MERR_OK
         
testHook = HexraysDecompilationHook()
print(testHook.hook())
from ida_hexrays import *
def add_new_minsn(mba: mba_t):
    mblock:mblock_t = mba.get_mblock(2)
     
    # 新建左操作数,使用第一条指令的目标寄存器
    new_mop_l = mop_t()
    new_mop_l.t = mop_r
    new_mop_l.r = mblock.head.d.r
    new_mop_l.size = mblock.head.d.size
 
    # 新建右操作数,新建一个常数
    new_mop_r = mop_t()
    new_mop_r.t = mop_n
    new_mop_r.nnn = mnumber_t(0x24279280)
    new_mop_r.size = mblock.head.l.size
 
    # 新建目标操作数,使用第一条指令寄存器
    new_mop_d = mop_t()
    new_mop_d.t = mop_r
    new_mop_d.r = mblock.head.d.r
    new_mop_d.size = mblock.head.d.size
 
    # 新建指令,设定操作码和所有操作数
    new_minsn = minsn_t(mblock.tail.ea)
    new_minsn.opcode = m_sub
    new_minsn.d = new_mop_d
    new_minsn.l = new_mop_l
    new_minsn.r = new_mop_r
 
    # 在参数二指令的后面添加新指令
    mblock.insert_into_block(new_minsn, mblock.head)
    # 用于打印mblock内容
    vp = vd_printer_t()
    mblock._print(vp)
    mba.verify(True)
 
class HexraysDecompilationHook(Hexrays_Hooks):
    def __init__(self):
        super().__init__()
 
    def glbopt(self, mba: mbl_array_t) -> "int":
        print(f"glbopt mba maturity: {mba.maturity}")
        change_minsn(mba)
        return MERR_OK
         
testHook = HexraysDecompilationHook()
print(testHook.hook())
from ida_hexrays import *
def add_new_minsn(mba: mba_t):
    mblock:mblock_t = mba.get_mblock(2)
     
    # 新建左操作数,使用第一条指令的目标寄存器
    new_mop_l = mop_t()
    new_mop_l.t = mop_r
    new_mop_l.r = mblock.head.d.r
    new_mop_l.size = mblock.head.d.size
 
    # 新建右操作数,新建一个常数
    new_mop_r = mop_t()
    new_mop_r.t = mop_n
    new_mop_r.nnn = mnumber_t(0x24279280)
    new_mop_r.size = mblock.head.l.size
 
    # 新建目标操作数,使用第一条指令寄存器
    new_mop_d = mop_t()
    new_mop_d.t = mop_r
    new_mop_d.r = mblock.head.d.r
    new_mop_d.size = mblock.head.d.size
 
    # 新建指令,设定操作码和所有操作数
    new_minsn = minsn_t(mblock.tail.ea)
    new_minsn.opcode = m_sub
    new_minsn.d = new_mop_d
    new_minsn.l = new_mop_l
    new_minsn.r = new_mop_r
 
    # 在参数二指令的后面添加新指令
    mblock.insert_into_block(new_minsn, mblock.head)
    # 用于打印mblock内容
    vp = vd_printer_t()
    mblock._print(vp)
    mba.verify(True)
 

[培训]传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 132
支持
分享
最新回复 (58)
雪    币: 209
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2025-10-20 19:05
0
雪    币: 397
活跃值: (2718)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
3
感谢分享
2025-10-20 19:18
0
雪    币: 23
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
1
2025-10-20 19:44
0
雪    币: 2
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
5
感谢分享
2025-10-20 21:28
0
雪    币: 10
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
6
66
2025-10-20 23:27
0
雪    币: 477
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
7
这个讨论对我很有帮助,谢谢!
2025-10-21 07:23
0
雪    币: 6448
活跃值: (5389)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
谢谢分享 
2025-10-21 08:35
0
雪    币: 204
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
9
66666
2025-10-21 09:00
0
雪    币: 5444
活跃值: (8925)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10

最后于 2025-10-21 09:24 被huangjw编辑 ,原因:
2025-10-21 09:23
0
雪    币: 587
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
11
6666
2025-10-21 09:30
0
雪    币: 183
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
12
6666
2025-10-21 09:34
0
雪    币: 8451
活跃值: (6097)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
感谢分享
2025-10-21 09:50
0
雪    币: 104
活跃值: (6838)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
tql
2025-10-21 15:14
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
15
111
2025-10-21 15:57
0
雪    币: 10
活跃值: (862)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
666
2025-10-21 17:27
0
雪    币: 2600
活跃值: (1200)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
17
6666
2025-10-22 09:40
0
雪    币: 3549
活跃值: (3700)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
6
2025-10-23 13:21
0
雪    币: 305
活跃值: (400)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
666
2025-10-23 19:23
0
雪    币: 2313
活跃值: (4440)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
666
2025-10-24 00:05
0
雪    币: 0
活跃值: (1050)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
666
2025-10-24 00:06
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
22
爸爸
2025-10-24 01:14
0
雪    币: 5538
活跃值: (3804)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
666
2025-10-24 10:26
0
雪    币: 1476
活跃值: (2313)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
666
2025-10-24 10:43
0
雪    币: 34
活跃值: (1742)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
6666
2025-10-24 10:58
0
游客
登录 | 注册 方可回帖
返回