本文最早上传于先知社区IDA旧版本插件移植后卡死的研究及修复-先知社区 (aliyun.com)
修复后ida下载地址
通过网盘分享的文件:IDA_Pro_v8.3_Portable.7z
链接: a25K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6H3j5h3&6Q4x3X3g2T1j5h3W2V1N6g2)9J5k6h3y4G2L8g2)9J5c8Y4y4Q4x3V1j5I4b7g2N6E0x3K6q4I4K9p5N6J5d9U0q4u0d9K6g2%4d9#2m8c8N6@1A6g2f1g2)9K6c8Y4m8%4k6q4)9K6c8r3c8V1L8%4x3`. 提取码: ddos
如还存在问题可以联系Q :3824970852 笔者抽空时可以研究修复一下
近日在研究异构路由器漏洞时,笔者使用的IDA出现了反编译异构路由器卡死的问题,和身边是师傅们交流后发现,这种问题不在少数,这种工具类的问题严重影响了正常的工作,故进行研究。
出现问题的直接原因在于此前由于IDA 8.3及以后的hexrays
并未泄露,无法使用过去IDA 7.7的插件进行反编译,一通操作下通过ida_dll_shim
等项目对7.7的hexrays
进行了移植。移植完成后虽然可以使用,但部分函数仍出现IDA反编译时出现卡死等情况,导致vulfi
等一众扫描类的插件不能以预期状态运行。
不过功夫不负有心人,笔者在搜寻的过程中找到了一篇帖子 在新版IDA中使用旧版本反编译插件,帖子提供了一种修复的方法,但帖子中提供的修复方法并非不详细,并且修复的方法并不合理,对正常逆向存在一定的影响,故笔者决定自己对这次异常进行研究,并给予修复方案。
在研究开始时,我的第一反应是需要了解IDA是在什么函数的什么地方出现了卡死,毕竟只有跟踪到了出现异常的点,才能进一步研究。这里我选择了xdbg
进行跟踪分析函数调用,来解答我的下面两个疑问:
根据异常出现在arm32
位反编译的情况下,不难猜测出这个问题大概率出现在hexarm.dll
这个链接库中,所以接下来的分析主要针对涉hexarm.dll
调用的相关函数。为了找到卡死的点,我先写了一个IDAPython
脚本,来依次反编译程序的所有函数,直至卡死为止。
这里我使用的是一个16KB的小的ARM32文件,在正常情况下只需要不到几秒中的时间就会运行完毕,但发现即使经过长时间后程序仍然卡在在sub_8DB0
这里,那么不必多是,此时就是想要的异常情况了。

接下来我使用xdbg来附加现在处于卡死状态的IDA,为了找出此时死循环运行的函数,我通过alt+k
去查看目前函数的调用关系,来确定函数,下面是我捕获的函数调用关系(主线程)
通过栈帧的调用关系可以发现程序在不停止的运行ida-orig.is_numop+191
函数,此函数是ida.dll
中的API,7.7的插件这里出现了问题,且两个插件本在各自的版本都没有出现问题,移植后却出现卡死的问题,这里合理怀疑是IDA对这个API进行了部分改动,所以我特地去查看了其相关的信息。

根据hexray官网给出的信息,这个函数确实在7.x到8.x进行了内容的变动,并且这个函数的功能是判断转入的数是否为该进制表示方法数字。
对此,问题出现的原因就已经明确了,IDA再进行更新时有着API的变动,而可能时函数内部逻辑的改变使得结果的不同,导致陷入死循环,那么接下来就是这时候我选择先对IDA7.7和IDA8.4的ida-orig.is_numop
进行对比分析。
这里我们从复杂的8.4版本入手,抛开其他结构只观察函数逻辑本身的情况下,函数is_numop
的作用是检查给定的64位整数a1
中特定的四位字段是否匹配预定义的数值模式,具体取决于第二个参数a2
的低四位值。
字段位置计算:
模式匹配:
每个四位字段需要等于以下值之一(掩码为0xF左移后的结果):
而我们分析完复杂的8.4版本后,再看一眼7.7版本时,顿时感到7.7的函数眉清目秀的,这里就不详细分析它的逻辑了,只给出它俩的差异。
简单的理解来看新版的is_numop
传入的参数a1
是去判读64个bit的操作,而7.7版本及以前都是32个bit判断的简单逻辑,并且逻辑不完全相同。既然分析出了具体原因,接下来的就是对dll文件进行修复了。
修复这个问题,也分为多个思路,而笔者并不采用先前文章中的修复方法(先前文章是通过使用is_numop0
替换is_numop
),因为新版is_numop0
函数的本质逻辑是调用了is_numop(a1,0)
,根据我们上方的分析来看,is_numop0
对应的判断逻辑应该是这样的
这样的情况下is_numop0
只会对20-23位进行操作,但正常情况下对24-27的判断就会失效,也就是当n传入的值不等于0
或0xf
时,进行的判断和原先的函数是不同的。为了不影响反编译的结果和程序的健壮性,我需要一个更靠谱的方法去修复。
最容易想到的方法是将老版本is_numop
写入hexarm.dll
并修改名称,并将原先的is_numop
调用修改为新函数,不过这种方法在操作上稍显麻烦。第二种容易想到方法是根据函数的逻辑,对函数外的代码进行部分修改,使他进入函数是时满足条件切正确,但过少的空间使得第二种方法并不容易,甚至无法完成,第三种方法是则是通过dll劫持,将is_numop
指向到新的函数。思考再三,为了追求稳定性,最终选择了第三种修复方法。
在修复之前,先缕一便当前IDA在执行反编译时链接库之间的依赖关系,下图是笔者修复前链接库的关系。

经过上图我们可以看到,我先前使用的项目ida_dll_shim
本质上就是进行了一个dll的劫持来修复旧版本插件不识别的问题,但由于is_numop
只是改变函数内容,如果将把8.4dll
的is_numop
直接修改为7.7的is_numop
后,原先自带的8.4hexrays-x86_64
则可能出现问题,为了不影响新插件的功能,故这个项目并没有对这种内容改变函数进行明确修改,最终导致这个问题。
再回头来考虑我们修复的实现方法,为解决这个问题我们可以通过在ida.dll
中创建一个新的函数is_num0p
来代替is_numop
,并在老版本插件将新函数的替换原先的is_num0p
。

首先我们要重新编译ida_dll_shim
中的ida(这里建议大家先看一遍原先的项目文件,并跟着项目操作完,因为这里是在操作完一次项目操作后进行的,这里我默认大家已经跟着项目修复完第一次了,已经有ida-orig
和ida64-orig
文件),上文提到过,ida_dll_shim
是通过dll劫持实现的,本质上是创建一个新ida.dll
转发了ida-orig
中的函数,并添加了新函数,这里我们在项目的ida_dll_exports.h
中创建一个新的函数并放入老版ida的代码。
最终使用VS重新编译出ida和ida64,替换第一次生成的ida和ida64,生成完成后可以使用ida查看export来检查是否生成正确,正确的情况下是可以看到is_numop
和is_num0p
同时存在并且可以点击进入的。至此,我们对ida.dll
的修复已经完成。接下来就是改变hex异构反编译dll的导入函数表了。
这里我使用的是CFF
,将异构hex反编译dll->importDirectory->导入函数is_numop
改为is_num0p
并保存,如图是修改后的情况。

修复完成后再一次启动ida,并用xdbg进行跟踪,发现程序已经进入到我们所创建的函数中。

再次运行测试案例,程序可以正常运行完毕,并未出现卡死的情况,至此我们的修复已经完成。
import
idautils
import
idaapi
def
decompile_all_functions():
functions
=
list
(idautils.Functions())
total
=
len
(functions)
for
i, func_ea
in
enumerate
(functions):
func_name
=
idaapi.get_func_name(func_ea)
print
(f
"\r进度: {i+1}/{total} | 当前函数: {func_name}"
, end
=
"")
try
:
cfunc
=
idaapi.decompile(func_ea)
if
not
cfunc:
idc.generate_pseudo(func_ea)
except
Exception as e:
print
(f
"\n反编译失败 @ {func_name} (0x{func_ea:x}): {str(e)}"
)
if
__name__
=
=
"__main__"
:
decompile_all_functions()
import
idautils
import
idaapi
def
decompile_all_functions():
functions
=
list
(idautils.Functions())
total
=
len
(functions)
for
i, func_ea
in
enumerate
(functions):
func_name
=
idaapi.get_func_name(func_ea)
print
(f
"\r进度: {i+1}/{total} | 当前函数: {func_name}"
, end
=
"")
try
:
cfunc
=
idaapi.decompile(func_ea)
if
not
cfunc:
idc.generate_pseudo(func_ea)
except
Exception as e:
print
(f
"\n反编译失败 @ {func_name} (0x{func_ea:x}): {str(e)}"
)
if
__name__
=
=
"__main__"
:
decompile_all_functions()
线程
ID
地址 返回到 返回自 大小 方 注释
13192
-
主线程
0000001794DF9408
00000000589D775B
00000000592B2861
30
用户模块 ida
-
orig.is_numop
+
191
0000001794DF9438
00000000589D5321
00000000589D775B
60
用户模块 hexarm_0.
00000000589D775B
0000001794DF9498
00000000589E08EE
00000000589D5321
30
用户模块 hexarm_0.
00000000589D5321
0000001794DF94C8
0000000058967AFE
00000000589E08EE
30
用户模块 hexarm_0.
00000000589E08EE
0000001794DF94F8
0000000058967D78
0000000058967AFE
30
用户模块 hexarm_0.
0000000058967AFE
0000001794DF9528
0000000058967C20
0000000058967D78
30
用户模块 hexarm_0.
0000000058967D78
0000001794DF9558
0000000058967D78
0000000058967C20
30
用户模块 hexarm_0.
0000000058967C20
0000001794DF9588
000000005896D1F1
0000000058967D78
30
用户模块 hexarm_0.
0000000058967D78
0000001794DF95B8
0000000058967AFE
000000005896D1F1
30
用户模块 hexarm_0.
000000005896D1F1
0000001794DF95E8
0000000058967D78
0000000058967AFE
30
用户模块 hexarm_0.
0000000058967AFE
0000001794DF9618
0000000058967C5F
0000000058967D78
30
用户模块 hexarm_0.
0000000058967D78
0000001794DF9648
0000000058967EA4
0000000058967C5F
70
用户模块 hexarm_0.
0000000058967C5F
0000001794DF96B8
00000000589D0829
0000000058967EA4
C0 用户模块 hexarm_0.
0000000058967EA4
0000001794DF9778
00000000589689B1
00000000589D0829
B0 用户模块 hexarm_0.
00000000589D0829
0000001794DF9828
0000000058924226
00000000589689B1
220
用户模块 hexarm_0.
00000000589689B1
0000001794DF9A48
00000000588555CC
0000000058924226
1C0
用户模块 hexarm_0.
0000000058924226
0000001794DF9C08
0000000058854904
00000000588555CC
50
用户模块 hexarm_0.
00000000588555CC
0000001794DF9C58
0000000058921295
0000000058854904
400
用户模块 hexarm_0.
0000000058854904
0000001794DFA058
00007FFDACEB1646
0000000058921295
E0 用户模块 hexarm_0.
0000000058921295
0000001794DFA138
00007FFD95A4DF8D
00007FFDACEB1646
30
用户模块 _ida_hexrays.
00007FFDACEB1646
线程
ID
地址 返回到 返回自 大小 方 注释
13192
-
主线程
0000001794DF9408
00000000589D775B
00000000592B2861
30
用户模块 ida
-
orig.is_numop
+
191
0000001794DF9438
00000000589D5321
00000000589D775B
60
用户模块 hexarm_0.
00000000589D775B
0000001794DF9498
00000000589E08EE
00000000589D5321
30
用户模块 hexarm_0.
00000000589D5321
0000001794DF94C8
0000000058967AFE
00000000589E08EE
30
用户模块 hexarm_0.
00000000589E08EE
0000001794DF94F8
0000000058967D78
0000000058967AFE
30
用户模块 hexarm_0.
0000000058967AFE
0000001794DF9528
0000000058967C20
0000000058967D78
30
用户模块 hexarm_0.
0000000058967D78
0000001794DF9558
0000000058967D78
0000000058967C20
30
用户模块 hexarm_0.
0000000058967C20
0000001794DF9588
000000005896D1F1
0000000058967D78
30
用户模块 hexarm_0.
0000000058967D78
0000001794DF95B8
0000000058967AFE
000000005896D1F1
30
用户模块 hexarm_0.
000000005896D1F1
0000001794DF95E8
0000000058967D78
0000000058967AFE
30
用户模块 hexarm_0.
0000000058967AFE
0000001794DF9618
0000000058967C5F
0000000058967D78
30
用户模块 hexarm_0.
0000000058967D78
0000001794DF9648
0000000058967EA4
0000000058967C5F
70
用户模块 hexarm_0.
0000000058967C5F
0000001794DF96B8
00000000589D0829
0000000058967EA4
C0 用户模块 hexarm_0.
0000000058967EA4
0000001794DF9778
00000000589689B1
00000000589D0829
B0 用户模块 hexarm_0.
00000000589D0829
0000001794DF9828
0000000058924226
00000000589689B1
220
用户模块 hexarm_0.
00000000589689B1
0000001794DF9A48
00000000588555CC
0000000058924226
1C0
用户模块 hexarm_0.
0000000058924226
0000001794DF9C08
0000000058854904
00000000588555CC
50
用户模块 hexarm_0.
00000000588555CC
0000001794DF9C58
0000000058921295
0000000058854904
400
用户模块 hexarm_0.
0000000058854904
0000001794DFA058
00007FFDACEB1646
0000000058921295
E0 用户模块 hexarm_0.
0000000058921295
0000001794DFA138
00007FFD95A4DF8D
00007FFDACEB1646
30
用户模块 _ida_hexrays.
00007FFDACEB1646
bool
__fastcall is_numop(
int
a1,
char
a2)
{
int
v2;
int
v3;
int
v4;
int
v6;
v2 = a2 & 0xF;
if
( v2 )
{
if
( v2 == 15 )
{
v3 = a1 & 0xF00000;
if
( (a1 & 0xF00000) == 0x200000 || v3 == 0x700000 || v3 == 0x600000 || v3 == 0x100000 )
return
1;
}
v4 = a1 & 0xF000000;
if
( v4 == 0x2000000 || v4 == 0x7000000 || v4 == 0x6000000 )
return
1;
return
v4 == 0x1000000;
}
else
{
v6 = a1 & 0xF00000;
if
( v6 == 0x200000 || v6 == 0x700000 || v6 == 0x600000 )
return
1;
return
v6 == 0x100000;
}
}
bool
__fastcall is_numop(
int
a1,
char
a2)
{
int
v2;
int
v3;
int
v4;
int
v6;
v2 = a2 & 0xF;
if
( v2 )
{
if
( v2 == 15 )
{
v3 = a1 & 0xF00000;
if
( (a1 & 0xF00000) == 0x200000 || v3 == 0x700000 || v3 == 0x600000 || v3 == 0x100000 )
return
1;
}
v4 = a1 & 0xF000000;
if
( v4 == 0x2000000 || v4 == 0x7000000 || v4 == 0x6000000 )
return
1;
return
v4 == 0x1000000;
}
else
{
v6 = a1 & 0xF00000;
if
( v6 == 0x200000 || v6 == 0x700000 || v6 == 0x600000 )
return
1;
return
v6 == 0x100000;
}
}
bool
__fastcall is_numop(
__int64
a1,
char
a2)
{
unsigned
int
v2;
unsigned
int
v3;
__int64
v4;
__int64
v5;
__int64
v6;
__int64
v7;
__int64
v8;
__int64
v9;
__int64
v10;
__int64
v11;
v2 = a2 & 0xF;
if
( v2 == 15 )
{
v3 = 0;
while
( 1 )
{
if
( v3 > 7 )
{
v4 = 0i64;
v5 = 0i64;
}
else
{
v4 = 2i64 << (4 * ((unsigned
__int8
)v3 + (v3 > 1) + 5));
v5 = 15i64 << (4 * ((unsigned
__int8
)v3 + (v3 > 1) + 5));
}
if
( (a1 & v5) == v4 )
break
;
if
( v3 > 7 )
{
v6 = 0i64;
v7 = 0i64;
}
else
{
v6 = 7i64 << (4 * ((unsigned
__int8
)v3 + (v3 > 1) + 5));
v7 = 15i64 << (4 * ((unsigned
__int8
)v3 + (v3 > 1) + 5));
}
if
( (a1 & v7) == v6 )
break
;
if
( v3 > 7 )
{
v8 = 0i64;
v9 = 0i64;
}
else
{
v8 = 6i64 << (4 * ((unsigned
__int8
)v3 + (v3 > 1) + 5));
v9 = 15i64 << (4 * ((unsigned
__int8
)v3 + (v3 > 1) + 5));
}
if
( (a1 & v9) == v8 )
break
;
if
( v3 > 7 )
{
v10 = 0i64;
v11 = 0i64;
}
else
{
v10 = 1i64 << (4 * ((unsigned
__int8
)v3 + (v3 > 1) + 5));
v11 = 15i64 << (4 * ((unsigned
__int8
)v3 + (v3 > 1) + 5));
}
if
( (a1 & v11) == v10 )
break
;
if
( (
int
)++v3 >= 8 )
return
0;
}
return
1;
}
else
{
return
v2 < 8
&& ((a1 & (15i64 << (4 * ((unsigned
__int8
)v2 + (v2 > 1) + 5)))) == 2i64 << (4*unsigned
__int8
)v2 + (v2 > 1) + 5))
|| (a1 & (15i64 << (4 * ((unsigned
__int8
)v2 + (v2 > 1) + 5)))) == 7i64 << (4*((unsigned
__int8
)v2 + (v2 > 1) + 5))
|| (a1 & (15i64 << (4 * ((unsigned
__int8
)v2 + (v2 > 1) + 5)))) == 6i64 << (4*unsigned
__int8
)v2 + (v2 > 1) + 5))
|| (a1 & (15i64 << (4 * ((unsigned
__int8
)v2 + (v2 > 1) + 5)))) == 1i64 << (4*((unsigned
__int8
)v2 + (v2 > 1) + 5)));
}
}
bool
__fastcall is_numop(
__int64
a1,
char
a2)
{
unsigned
int
v2;
unsigned
int
v3;
__int64
v4;
__int64
v5;
__int64
v6;
__int64
v7;
__int64
v8;
__int64
v9;
__int64
v10;
__int64
v11;
v2 = a2 & 0xF;
if
( v2 == 15 )
{
v3 = 0;
while
( 1 )
{
if
( v3 > 7 )
{
v4 = 0i64;
v5 = 0i64;
}
else
{
v4 = 2i64 << (4 * ((unsigned
__int8
)v3 + (v3 > 1) + 5));
v5 = 15i64 << (4 * ((unsigned
__int8
)v3 + (v3 > 1) + 5));
}
if
( (a1 & v5) == v4 )
break
;
[培训]科锐逆向工程师培训第53期2025年7月8日开班!