这里将会写angr模拟寄存器,栈,bss段,模拟堆,模拟文件
补充:格式化是angr的弱点,需要尽量避开
0x03设置寄存器的值
# -*- coding:utf-8 -*-
import angr
import claripy
import sys
reload(sys)
sys.setdefaultencoding("utf8")
#设置寄存器值
"""
angr只支持一次scanf,多次scanf需要绕过。
因为是32位寄存器所以需要32位
initial_state.regs.eax = password0 可以设置寄存器的值
solution0 = solution_state.se.eval(password0) 可以获取解决方案,但是只有一个位向量的
加载程序,设置开始地址,设置寄存器值(设置初始状态) 设置正确和错误的结果探索 取出跑出来的结果
"""
def main(argv):
project=angr.Project("./1")
#这个地址是从ida里面找出来的,读入了数据之后的值
"""
.text:08048911 call get_user_input
.text:08048916 mov [ebp+var_14], eax
.text:08048919 mov [ebp+var_10], ebx
.text:0804891C mov [ebp+var_C], edx
"""
start_address=0x08048916
initial_state=project.factory.blank_state(addr=start_address) #用blank_state 来实现从某个地址处载入
#因为32位程序寄存器最多放32位
password0_size_in_bits=32
#用来生成位向量 这个东西应该是类似列表之类的东西
password0=claripy.BVS('password0',password0_size_in_bits)
password1 = claripy.BVS('password1', password0_size_in_bits)
password2 = claripy.BVS('password2', password0_size_in_bits)
#给寄存器赋值 ida里面可以看到这三个寄存器是决定程序的值是否走到 good job的值
initial_state.regs.eax=password0
initial_state.regs.ebx = password1
initial_state.regs.edx = password2
simulation=project.factory.simgr(initial_state)
def is_successful(state):
stdout_output=state.posix.dumps(sys.stdout.fileno())
return "Good" in stdout_output
def should_abort(state):
stdout_output=state.posix.dumps(sys.stdout.fileno())
return "Try" in stdout_output
simulation.explore(find=is_successful,avoid=should_abort)
if simulation.found:
solution_state=simulation.found[0]
#找到了之后想要拿出来需要一个一个取 应该是字典之类的东东西
solution0=solution_state.se.eval(password0)
solution1=solution_state.se.eval(password1)
solution2=solution_state.se.eval(password2)
solution= str(solution0)+","+str(solution1)+","+str(solution2)
print hex(solution0), hex(solution1), hex(solution2)
print solution
else:
raise Exception("Could not find the solution")
if __name__ == '__main__':
main(sys.argv)
0x04设置栈
import angr
import claripy
import sys
def main(argv):
path_to_binary = "./04_angr_symbolic_stack"
project = angr.Project(path_to_binary) #设置加载路径
start_address = 0x08048697
initial_state = project.factory.blank_state(addr=start_address) #设置开始地址
initial_state.regs.ebp = initial_state.regs.esp #设置栈的开始数据
password0 = claripy.BVS('password0', 32)
password1 = claripy.BVS('password1', 32)
padding_length_in_bytes = 8 # :integer
initial_state.regs.esp -= padding_length_in_bytes #放入栈中
initial_state.stack_push(password0) # :bitvector (claripy.BVS, claripy.BVV, claripy.BV)
initial_state.stack_push(password1)
simulation = project.factory.simgr(initial_state) #运行,找到地址
def is_successful(state):
stdout_output = state.posix.dumps(sys.stdout.fileno())
return 'Good Job' in str(stdout_output)
def should_abort(state):
stdout_output = state.posix.dumps(sys.stdout.fileno())
return 'Try again.' in str(stdout_output)
simulation.explore(find=is_successful, avoid=should_abort)
if simulation.found: #处理结果
solution_state = simulation.found[0]
solution0 = solution_state.se.eval(password0)
solution1 = solution_state.se.eval(password1)
solution = ' '.join(map('{:x}'.format, [solution0, solution1]))
print(solution)
else:
raise Exception('Could not find the solution')
if __name__ == '__main__':
main(sys.argv)
核心代码
initial_state.regs.ebp = initial_state.regs.esp
password0 = claripy.BVS('password0', 32)
padding_length_in_bytes = 8 # :integer 减8是因为两个数据,每个32bit也就是4个字节共8个字节
initial_state.regs.esp -= padding_length_in_bytes #放入栈中
initial_state.stack_push(password0)
0x05模拟bass段
import angr
import claripy
import sys
import binascii
def main(argv):
path_to_binary = "./05_angr_symbolic_memory"
project = angr.Project(path_to_binary)
start_address = 0x08048601
initial_state = project.factory.blank_state(addr=start_address)
# The binary is calling scanf("%8s %8s %8s %8s").
# (!)
password0 = claripy.BVS('password0', 8*8) #设置数据个数,这里的数是bit数,一个字节是8个bit
password1 = claripy.BVS('password1', 8 * 8)
password2 = claripy.BVS('password2', 8 * 8)
password3 = claripy.BVS('password3', 8 * 8)
# Determine the address of the global variable to which scanf writes the user
# input. The function 'initial_state.memory.store(address, value)' will write
# 'value' (a bitvector) to 'address' (a memory location, as an integer.) The
# 'address' parameter can also be a bitvector (and can be symbolic!).
# (!)
password0_address = 0x09FD92A0 #把数据放到
initial_state.memory.store(password0_address, password0)
password0_address = 0x09FD92A8
initial_state.memory.store(password0_address, password1)
password0_address = 0x09FD92B0
initial_state.memory.store(password0_address, password2)
password0_address = 0x09FD92B8
initial_state.memory.store(password0_address, password3)
simulation = project.factory.simgr(initial_state)
def is_successful(state):
stdout_output = state.posix.dumps(sys.stdout.fileno())
return 'Good Job' in str(stdout_output)
def should_abort(state):
stdout_output = state.posix.dumps(sys.stdout.fileno())
return 'Try again.' in str(stdout_output)
simulation.explore(find=is_successful, avoid=should_abort)
if simulation.found:
solution_state = simulation.found[0]
# Solve for the symbolic values. We are trying to solve for a string.
# Therefore, we will use eval, with named parameter cast_to=str
# which returns a string instead of an integer.
# (!)
solution0 = solution_state.se.eval(password0)
solution1 = solution_state.se.eval(password1)
solution2 = solution_state.se.eval(password2)
solution3 = solution_state.se.eval(password3)
solution = ''.join(map('{:x}'.format, [solution0, solution1,solution2,solution3]))
print (binascii.a2b_hex(solution)) #16进制数转字符串
else:
raise Exception('Could not find the solution')
if __name__ == '__main__':
main(sys.argv)
设置数据的内容
password0_address = 0x09FD92A0 #把数据放到
initial_state.memory.store(password0_address, password0)
0x06模拟堆
import angr
import claripy
import sys
import binascii
def main(argv):
path_to_binary = "./06_angr_symbolic_dynamic_memory"
project = angr.Project(path_to_binary)
start_address = 0x08048699
initial_state = project.factory.blank_state(addr=start_address)
# The binary is calling scanf("%8s %8s").
# (!)
password0 = claripy.BVS('password0', 8*8) #buffer0
password1 = claripy.BVS('password1', 8*8) #buffer1
# Instead of telling the binary to write to the address of the memory
# allocated with malloc, we can simply fake an address to any unused block of
# memory and overwrite the pointer to the data. This will point the pointer
# with the address of pointer_to_malloc_memory_address0 to fake_heap_address.
# Be aware, there is more than one pointer! Analyze the binary to determine
# global location of each pointer.
# Note: by default, Angr stores integers in memory with big-endianness. To
# specify to use the endianness of your architecture, use the parameter
# endness=project.arch.memory_endness. On x86, this is little-endian.
# (!)
fake_heap_address0 = 0x40000
pointer_to_malloc_memory_address0 =0x09FD92AC
initial_state.memory.store(pointer_to_malloc_memory_address0, fake_heap_address0, endness=project.arch.memory_endness)
#buffer0 把数据放入内存堆地址(数据具体存到哪随意) 这个地址的指针,也就是变量的具体值要准确
fake_heap_address1 = 0x40010
pointer_to_malloc_memory_address1 = 0x09FD92B4
initial_state.memory.store(pointer_to_malloc_memory_address1, fake_heap_address1, endness=project.arch.memory_endness) #buffer1
# Store our symbolic values at our fake_heap_address. Look at the binary to
# determine the offsets from the fake_heap_address where scanf writes.
# (!)
initial_state.memory.store(fake_heap_address0, password0)
initial_state.memory.store(fake_heap_address1, password1)
simulation = project.factory.simgr(initial_state)
def is_successful(state):
stdout_output = state.posix.dumps(sys.stdout.fileno())
return 'Good Job' in str(stdout_output)
def should_abort(state):
stdout_output = state.posix.dumps(sys.stdout.fileno())
return 'Try again.' in str(stdout_output)
simulation.explore(find=is_successful, avoid=should_abort)
if simulation.found:
solution_state = simulation.found[0]
solution0 = solution_state.se.eval(password0)
solution1 = solution_state.se.eval(password1)
solution = ''.join(map("{:x}".format,[solution0,solution1]))
# print(solution)
print (binascii.a2b_hex(solution.strip()))
else:
raise Exception('Could not find the solution')
if __name__ == '__main__':
main(sys.argv)
一组数据进行两次写入,第一次把数据写入到具体位置也就是申请的空间
第二次把第一次写入的地址写入到程序的变量位置(这里是bss段)
其实就是写入内存和0x01没有本质区别
fake_heap_address0 = 0x40000
pointer_to_malloc_memory_address0 =0x09FD92AC
initial_state.memory.store(pointer_to_malloc_memory_address0, fake_heap_address0, endness=project.arch.memory_endness)
#buffer0 把数据放入内存堆地址(数据具体存到哪随意) 这个地址的指针,也就是变量的具体值要准确
initial_state.memory.store(fake_heap_address0, password0)
0x07angr 模拟文件
# This challenge could, in theory, be solved in multiple ways. However, for the
# sake of learning how to simulate an alternate filesystem, please solve this
# challenge according to structure provided below. As a challenge, once you have
# an initial solution, try solving this in an alternate way.
#
# Problem description and general solution strategy:
# The binary loads the password from a file using the fread function. If the
# password is correct, it prints "Good Job." In order to keep consistency with
# the other challenges, the input from the console is written to a file in the
# ignore_me function. As the name suggests, ignore it, as it only exists to
# maintain consistency with other challenges.
# We want to:
# 1. Determine the file from which fread reads.
# 2. Use Angr to simulate a filesystem where that file is replaced with our own
# simulated file.
# 3. Initialize the file with a symbolic value, which will be read with fread
# and propogated through the program.
# 4. Solve for the symbolic input to determine the password.
import binascii
import angr
import claripy
import sys
def main(argv):
path_to_binary = "./07_angr_symbolic_file"
project = angr.Project(path_to_binary)
start_address = 0x80488D6
initial_state = project.factory.blank_state(addr=start_address) #开始地址需要在打开文件之前,这里模拟了文件
filename = "MRXJKZYR.txt" # :string 设置文件名
symbolic_file_size_bytes = 0x40
password = claripy.BVS('password', symbolic_file_size_bytes * 8) #生成符号
password_file = angr.storage.SimFile(filename, content=password) #把内容放入文件
initial_state.fs.insert(filename, password_file)
simulation = project.factory.simgr(initial_state) #运行
def is_successful(state):
stdout_output = state.posix.dumps(sys.stdout.fileno())
return 'Good Job' in str(stdout_output)
def should_abort(state):
stdout_output = state.posix.dumps(sys.stdout.fileno())
return 'Try again.' in str(stdout_output)
simulation.explore(find=is_successful, avoid=should_abort)
if simulation.found:
solution_state = simulation.found[0]
solution = solution_state.se.eval(password)
solution="".join(map("{:x}".format,[solution]))
print (binascii.a2b_hex(solution))
else:
raise Exception('Could not find the solution')
if __name__ == '__main__':
main(sys.argv)
核心内容
filename = "MRXJKZYR.txt" # :string 设置文件名
symbolic_file_size_bytes = 0x40 # 设置文件长度
password = claripy.BVS('password', symbolic_file_size_bytes * 8) #生成符号
password_file = angr.storage.SimFile(filename, content=password) #把内容放入文件
initial_state.fs.insert(filename, password_file)