0x08对探索结果添加限制
#跳过一些函数来求解
import angr
import claripy
import sys
import binascii
def main(argv):
path_to_binary = "08_angr_constraints"
project = angr.Project(path_to_binary)
start_address = 0x8048625
initial_state = project.factory.blank_state(addr=start_address)
password = claripy.BVS('password', 0x10*8)
password_address = 0x0804A050
initial_state.memory.store(password_address, password)
simulation = project.factory.simgr(initial_state)
# Angr will not be able to reach the point at which the binary prints out
# 'Good Job.'. We cannot use that as the target anymore.
# (!)
address_to_check_constraint = 0x0804866C
simulation.explore(find=address_to_check_constraint) #先让程序运行到比较之前
if simulation.found:
solution_state = simulation.found[0]
# Recall that we need to constrain the to_check parameter (see top) of the
# check_equals_ function. Determine the address that is being passed as the
# parameter and load it into a bitvector so that we can constrain it.
# (!)
constrained_parameter_address = 0x0804A050 #获取对应内存区域在运行到这里的时候的值
constrained_parameter_size_bytes = 0x10
constrained_parameter_bitvector = solution_state.memory.load(
constrained_parameter_address,
constrained_parameter_size_bytes
)
# We want to constrain the system to find an input that will make
# constrained_parameter_bitvector equal the desired value.
# (!)
constrained_parameter_desired_value = "MRXJKZYRKMKENFZB" # :string 约束这些数据得到符合要求的
# Specify a claripy expression (using Pythonic syntax) that tests whether
# constrained_parameter_bitvector == constrained_parameter_desired_value.
# We will let z3 attempt to find an input that will make this expression
# true.
constraint_expression = constrained_parameter_bitvector == constrained_parameter_desired_value
# Add the constraint to the state to instruct z3 to include it when solving
# for input.
solution_state.add_constraints(constraint_expression)#添加约束条件
# Solve for the constrained_parameter_bitvector.
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)
# solution_state.add_constraints(constrained_parameter_bitvector == constrained_parameter_desired_value)获取到走到这里的好多数据中满足条件的输入
'''
constrained_parameter_bitvector = solution_state.memory.load(
constrained_parameter_address,
constrained_parameter_size_bytes
)
获取一个地址处运行到这个时候的值
'''
核心代码添加求解约束条件,运行到这里已经得到了所有的结果,加上这个条件进一步过滤结果
constraint_expression = constrained_parameter_bitvector == constrained_parameter_desired_value
# Add the constraint to the state to instruct z3 to include it when solving
# for input.
solution_state.add_constraints(constraint_expression)#添加约束条件
0x09对一个地址hook
# This level performs the following computations:
#
# 1. Get 16 bytes of user input and encrypt it.
# 2. Save the result of check_equals_AABBCCDDEEFFGGHH (or similar)
# 3. Get another 16 bytes from the user and encrypt it.
# 4. Check that it's equal to a predefined password.
#
# The ONLY part of this program that we have to worry about is #2. We will be
# replacing the call to check_equals_ with our own version, using a hook, since
# check_equals_ will run too slowly otherwise.
'''
claripy.If(条件,条件为True时的返回值,条件为False时的返回值) => 创建条件判断
claripy.BVV(值,值大小) => 创建一个数值
'''
import angr
import claripy
import sys
def main(argv):
path_to_binary = "09_angr_hooks"
project = angr.Project(path_to_binary)
# Since Angr can handle the initial call to scanf, we can start from the
# beginning.
initial_state = project.factory.entry_state()
# Hook the address of where check_equals_ is called.
# (!)
check_equals_called_address = 0x80486B3 #这个地址是call的地址参数没有改变,只改变call
# The length parameter in angr.Hook specifies how many bytes the execution
# engine should skip after completing the hook. This will allow hooks to
# replace certain instructions (or groups of instructions). Determine the
# instructions involved in calling check_equals_, and then determine how many
# bytes are used to represent them in memory. This will be the skip length.
# (!)
instruction_to_skip_length = 0x05 #不同系统下call指令的大小不同
@project.hook(check_equals_called_address, length=instruction_to_skip_length)
def skip_check_equals_(state): #hook成这个函数
# Determine the address where user input is stored. It is passed as a
# parameter ot the check_equals_ function. Then, load the string. Reminder:
# int check_equals_(char* to_check, int length) { ...
user_input_buffer_address = 0x0804A054 # :integer, probably hexadecimal
user_input_buffer_length = 0x10
# Reminder: state.memory.load will read the stored value at the address
# user_input_buffer_address of byte length user_input_buffer_length.
# It will return a bitvector holding the value. This value can either be
# symbolic or concrete, depending on what was stored there in the program.
user_input_string = state.memory.load( #加载这个地址处的值
user_input_buffer_address,
user_input_buffer_length
)
# Determine the string this function is checking the user input against.
# It's encoded in the name of this function; decompile the program to find
# it.
check_against_string = 'MRXJKZYRKMKENFZB'# :string
#因为check_equals_MRXJKZYRKMKENFZB函数的返回值放在eax寄存器里面
state.regs.eax = claripy.If(
user_input_string == check_against_string,
claripy.BVV(1, 32),
claripy.BVV(0, 32)
)
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]
# Since we are allowing Angr to handle the input, retrieve it by printing
# the contents of stdin. Use one of the early levels as a reference.
solution = solution_state.posix.dumps(sys.stdin.fileno())
print (solution)
else:
raise Exception('Could not find the solution')
if __name__ == '__main__':
main(sys.argv)
#用python 自定义函数来hook程序的函数跳过一些已知函数
#solution = solution_state.posix.dumps(sys.stdin.fileno()) 获取满足条件的格式化输入的数据
核心代码
check_equals_called_address = 0x80486B3 #这个地址是call的地址参数没有改变,只改变call
instruction_to_skip_length = 0x05 #不同系统下call指令的大小不同
@project.hook(check_equals_called_address, length=instruction_to_skip_length)
def skip_check_equals_(state): #hook成这个函数
check_equals_called_address为要hook的地址
def skip_check_equals_(state): 这个函数会代替这个地址处原来的函数
claripy.If(条件,条件为True时的返回值,条件为False时的返回值) => 创建条件判断
claripy.BVV(值,值大小) => 创建一个数值
state.regs.eax = claripy.If(
user_input_string == check_against_string,
claripy.BVV(1, 32),
claripy.BVV(0, 32)
)
0x10通过函数名字hook
# This challenge is similar to the previous one. It operates under the same
# premise that you will have to replace the check_equals_ function. In this
# case, however, check_equals_ is called so many times that it wouldn't make
# sense to hook where each one was called. Instead, use a SimProcedure to write
# your own check_equals_ implementation and then hook the check_equals_ symbol
# to replace all calls to scanf with a call to your SimProcedure.
#
# You may be thinking:
# Why can't I just use hooks? The function is called many times, but if I hook
# the address of the function itself (rather than the addresses where it is
# called), I can replace its behavior everywhere. Furthermore, I can get the
# parameters by reading them off the stack (with memory.load(regs.esp + xx)),
# and return a value by simply setting eax! Since I know the length of the
# function in bytes, I can return from the hook just before the 'ret'
# instruction is called, which will allow the program to jump back to where it
# was before it called my hook.
# If you thought that, then congratulations! You have just invented the idea of
# SimProcedures! Instead of doing all of that by hand, you can let the already-
# implemented SimProcedures do the boring work for you so that you can focus on
# writing a replacement function in a Pythonic way.
# As a bonus, SimProcedures allow you to specify custom calling conventions, but
# unfortunately it is not covered in this CTF.
import angr
import claripy
import sys
def main(argv):
path_to_binary = "10_angr_simprocedures"
project = angr.Project(path_to_binary)
initial_state = project.factory.entry_state()
# Define a class that inherits angr.SimProcedure in order to take advantage
# of Angr's SimProcedures.
class ReplacementCheckEquals(angr.SimProcedure):
def run(self, to_check,check_data_length): #to_check,check_data_length代表着被hook的函数的两个参数
# We can almost copy and paste the solution from the previous challenge.
# Hint: Don't look up the address! It's passed as a parameter.
# (!)
user_input_buffer_address = to_check
user_input_buffer_length = check_data_length
# Note the use of self.state to find the state of the system in a
# SimProcedure.
user_input_string = self.state.memory.load(
user_input_buffer_address,
user_input_buffer_length
)
check_against_string = 'MRXJKZYRKMKENFZB'
# Finally, instead of setting eax, we can use a Pythonic return statement
# to return the output of this function.
# Hint: Look at the previous solution.
return claripy.If(
check_against_string==user_input_string,
claripy.BVV(1,32),
claripy.BVV(0,32)
)
# Hook the check_equals symbol. Angr automatically looks up the address
# associated with the symbol. Alternatively, you can use 'hook' instead
# of 'hook_symbol' and specify the address of the function. To find the
# correct symbol, disassemble the binary.
# (!)
check_equals_symbol = 'check_equals_MRXJKZYRKMKENFZB' # :string 要hook的函数名字
project.hook_symbol(check_equals_symbol, ReplacementCheckEquals()) #仅仅指定函数名字和设置参数获取的变量,能自动获取到参数和函数
#和9不同这个二进制文件有很多call check_equals_MRXJKZYRKMKENFZB指令 不知道要hook哪一个
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.posix.dumps(sys.stdin.fileno())
print (solution)
else:
raise Exception('Could not find the solution')
if __name__ == '__main__':
main(sys.argv)
核心代码
通过函数名hook一堆函数,并且获取这些函数的参数
class ReplacementCheckEquals(angr.SimProcedure):
def run(self, to_check,check_data_length): #to_check,check_data_length代表着被hook的函数的两个参数
project.hook_symbol(check_equals_symbol, ReplacementCheckEquals()) #仅仅指定函数名字和设置参数获取的变量,能自动获取到参数和函数
#和9不同这个二进制文件有很多call check_equals_MRXJKZYRKMKENFZB指令 不知道要hook哪一个
0x11hook scanf函数,声明最终要解析的变量
# This time, the solution involves simply replacing scanf with our own version,
# since Angr does not support requesting multiple parameters with scanf.
import angr
import claripy
import sys
import binascii
def main(argv):
path_to_binary = "11_angr_sim_scanf"
project = angr.Project(path_to_binary)
initial_state = project.factory.entry_state()
class ReplacementScanf(angr.SimProcedure):
# Finish the parameters to the scanf function. Hint: 'scanf("%u %u", ...)'.
# (!)
def run(self, format_string, scanf0_address, scanf1_address):
scanf0 = claripy.BVS('scanf0', 4*8)
scanf1 = claripy.BVS('scanf1', 4 * 8)
# The scanf function writes user input to the buffers to which the
# parameters point.
self.state.memory.store(scanf0_address, scanf0, endness=project.arch.memory_endness)
self.state.memory.store(scanf1_address, scanf1, endness=project.arch.memory_endness)
# Now, we want to 'set aside' references to our symbolic values in the
# globals plugin included by default with a state. You will need to
# store multiple bitvectors. You can either use a list, tuple, or multiple
# keys to reference the different bitvectors.
# (!)
self.state.globals['solution0'] = scanf0
self.state.globals['solution1'] = scanf1
scanf_symbol = "__isoc99_scanf"
project.hook_symbol(scanf_symbol, ReplacementScanf())
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]
# Grab whatever you set aside in the globals dict.
stored_solutions0 = solution_state.globals['solution0']
stored_solutions1 = solution_state.globals['solution1']
solution0 = solution_state.se.eval(stored_solutions0)
solution1 = solution_state.se.eval(stored_solutions1)
solution = "".join(map("{:x}".format,[solution0,solution1]))
print (binascii.a2b_hex(solution))
else:
raise Exception('Could not find the solution')
if __name__ == '__main__':
main(sys.argv)
'''
stored_solutions1 = solution_state.globals['solution1']
solution0 = solution_state.se.eval(stored_solutions0)
获取全局变量
self.state.globals['solution1'] = scanf1
这样声明全局变量
'''
核心代码
生成二位向量,把变量放入内存,声明这个变量最终求解时用到
scanf0 = claripy.BVS('scanf0', 4*8)
scanf1 = claripy.BVS('scanf1', 4 * 8)
# The scanf function writes user input to the buffers to which the
# parameters point.
self.state.memory.store(scanf0_address, scanf0, endness=project.arch.memory_endness)
self.state.memory.store(scanf1_address, scanf1, endness=project.arch.memory_endness)
# Now, we want to 'set aside' references to our symbolic values in the
# globals plugin included by default with a state. You will need to
# store multiple bitvectors. You can either use a list, tuple, or multiple
# keys to reference the different bitvectors.
# (!)
self.state.globals['solution0'] = scanf0
self.state.globals['solution1'] = scanf1
求解声明的变量
stored_solutions0 = solution_state.globals['solution0']
solution0 = solution_state.se.eval(stored_solutions0)
0x12对比较长的变量求解
import angr
import sys
def main(argv):
path_to_binary="12_angr_veritesting"
project=angr.Project(path_to_binary)
initial_state=project.factory.entry_state()
simulation=project.factory.simgr(initial_state,veritesting=True)
def is_successful(state):
stdout_output=state.posix.dumps(sys.stdout.fileno())
return 'Good Job'.encode() in stdout_output
def should_abord(state):
should_output=state.posix.dumps(sys.stdout.fileno())
return 'Try again'.encode() in should_output
simulation.explore(find=is_successful,avoid=should_abord)
if simulation.found:
solution_state = simulation.found[0]
print(solution_state.posix.dumps(sys.stdin.fileno()))
else:
raise Exception('Could not find the solution')
if __name__ == '__main__':
main(sys.argv)
核心代码
用veritesting=True选项来解决比较长的变量求解
simulation=project.factory.simgr(initial_state,veritesting=True)
0x04针对自定义的库函数求解
把函数hook掉(如果不hook会很难求解)
# This challenge is the exact same as the first challenge, except that it was
# compiled as a static binary. Normally, Angr automatically replaces standard
# library functions with SimProcedures that work much more quickly.
#
# Here are a few SimProcedures Angr has already written for you. They implement
# standard library functions. You will not need all of them:
# angr.SIM_PROCEDURES['libc']['malloc']
# angr.SIM_PROCEDURES['libc']['fopen']
# angr.SIM_PROCEDURES['libc']['fclose']
# angr.SIM_PROCEDURES['libc']['fwrite']
# angr.SIM_PROCEDURES['libc']['getchar']
# angr.SIM_PROCEDURES['libc']['strncmp']
# angr.SIM_PROCEDURES['libc']['strcmp']
# angr.SIM_PROCEDURES['libc']['scanf']
# angr.SIM_PROCEDURES['libc']['printf']
# angr.SIM_PROCEDURES['libc']['puts']
# angr.SIM_PROCEDURES['libc']['exit']
#
# As a reminder, you can hook functions with something similar to:
# project.hook(malloc_address, angr.SIM_PROCEDURES['libc']['malloc'])
#
# There are many more, see:
# https://github.com/angr/angr/tree/master/angr/procedures/libc
#
# Additionally, note that, when the binary is executed, the main function is not
# the first piece of code called. In the _start function, __libc_start_main is
# called to start your program. The initialization that occurs in this function
# can take a long time with Angr, so you should replace it with a SimProcedure.
# angr.SIM_PROCEDURES['glibc']['__libc_start_main']
# Note 'glibc' instead of 'libc'.
import angr
import sys
def main(argv):
path_to_binary="13_angr_static_binary"
project=angr.Project(path_to_binary)
initial_state=project.factory.entry_state()
simulation=project.factory.simgr(initial_state,veritesting=True)
project.hook(0x804ed40,angr.SIM_PROCEDURES['libc']['printf']())
project.hook(0x804ed80, angr.SIM_PROCEDURES['libc']['scanf']())
project.hook(0x804f350, angr.SIM_PROCEDURES['libc']['puts']())
project.hook(0x8048d10, angr.SIM_PROCEDURES['glibc']['__libc_start_main']())
def is_successful(state):
stdout_output=state.posix.dumps(sys.stdout.fileno())
return 'Good Job'.encode() in stdout_output
def should_abord(state):
should_output=state.posix.dumps(sys.stdout.fileno())
return 'Try again'.encode() in should_output
simulation.explore(find=is_successful,avoid=should_abord)
if simulation.found:
solution_state = simulation.found[0]
print(solution_state.posix.dumps(sys.stdin.fileno()))
else:
raise Exception('Could not find the solution')
if __name__ == '__main__':
main(sys.argv)
# project.hook(0x804ed40,angr.SIM_PROCEDURES['libc']['printf']())
#获取angr内部实现的函数
angr已经实现了系统函数,想hook很简单
不过这里好像只需要hook输入输出函数就行了还有这个函数__libc_start_main
用来hook系统函数,注意库函数不同,这个地址为函数被call过之后的开始
project.hook(0x804f350, angr.SIM_PROCEDURES['libc']['puts']())
project.hook(0x8048d10, angr.SIM_PROCEDURES['glibc']['__libc_start_main']())
0x14分析动态链接库
import angr
import claripy
import sys
import binascii
def main(argv):
path_to_binary ="lib14_angr_shared_library.so"
base = 0x400000
project = angr.Project(path_to_binary, load_options={
'main_opts' : {
'custom_base_addr' : base
}
}) #加载动态链接库
buffer_pointer=claripy.BVV(0x3000000,32)#创造一个32位的指针,值是任意的但这个值指向输入数据
validate_function_address = base+0x000006D7
initial_state = project.factory.call_state(validate_function_address, buffer_pointer,claripy.BVV(8,32))#要调用的库函数和他的参数
# You will need to add code to inject a symbolic value into the program at the
# end of the function that constrains eax to equal true (value of 1) just
# before the function returns. There are multiple ways to do this:
# 1. Use a hook.
# 2. Search for the address just before the function returns and then
# constrain eax (this may require putting code elsewhere)
password=claripy.BVS('password',8*8)
initial_state.memory.store(buffer_pointer,password) #向0x30000000地址处存入数据
simulation = project.factory.simgr(initial_state)
success_address = base+0x0000783 #函数结束的地址
simulation.explore(find=success_address)
if simulation.found:
solution_state = simulation.found[0]
solution_state.add_constraints(solution_state.regs.eax != 0) #添加限制条件
# Determine where the program places the return value, and constrain it so
# that it is true. Then, solve for the solution and print it.
# (!)
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)
'''
base = 0x400000
project = angr.Project(path_to_binary, load_options={
'main_opts' : {
'custom_base_addr' : base
}
}) #加载动态链接库
加载动态链接库
buffer_pointer=claripy.BVV(0x3000000,32)#创造一个32位的指针,值是任意的但这个值指向输入数据
validate_function_address = base+0x000006D7
initial_state = project.factory.call_state(validate_function_address, buffer_pointer,claripy.BVV(8,32))#要调用的库函数和他的参数
设置要调用的库函数
获取运行到这里时寄存器的值
solution = solution_state.se.eval(password)
获取运行到这里时满足的输入
'''
对动态库的操作
base = 0x400000
project = angr.Project(path_to_binary, load_options={
'main_opts' : {
'custom_base_addr' : base
}
}) #加载动态链接库
加载动态链接库
buffer_pointer=claripy.BVV(0x3000000,32)#创造一个32位的指针,值是任意的但这个值指向输入数据
validate_function_address = base+0x000006D7
initial_state = project.factory.call_state(validate_function_address, buffer_pointer,claripy.BVV(8,32))#要调用的库函数和他的参数
设置要调用的库函数