您现在的位置: 首页 > 网站导航收录 > 百科知识百科知识
gr是什么单位 gr是什么单位的缩写
函数,节点,基本gr是什么单位 gr是什么单位的缩写
发布时间:2019-02-08加入收藏来源:互联网点击:
-
func.name :函数名字func.is_plt:是否是外部库函数func.addr:函数入口地址func.binary_name:函数所在的二进制func.is_syscall:是否是系统调用func.block_addrs:属于函数的基本块的地址集合func.transition_graph :函数内部的控制流图,类似在ida里看到的一样func.get_call_sites():获取函数的调用点
在实际应用的过程中,我遇到了一个问题:知道某个指令的地址,怎么求出其所在的函数地址?
我的思路是分为以下两步:
1.将指令地址转换为基本块地址
2.遍历函数管理器,看基本块地址是否在函数内
# 1.将指令地址addr转为cfg节点对象target_nodetarget_node = cfg.model.get_any_node(addr,anyaddr=True)# 2.遍历函数管理器,看基本块地址是否在函数内,若在,则说明指令属于该函数target_func = Nonefor _,func in self._cfg.kb.functions.items(): if block_addr in func.block_addrs: target_func = func breakprint(target_func.name)同样的,如果已知指令地址和其所在的基本块,获取指令在基本块的索引,可以用下面的代码来实现:
# 从指令地址addr挖出指令在基本块的索引def find_index(addr): # 1.获取指令所在的基本块 node = cfg.model.get_any_node(addr,anyaddr=True) # 2.遍历基本块的指令地址,找到指令对应的索引 for idx,instruction_addr in enumerate(node.instruction_addrs): if instruction_addr == addr: return (node.addr,idx) # 没找到,则返回None return (node.addr,None)后向切片可以发现angr的后向切片函数的参数包括控制流图cfg,控制依赖图cdg,数据依赖图ddg,以及切片开始的起点target。
BackwardSlice(cfg, cdg=cdg, ddg=ddg, targets=[ (target_node, -1) ])
其中数据依赖图可以用基于cfg构建的数据依赖图或者基于值集分析的VFG。target参数存着是一个列表,列表中包含一个元组(基本块节点,指令在基本块中的索引)。
下面的代码是官方的样例,实现了从exit函数开始做的后向切片。
import angr# Load the project b = angr.Project("examples/fauxware/fauxware", load_options={"auto_load_libs": False})# 要基于CFG生成数据依赖图的话,需要在生成CFG的时候添加下面两个选项# 1. 保留所有状态 keep_state=True # 2. 保存内存、寄存器和临时变量的访问angr.options.refs option cfg = b.analyses.CFGEmulated(keep_state=True, ... state_add_options=angr.sim_options.refs, ... context_sensitivity_level=2)# 生成控制依赖图 cdg = b.analyses.CDG(cfg)# 生成数据依赖图,或者用angr的vsa生成VFG,也可以传入切片的ddg参数中去 ddg = b.analyses.DDG(cfg)# See where we wanna go... let’s go to the exit() call, which is modeled as a # SimProcedure. target_func = cfg.kb.functions.function(name="exit")# 获取一个CFG的节点实例 target_node = cfg.model.get_any_node(target_func.addr)# 获取切片# targets是一个列表,每个元素是CodeLocation对象或者是一个元组包含CFGNode节点和语句ID。# ID是-1表示CFGNode的节点的开始,由于一个simprocedure是没有任何语句的,所以需要设置为-1 bs = b.analyses.BackwardSlice(cfg, cdg=cdg, ddg=ddg,control_flow_slice=True, targets=[ (target_node, -1) ])# 使用切片# 输出控制流切片的结果,如果可视化CFG图看的话,会发现这个切片的结果基本上就是从reject一路推回main函数的CFG节点 print([hex(node.addr) for node in bs.cfg_nodes_in_slice])['0x400713', '0x400570', '0x4006fd', '0x700008', '0x400520', '0x4007c9', '0x4007b3', '0x4007a0', '0x4006eb', '0x4006e6', '0x4006db', '0x4006c8', '0x4006af', '0x700010', '0x400530', '0x400699', '0x40068e', '0x400664', '0x40078a', '0x700010', '0x400774', '0x700010', '0x40076a', '0x700000', '0x400510', '0x400754', '0x700010', '0x40073e', '0x700010', '0x40071d', '0x700000', '0x400692', '0x4006df']# 输出切片中每个基本块里选的指令# 由于我们选择的是exit函数作为target,exit的参数是常数,也就没有数据依赖,所以chosen_statements这个结果应该是空集合。# 但由于我们加上了control_flow_slice=True,所以会输出如下结果: print(bs.chosen_statements){4195696: True, 4196115: True, 7340040: True, 4195616: True, 4196093: True, 4196297: True, 4196275: True, 4196070: True, 4196059: True, 4196040: True, 7340048: True, 4195632: True, 4196015: True, 4195993: True, 4195982: True, 4195940: True, 4196256: True, 4196234: True, 4196212: True, 7340032: True, 4195600: True, 4196202: True, 4196180: True, 4196158: True, 4196125: True, 4196075: True, 4196063: True, 4195986: True}# 问题来了,这里输出的结果是28个基本块,而上面cfg_nodes_in_slice的结果是33个基本块。# 将这两个列表求差集,发现差集为空集。# 实际上,可以发现cfg_nodes_in_slice中有许多重复的基本块。而chosen_statements是放在字典中的,自动做了个去重的操作。# 因此,求控制流切片的话,两个接口都可以用的。 print(bs.chosen_statements.keys())['0x400570', '0x400713', '0x700008', '0x400520', '0x4006fd', '0x4007c9', '0x4007b3', '0x4006e6', '0x4006db', '0x4006c8', '0x700010', '0x400530', '0x4006af', '0x400699', '0x40068e', '0x400664', '0x4007a0', '0x40078a', '0x400774', '0x700000', '0x400510', '0x40076a', '0x400754', '0x40073e', '0x40071d', '0x4006eb', '0x4006df', '0x400692']# 如果将runs_in_slice的图的节点和边与cfg_nodes_in_slice的图进行比较,二者的节点和边的集合都是相同的。# 可以理解为runs_in_slice是cfg_nodes_in_slice的去重版本。 print([hex(item) for item in bs.runs_in_slice])['0x400713', '0x400570', '0x4006fd', '0x700008', '0x400520', '0x4007c9', '0x4007b3', '0x4007a0', '0x4006eb', '0x4006e6', '0x4006db', '0x4006c8', '0x4006af', '0x700010', '0x400530', '0x400699', '0x40068e', '0x400664', '0x40078a', '0x400774', '0x40076a', '0x700000', '0x400510', '0x400754', '0x40073e', '0x40071d', '0x400692', '0x4006df']此外,如果可视化runs_in_slice和cfg_nodes_in_slice,也能很明显地看出二者的节点类型不一样,但图的拓扑结构差不多。
runs_in_slice的每个节点都是基本块的地址。
cfg_nodes_in_slice的每个节点都是CFG节点实例。
很遗憾没有找到比较好的例子来说明分析数据依赖的切片。实际用数据流切片中,我发现使用chosen_statements会打印出如下的字典,字典的键为基本块的地址,值为基本块内的索引,也就是第几条指令。可以发现索引中出现了大量的-2,推测指的是跳转指令上面的那一条指令。
总结本文只是很粗浅地介绍了angr的静态分析功能的基本使用,如果要实现文章中没介绍的功能,还是要深入angr的源码去看这些对象有哪些属和方法。angr的大部分的静态分析的源码都在angr/angr/analyses目录下,也有一些关于cfg,function的信息是在angr/angr/knowledge_plugins下。
此外,如果觉得看源码还是看不懂API是怎么用的,也可以直接去看angr/tests目录下有没有对应API的测试脚本。
下一篇:返回列表
相关链接 |
||
网友回复(共有 0 条回复) |