第一次在看雪平台投稿,还是有点忐忑的,一直想分享些 idapython 的内容,网上现在的内容太少,都只是教了一些基础的用法。官方的文档和例子又比较散。希望我的分享能让大家更加快乐的逆向吧,哈哈!
这是这个系列的第一篇,分享一下如何用IDAPython 画出两个函数之间的交叉引用图,可视化一直是我很喜欢的一个东西,逆向的目的就是理解代码嘛,可视化是理解代码的一个很重要的工具。
此外,本教程的实现还依赖了几个 Python 包:
在这里,我们定义了一个名为 find_cross_refs 的递归函数,用于查找两个函数之间的交叉引用关系。该函数包含以下参数:
函数中主要分为以下几个步骤:
下面是 find_cross_refs 函数的详细实现代码:
第二步,我们要向 IDA 中添加 action,通过 action 来执行我们的 find_cross_refs函数,首先我们了解一下 IDA 中 action 的概念:
给一段代码,看一下如何注册一个 Action
然后是将 action 放到 UI 上的代码
了解完这些我们就可以写自己的 Action 了,为了方便我对官方的 Action api 做了一些封装, 下面是我自己的 action.py 文件
然后我们开始定义显示交叉引用图的 Action,我把它叫做 XrefRoadMapAction
具体来说,该类包含以下方法:
可以看出,该类实现的核心是 activate 方法。其主要流程如下:
下面是 XrefRoadMapAction 类的详细实现代码:
代码里面其实还用了很多 sark 库的函数,大家可以自己学习其用法,这个库是专门对 idapython 的 api 做封装的,比较 pythonic,非常好用,我自己也给这个库添加了很多新的功能。
如下所示:
MAX_SEARCH_DEPTH
=
10
def
find_cross_refs(func: sark.Function, target_func, G, max_depth, include_data_xref):
if
max_depth
=
=
0
:
return
False
max_depth
-
=
1
if
include_data_xref:
refs
=
list
(func.xrefs_from)
else
:
refs
=
list
(func.calls_from)
for
ref
in
refs:
ref_addr
=
ref.to
if
ref_addr
=
=
target_func.start_ea:
G.add_edge(func.ea, target_func.ea)
return
True
seg
=
sark.Segment(ea
=
ref_addr)
if
seg.name !
=
"__text"
:
continue
else
:
try
:
ref_func
=
sark.Function(ea
=
ref_addr)
except
Exception as e:
print
(e)
continue
if
find_cross_refs(ref_func, target_func, G, max_depth, include_data_xref):
G.add_edge(func.ea, ref_func.ea)
return
True
return
False
MAX_SEARCH_DEPTH
=
10
def
find_cross_refs(func: sark.Function, target_func, G, max_depth, include_data_xref):
if
max_depth
=
=
0
:
return
False
max_depth
-
=
1
if
include_data_xref:
refs
=
list
(func.xrefs_from)
else
:
refs
=
list
(func.calls_from)
for
ref
in
refs:
ref_addr
=
ref.to
if
ref_addr
=
=
target_func.start_ea:
G.add_edge(func.ea, target_func.ea)
return
True
seg
=
sark.Segment(ea
=
ref_addr)
if
seg.name !
=
"__text"
:
continue
else
:
try
:
ref_func
=
sark.Function(ea
=
ref_addr)
except
Exception as e:
print
(e)
continue
if
find_cross_refs(ref_func, target_func, G, max_depth, include_data_xref):
G.add_edge(func.ea, ref_func.ea)
return
True
return
False
class
MyHandler(idaapi.action_handler_t):
def
__init__(
self
):
idaapi.action_handler_t.__init__(
self
)
def
activate(
self
, ctx):
print
"Hello!"
return
1
def
update(
self
, ctx):
return
idaapi.AST_ENABLE_ALWAYS
action_desc
=
idaapi.action_desc_t(
'my:action'
,
'Say hello!'
,
MyHandler(),
'Ctrl+H'
,
'Says hello'
,
199
)
idaapi.register_action(action_desc)
class
MyHandler(idaapi.action_handler_t):
def
__init__(
self
):
idaapi.action_handler_t.__init__(
self
)
def
activate(
self
, ctx):
print
"Hello!"
return
1
def
update(
self
, ctx):
return
idaapi.AST_ENABLE_ALWAYS
action_desc
=
idaapi.action_desc_t(
'my:action'
,
'Say hello!'
,
MyHandler(),
'Ctrl+H'
,
'Says hello'
,
199
)
idaapi.register_action(action_desc)
idaapi.attach_action_to_menu(
'Edit/Other/Manual instruction...'
,
'my:action'
,
idaapi.SETMENU_APP)
idaapi.attach_action_to_toolbar(
"AnalysisToolBar"
,
'my:action'
)
form
=
idaapi.get_current_tform()
idaapi.attach_action_to_popup(form,
None
,
"my:action"
,
None
)
idaapi.attach_action_to_menu(
'Edit/Other/Manual instruction...'
,
'my:action'
,
idaapi.SETMENU_APP)
idaapi.attach_action_to_toolbar(
"AnalysisToolBar"
,
'my:action'
)
form
=
idaapi.get_current_tform()
idaapi.attach_action_to_popup(form,
None
,
"my:action"
,
None
)
import
idaapi
from
.hookers
import
global_hooker_manager
from
typing
import
Optional
class
ActionManager(
object
):
def
__init__(
self
):
self
.__actions
=
[]
def
register(
self
, action):
self
.__actions.append(action)
idaapi.register_action(
idaapi.action_desc_t(action.name, action.description, action, action.hotkey)
)
if
isinstance
(action, HexRaysPopupAction):
global_hooker_manager.register(HexRaysPopupRequestHandler(action))
def
initialize(
self
):
pass
def
finalize(
self
):
for
action
in
self
.__actions:
idaapi.unregister_action(action.name)
action_manager
=
ActionManager()
class
Action(idaapi.action_handler_t):
description: Optional[
str
]
=
None
hotkey: Optional[
str
]
=
None
def
__init__(
self
):
super
(Action,
self
).__init__()
@property
def
name(
self
):
return
"HexRaysPyTools:"
+
type
(
self
).__name__
def
activate(
self
, ctx: idaapi.action_ctx_base_t):
raise
NotImplementedError
def
update(
self
, ctx: idaapi.action_ctx_base_t):
raise
NotImplementedError
class
HexRaysPopupAction(Action):
def
__init__(
self
):
super
(HexRaysPopupAction,
self
).__init__()
def
activate(
self
, ctx: idaapi.action_ctx_base_t):
raise
NotImplementedError
def
check(
self
, hx_view):
raise
NotImplementedError
def
update(
self
, ctx: idaapi.action_ctx_base_t):
if
ctx.widget_type
=
=
idaapi.BWN_PSEUDOCODE:
return
idaapi.AST_ENABLE_FOR_WIDGET
return
idaapi.AST_DISABLE_FOR_WIDGET
class
HexRaysPopupRequestHandler(idaapi.Hexrays_Hooks):
def
__init__(
self
, action):
super
().__init__()
self
.__action
=
action
def
populating_popup(
self
, widget, popup_handle, vu):
if
self
.__action.check(vu):
idaapi.attach_action_to_popup(widget, popup_handle,
self
.__action.name,
None
)
return
0
import
idaapi
from
.hookers
import
global_hooker_manager
from
typing
import
Optional
class
ActionManager(
object
):
def
__init__(
self
):
self
.__actions
=
[]
def
register(
self
, action):
self
.__actions.append(action)
idaapi.register_action(
idaapi.action_desc_t(action.name, action.description, action, action.hotkey)
)
if
isinstance
(action, HexRaysPopupAction):
global_hooker_manager.register(HexRaysPopupRequestHandler(action))
def
initialize(
self
):
pass
def
finalize(
self
):
for
action
in
self
.__actions:
idaapi.unregister_action(action.name)
action_manager
=
ActionManager()
class
Action(idaapi.action_handler_t):
description: Optional[
str
]
=
None
hotkey: Optional[
str
]
=
None
def
__init__(
self
):
super
(Action,
self
).__init__()
@property
def
name(
self
):
return
"HexRaysPyTools:"
+
type
(
self
).__name__
def
activate(
self
, ctx: idaapi.action_ctx_base_t):
raise
NotImplementedError
def
update(
self
, ctx: idaapi.action_ctx_base_t):
raise
NotImplementedError
class
HexRaysPopupAction(Action):
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!