状态插件(state plugin)

除了刚刚讨论过的选项集,所有存储在 SimState 中的东西实际上都存储在附加在 state 上的“插件”中。到目前为止我们讨论的几乎所有 state 的属性都是一个插件—— memoryregistersmemregssolver 等等。这种设计带来了代码的模块化和能够便捷地为模拟状态的其他方面实现新的数据存储,或者提供插件的替代实现能力。

比如说,通常 memory 插件模拟一个平坦地址空间,但是在分析中可以选择开启“抽象内存”插件来支持 state.memory,“抽象内存”使用新的数据类型表示地址,以模拟浮动的独立内存空间映射。反过来,插件可以减少代码的复杂性:state.memorystate.registers 实际上是同一个插件的不同实例,因为寄存器也是用一块地址空间模拟的。

能够控制仿真程序所看到的环境,包括如何从环境中引入符号数据,这一点非常重要!angr 具有一系列可靠的抽象概念,可帮助您设置所需的环境。

仿真文件系统 -The Emulated Filesystem

这题的关键是利用了 angr 强大的仿真文件系统。在 angr 中与文件系统,套接字,管道或终端的任何交互的根源都是 SimFile 对象。SimFile 是一种存储抽象,它定义符号或其他形式的字节序列。您可以从某个位置读取文件,可以在某个位置写入文件,可以询问文件中当前存储了多少字节,还可以具体化文件,并为其生成测试用例。

简单来说利用 SimFile 形成符号化的文件的格式:

simgr_file = angr.storage.SimFile(filename, content=xxxxxx, size=file_size)

然后需要传给 state 的初始化过程来影响对文件系统的使用。我们可以利用 fs 选项以文件名的字典来预配置 SimFile 对象,也可以 fs.insert 是将文件插入到文件系统中,需要文件名与符号化的文件

initial_state.fs.insert(filename, simgr_file)

我们从 IDA 可以知道输入的是格式化字符串 %64s 也就是 64 个字符,一个字符是 8 比特,故最后是 512 比特

最后的得到这一部分代码:

filename = 'OJKSQYDP.txt'
symbolic_file_size_bytes = 64
passwd0 = claripy.BVS('password', symbolic_file_size_bytes * 8)
passwd_file = angr.storage.SimFile(filename, content=passwd0, size=symbolic_file_size_bytes)
 
initial_state.fs.insert(filename, passwd_file)
 
simulation = project.factory.simgr(initial_state)
import angr  
import claripy  
  
  
def Go():  
    path_to_binary = "./07_angr_symbolic_file"  
    project = angr.Project(path_to_binary, auto_load_libs=False)  
    start_address = 0x80488EA  
    initial_state = project.factory.blank_state(addr=start_address)  
  
    filename = 'OJKSQYDP.txt'  
    symbolic_file_size_bytes = 64  
    passwd0 = claripy.BVS('password', symbolic_file_size_bytes * 8)  
    passwd_file = angr.storage.SimFile(filename, content=passwd0, size=symbolic_file_size_bytes)  
  
    initial_state.fs.insert(filename, passwd_file)  
  
    simulation = project.factory.simgr(initial_state)  
  
    def is_successful(state):  
        stdout_output = state.posix.dumps(1)  
        if b'Good Job.\n' in stdout_output:  
            return True  
        else:  
            return False  
  
    def should_abort(state):  
        stdout_output = state.posix.dumps(1)  
        if b'Try again.\n' in stdout_output:  
            return True  
        else:  
            return False  
  
    simulation.explore(find=is_successful, avoid=should_abort)  
  
    if simulation.found:  
        for i in simulation.found:  
            solution_state = i  
            solution0 = solution_state.solver.eval(passwd0, cast_to=bytes)  
            print("[+] Success! Solution is: {0}".format(solution0.decode('utf-8')))  
            # print(solution0)  
    else:  
        raise Exception('Could not find the solution')  
  
  
if __name__ == "__main__":  
    Go()