這裏將會寫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)