您现在的位置: 首页 > 网站导航收录 > 百科知识百科知识
gr是什么单位 gr是什么单位的缩写
函数,节点,基本gr是什么单位 gr是什么单位的缩写
发布时间:2019-02-08加入收藏来源:互联网点击:
很多朋友想了解关于gr是什么单位的一些资料信息,下面是小编整理的与gr是什么单位相关的内容分享给大家,一起来看看吧。
前言angr是有名的一个二进制分析框架。官方文档关于二进制静态分析部分的介绍比较少。本文不会详细介绍静态分析的原理,只是简单地介绍如何用angr来实现一些基本的静态分析功能,比如后向切片,遍历调用图计算距离等等的操作。
概述二进制研究的很多应用都离不开二进制的静态分析。比如符号执行、模糊测试等技术可以利用静态分析的结果用来进行进一步的优化。
angr内部实现了很多静态分析功能,本文先从最基本的一些图来展开介绍,比如控制流图、控制依赖图、数据依赖图等等。至于angr内置的一些数据流分析方法,后续有时间会更新一下。因此,本文大体上分为以下这几个部分:
1.控制流图2.调用图3.后向切片
需要注意本文的代码是基于angr 9.0.10576这个版本写的。早期版本可能会有部分api的名字变了。比如下文的anyaddr参数,在早期版本的名字是any。
控制流图在二进制上最基础的分析应该就是生成一个控制流图(Control Flow Graph)。控制流图的节点是基本块,基本块可以理解为是一段以跳转指令或者分支指令为结尾的汇编代码。基本块具有原子,也就是不可分割,基本块内的代码要么全部执行,要么不执行。控制流图的边则表示跳转或者分支指令的流向。
angr中有两种控制流图,一种是静态的CFGFast,另一种是用符号执行实现的动态的CFGEmulated。CFGFast基于静态实现,所以能够恢复地比较全,而且生成得比较快。但是有些控制流关系只能在运行时才能确定,因此静态的CFGFast可能无法恢复这部分的关系。CFGEmulated基于符号执行实现,考虑了上下文关系,也能够恢复更准确的CFG,但缺点在于比较慢才能生成,并且因为系统调用、硬件特征模拟上的精度问题,导致控制流图可能恢复得不完整。二者的区别整理为下表。
区别
CFGFast
CFGEmulated
实现
静态分析实现
动态符号执行实现
考虑上下文
未考虑
考虑了
特点
更全
更精准
生成时间
快
慢
angr文档中也提到,如果不知道用哪个CFG,就先用CFGFast。
在angr中生成控制流图的代码如下:
import angr# 对要分析的二进制生成一个project对象p = angr.Project("/bin/ture",load_options={'auto_load_libs': False})# 生成静态的CFGcfg_fast = p.analyses.CFGFast()# 生成动态的CFG,keep_state参数表示保留状态cfg_emulated = p.analyses.CFGEmulated(keep_state=True)文档中提到angr的CFG的核心是基于NetworkX构建的,也就意味着所有NetworkX的API都可以使用。一开始没觉得这句话有啥,直到我看了下NetworkX的文档,才发现一下子格局就打开了。
NetworkX提供了很多图算法的接口,包括基础的DFS,BFS遍历,也包括一些最短路径的算法,比如A*,dijkstra等。这就意味着,我们可以很容易地利用NetworkX的API来实现控制流图的遍历和分析,甚至还可以和community包结合来实现louvain这种社区发现算法来发现CFG里的内部关系。
下面给出一个例子来介绍如何结合networkx来对angr生成的控制流图进行分析。
比如说,我们要获取某个节点的BFS遍历顺序,可以用networkx包里的shortest_path方法。
shortest_path(G, source=None, target=None, weight=None, method=”dijkstra”):
其中G表示networkx的图,source表示最短路径的起点,target表示最短路径的终点,最后返回一个最短路径列表。
需要注意下面的例子中除了用angr外,还使用了angrutils和networkx这两个包,需要安装才能运行下面的脚本。
安装networkx:pip install networkx
angrutils用于可视化,安装可以参考:https://github.com/axt/angr-utils
为方便测试,写了个小程序
#includestdio.hvoid error(char *error){ puts(error);}void alpha(){ puts("alpha"); error("alpha!");}void beta(){ puts("beta"); error("beta!");}void main(int argc,char * argv[]){ if(argv[1]=="a"){ alpha(); beta(); }else{ beta(); }}用gcc编译后,用下面的angr脚本先画个CFG图看看。
import angrfrom angrutils import *proj = angr.Project("testcase/call",load_options={'auto_load_libs': False})#从符号表获取main函数对象main = proj.loader.main_object.get_symbol("main")#生成起点从main函数开始的cfgcfg = proj.analyses.CFGEmulated(starts=[main.rebased_addr])# 调用angrutils的方法来画图plot_cfg(cfg,"cfg",format='png', asminst=True,remove_imports=True)这里我们截取部分的CFG图,假设我们要计算main函数的基本块到alpha函数中(0x400695)的最短路径。
我们就可以在之前的代码上添加如下几行:
from networkx import shortest_path# 根据地址获取cfg图的节点对象source_node = cfg.model.get_any_node(main.rebased_addr)target_node = cfg.model.get_any_node(0x400695)# 调用shortest_path方法path = shortest_path(G=cfg.graph,source=source_node,target=target_node) [CFGENode main 0x4006c3[38], CFGENode main+0x26 0x4006e9[10], CFGENode alpha 0x400685[16], CFGENode alpha+0x10 0x400695[12]]可以发现最后输出的路径也很容易从这部分的图上看出来。至于其他的networkx的api的用法就不一一演示了。原理上是相同的,只要是networkx对象,就都可以用它的api来实现图的分析。
至于可视化的地方,当然也可以直接用networkx将图导出为dot文件,再用其他可视化dot文件的工具来可视化,这样做更灵活,可以可视化一些图里的子图。
另外,补充一点,上面根据地址获取cfg图的节点对象的代码中,如果我们的地址是基本块中间的地址,而不是基本块开始的地址,我们需要加个参数anyaddr=True,如下:
target_node = cfg.model.get_any_node(0x400689,anyaddr=True)调用图控制流图是以基本块为粒度,而调用图则是以函数为粒度,是一种更粗的粒度。所以,有时候在考虑能开销的情况下,用调用图分析会比CFG要快得多。
调用图的可视化,也可以用angr-util来实现,具体代码如下:
import angrfrom angrutils import *proj = angr.Project("testcase/call",load_options={'auto_load_libs': False})main = proj.loader.main_object.get_symbol("main")cfg = proj.analyses.CFGEmulated(starts=[main.rebased_addr])callgraph = cfg.kb.callgraphplot_cg(cfg.kb,"call_graph",format='png')画出的调用图如下所示:
angr生成的调用图也是networkx对象,所以networkx的API同样也能对调用图来使用。这里就简单列几个比较常用的。
MultiDiGraph.nodes #返回一个节点列表MultiDiGraph.has_node(n)#是否有n节点MultiDiGraph.predecessors(n)#返回节点n的前继节点列表MultiDiGraph.successors(n)#返回节点n的后继节点列表调用图的粒度是以函数为单位。而angr中也内置了一个函数管理器cfg.kb.functions来管理函数。
#获取main函数的函数对象# 1. 先从符号表获取main函数的地址# 2. 再用地址从函数管理器获取main函数对象main = proj.loader.main_object.get_symbol("main")main_func = cfg.kb.functions[main.rebased_addr]# 直接从函数名获取函数对象main_func = cfg.kb.functions.function(name='main')一个函数对象有非常多对分析有用的属,这里列几个我觉得比较重要的,关于更多的属,可以去看angr源码的function部分
下一篇:返回列表
相关链接 |
||
网友回复(共有 0 条回复) |