前言
继续做题,冲冲冲,本文每一个章节都是先按照自己的思路做完然后看出题人的答案
每次进虚拟环境敲代码太麻烦了,在这存一下
cd angrfile
virtualenv env
source venv/bin/activate
0x0.03_angr_symbolic_registers

Emm…..不还是那一套嘛…..
import angr
import sys
def main(argv):
Path = argv[1]
p = angr.Project(Path,auto_load_libs = False)
init_state = p.factory.entry_state()
sm = p.factory.simgr(init_state)
target_address = 0x080495FA
sm.explore(find = target_address)
if sm.found:
solution_state = sm.found[0]
print(solution_state.posix.dumps(0))
if __name__ == '__main__':
main(sys.argv)
也是出了答案,看一眼题解
OK啊,也是有很多新东西,开始学习出题人的思路:在通常情况下,想要从main函数入口点找到一条正确的路径是很耗时的,但是我们可以指定一个start_address,然后自己分析之前的部分,将此时的要求的值在哪个寄存器里搞明白,可以自己加限制来提高效率,用angr输出这时候的寄存器的值,再一步步向上逆
import angr
import claripy
import sys
def main(argv):
Path = argv[1]
p = angr.Project(Path,auto_load_libs = False)
start_address = 0x08049592
init_state = p.factory.blank_state(addr = start_address , auto_load_libs =False)
#创建三个变量,包括名字和大小,怎么一股z3的味道...
password0_size_in_bits = 32
password0 = claripy.BVS('password0',password0_size_in_bits)
password1_size_in_bits = 32
password1 = claripy.BVS('password1',password1_size_in_bits)
password2_size_in_bits = 32
password2 = claripy.BVS('password2',password2_size_in_bits)
#将三个数字交给state状态下的这三个寄存器
init_state.regs.eax = password0
init_state.regs.ebx = password1
init_state.regs.edx = password2
sm = p.factory.simgr(init_state)
def is_sucessful(state):
stdout_output = state.posix.dumps(1)
return True if b'Good Job.' in stdout_output else False
def should_abort(state):
stdout_output = state.posix.dumps(1)
return True if b'Try again.' in stdout_output else False
sm.explore(find = is_sucessful,avoid = should_abort)
if sm.found:
solution_state = sm.found[0]
solution0 = solution_state.solver.eval(password0)
solution1 = solution_state.solver.eval(password1)
solution2 = solution_state.solver.eval(password2)
#这里不是dumps(0),我们要的值不是state的时候的输入,是寄存器的值
print(hex(solution0),hex(solution1),hex(solution2))
if __name__ == '__main__':
main(sys.argv)
写本文时本人并不熟练python的格式化字符串和代码简写,代码有点史,能跑就行

0x1.04_angr_symbolic_stack
根据名字来看的话应该是跟栈有关,进去一看果然是把读的数放在了栈上,这个程序很简单,为了练习就不以做出来为目的了,直接往出题人的思路上去靠一下

然后我大概写了一个exp,但是因为不知道能不能直接对esp操作,再加上一些函数并不了解,直接学习一手
import angr,claripy
import sys
def main(argv):
path = argv[1]
p = angr.Project(path,auto_load_libs = False)
start_address = 0x80493EF
init_state = p.factory.blank_state(addr = start_address)
password0 = claripy.BVS('password0',32)
password1 = claripy.BVS('password1',32)
init_state.regs.esp = ... #初始化esp
sm = p.factory.simgr(init_state)
def is_sucessful(state):
stdout_output = state.posix.dumps(1)
return True if b'Good Job.' in stdout_output else False
def should_abort(state):
stdout_output = state.posix.dumps(1)
return True if b'Try again.' in stdout_output else False
sm.explore(find = is_sucessful,avoid = should_abort)
if sm.found:
solution_state = sm.found[0]
...
#得到当前的state的esp然后减一下
print(solution)
if __name__ == '__main__':
main(sys.argv)
这个题好像要比我想象的要复杂得多啊,为了还原栈在scanf前后的状态要分析一下栈的变化

先是将esp交给了ebp,为接下来的函数开辟了一部分的栈空间,然后esp下降,然后将ebp-0x10,ebp-0xc压入栈中,与格式化字符串一起传给scanf,然后可以看到在第一个加密函数对第一个输入进行了操作,所以password0就是第一个输入,现在对上面的代码进行一下改进
import angr,claripy
import sys
def main(argv):
path = argv[1]
p = angr.Project(path,auto_load_libs = False)
start_address = 0x080493F2
init_state = p.factory.blank_state(addr = start_address)
password0 = claripy.BVS('password0',32)
password1 = claripy.BVS('password1',32)
init_state.regs.ebp = init_state.regs.esp
init_state.regs.esp -= 0x8
init_state.stack_push(password0)
init_state.stack_push(password1)
sm = p.factory.simgr(init_state)
def is_sucessful(state):
stdout_output = state.posix.dumps(1)
return True if b'Good Job.' in stdout_output else False
def should_abort(state):
stdout_output = state.posix.dumps(1)
return True if b'Try again.' in stdout_output else False
sm.explore(find = is_sucessful,avoid = should_abort)
if sm.found:
solution_state = sm.found[0]
solution0 = solution_state.solver.eval(password0)
solution1 = solution_state.solver.eval(password1)
print(solution0,solution1)
else:
print('Not Found')
if __name__ == '__main__':
main(sys.argv)
要特别注意取的起始地址start_address,地址不同,栈的情况也不一样,要注意还原,stack_push函数可以完全模拟入栈操作的寄存器和操作数的变化
我调试了一下,在add esp,0x10结束后esp 并不在我们设计的ebp-0x10的位置,但是之后的操作栈只会向下开辟,不污染我们的password所以能出答案

0x2.05_angr_symbolic_memory

很显然,这题我们的思路就是要去初始化四个变量,然后将他们交给scanf之后的state的那四个特定地址user_input, &unk_9BFC3C8, &unk_9BFC3D0, &unk_9BFC3D8,怎么交给这四个地址肯定是有个函数的,但是之前的代码中并未提到
看了一下函数的格式是这样的
initial_state.memory.store(password0_address, password0)
并且最后为了得到字符串而不是一串数字,还进行了如下操作
solution0 = solution_state.solver.eval(password0,cast_to=bytes).decode()
好了,现在可以写出我们的exp了
import angr
import claripy
import sys
def main(argv):
path = argv[1]
p = angr.Project(path,auto_load_libs = False)
start_address = 0x08049315
init_state = p.factory.blank_state(addr = start_address)
password0 = claripy.BVS('password0',64)
password1 = claripy.BVS('password1',64)
password2 = claripy.BVS('password2',64)
password3 = claripy.BVS('password3',64)
init_state.memory.store(0x09BFC3C0, password0)
init_state.memory.store(0x09BFC3C8, password1)
init_state.memory.store(0x09BFC3D0, password2)
init_state.memory.store(0x09BFC3D8, password3)
sm = p.factory.simgr(init_state)
def is_sucessful(state):
stdout_output = state.posix.dumps(1)
return True if b'Good Job.' in stdout_output else False
def should_abort(state):
stdout_output = state.posix.dumps(1)
return True if b'Try again.' in stdout_output else False
sm.explore(find = is_sucessful,avoid = should_abort)
if sm.found:
solution_state = sm.found[0]
solution0 = solution_state.solver.eval(password0,cast_to = bytes).decode()
solution1 = solution_state.solver.eval(password1,cast_to = bytes).decode()
solution2 = solution_state.solver.eval(password2,cast_to = bytes).decode()
solution3 = solution_state.solver.eval(password3,cast_to = bytes).decode()
print(solution0,solution1,solution2,solution3)
else:
print('Not Found')
if __name__ == '__main__':
main(sys.argv)

0x3.06_angr_symbolic_dynamic_memory

与上个题不同的是这个不是静态的地址,是从堆上开辟的一段地址,所以在还原环境的时候我们也要在堆上开辟地址,交给buffer0和buffer1
出题人的exp中提到angr是默认大段排序,所以要用 endness = p.arch.memory_endness 改为小段存储数据,直接上exp了:
import angr
import claripy
import sys
def main(argv):
path = argv[1]
p = angr.Project(path,auto_load_libs = False)
start_address = 0x0804938C
init_state = p.factory.blank_state(addr = start_address)
#print('ESP:',init_state.regs.esp)
esp = 0x7fff0000
password0 = claripy.BVS('password0',64)
password1 = claripy.BVS('password1',64)
heap_0 = esp - 0x200
buffer0 = 0x093D3B38
init_state.memory.store(buffer0, heap_0,endness = p.arch.memory_endness)
init_state.memory.store(heap_0,password0)
heap_1 = esp - 0x300
buffer1 = 0x093D3B40
init_state.memory.store(buffer1, heap_1,endness = p.arch.memory_endness)
init_state.memory.store(heap_1,password1)
sm = p.factory.simgr(init_state)
def is_sucessful(state):
stdout_output = state.posix.dumps(1)
return True if b'Good Job.' in stdout_output else False
def should_abort(state):
stdout_output = state.posix.dumps(1)
return True if b'Try again.' in stdout_output else False
sm.explore(find = is_sucessful,avoid = should_abort)
if sm.found:
solution_state = sm.found[0]
solution0 = solution_state.solver.eval(password0,cast_to = bytes).decode()
solution1 = solution_state.solver.eval(password1,cast_to = bytes).decode()
print(solution0,solution1)
else:
print('Not Found')
if __name__ == '__main__':
main(sys.argv)

今天的题就先做到这吧 : )