CTF 逆向工具angr的学习笔记

article/2025/11/8 10:28:21

angr

  • 概述
  • 如何学习
  • 题目列表
    • 00_angr_find
    • 01_angr_avoid
    • 02_angr_find_condition
    • 03_angr_symbolic_registers
    • 04_angr_symbolic_stack
    • 05_angr_symbolic_memory
    • 06_angr_symbolic_dynamic_memory
    • 07_angr_symbolic_file
    • 08_angr_constraints
    • 09_angr_hooks
    • 10_angr_simprocedures
    • 11_angr_sim_scanf
    • 12_angr_veritesting
    • 13_angr_static_binary
    • 14_angr_shared_library
    • 15_angr_arbitrary_read
    • 16_angr_arbitrary_write
    • 17_angr_arbitrary_jump
  • 总结

概述

  angr
  简单介绍一下angr,借助官方的原话就是 – A powerful and user-friendly binary analysis platform!,一个功能强大且用户友好的二进制分析平台。这里主要总结一下使用angr解决ctf逆向题的一些用法和套路。
  安装的话,大家可以直接使用pip安装,不过这里可能会遇到一个小坑。我在安装angr之前已经安装了pwntools,此时再安装angr,由于有一个依赖库两者需要的版本是不一样的,所以安装后导致pwntools无法使用。解决的话,大家可以采用python虚拟环境将做题环境分开,推荐使用pipenv,有空的话再写一个笔记,不过这个操作比较简单,读者简单搜索即可解决。

如何学习

  angr官方文档
  个人在网上发现了一个名为 – angr_ctf的项目,非常适合新手入门学习。作者也是通过一道道基本题目来帮助读者入手angr,对于我们这种re手来说,直接去阅读文档肯定是效率极低的,所以通过做题的方式来学习我感觉是非常可以的。
  首先直接git clone下整个项目,然后如下截图所示,是其部分的项目内容截图,其中带有数字编号的是题目,一共有18道题,进入每道有编号的题目里,会有相应生成c程序的模板和脚本。dist目录的话存放的就是已经生成好了的二进制程序,solutions目录下存放了对应程序和解题脚本,所以我们直接在这个目录下学习就好。

angr-0
  如下截图所示,进入solutions目录,然后再进入编号为00的题目目录里,可以看到一共有三个文件,第一个对应二进制程序,第二个名为scaffold00.py的脚本文件是需要我们完成的解题脚本,作者在里面给了充分的解释和代码来帮助我们学习并解决题目,第三个文件就是作者给出的完整解题脚本。

angr-1
  下面直接开始学习,我会将自己的解题脚本贴出来,由于作者已经给了足够的注释,我就不详细介绍每个API的用途,个别需要思考的地方我会单独注释。

题目列表

00_angr_find

  如下截图所示,是该题目的主要逻辑,print_msg函数用于打印提示信息,然后要求我们输入密码,之后会用complex_function对密码进行变换,最终和程序中给出的字符串进行比较,相同即成功。

00_angr_find-0
  下面我们用angr进行求解,脚本如下。

import angr# Create a Pro --> Create a simu --> Explore
pro = angr.Project("./00_angr_find")init_state = pro.factory.entry_state()  # start() addr
simu = pro.factory.simgr(init_state)good_addr = 0x804867d
simu.explore(find=good_addr)# get res
if simu.found:res = simu.found[0]for i in range(3):# print stdin/stdout/stderr, stdin is flagprint(res.posix.dumps(i))
else:print("No result!")

  如下是程序的运行结果,上面一开始是一些警告信息,主要是由于angr的求解代码没有进一步设置更多的值,这表明我们的代码确实不是很完善,当然应对简单的题目足够,当后面学习更多的知识时再解决。最后三行输出依次是stdin/stdout/stderr的值,stdin代表输入的passwd即flag,stdout是程序运行的输出,程序没有运行出错,所以stderr没有输出。

00_angr_find-1

01_angr_avoid

  如下截图所示,由于main函数中逻辑太长无法反编译,所以只能尝试分析汇编,可以发现整个逻辑和上题中是一样的,要求输入密码然后变换后和已知字符串进行比对。有区别的是最后判断加入了should_succeed,而avoid_me函数会将其值置为0从而无法达到good_addr,因此这里的angr求解脚本需要避免进入到avoid中。

01_angr_avoid-0
01_angr_avoid-1
  求解脚本如下,经过实际测试不加入avoid也是可以求解的,不过会使用更多的时间。

import angrpro = angr.Project("./01_angr_avoid")init_state = pro.factory.entry_state()
simu = pro.factory.simgr(init_state)good_addr = 0x080485E0
avoid_addr = 0x080485A8   # avoid_me func
simu.explore(find=good_addr, avoid=avoid_addr)if simu.found:res = simu.found[0]for i in range(3):print(res.posix.dumps(i))
else:print("No result!")
"""
b'RNGFXITY'
b'placeholder\nEnter the password: '
b''
"""

02_angr_find_condition

  如下截图所示,是本题的主要逻辑,和前面的题目差不多,此处就不多分析。

02_angr_find_condition
  求解脚本如下,这道题的目的主要是学习另外一种条件判断的方法,前面的题目指定是地址,这里也可以指定为一个条件函数。

import angrpro = angr.Project("./02_angr_find_condition")init_state = pro.factory.entry_state()
simu = pro.factory.simgr(init_state)def success(state):output = state.posix.dumps(1)   # get output from stdoutreturn b"Good Job." in outputdef abort(state):output = state.posix.dumps(1)   # get output from stdoutreturn b"Try again." in outputsimu.explore(find=success, avoid=abort)
if simu.found:res = simu.found[0]for i in range(3):print(res.posix.dumps(i))
else:print("No result!")
"""
b'UFOHHURD'
b'placeholder\nEnter the password: Good Job.\n'
b''
"""

03_angr_symbolic_registers

  如下截图所示,是本题的主要逻辑,同样也是先获取输入,然后使用了三个函数进行变换,最后进行判断。

03_angr_sym-0
  这道题最主要的区别在于scanf读取了三个参数,以前的angr版本不支持scanf获取多个参数,所以会采用设置寄存器求解的方法,如下脚本所示。不过现在安装最新版本的话是可以支持scanf获取多个参数的,所以仍然可以用上面的方法直接求解。

import angr
import claripypro = angr.Project("./03_angr_symbolic_registers")start_addr = 0x080488D1
init_state = pro.factory.blank_state(addr=start_addr)  # blank_state, not entry_state# create three vars
size_in_bits = 32
passwd0 = claripy.BVS("passwd0", size_in_bits)
passwd1 = claripy.BVS("passwd1", size_in_bits)
passwd2 = claripy.BVS("passwd2", size_in_bits)# scanf --> eax/ebx/edx
init_state.regs.eax = passwd0
init_state.regs.ebx = passwd1
init_state.regs.edx = passwd2simu = pro.factory.simgr(init_state)def success(state):output = state.posix.dumps(1)return b"Good Job." in outputdef abort(state):output = state.posix.dumps(1)return b"Try again." in outputsimu.explore(find=success, avoid=abort)if simu.found:res = simu.found[0]solu0 = res.solver.eval(passwd0)  # you can also use init_state.regs.eax replace passwd0solu1 = res.solver.eval(passwd1)solu2 = res.solver.eval(passwd2)solu = " ".join(map("{:x}".format, [solu0, solu1, solu2]))print(solu)
else:print("No result!")
"""
db01abf7 4930dc79 d17de5ce
"""

04_angr_symbolic_stack

  如下截图所示,是该程序的主逻辑,这道题和上面一道题类似,同样需要设置参数来求解。

04_angr_stack
  脚本如下,由于设置参数是在栈上,所以我们需要在初始状态时模拟程序本身的堆栈情况,即在正确的栈位置将参数传进入,主要看esp和ebp两个指针。

import angr
import claripypro =angr.Project("./04_angr_symbolic_stack")start_addr = 0x08048697
init_state = pro.factory.blank_state(addr=start_addr)# 初始时ebp无值,esp有值,将两个置于同一个值
init_state.regs.ebp = init_state.regs.esppasswd0 = claripy.BVS("passwd0", 32)
passwd1 = claripy.BVS("passwd1", 32)# 安装程序的运行逻辑构造正确的栈帧
init_state.regs.esp -= 8
init_state.stack_push(passwd0)
init_state.stack_push(passwd1)# test esp
# 因为程序是用ebp索引局部变量,所以局部变量和ebp的位置一定要准确
# 而对于esp,只需要保证ebp索引局部变量时esp的值是小于该局部变量的位置即可
# init_state.regs.esp -= 0x100
# print(init_state.regs.esp, init_state.regs.ebp)simu = pro.factory.simgr(init_state)def success(state):output = state.posix.dumps(1)return b"Good Job." in outputdef abort(state):output = state.posix.dumps(1)return b"Try again." in outputsimu.explore(find=success, avoid=abort)if simu.found:res = simu.found[0]solu0 = res.solver.eval(passwd0)solu1 = res.solver.eval(passwd1)solu = " ".join(map(str, [solu0, solu1]))print(solu)
else:print("No result!")
"""
1213922930 1153451551
"""

05_angr_symbolic_memory

  如下截图所示,是本题的主逻辑,同样也是scanf读取多个参数,其中有四个参数都在bss段中。

05_angr_memory
  求解脚本如下。

import angr
import claripypro = angr.Project("./05_angr_symbolic_memory")start_addr = 0x08048603
init_state = pro.factory.blank_state(addr=start_addr)# symbolics
syms = []
for i in range(4):syms.append(claripy.BVS(str(i), 64))# scanf 参数位置
bss = [0x0A29FAA0, 0x0A29FAA8, 0x0A29FAB0, 0x0A29FAB8]
for i in range(4):init_state.memory.store(bss[i], syms[i])good = 0x08048677
bad = 0x08048665
simu = pro.factory.simgr(init_state)
simu.explore(find=good, avoid=bad)if simu.found:res = simu.found[0]flag = b""for i in range(4):flag += res.solver.eval(syms[i], cast_to=bytes) + b" "   # cast_to only bytes or intprint(flag)
else:print("No result!")
"""
QLVJFWGI YPEKZGCV LCWKCULV STBDTTXE
"""

06_angr_symbolic_dynamic_memory

  如下截图所示,是本题的主要逻辑,scanf会读取两个参数,而两个参数的内存位置是由malloc动态分配的。

06_angr_symbolic_dynamic_memory
  求解脚本如下。

import angr
import claripypro = angr.Project("./06_angr_symbolic_dynamic_memory")start_addr = 0x0804869B
init_state = pro.factory.blank_state(addr=start_addr)syms = []
for i in range(2):syms.append(claripy.BVS(str(i), 64))# 假的未使用的地址
fake_heap_addr = [0x4444444, 0x4444454]
# 参数指针地址
buffer_addr = [0x0A79A118, 0x0A79A120]
for i in range(2):# angr 默认为大端,这里要使用程序的archinit_state.memory.store(buffer_addr[i], fake_heap_addr[i], endness=pro.arch.memory_endness)init_state.memory.store(fake_heap_addr[i], syms[i])good = 0x08048763
bad = 0x08048751
simu = pro.factory.simgr(init_state)
simu.explore(find=good, avoid=bad)if simu.found:res = simu.found[0]flag = b""for i in range(2):flag += res.solver.eval(syms[i], cast_to=bytes) + b" "print(flag)
else:print("No result!")
"""
IDMRHRCZ PLBQSLBO
"""

07_angr_symbolic_file

  如下截图所示,是本题的主要逻辑,在该题目中使用了fread函数来从文件中读取输入,因此接下来将尝试使用angr的文件系统来解题。

07_angr_file
  解题脚本如下。

import angr
import claripypro = angr.Project("./07_angr_symbolic_file")start_addr = 0x080488D8
init_state = pro.factory.blank_state(addr=start_addr)# 构造文件
filename = "WCEXPXBW.txt"
size = 64
file_con = claripy.BVS("flag", size * 8)
sym_file = angr.storage.SimFile(filename, content=file_con, size=size)
init_state.fs.insert(filename, sym_file)good = 0x080489BA
bad = 0x080489A0
simu = pro.factory.simgr(init_state)
simu.explore(find=good, avoid=bad)if simu.found:res = simu.found[0]flag = res.solver.eval(file_con, cast_to=bytes)print(flag)
else:print("No result!")
"""
GQLWJWWI\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
"""

08_angr_constraints

  如下截图所示,是本题的主要逻辑,该题目的重点在于check函数,check会将经过complex_function变换的字符串和程序中固定字符串进行逐一比较。如果check过于复杂的话,而用于比较的字符串本身就存在,我们可以将find设置为check函数,同时增加约束为结果字符串,这样就可以节省运行check函数的时间。

08_angr_constraints
  求解脚本如下。

import angr
import claripypro = angr.Project("./08_angr_constraints")start_addr = 0x0804862A
init_state = pro.factory.blank_state(addr=start_addr)flag = claripy.BVS("flag", 16*8)
buffer = 0x0804A050
init_state.memory.store(buffer, flag)check = 0x08048671
simu = pro.factory.simgr(init_state)
simu.explore(find=check)if simu.found:res = simu.found[0]constraints = res.memory.load(buffer, 16)r_value = "BWYRUBQCMVSBRGFU"res.add_constraints(constraints == r_value)flag = res.solver.eval(flag, cast_to=bytes)print(flag)
else:print("No result!")
"""
MILFJRHUFPNXOEEU
"""

09_angr_hooks

  如下截图所示,是本题目的主逻辑,该题目和上道题不同的点在于check函数有返回值,
因此这里将利用hook技术来解题。

09_angr_hooks
  求解脚本如下。

import angr
import claripypro = angr.Project("./09_angr_hooks")init_state = pro.factory.entry_state()check_addr = 0x080486B8 # check func addr
check_instr_len = 0x5   # instr "call check_equals_XKSPZSJKJYQCQXZV" length 
@pro.hook(check_addr, length=check_instr_len)
def skip_check(state):buffer = 0x0804A054size = 16flag = state.memory.load(buffer, size)check_str = "XKSPZSJKJYQCQXZV"# 设置返回值state.regs.eax = claripy.If(flag == check_str,claripy.BVV(1, 32),   # BVV创建具体值,BVS创建符号变量claripy.BVV(0, 32))good = 0x08048772
bad = 0x08048760
simu = pro.factory.simgr(init_state)
simu.explore(find=good, avoid=bad)if simu.found:res = simu.found[0]flag = res.posix.dumps(0)print(flag)
else:print("No result!")
"""
ZJOIPFTRNZOXIMLEWGLFMCQOKWLUFJIB
"""

10_angr_simprocedures

  如下截图所示,这道题初看和前面的题差不多,但实际上看汇编会发现多次调用了check函数,实际上反编译的代码应该是很长的,看来IDA是优化处理过了,只显示调用了一次check。

10_angr_simprocedures
  对于调用了很多次的函数来说,单独hook就不起作用了,此时需要使用angr的SimProcedure模块,求解脚本如下。

import angr
import claripypro = angr.Project("./10_angr_simprocedures")init_state = pro.factory.entry_state()# 构造一个check函数
class ReplaceCheck(angr.SimProcedure):def run(self, to_check, length):buffer = to_checklength = lengthflag = self.state.memory.load(buffer,length)check_str = "WQNDNKKWAWOLXBAC"return claripy.If(flag == check_str,claripy.BVV(1, 32),claripy.BVV(0, 32))# 使用符号hook源程序的check函数
check_sym = "check_equals_WQNDNKKWAWOLXBAC"
pro.hook_symbol(check_sym, ReplaceCheck())good = 0x0804A98E
bad = 0x0804A97C
simu = pro.factory.simgr(init_state)
simu.explore(find=good, avoid=bad)if simu.found:res_state = simu.found[0]flag = res_state.posix.dumps(0)print(flag)
else:print("No result!")
"""
URRKXXAPWVQQFMOT
"""

11_angr_sim_scanf

  如下截图所示,这道题单看反编译后的代码和前面的差不多,但是实际上这里的scanf存在多次调用,和上道题的check函数一样,需要看IDA的函数图表才能发现。

11_angr_sim_scanf
  因此这里的求解思路也是需要使用符号hook来替换程序中的scanf函数,求解脚本如下。

import angr
import claripypro = angr.Project("./11_angr_sim_scanf")init_state = pro.factory.entry_state()# 构造一个scanf函数
class ReplaceScanf(angr.SimProcedure):def run(self, format_str, param0, param1):scanf0 = claripy.BVS("0", 32)scanf1 = claripy.BVS("1", 32)self.state.memory.store(param0, scanf0, endness=pro.arch.memory_endness)self.state.memory.store(param1, scanf1, endness=pro.arch.memory_endness)self.state.globals["solutions"] = (scanf0, scanf1)# 符号hook
scanf_sym = "__isoc99_scanf"
pro.hook_symbol(scanf_sym, ReplaceScanf())good = 0x0804FCA6
bad = 0x0804FC94 
simu = pro.factory.simgr(init_state)
simu.explore(find=good, avoid=bad)if simu.found:solu_state = simu.found[0]res = solu_state.globals["solutions"]flag = b""for i in range(2):flag += solu_state.solver.eval(res[i], cast_to=bytes) + b" "print(flag)
else:print("No result!")
"""
DRFD MEHQ
"""

12_angr_veritesting

  如下图所示,是本题的主要逻辑,这道题本身也不复杂,主要是在complex_function后加了判断,导致angr在求解过程中会产生很多分支。

12_angr_veritesting
  因此这道题就是使用veritesting参数来缓解路径爆炸,原理简单引用如下:从高层面来说,有两种符号执行,一种是动态符号执行(Dynamic Symbolic Execution,简称 DSE),另一种是静态符号执行(Static Symbolic Execution,简称 SSE)。动态符号执行会去执行程序然后为每一条路径生成一个表达式。而静态符号执行将程序转换为表达式,每个表达式都表示任意条路径的属性。基于路径的 DSE 在生成表达式上引入了很多的开销,然而生成的表达式很容易求解。而 SSE 虽然生成表达式容易,但是表达式难求解。veritesting 就是在这二者中做权衡,使得能够在引入低开销的同时,生成较易求解的表达式。
  求解脚本如下。

import angrpro = angr.Project("./12_angr_veritesting")init_state = pro.factory.entry_state()good = 0x08048689
bad = 0x0804869B
# 可以尝试不加veritesting参数来看看运行时间
simu = pro.factory.simgr(init_state, veritesting=True)
simu.explore(find=good, avoid=bad)if simu.found:solu_state = simu.found[0]flag = solu_state.posix.dumps(0)print(flag)
else:print("No result!")
"""
CXSNIDYTOJEZUPKFAVQLGBWRMHCXSNID
"""

13_angr_static_binary

  如下截图所示,该题目和编号为00的题咋看是一样的,但实际上本题采用的是静态链接方式,也就是说像printf/puts等函数都是以源代码的形式在程序中出现,直接执行的话,angr不可避免的会陷入到这些无关紧要的库函数中而不可自拔(代码增加,程序流程增加,路径爆炸,耗时更多)。

13_angr_static_binary
  因此求解方式需要将静态链接的库函数同样用angr自带的模块hook,这样能加快求解速度,求解脚本如下。

import angrpro = angr.Project("./13_angr_static_binary")init_state = pro.factory.entry_state()# hook静态编译的库函数
pro.hook(0x804ed40, angr.SIM_PROCEDURES["libc"]["printf"]())
pro.hook(0x804ed80, angr.SIM_PROCEDURES["libc"]["scanf"]())
pro.hook(0x804f350, angr.SIM_PROCEDURES["libc"]["puts"]())
pro.hook(0x8048d10, angr.SIM_PROCEDURES["glibc"]["__libc_start_main"]())good = 0x080489E6
bad = 0x080489D4 
simu = pro.factory.simgr(init_state)
simu.explore(find=good, avoid=bad)if simu.found:solu_state = simu.found[0]flag = solu_state.posix.dumps(0)print(flag)
else:print("No result!")
"""
LYZGMMMV
"""

14_angr_shared_library

  如下截图所示,该题目中validate函数是由动态库实现的,因此本题的解决方案将会使用angr来处理动态链接库so,而不是程序本身。

14_angr_shared_library
  求解脚本如下。

import angr
import claripybase = 0x04000000  # 设置动态链接库的基址,不唯一
pro = angr.Project("./lib14_angr_shared_library.so", load_options={"main_opts": {"custom_base_addr": base}}
)buf_pointer = claripy.BVV(0x03000000, 32)  # 变量地址
validate_addr = base+0x6d7                 # 函数地址
# validate(char* buffer, int length)
init_state = pro.factory.call_state(validate_addr, buf_pointer, claripy.BVV(8, 32))flag = claripy.BVS("flag", 8*8)            # 要求解的输入
init_state.memory.store(buf_pointer, flag)good = base+0x783  # validate返回地址
simu = pro.factory.simgr(init_state)
simu.explore(find=good)if simu.found:solu_state = simu.found[0]# 限制返回时的寄存器值不为0才是正确结果solu_state.add_constraints(solu_state.regs.eax != 0)flag = solu_state.solver.eval(flag, cast_to=bytes)print(flag)
else:print("No result!")
"""
WWGNDMKG
"""

15_angr_arbitrary_read

  如下截图所示,是本题的主要逻辑,scanf函数读取到v4时存在溢出,这里将会利用这个溢出来覆盖s变量为正确字符串的地址。

15_angr_arbitrary_read_0
15_angr_arbitrary_read_1
  求解脚本如下。

import angr
import claripypro = angr.Project("./15_angr_arbitrary_read")init_state = pro.factory.entry_state()# replace scanf
class ReplaceScanf(angr.SimProcedure):def run(self, format_str, param0, param1):scanf0 = claripy.BVS("0", 32)scanf1 = claripy.BVS("1", 20*8)# 限制单个字符的求解范围for ch in scanf1.chop(bits=8):self.state.add_constraints(ch >= "A", ch <= "Z")self.state.memory.store(param0, scanf0, endness=pro.arch.memory_endness)self.state.memory.store(param1, scanf1)self.state.globals["solutions"] = (scanf0, scanf1)scanf_sym = "__isoc99_scanf"
pro.hook_symbol(scanf_sym, ReplaceScanf())# 通过检查puts的输出来确定是否是想要的结果
def check_puts(state):puts_para = state.memory.load(state.regs.esp+4, 4, endness=pro.arch.memory_endness)if state.solver.symbolic(puts_para):good_str = 0x594E4257copy_state = state.copy()copy_state.add_constraints(puts_para == good_str)if copy_state.satisfiable():# 先通过拷贝的状态判断是否满足,然后再直接在原状态增加限制state.add_constraints(puts_para == good_str)return Trueelse:return Falseelse:return Falsedef success(state):puts_plt = 0x08048370if state.addr == puts_plt:return check_puts(state)else:return Falsesimu = pro.factory.simgr(init_state)
simu.explore(find=success)if simu.found:solu_state = simu.found[0](scanf0, scanf1) = solu_state.globals["solutions"]flag = str(solu_state.solver.eval(scanf0)).encode("utf-8")flag += b" " + solu_state.solver.eval(scanf1, cast_to=bytes)print(flag)
else:print("No result!")
"""
19511649 AABBAABABBBAAAAAWBNY
"""

16_angr_arbitrary_write

  如下截图所示,是本题的主要逻辑,在该题目中scanf读取值到s时仍然存在溢出,我们需要利用这个溢出覆盖dest指针变量的值,然后将正确的字符串写到password_buffer中。

16_angr_write_0
  求解脚本如下。

import angr
import claripypro = angr.Project("./16_angr_arbitrary_write")init_state = pro.factory.entry_state()# replace scanf
class ReplaceScanf(angr.SimProcedure):def run(self, format_str, param0, param1):scanf0 = claripy.BVS("0", 32)scanf1 = claripy.BVS("1", 20*8)for ch in scanf1.chop(bits=8):self.state.add_constraints(ch >= 48, ch <= 96)self.state.memory.store(param0, scanf0, endness=pro.arch.memory_endness)self.state.memory.store(param1, scanf1)self.state.globals["solutions"] = (scanf0, scanf1)scanf_sym = "__isoc99_scanf"
pro.hook_symbol(scanf_sym, ReplaceScanf())def check_strncpy(state):dest = state.memory.load(state.regs.esp+4, 4, endness=pro.arch.memory_endness)src = state.memory.load(state.regs.esp+8, 4, endness=pro.arch.memory_endness)length = state.memory.load(state.regs.esp+12, 4, endness=pro.arch.memory_endness)src_con = state.memory.load(src, length)if state.solver.symbolic(src_con) and state.solver.symbolic(dest):flag = "DVTBOGZL"buf_addr = 0x4655544C# 两个限制条件is_str = src_con[-1:-64] == flagis_addr = dest == buf_addrif state.satisfiable(extra_constraints=(is_str, is_addr)):state.add_constraints(is_str, is_addr)return Trueelse:return Falseelse:return Falsedef success(state):strncpy_address = 0x08048410if state.addr == strncpy_address:return check_strncpy(state)else:return Falsesimu = pro.factory.simgr(init_state)
simu.explore(find=success)if simu.found:solu_state = simu.found[0]scanf0, scanf1 = solu_state.globals["solutions"]flag = str(solu_state.solver.eval(scanf0)).encode("utf-8")flag += b" " + solu_state.solver.eval(scanf1, cast_to=bytes)print(flag)
else:print("No result!")
"""
24173502 DVTBOGZL0@000000LTUF
"""

17_angr_arbitrary_jump

  如下截图所示,该题与上面题目都不同的地方在于函数主逻辑中不存在期望的执行代码,需要我们利用angr故意跳转到目标执行路径上。

17_angr_jump_0
17_angr_jump_1
  这里题目中的scanf读入也存在溢出,所以当输入足够长时会覆盖ret地址,此时程序的运行由用户的输入决定,angr会将其定义为不确定状态从而抛出异常。所以在这道题的脚本中我们将会关闭其默认行为,使用angr来找到正确的执行路径。

import angr
import claripypro = angr.Project("./17_angr_arbitrary_jump")init_state = pro.factory.entry_state()# replace scanf
class ReplaceScanf(angr.SimProcedure):def run(self, format_str, buf_addr):input_buffer = claripy.BVS("buf", 64 * 8) for char in input_buffer.chop(bits=8):# 限制字符的输入范围self.state.add_constraints(char >= 'A', char <= 'z')self.state.memory.store(buf_addr, input_buffer)self.state.globals["solution"] = input_bufferscanf_sym = "__isoc99_scanf"
pro.hook_symbol(scanf_sym, ReplaceScanf())# 关闭默认的不确定状态行为
simu = pro.factory.simgr(init_state,save_unconstrained=True,stashes={"active": [init_state],"unconstrained": [],"found": [],"not_needed": []}
)def has_found_solution():return simu.founddef has_unconstrained():return simu.unconstraineddef has_active():return simu.activewhile ((has_active()) or has_unconstrained()) and (not has_found_solution()):for state in simu.unconstrained:def should_move(s):return s is statesimu.move("unconstrained", "found", filter_func=should_move)simu.step()if simu.found:solu_state = simu.found[0]solu_state.add_constraints(solu_state.regs.eip == 0x4D4C4749)flag = solu_state.solver.eval(solu_state.globals["solution"], cast_to=bytes)print(flag)
else:print("No result!")
"""
`````PB`P`PB``PBABPPPB`HHHAAHHHPHHIGLMAH`````````````BHBP`AAP`AB
"""

总结

不忘初心,砥砺前行!


http://chatgpt.dhexx.cn/article/Tisab26M.shtml

相关文章

angr初探

angr 安装与简单使用 介绍 angr 总结来说&#xff0c;angr用于逆向工程中进行二进制分析的一个python框架 具体介绍见其github主页angr 符号执行 符号执行 &#xff08;Symbolic Execution&#xff09;是一种程序分析技术。其可以通过分析程序来得到让特定代码区域执行的输…

Angr_ctf

Angr_ctf&#xff1a;1~13练习 文章目录 Angr_ctf&#xff1a;1~13练习#、angr 入门00_angr_find&#xff08;1&#xff09;总结&#xff08;2&#xff09;练习 01_angr_avoid&#xff08;1&#xff09;总结&#xff08;2&#xff09;练习 02_angr_condition&#xff08;1&…

Angr CTF 从入门到入门(1)

angr是一个很厉害的二进制分析工具&#xff0c;能够实现很多自动化的逆向工作。最近正在学习&#xff0c;在看文档的时候发现了有个angrCTF的实战可以练习angr。 angrCTF:http://angr.oregonctf.org/ angr文档&#xff1a;https://docs.angr.io/ 这篇文章会是这个系列的第一篇文…

angr的windows安装——萌新

window10中符号执行&#xff08;angr&#xff09;的安装——小白篇 最近做题的时候遇到了一些需要使用angr来完成的题目&#xff0c;之后在网上搜了好久发现大多是Linux以及其它系统的angr安装教程。windows系统的安装方法几乎没有。身为一个萌新&#xff0c;猜测同类们应该也会…

Angr 安装

1、安装必要的软件环境 sudo apt-get install python3-dev libffi-dev build-essential virtualenvwrapper 2、开始正式安装angr mkvirtualenv --python$(which python3) angr && pip install angr 3、遇到 mkvirtualenv: command not found 问题 在终端执行以下命…

Angr 01 avoid 忽略的条件

01_angr_avoid无法反编译主函数&#xff0c;模块比较多&#xff0c;加上avoid过滤条件之后&#xff0c;就没那么慢了。 import angr …

图解angr中两种CFG的区别

angr里提供两种CFG的生成&#xff0c;一种是CFGFast&#xff0c;一种是CFGEmulated。这两种究竟有什么不同呢&#xff1f; 本文主要是用图来说明下这个问题。可能回答的不是很完整。 CFGFast这种CFG生成的比较快&#xff0c;但是没有考虑上下文关系。比如函数A调用了printf函…

Angr 02_angr_find_condition 根据输出状态条件搜索正确输入

explore的find和avoid支持函数作为参数&#xff0c;根据函数返回值来判断是否成功。Angr把状态传入了函数&#xff0c;从而判断成功与否。 import angr import sysdef main(argv):path_to_binary argv[1]project angr.Project(path_to_binary)initial_state project.factor…

angr的安装

ubuntu要先安装pip&#xff0c;ANGR官方给出的为pip命令pip install angr&#xff1b; 就算将pip改为apt-get 也不行。 借鉴Ubuntu安装pip的安装方式&#xff0c;安装pip&#xff0c;然后运行pip install angr&#xff0c;结束。 angr安装完后&#xff0c;要安装图形生成插件…

angr 学习笔记

附件&#xff0c;参考1&#xff0c;参考2 符号执行原理 基本概念 即初始参数用变量代替&#xff0c;模拟程序执行过程&#xff0c;维护执行到各个位置时的状态&#xff08;用各个变量之间的代数关系表示&#xff09;。 符号状态&#xff08;Symbolic State&#xff09; 当前…

利用angr获取CFG

静态二进制分析中&#xff0c;对于程序控制流图CFG的计算是很基础且重要的一步&#xff0c;很多的分析是要建立在CFG的基础上。angr作为二进制分析工具&#xff0c;当然提供了CFG功能&#xff0c;下面我们就来探索下要如何使用angr计算CFG&#xff0c;以及其中的坑。 angr中的…

Angr 内存符号化 05_angr_symbolic_memory

说明 通过查看下面的源码或IDA汇编&#xff0c;可知此例需要输入4个输入字符串&#xff0c;给每个输入字符串赋值给了user_input数组这块已经开辟的内存空间&#xff0c;我们可以监测user_input在内存中的值来获取最终的答案。 随机生成的源码 #include <stdio.h> #in…

Angr学习笔记

Angr学习笔记 前言 本文记录一下Angr的基本使用方法&#xff0c;主要是基于Github上的开源项目以及笔记AngrCTF_FITM整理&#xff0c;Angr在逆向方面确实用处比较大&#xff0c;特此记录一下。 什么是Angr angr是一个用于分析二进制文件的python框架。它专注于静态和符号分…

angr纠错和易错点

现在环境已经没有问题了。我运行了几个代码&#xff08;使用python3&#xff09;&#xff0c;都会出现不同的问题。 运行报错 解决方法&#xff1a; 添加b 运行报错&#xff1a; 解决方法&#xff1a; 删掉cast_to; 因为python2中str就是字节流 python3中不一样&#xff0c…

git本地分支管理

文章目录 一、master分支没有改变&#xff0c;合并其他分支二、master分支有改变&#xff0c;合并其他分支 作为开发人员&#xff0c;我们应该尽可能多地建立分支&#xff0c;在分支上进行开发&#xff0c;功能测试稳定后&#xff0c;再将分支上地代码合并到指定的分支 git bra…

Git 分支管理

Git 分支管理 一、主分支Master 首先&#xff0c;代码库应该有一个、且仅有一个主分支。所有提供给用户使用的正式版本&#xff0c;都在这个主分支上发布。 Git主分支的名字&#xff0c;默认叫做Master。它是自动建立的&#xff0c;版本库初始化以后&#xff0c;默认就是在主分…

git分支管理策略

git分支管理策略 1 总览 git 的分支整体预览图如下&#xff1a; 从上图可以看到主要包含下面几个分支&#xff1a; master&#xff1a;git默认主分支&#xff08;这里不作操作&#xff09;。 stable&#xff1a;稳定分支&#xff0c;替代master&#xff0c;主要用来版本发布。…

IDEA中使用Git功能和IDEA中的Git分支管理

IDEA中使用Git功能 IDEA中创建Git仓库 1、设置Git程序的路径 2、设置编译器的GitHub账号 3、新建项目 4、发布项目到GitHub IDEA向Git提交修改后的代码 1、实现git add 2、开始commit 3、实现git commit -m 4、实现git push origin master 项目成员使用IDEA的Git功…

【Git-10】Eclipse中Git分支管理

分支管理&#xff0c;是 Git 开发中的一个非常有效的团队开发策略。多个程序员并行开发&#xff0c;每个程序员可以定义各自的分支&#xff0c;在自己的分支上开发工程。再开发结束测试完毕后&#xff0c;再合并到主干工程中&#xff0c;一次性提交到远程。由其他程序员使用。 …

Git 分支管理最佳实践

Git 是目前最流行的源代码管理工具。大量的软件项目由 GitHub、Bitbucket 和 GitLab 这样的云服务平台或是私有的 Git 仓库来管理。在使用 Git 时通常会遇到的一个问题是采用何种分支管理实践&#xff0c;即如何管理仓库中作用不同的各类分支。和软件开发中的其他实践一样&…