标题是bits of static binary analysis,意思为碎片化粒度的静态二进制分析
- 作为安全研究人员,如何从复杂系统的二进制文件中挖掘出漏洞是个难题
- 在这篇随笔中,阅读bits of static binary analysis演讲内容,学习查找二进制程序中的漏洞,并快速找到它们
- 静态分析,使用VEX和CFG来表示分析的程序,污点分析,使用关系依赖图和Reaching Definition analysis(可达定义分析)
静态分析
在不实际运行程序的情况下收集程序中数据的运行时信息的技术。一次同时对几个状态进行推理,但不太精确
源代码VS二进制
很简单,对于二进制安全研究人员来说,不是一切二进制文件都能找到源代码,所以研究如何分析二进制文件是一个必要的工作
VEX中间表示(IR)
不展开解释,https://github.com/angr/pyvex#vex-intermediate-representation
控制流图(CFG)
学二进制的人很常见,IDA反编译好的时候就会切换到控制流视图。https://docs.angr.io/built-in-analyses/cfg#cfgfast-details
这里有个例子,在bits of static binary analysis对于的github仓库里
编译出vex_and_cfg,main函数很简单
int __cdecl main(int argc, const char **argv, const char **envp) { puts("hello world!"); return 0; }
输出一个hello world!
vex_and_cfg
from angr import Project
project = Project('../build/vex_and_cfg', auto_load_libs=False)
architecture = project.arch
cfg = project.analyses.CFGFast()
‘#’使用project.kb.functions.function(name='main')获取名为'main'的函数对象
main_function = project.kb.functions.function(name='main')
‘#’ 获取'main'函数的所有基本块(basic blocks)并存储在blocks_of_main列表中。
blocks_of_main = list(main_function.blocks)
‘#’ 从'main'函数的基本块列表中获取第一个基本块,并获取该基本块的VEX表示。
main_vex = blocks_of_main[0].vex
‘#’ 从CFG中获取' main '的第一个节点(基本块)。
main_entry_node = cfg.model.get_any_node(main_function.addr)
‘#’ 通过main_entry_node.successors可以获得所有直接后继节点的列表,而使用索引 [0] 获取列表中的第一个后继节点。
mystery_node = main_entry_node.successors[0]
print(mystery_node.addr)
‘#’ Simprocedure!?Simprocedure是一种特殊的函数处理机制。它们是对特定函数进行模拟的过程,用于处理无法静态分析的函数、外部库函数或操作系统调用等。这里应该是表示调用导入的puts?
mystery_simprocedure = mystery_node.successors[0]
print(mystery_simprocedure.name)
‘#’ The mystery returns to main
.
main_other_node = mystery_simprocedure.successors[0]
print(main_other_node.addr)
一些补充说明
- main_entry_node.successors[0]是获取main_entry_node的第一个后继节点的方式。在Angr库中,控制流图中的节点表示程序的基本块,而后继节点表示控制流图中当前节点的直接后继节点。通过main_entry_node.successors可以获得所有直接后继节点的列表,而使用索引 [0] 获取列表中的第一个后继节点。所以,main_entry_node.successors[0]表示获取了main_entry_node的第一个后继节点。根据代码的上下文,这个节点被赋值给了mystery_node。
- 在Angr库中,Simprocedure是一种特殊的函数处理机制。它们是对特定函数进行模拟的过程,用于处理无法静态分析的函数、外部库函数或操作系统调用等。根据给定的代码,mystery_node.successors[0]返回的节点被认为是一个Simprocedure节点。通过将该节点赋值给mystery_simprocedure,可以对该Simprocedure节点进行进一步的分析和处理。Simprocedure节点通常表示对于某个特定函数的模拟过程,而不是真正的代码。可能是对函数调用的模拟、处理外部库函数的模拟等。要了解具体的Simprocedure类型和其模拟的功能,需要进一步研究或查看相关文档。
作为一个Simprocedure节点,它可能具有以下一些常见的成员变量(属性):
name: Simprocedure的名称,表示所模拟的函数或操作的名称。
addr: Simprocedure的地址,表示在二进制文件中的位置。
successors: 后继节点列表,表示在Simprocedure执行后可能到达的下一个节点。
predecessors: 前驱节点列表,表示在Simprocedure执行前可能到达该节点的前一个节点。
statements: Simprocedure的语句列表,表示模拟函数或操作的具体执行过程。
arguments: 表示传递给Simprocedure的参数。
returns: 表示Simprocedure的返回值。
这些成员变量的具体名称和内容可能根据使用的Angr版本、Simprocedure类型以及代码中的具体实现而有所不同。要查看mystery_simprocedure对象的成员变量,可以打印或使用调试工具查看对象的属性。例如,可以尝试使用print(mystery_simprocedure.dict)来查看该对象的所有成员变量。