
初始化:
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条)