初始化:
p = angr.Project('./test',load_options={"auto_load_libs":False})
载入文件,auto_load_libs设置为false,大概是启用angr自带的函数定义,避免一些逻辑过于复杂,机器跑不出来。
import claripy
arg = claripy.BVS(‘arg1′, 8)
我们使用claripy这个模块来定义抽象的数据,claripy的BVS函数可以创建一个指定长度的抽象数据,BVS函数要求两个参数,第一个参数为变量名,第二个参数为变量长度。符号化变量;
state = p.factory.entry_state(args=argv)
entry_state()函数接收一个list作为程序的命令行参数并且返回程序入口的状态
state.posix.files[0].read_from(1)
表示从标准输入读取一个字节
st = p.factory.blank_state(addr=)
创建一个 blank_state 对象,这个对象里面很多东西都是未初始化的,当程序访问未初始化的数据时,会返回一个不受约束的符号量
sm = p.factory.simulation_manager(state)
表示从state这个地址开始执行。
sm.explore(find=0x400676,avoid=[0x40073d])
当探索到find地方,就是想要的答案,avoid就是需要避免的地方。
sm.found.posix.dumps(1)
最后的输出
sm.found.posix.dumps(0)
found的输入
sm.found.solver.eval(arg1,cast_to = str)
使用约束求解引擎获取命令行参数,类型为字符串相关使用方法:
寄存器的符号化:
import angr import claripy p = angr.Project('') init_addr = 0x08048980 #scanf的下一条指令地址 state = p.factory.blank_state(addr=init_addr) #创建一个状态,并将该地址赋给它,也就是跳过输入,直接执行下一条指令,此处使用.blank_state()而不再是.entry_state() #定义三个位向量,即三个输入 p1 = claripy.BVS('p1',32) #32位寄存器(符号向量) p2 = claripy.BVS('p2',32) p3 = claripy.BVS('p3',32) state.regs.eax = p1 #.regs.eax 访问eax这个寄存器 state.regs.ebx = p2 state.regs.edx = p3 sm = p.factory.simulation_manager(state) def good(state): return b'Good Job.' in state.posix.dumps(1) def bad(state): return b'Try again.' in state.posix.dumps(1) sm.explore(find = good, avoid = bad) if sm.found: find_state = sm.found[0] flag1 = find_state.solver.eval(p1)#将探索成功时的第一个输入赋给flag1,下面两个类似 flag2 = find_state.solver.eval(p2) flag3 = find_state.solver.eval(p3) print('{:x} {:x} {:x}'.format(flag1,flag2,flag3))
栈的符号化:
import angr import claripy import sys def main(argv): p = angr.Project('') def good(state): return b'Good Job.' in state.posix.dumps(1) def bad(state): return b'Try again.' in state.posix.dumps(1) #创建开始状态 start_addr = 0x08048697 #scanf之后的地址,之所以是这儿,是因为上一行'add esp,10h'的作用是清理scanf的栈空间 state = p.factory.blank_state(addr=start_addr) #因为跳过了scanf函数,所以我们需要模拟它的整个 *** 作(对栈的 *** 作) #state.stack_push(state.regs.ebp) state.regs.ebp = state.regs.esp #初始化ebp、esp space = 0x8 #一个变量占4个空间,所以两个就是8 state.regs.esp -= space #模拟scanf时栈的情况(剔除了对空间的浪费,即只开辟了两个变量的空间) ps1 = claripy.BVS('ps1',32) #符号化两个输入 ps2 = claripy.BVS('ps2',32) state.stack_push(ps1) #将符号化的输入入栈 state.stack_push(ps2) #至此对scanf的模拟过程就完成了 #创建模拟管理器 simulation = p.factory.simgr(state) #开始探索 simulation.explore(find=good,avoid=bad) if simulation.found: solution_state = simulation.found[0] flag1 = solution_state.solver.eval(ps1) flag2 = solution_state.solver.eval(ps2) print('{} {}'.format(flag1,flag2)) if __name__ == '__main__': main(sys.argv)
内存的符号化:
import angr import claripy import sys def main(argv): path = argv[1] p = angr.Project(path) start_addr = 0x08048601 state = p.factory.blank_state(addr=start_addr) #创建四个位向量,模拟输入 p1 = claripy.BVS('p1',64) #一个变量输入8个字符,一个字符8位bit,总共64bit p2 = claripy.BVS('p2',64) p3 = claripy.BVS('p3',64) p4 = claripy.BVS('p4',64) #开始对输入进行模拟 state.memory.store(0x0A1BA1C0,p1)#让四个位向量指向输入在内存中的地址 state.memory.store(0x0A1BA1C8,p2) state.memory.store(0x0A1BA1D0,p3) state.memory.store(0x0A1BA1D8,p4) #scanf模拟结束 sm = p.factory.simgr(state) #创建模拟管理器 def good(state): return b'Good Job.' in state.posix.dumps(1) def bad(state): return b'Try again.' in state.posix.dumps(1) sm.explore(find = good,avoid = bad) if sm.found: solution_state = sm.found[0] flag1 = solution_state.solver.eval(p1,cast_to=bytes) flag2 = solution_state.solver.eval(p2,cast_to=bytes) flag3 = solution_state.solver.eval(p3,cast_to=bytes) flag4 = solution_state.solver.eval(p4,cast_to=bytes) print("{} {} {} {}".format(flag1.decode('utf-8'),flag2.decode('utf-8'),flag3.decode('utf-8'),flag4.decode('utf-8'))) else: print("NO") if __name__ == '__main__': main(sys.argv)
hook:
在 angr 中使用 hook 来把指定地址的二进制代码替换为 python 代码。angr 在模拟执行程序时,执行每一条指令前会检测该地址处是否已经被 hook ,如果是就不执行这条语句,转而执行hook 时指定的 python 处理代码。
#!/usr/bin/env python # coding=utf-8 import angr import claripy def hook_demo(state): state.regs.eax = 0 state.regs.ebx = 0xdeadbeef p = angr.Project("./examples/sym-write/issue", load_options={"auto_load_libs": False}) p.hook(addr=0x08048485, hook=hook_demo, length=2) # 使用 p.hook 把 0x08048485 处的 2 字节的指令 为 hook_demo,之后执行 0x08048485就会去执行 hook_demo state = p.factory.blank_state(addr=0x0804846B, add_options={"SYMBOLIC_WRITE_ADDRESSES"})#创建一个 state , 因为要往内存里面设置 符号量 ( BVS ),设置SYMBOLIC_WRITE_ADDRESSES u = claripy.BVS("u", 8) state.memory.store(0x0804A021, u) #新建一个 8 位长度的符号量,并把它存到 0x0804A021 (全局变量 u 的位置) sm = p.factory.simgr(state) sm.explore(find=0x080484DB) st = sm.found[0] print hex(st.se.eval(st.regs.ebx))
p.hook(addr=0x08048485, hook=hook_demo, length=2)
-
addr 为待 hook 指令的地址
-
hook 为 hook 的处理函数,在执行到 addr 时,会执行 这个函数,同时把 当前的 state 对象作为参数传递过去
-
length 为 待 hook 指令的长度,在 执行完 hook 函数以后,angr 需要根据 length 来跳过这条指令,执行下一条指令
报错:
The main binary is a position-independent executable. It is being loaded with a base address of 0x400000.
我们后面程序的地址要加上基址偏移。
参考:
大佬的代码
大佬的博客
大佬的博客
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)