标题: IDAPython获取函数参数个数 创建: 2022-11-02 22:08 更新: 2022-11-04 10:38 链接: https://scz.617.cn/python/202211022208.txt -------------------------------------------------------------------------- 目录: ☆ 背景介绍 ☆ idaapi.decompile ☆ FLARE IDA Decompiler Library (FIDL) 1) 安装FIDL 2) 用FIDL获取函数参数个数 3) FIDL对idaapi.decompile的封装 ☆ 后记 ☆ 参考资源 -------------------------------------------------------------------------- ☆ 背景介绍 起因是在IDA中快速识别静态链接的OpenSSL库函数SSL_read、SSL_write,有很多搞 法。参看 《IoT设备逆向工程中的函数识别》 https://scz.617.cn/misc/201905081756.txt 就此次原始需求而言,上文中各方案显得重型。bluerust用了一种轻型方案,基于特 征字符串交叉引用定位多个函数,根据函数特征过滤出最终结果,这是逆向工程常见 动作。函数特征包含但不限于对指定地址的交叉引用计数,call指令计数、block计 数、参数个数等等。我卡在IDAPython获取函数参数个数这个问题上。 ☆ idaapi.decompile uid(5162883301)、uid(3907374211)指出可以借助idaapi.decompile获取函数参数个 数,uid(7483708707)在后台直接给我下列完整实现。 -------------------------------------------------------------------------- # # IDASDK77\include\typeinf.hpp # # dos2unix CC_Map.txt # awk -F' ' '{printf("%8s : \"%s\",\n",tolower($3),$1);}' CC_Map.txt # CC_Map = \ { 0x00 : "CM_CC_INVALID", 0x10 : "CM_CC_UNKNOWN", 0x20 : "CM_CC_VOIDARG", 0x30 : "CM_CC_CDECL", 0x40 : "CM_CC_ELLIPSIS", 0x50 : "CM_CC_STDCALL", 0x60 : "CM_CC_PASCAL", 0x70 : "CM_CC_FASTCALL", 0x80 : "CM_CC_THISCALL", 0x90 : "CM_CC_MANUAL", 0xa0 : "CM_CC_SPOILED", 0xb0 : "CM_CC_GOLANG", 0xc0 : "CM_CC_RESERVE3", 0xd0 : "CM_CC_SPECIALE", 0xe0 : "CM_CC_SPECIALP", 0xf0 : "CM_CC_SPECIAL" } # # from uid(7483708707) # # generate_func_info( idc.here() ) # def generate_func_info ( ea ) : func = idaapi.get_func( ea ) cfunc = idaapi.decompile( func ) # # 这两步有替代方案 # func_type = idaapi.tinfo_t() cfunc.get_func_type( func_type ) # # IDASDK77\include\typeinf.hpp # nargs = func_type.get_nargs() arg_list = [] for i in range( nargs ) : arg_list.append( str( func_type.get_nth_arg(i) ) ) rettype = str( func_type.get_rettype() ) fi = idaapi.func_type_data_t() func_type.get_func_details( fi ) func_info = {} func_info['args'] = arg_list func_info['ret'] = rettype func_info['cc'] = CC_Map[fi.cc] func_info['name'] = idc.get_func_name( ea ) return func_info # # end of generate_func_info # -------------------------------------------------------------------------- # # generate_func_info_1( idc.here() ) # def generate_func_info_1 ( ea ) : func = idaapi.get_func( ea ) cfunc = idaapi.decompile( func ) nargs = cfunc.type.get_nargs() arg_list = [] for i in range( nargs ) : arg_list.append( str( cfunc.type.get_nth_arg(i) ) ) rettype = str( cfunc.type.get_rettype() ) fi = idaapi.func_type_data_t() cfunc.type.get_func_details( fi ) func_info = {} func_info['args'] = arg_list func_info['ret'] = rettype func_info['cc'] = CC_Map[fi.cc] func_info['name'] = idc.get_func_name( ea ) return func_info # # end of generate_func_info_1 # -------------------------------------------------------------------------- bluerust指出,对idc.get_type(idc.here())的返回值进行字符串解析也能得到一些 信息,形如 '__int64 __fastcall(__int64, void *, int)' 显然idaapi.decompile更优雅,此处有其详解 IDAPython CTREE https://gist.github.com/icecr4ck/9dea9d1de052f0b2b417abf0046cc0f6 generate_func_info_2与generate_func_info本质相同,取函数参数的办法略有不同, 用到了cfunc.argidx,uid(3907374211)也提到这个点。 -------------------------------------------------------------------------- # # generate_func_info_2( idc.here() ) # def generate_func_info_2 ( ea ) : func = idaapi.get_func( ea ) cfunc = idaapi.decompile( func ) lvars = cfunc.get_lvars() arg_list = [] for i in cfunc.argidx : tinfo = lvars[i].type() arg_list.append( tinfo ) rettype = cfunc.type.get_rettype() fi = idaapi.func_type_data_t() cfunc.type.get_func_details( fi ) func_info = {} func_info['args'] = arg_list func_info['ret'] = rettype func_info['cc'] = CC_Map[fi.cc] func_info['name'] = idc.get_func_name( ea ) return func_info # # end of generate_func_info_2 # -------------------------------------------------------------------------- ☆ FLARE IDA Decompiler Library (FIDL) uid(5162883301)、bluerust分别提及FIDL的实现,我没用过这个IDA插件,简单测试 之。 1) 安装FIDL 参看 -------------------------------------------------------------------------- 《Portable Python》 https://scz.617.cn/python/202011191444.txt 《Portable IDA+IDAPython》 https://scz.617.cn/python/202011182246.txt https://fidl.readthedocs.io/en/latest/installation.html -------------------------------------------------------------------------- 测试环境是"Portable Python + Portable IDA",FIDL严重依赖IDA,不想安装到 "Portable Python"中,只想在"Portable IDA"环境中使用FIDL。 git clone https://github.com/mandiant/FIDL.git FIDL cd /d X:\work\FIDL X:\temp\Python39\python.exe -m pip install . "X:\temp\Python39"源自"X:\Green\Python\portable\Python39",此外还复制了一 份"X:\temp\Python39_"。安装完FIDL,用BC进行目录比较,找出实际改动: -------------------------------------------------------------------------- X:\temp\Python39\ share\ doc\ networkx-2.8.8\ Lib\ site-packages\ FIDL\ FIDL-1.3.dist-info\ networkx\ networkx-2.8.8.dist-info\ six-1.16.0.dist-info\ six.py -------------------------------------------------------------------------- share目录下是文档,不需要;将"X:\temp\Python39\Lib\site-packages\"下的几项 复制到"X:\Green\IDA\Lib\site-packages\"即可。此外,FIDL依赖bz2模块,需要复 制_bz2.pyd到IDA目录。 X:\temp\Python39\_bz2.pyd X:\Green\IDA\_bz2.pyd 2) 用FIDL获取函数参数个数 在IDA的Python提示符中测试如下命令 import FIDL.decompiler_utils as fdu c = fdu.controlFlowinator( ea=idc.here(), fast=False ) dir(c) c.args len(c.args) dir(c.args[0]) type(c.args[0].ti) c.args[0] c.args[0].name c.args[0].type_name c.args[0].size 3) FIDL对idaapi.decompile的封装 参看 https://github.com/mandiant/FIDL/blob/master/FIDL/decompiler_utils.py 就此次原始需求而言,主要查看这些类与函数 class controlFlowinator def my_decompile def get_function_vars def get_return_type 由于uid(7483708707)珠玉在前,很容易看懂FIDL如何封装idaapi.decompile的,但 说实话,无基础时直接看FIDL实现,这些封装没那么浅显易懂。 ☆ 后记 回到原始需求,取函数参数个数,最简写法有两种 idaapi.decompile( func ).type.get_nargs() len( idaapi.decompile( func ).argidx ) 这种搞法依赖Hex-Rays反编译效果,不是太准,将就着用吧。 非常感谢uid(7483708707)提供具体实现,bluerust看过其实现后大加赞赏,同时感 谢uid(5162883301)、uid(3907374211)提供靠谱思路。此番微博请教技术问题,得到 的全部是有效回复,实属罕见,真地是曲指可数的几次之一。 bluerust作为湾区人形蜘蛛Top 10,爬到了[2],与IDAPython有交集的逆向工程人员, 不妨遍历之。事后与bluerust复盘时,有一段对话 scz: 哦,我想起来了,我应该直接召唤hume的! brt: 我本来想说,这事情,天下没有比hume更强的 brt: 说来惭愧,从没遍历过IDA SDK文档 scz: hume干过 scz: 超级老司机 brt: 还是我勤奋不足! scz: 是你精力发散 brt: 那可不,朝廷美女事事关心 ☆ 参考资源 [1] Porting from IDAPython 6.x-7.3, to 7.4 https://www.hex-rays.com/products/ida/support/ida74_idapython_no_bc695_porting_guide.shtml IDAPython documentation https://www.hex-rays.com/products/ida/support/idapython_docs/ Hex-Rays Decompiler Primer https://hex-rays.com/blog/hex-rays-decompiler-primer/ Hex-Rays SDK Reference https://www.hex-rays.com/products/decompiler/manual/sdk/hexrays_8hpp_source.shtml [2] https://gist.github.com/icecr4ck/ IDAPython cheatsheet https://gist.github.com/icecr4ck/7a7af3277787c794c66965517199fc9c (入门推荐阅读) IDAPython CTREE https://gist.github.com/icecr4ck/9dea9d1de052f0b2b417abf0046cc0f6 (详解idaapi.decompile用法) [3] FLARE IDA Decompiler Library (FIDL) https://fidl.readthedocs.io/en/latest/installation.html https://fidl.readthedocs.io/en/latest/tutorial.html https://fidl.readthedocs.io/en/latest/api.html https://github.com/mandiant/FIDL https://github.com/mandiant/FIDL/blob/master/FIDL/decompiler_utils.py (A sane API for IDA Pro's decompiler) [4] IDAPython: How to get function argument values - joxeankoret [2018-03-04] https://reverseengineering.stackexchange.com/questions/17593/idapython-how-to-get-function-argument-values print( map(hex, ida_typeinf.get_arg_addrs(idc.here()))) Getting function arguments in ida - [2020-06-15] https://reverseengineering.stackexchange.com/questions/25301/getting-function-arguments-in-ida (解释为什么ida_typeinf.get_arg_addrs不灵) idahunt https://github.com/nccgroup/idahunt/ https://github.com/nccgroup/idahunt/blob/master/ida_helper.py