抽空系统学下angr关于符号执行的一些api。通过angr_ctf 来学,可以自己构建,不过solution
目录下有已经构建好的程序、练习文件和参考答案,直接用就行了。目录下的SymbolicExecution.pptx
还详细讲了一些符号执行的入门知识,可以看看。
00_angr_find
解常规逆向的基本框架,输入来自stdin
。同时如果想默认从main
函数开始执行,使用entry_state
作为初始状态。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 import angrimport sysdef main (argv ): path_to_binary = './00_angr_find' project = angr.Project(path_to_binary) initial_state = project.factory.entry_state( add_options = { angr.options.SYMBOL_FILL_UNCONSTRAINED_MEMORY, angr.options.SYMBOL_FILL_UNCONSTRAINED_REGISTERS} ) simulation = project.factory.simgr(initial_state) print_good_address = 0x804868f simulation.explore(find=print_good_address) if simulation.found: solution_state = simulation.found[0 ] print (solution_state.posix.dumps(sys.stdin.fileno()).decode()) else : raise Exception('Could not find the solution' ) if __name__ == '__main__' : main(sys.argv)
01_angr_avoid
simulation.explore
可以通过avoid
来减少搜索空间。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 import angrimport sysdef main (argv ): path_to_binary = './01_angr_avoid' project = angr.Project(path_to_binary) initial_state = project.factory.entry_state( add_options = { angr.options.SYMBOL_FILL_UNCONSTRAINED_MEMORY, angr.options.SYMBOL_FILL_UNCONSTRAINED_REGISTERS} ) simulation = project.factory.simgr(initial_state) print_good_address = 0x80485f7 will_not_succeed_address = [0x80485bf , 0x8048575 , 0x8048609 ] simulation.explore(find=print_good_address, avoid=will_not_succeed_address) if simulation.found: solution_state = simulation.found[0 ] print (solution_state.posix.dumps(sys.stdin.fileno()).decode()) else : raise Exception('Could not find the solution' ) if __name__ == '__main__' : main(sys.argv)
02_angr_find_condition
explore
方法的find
和avoid
参数允许接受一个函数,以处理复杂的state判定问题。这个函数接受一个SimState
参数,并返回True
和False
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 import angrimport sysdef main (argv ): path_to_binary = "./02_angr_find_condition" project = angr.Project(path_to_binary) initial_state = project.factory.entry_state( add_options = { angr.options.SYMBOL_FILL_UNCONSTRAINED_MEMORY, angr.options.SYMBOL_FILL_UNCONSTRAINED_REGISTERS} ) simulation = project.factory.simgr(initial_state) def is_successful (state: angr.SimState ): stdout_output = state.posix.dumps(sys.stdout.fileno()) return b'Good Job.' in stdout_output def should_abort (state ): stdout_output = state.posix.dumps(sys.stdout.fileno()) return b'Try again.' in stdout_output simulation.explore(find=is_successful, avoid=should_abort) if simulation.found: solution_state = simulation.found[0 ] print (solution_state.posix.dumps(sys.stdin.fileno()).decode()) else : raise Exception('Could not find the solution' ) if __name__ == '__main__' : main(sys.argv)
03_angr_symbolic_registers
**当输入来源比较复杂时,可以直接在程序获取输入之后将符号值注入到指定地方。**这个例子注入到寄存器。
如果想自定义起始地址,起始状态应该使用blank_state
。
claripy.BVS(name, bit)
接受bit数创建符号。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 import angrimport claripyimport sysdef main (argv ): path_to_binary = argv[1 ] project = angr.Project(path_to_binary) start_address = 0x80488c7 initial_state = project.factory.blank_state( addr=start_address, add_options = { angr.options.SYMBOL_FILL_UNCONSTRAINED_MEMORY, angr.options.SYMBOL_FILL_UNCONSTRAINED_REGISTERS} ) password0_size_in_bits = 32 password0 = claripy.BVS('password0' , password0_size_in_bits) password1_size_in_bits = 32 password1 = claripy.BVS('password0' , password1_size_in_bits) password2_size_in_bits = 32 password2 = claripy.BVS('password0' , password2_size_in_bits) 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 b'Good Job.' in stdout_output def should_abort (state ): stdout_output = state.posix.dumps(sys.stdout.fileno()) return b'Try again.' in stdout_output simulation.explore(find=is_successful, avoid=should_abort) if simulation.found: solution_state = simulation.found[0 ] solution0 = solution_state.solver.eval (password0) solution1 = solution_state.solver.eval (password1) solution2 = solution_state.solver.eval (password2) solution = f'{solution0:x} {solution1:x} {solution2:x} ' print (solution) else : raise Exception('Could not find the solution' ) if __name__ == '__main__' : main(sys.argv)
04_angr_symbolic_stack
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 import angrimport claripyimport sysdef main (argv ): path_to_binary = argv[1 ] project = angr.Project(path_to_binary) start_address = 0x80486ae initial_state = project.factory.blank_state( addr=start_address, add_options = { angr.options.SYMBOL_FILL_UNCONSTRAINED_MEMORY, angr.options.SYMBOL_FILL_UNCONSTRAINED_REGISTERS} ) initial_state.regs.ebp = initial_state.regs.esp password0 = claripy.BVS('password0' , 32 ) password1 = claripy.BVS('password1' , 32 ) padding_length_in_bytes = 8 initial_state.regs.esp -= padding_length_in_bytes initial_state.stack_push(password0) initial_state.stack_push(password1) simulation = project.factory.simgr(initial_state) def is_successful (state ): stdout_output = state.posix.dumps(sys.stdout.fileno()) return b'Good Job.' in stdout_output def should_abort (state ): stdout_output = state.posix.dumps(sys.stdout.fileno()) return b'Try again.' in stdout_output simulation.explore(find=is_successful, avoid=should_abort) if simulation.found: solution_state = simulation.found[0 ] solution0 = solution_state.solver.eval (password0) solution1 = solution_state.solver.eval (password1) solution = ' ' .join(map (str , [ solution0, solution1 ])) print (solution) else : raise Exception('Could not find the solution' ) if __name__ == '__main__' : main(sys.argv)
05_angr_symbolic_memory
state.memory.store(addr, value, endness=project.arch.memory_endness)
,addr
和value
可以是具体值,也可以是符号。当存储具体数值时,默认是大端,需要使用endness
参数指定小端。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 import angrimport claripyimport sysdef main (argv ): path_to_binary = argv[1 ] project = angr.Project(path_to_binary) start_address = 0x8048618 initial_state = project.factory.blank_state( addr=start_address, add_options = { angr.options.SYMBOL_FILL_UNCONSTRAINED_MEMORY, angr.options.SYMBOL_FILL_UNCONSTRAINED_REGISTERS} ) password0 = claripy.BVS('password0' , 8 *8 ) password1 = claripy.BVS('password1' , 8 *8 ) password2 = claripy.BVS('password2' , 8 *8 ) password3 = claripy.BVS('password3' , 8 *8 ) password0_address = 0xab232c0 initial_state.memory.store(password0_address, password0) password1_address = 0xab232c8 initial_state.memory.store(password1_address, password1) password2_address = 0xab232d0 initial_state.memory.store(password2_address, password2) password3_address = 0xab232d8 initial_state.memory.store(password3_address, password3) simulation = project.factory.simgr(initial_state) def is_successful (state ): stdout_output = state.posix.dumps(sys.stdout.fileno()) return b'Good Job.' in stdout_output def should_abort (state ): stdout_output = state.posix.dumps(sys.stdout.fileno()) return b'Try again.' in stdout_output simulation.explore(find=is_successful, avoid=should_abort) if simulation.found: solution_state = simulation.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() solution = ' ' .join([solution0, solution1, solution2, solution3]) print (solution) else : raise Exception('Could not find the solution' ) if __name__ == '__main__' : main(sys.argv)
06_angr_symbolic_dynamic_memory
对于动态分配的内存,我们可以直接指定一个地址假设其已经得到了分配,angr会自行进行处理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 import angrimport claripyimport sysdef main (argv ): path_to_binary = argv[1 ] project = angr.Project(path_to_binary) start_address = 0x80486af initial_state = project.factory.blank_state( addr=start_address, add_options = { angr.options.SYMBOL_FILL_UNCONSTRAINED_MEMORY, angr.options.SYMBOL_FILL_UNCONSTRAINED_REGISTERS} ) password0 = claripy.BVS('password0' , 8 *8 ) password1 = claripy.BVS('password1' , 8 *8 ) fake_heap_address0 = 0x12345678 pointer_to_malloc_memory_address0 = 0xa2def74 initial_state.memory.store(pointer_to_malloc_memory_address0, fake_heap_address0, endness=project.arch.memory_endness) fake_heap_address1 = 0x11223344 pointer_to_malloc_memory_address0 = 0xa2def7c initial_state.memory.store(pointer_to_malloc_memory_address0, fake_heap_address1, endness=project.arch.memory_endness) 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 b'Good Job' in stdout_output def should_abort (state ): stdout_output = state.posix.dumps(sys.stdout.fileno()) return b'Try again' in stdout_output simulation.explore(find=is_successful, avoid=should_abort) if simulation.found: solution_state = simulation.found[0 ] solution0 = solution_state.solver.eval (password0,cast_to=bytes ).decode() solution1 = solution_state.solver.eval (password1,cast_to=bytes ).decode() solution = ' ' .join([solution0, solution1]) print (solution) else : raise Exception('Could not find the solution' ) if __name__ == '__main__' : main(sys.argv)
07_angr_symbolic_file
通过angr.storage.SimFile
和state.fs.insert
来插入符号化文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 import angrimport claripyimport sysdef main (argv ): path_to_binary = argv[1 ] project = angr.Project(path_to_binary) start_address = 0x80488bc initial_state = project.factory.blank_state( addr=start_address, add_options = { angr.options.SYMBOL_FILL_UNCONSTRAINED_MEMORY, angr.options.SYMBOL_FILL_UNCONSTRAINED_REGISTERS} ) filename = 'FOQVSBZB.txt' 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 b'Good Job' in stdout_output def should_abort (state ): stdout_output = state.posix.dumps(sys.stdout.fileno()) return b'Try again' in stdout_output simulation.explore(find=is_successful, avoid=should_abort) if simulation.found: solution_state = simulation.found[0 ] solution = solution_state.solver.eval (password,cast_to=bytes ).decode() print (solution) else : raise Exception('Could not find the solution' ) if __name__ == '__main__' : main(sys.argv)
08_angr_constraints
当最后的限制函数复杂,会导致angr路径爆炸的话,可以手动通过state.add_constraints
添加约束 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 import angrimport claripyimport sysdef main (argv ): path_to_binary = argv[1 ] project = angr.Project(path_to_binary) start_address = 0x804863c initial_state = project.factory.blank_state( addr=start_address, add_options = { angr.options.SYMBOL_FILL_UNCONSTRAINED_MEMORY, angr.options.SYMBOL_FILL_UNCONSTRAINED_REGISTERS} ) password = claripy.BVS('password' , 16 *8 ) password_address = 0x804a040 initial_state.memory.store(password_address, password) simulation = project.factory.simgr(initial_state) address_to_check_constraint = 0x8048680 simulation.explore(find=address_to_check_constraint) if simulation.found: solution_state = simulation.found[0 ] constrained_parameter_address = 0x804a040 constrained_parameter_size_bytes = 16 constrained_parameter_bitvector = solution_state.memory.load( constrained_parameter_address, constrained_parameter_size_bytes ) constrained_parameter_desired_value = b'OSIWHBXIFOQVSBZB' solution_state.add_constraints(constrained_parameter_bitvector == constrained_parameter_desired_value) solution = solution_state.solver.eval (password, cast_to=bytes ).decode() print (solution) else : raise Exception('Could not find the solution' ) if __name__ == '__main__' : main(sys.argv)
09_angr_hooks
除了手动加约束,还可以使用@project.hook
修饰一个以state
为参数的hook函数 来hook一段代码 。
hook函数返回值要传递给约束求解器的话应使用claripy
接受的值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 import angrimport claripyimport sysdef main (argv ): path_to_binary = argv[1 ] project = angr.Project(path_to_binary) initial_state = project.factory.entry_state( add_options = { angr.options.SYMBOL_FILL_UNCONSTRAINED_MEMORY, angr.options.SYMBOL_FILL_UNCONSTRAINED_REGISTERS} ) check_equals_called_address = 0x80486ca instruction_to_skip_length = 5 @project.hook(check_equals_called_address, length=instruction_to_skip_length ) def skip_check_equals_ (state ): user_input_buffer_address = 0x804a044 user_input_buffer_length = 16 user_input_string = state.memory.load( user_input_buffer_address, user_input_buffer_length ) check_against_string = b'OSIWHBXIFOQVSBZB' 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 b'Good Job.' in stdout_output def should_abort (state ): stdout_output = state.posix.dumps(sys.stdout.fileno()) return b'Try again.' in 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()).decode() print (solution) else : raise Exception('Could not find the solution' ) if __name__ == '__main__' : main(sys.argv)
10_angr_simprocedures
对于程序里的函数,可以使用SimProcedure
进行hook:为需要hook的函数定义一个SimProcedure
的子类,并定义run(self, arg1, arg2, ...)
函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 import angrimport claripyimport sysdef main (argv ): path_to_binary = argv[1 ] project = angr.Project(path_to_binary) initial_state = project.factory.entry_state( add_options = { angr.options.SYMBOL_FILL_UNCONSTRAINED_MEMORY, angr.options.SYMBOL_FILL_UNCONSTRAINED_REGISTERS} ) class ReplacementCheckEquals (angr.SimProcedure): def run (self, to_check, length ): user_input_buffer_address = to_check user_input_buffer_length = length user_input_string = self.state.memory.load( user_input_buffer_address, user_input_buffer_length ) check_against_string = b'OSIWHBXIFOQVSBZB' return claripy.If(user_input_string == check_against_string, claripy.BVV(1 , 32 ), claripy.BVV(0 , 32 )) check_equals_symbol = 'check_equals_OSIWHBXIFOQVSBZB' project.hook_symbol(check_equals_symbol, ReplacementCheckEquals()) simulation = project.factory.simgr(initial_state) def is_successful (state ): stdout_output = state.posix.dumps(sys.stdout.fileno()) return b'Good Job.' in stdout_output def should_abort (state ): stdout_output = state.posix.dumps(sys.stdout.fileno()) return b'Try again.' in 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)
11_angr_sim_scanf
算是前一个挑战的练习:hook特定参数的scanf
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 import angrimport claripyimport sysdef main (argv ): path_to_binary = argv[1 ] project = angr.Project(path_to_binary) initial_state = project.factory.entry_state( add_options = { angr.options.SYMBOL_FILL_UNCONSTRAINED_MEMORY, angr.options.SYMBOL_FILL_UNCONSTRAINED_REGISTERS} ) class ReplacementScanf (angr.SimProcedure): def run (self, format_string, scanf0_address, scanf1_address ): scanf0 = claripy.BVS('scanf0' , 4 *8 ) scanf1 = claripy.BVS('scanf1' , 4 *8 ) self.state.memory.store(scanf0_address, scanf0, endness=project.arch.memory_endness) self.state.memory.store(scanf1_address, scanf1, endness=project.arch.memory_endness) 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 b'Good Job.' in stdout_output def should_abort (state ): stdout_output = state.posix.dumps(sys.stdout.fileno()) return b'Try again.' in stdout_output simulation.explore(find=is_successful, avoid=should_abort) if simulation.found: solution_state = simulation.found[0 ] stored_solutions0 = solution_state.globals ['solution0' ] stored_solutions1 = solution_state.globals ['solution1' ] solution = ' ' .join(map (str , [solution_state.solver.eval (stored_solutions0), solution_state.solver.eval (stored_solutions1)])) print (solution) else : raise Exception('Could not find the solution' ) if __name__ == '__main__' : main(sys.argv)
12_angr_veritesting
如果实在绕不开循环,可以尝试为SimulationManager
开启veritesting
:project.factory.simgr(initial_state, veritesting=True)
来优化循环处理。
但不知道为什么我电脑还是卡住了,搜遍全网也不知道为啥。。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 import angrimport sysdef main (argv ): path_to_binary = argv[1 ] project = angr.Project(path_to_binary, load_options={'auto_load_libs' : False }) initial_state = project.factory.entry_state() simulation = project.factory.simgr(initial_state, veritesting=True ) def is_successful (state: angr.SimState ): stdout_output = state.posix.dumps(sys.stdout.fileno()) return b'Good Job.' in stdout_output def should_abort (state ): stdout_output = state.posix.dumps(sys.stdout.fileno()) return b'Try again.' in stdout_output simulation.explore(find=is_successful, avoid=should_abort) if simulation.found: solution_state = simulation.found[0 ] print (solution_state.posix.dumps(sys.stdin.fileno()).decode()) else : raise Exception('Could not find the solution' ) if __name__ == '__main__' : main(sys.argv)
13_angr_static_binary
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 import angrimport sysdef main (argv ): path_to_binary = argv[1 ] project = angr.Project(path_to_binary) initial_state = project.factory.entry_state( add_options = { angr.options.SYMBOL_FILL_UNCONSTRAINED_MEMORY, angr.options.SYMBOL_FILL_UNCONSTRAINED_REGISTERS} ) project.hook(0x8048d60 , angr.SIM_PROCEDURES['glibc' ]['__libc_start_main' ]()) project.hook(0x804fab0 , angr.SIM_PROCEDURES['libc' ]['printf' ]()) project.hook(0x804fb10 , angr.SIM_PROCEDURES['libc' ]['scanf' ]()) project.hook(0x80503f0 , angr.SIM_PROCEDURES['libc' ]['puts' ]()) project.hook(0x804f050 , angr.SIM_PROCEDURES['libc' ]['exit' ]()) project.hook(0x8048228 , angr.SIM_PROCEDURES['libc' ]['strcmp' ]()) simulation = project.factory.simgr(initial_state) print_good_address = 0x8048ac2 simulation.explore(find=print_good_address) if simulation.found: solution_state = simulation.found[0 ] print (solution_state.posix.dumps(sys.stdin.fileno()).decode()) else : raise Exception('Could not find the solution' ) if __name__ == '__main__' : main(sys.argv)
14_angr_shared_library
如何处理PIE程序和处理单个函数。
对于PIE程序,在创建project时需要在load_options
中指定base
。
对于要处理的单个函数,可以使用call_state(addr, args, ...)
作为初始状态。
在传递常量时要使用claripy.BVV
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 import angrimport claripyimport sysdef main (argv ): path_to_binary = argv[1 ] base = 0x9000000 project = angr.Project(path_to_binary, load_options={ 'main_opts' : { 'base_addr' : base } }) buffer_pointer = claripy.BVV(0x9003000 , 32 ) validate_function_address = base + 0x670 initial_state = project.factory.call_state( validate_function_address, buffer_pointer, claripy.BVV(8 , 32 ), add_options = { angr.options.SYMBOL_FILL_UNCONSTRAINED_MEMORY, angr.options.SYMBOL_FILL_UNCONSTRAINED_REGISTERS} ) password = claripy.BVS( 'password' , 8 *8 ) initial_state.memory.store( buffer_pointer , password ) simulation = project.factory.simgr(initial_state) check_constraint_address = base + 0x718 simulation.explore(find=check_constraint_address) if simulation.found: solution_state = simulation.found[0 ] solution_state.add_constraints( solution_state.regs.eax != 0 ) solution = solution_state.solver.eval (password, cast_to=bytes ) print (solution) else : raise Exception('Could not find the solution' ) if __name__ == '__main__' : main(sys.argv)
15_angr_arbitrary_read
如何用angr检查是否存在溢出以及可以用来任意读取数据:使用solver.symbolic
检查puts
的参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 import angrimport claripyimport sysdef main (argv ): path_to_binary = argv[1 ] project = angr.Project(path_to_binary) initial_state = project.factory.entry_state( add_options = { angr.options.SYMBOL_FILL_UNCONSTRAINED_MEMORY, angr.options.SYMBOL_FILL_UNCONSTRAINED_REGISTERS} ) class ReplacementScanf (angr.SimProcedure): def run (self, format_string, key, buf ): scanf0 = claripy.BVS('scanf0' , 4 *8 ) scanf1 = claripy.BVS('scanf1' , 20 *8 ) for char in scanf1.chop(bits=8 ): self.state.add_constraints(char >= 0x20 , char <= 0x7e ) scanf0_address = key self.state.memory.store(scanf0_address, scanf0, endness=project.arch.memory_endness) scanf1_address = buf self.state.memory.store(scanf1_address, scanf1) self.state.globals ['solution0' ] = scanf0 self.state.globals ['solution1' ] = scanf1 scanf_symbol = '__isoc99_scanf' project.hook_symbol(scanf_symbol, ReplacementScanf()) def check_puts (state ): puts_parameter = state.memory.load(state.regs.esp+4 , 4 , endness=project.arch.memory_endness) if state.solver.symbolic(puts_parameter): good_job_string_address = 0x4f534957 is_vulnerable_expression = puts_parameter == good_job_string_address if state.satisfiable(extra_constraints=(is_vulnerable_expression,)): state.add_constraints(is_vulnerable_expression) return True else : return False else : return False simulation = project.factory.simgr(initial_state) def is_successful (state ): puts_address = 0x8048370 if state.addr == puts_address: return check_puts(state) else : return False simulation.explore(find=is_successful) if simulation.found: solution_state = simulation.found[0 ] solution = [solution_state.solver.eval (solution_state.globals ['solution0' ]), solution_state.solver.eval (solution_state.globals ['solution1' ], cast_to=bytes )] print (solution) else : raise Exception('Could not find the solution' ) if __name__ == '__main__' : main(sys.argv)
16_angr_arbitrary_write
如何用angr检查是否存在溢出以及可以用来任意写:使用solver.symbolic
检查strncpy
的参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 import angrimport claripyimport sysdef main (argv ): path_to_binary = argv[1 ] project = angr.Project(path_to_binary) initial_state = project.factory.entry_state( add_options = { angr.options.SYMBOL_FILL_UNCONSTRAINED_MEMORY, angr.options.SYMBOL_FILL_UNCONSTRAINED_REGISTERS} ) class ReplacementScanf (angr.SimProcedure): def run (self, format_string, key, buf ): scanf0 = claripy.BVS('scanf0' , 4 *8 ) scanf1 = claripy.BVS('scanf1' , 20 *8 ) for char in scanf1.chop(bits=8 ): self.state.add_constraints(char >= 0x20 , char <= 0x7e ) scanf0_address = key self.state.memory.store(scanf0_address, scanf0, endness=project.arch.memory_endness) scanf1_address = buf self.state.memory.store(scanf1_address, scanf1) self.state.globals ['solutions' ] = [scanf0, scanf1] scanf_symbol = '__isoc99_scanf' project.hook_symbol(scanf_symbol, ReplacementScanf()) def check_strncpy (state ): strncpy_dest = state.memory.load(state.regs.esp+4 , 4 , endness=project.arch.memory_endness) strncpy_src = state.memory.load(state.regs.esp+8 , 4 , endness=project.arch.memory_endness) strncpy_len = state.memory.load(state.regs.esp+12 , 4 , endness=project.arch.memory_endness) src_contents = state.memory.load(strncpy_src, strncpy_len) if state.solver.symbolic(src_contents) and state.solver.symbolic(strncpy_dest): password_string = b'NEDVTNOP' buffer_address = 0x4D43523C does_src_hold_password = src_contents[-1 :-8 *8 ] == password_string does_dest_equal_buffer_address = strncpy_dest == buffer_address if state.satisfiable(extra_constraints=(does_src_hold_password, does_dest_equal_buffer_address)): state.add_constraints(does_src_hold_password, does_dest_equal_buffer_address) return True else : return False else : return False simulation = project.factory.simgr(initial_state) def is_successful (state ): strncpy_address = 0x8048410 if state.addr == strncpy_address: return check_strncpy(state) else : return False simulation.explore(find=is_successful) if simulation.found: solution_state = simulation.found[0 ] solution = [solution_state.solver.eval (solution_state.globals ['solutions' ][0 ]), solution_state.solver.eval (solution_state.globals ['solutions' ][1 ], cast_to=bytes )] print (solution) else : raise Exception('Could not find the solution' ) if __name__ == '__main__' : main(sys.argv)
17_angr_arbitrary_jump
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 import angrimport claripyimport sysdef main (argv ): path_to_binary = argv[1 ] project = angr.Project(path_to_binary) symbolic_input = claripy.BVS("input" , 100 *8 ) initial_state = project.factory.entry_state( stdin=symbolic_input, add_options = { angr.options.SYMBOL_FILL_UNCONSTRAINED_MEMORY, angr.options.SYMBOL_FILL_UNCONSTRAINED_REGISTERS } ) simulation = project.factory.simgr( initial_state, save_unconstrained=True , stashes={ 'active' : [initial_state], 'unconstrained' : [], 'found' : [], 'not_needed' : [] } ) def has_found_solution (): return simulation.found def has_unconstrained_to_check (): return simulation.unconstrained def has_active (): return simulation.active while (has_active() or has_unconstrained_to_check()) and (not has_found_solution()): for unconstrained_state in simulation.unconstrained: simulation.move('unconstrained' , 'found' ) simulation.step() if simulation.found: solution_state = simulation.found[0 ] solution_state.add_constraints(solution_state.regs.eip == 0x4D435250 ) for byte in symbolic_input.chop(bits=8 ): solution_state.add_constraints( byte >= 0x20 , byte <= 0x7e ) solution = solution_state.solver.eval (symbolic_input,cast_to=bytes ).decode() print (solution) else : raise Exception('Could not find the solution' ) if __name__ == '__main__' : main(sys.argv)