angr学习之ctf练习

前言

安装angr的链接:https://blog.csdn.net/qq_43682582/article/details/109790606
通过做ctf练习题来逐步熟悉angr的相关内容
相关文档: https://github.com/jakespringer/angr_ctf.
相关b站视频:https://space.bilibili.com/386563875/.
进入链接之后,这里面就是已经编译好的二进制文件,里面还有对应题目的解题框架和相关注释:
在这里插入图片描述angr思路:根据当前一些自己的体会(未来也许会有修改),即重点就是确定开始执行的那个状态的具体地址,根据这些不同来写程序,如:对寄存器、对栈、对内存等。
新人菜鸟一枚,如果出现了错误或者遗漏的地方,希望各位师傅能够帮忙指点出来,Thanks♪(・ω・)ノ

00_angr_find:

目的:使学习者一个对angr有一个大体的了解,初步知道使用大致步骤

import angr
import sys
def main(argv): #定义主函数
    path_to_binary = '/home/yuan/ctf/angr/angr0/00_angr_find'  #被执行文件路径
    project = angr.Project(path_to_binary)   #以被执行文件路径创建项目
    #或者project = angr.Project('/home/yuan/ctf/angr/angr0/00_angr_find')

    initial_state = project.factory.entry_state()  #通过entry_state()创建一个默认初始状态,这个状态是为了告诉
                                                   #angr该从哪里开始,此处为main()

    simulation = project.factory.simgr(initial_state)   #以该状态创建一个模拟管理器,这个模拟管理器里有许多工
                                                        #具可以帮助搜索和执行二进制文件
                                                        #或者simulation = project.factory.simulation_manager(initial_state),二者没有区别,只是前者更加方便写代码。。。

    print_good_address = 0x0804867D   #希望得到的输出的虚拟地址

    simulation.explore(find=print_good_address)  #开始执行直到到达希望的解决方案或者探索完所有的可能的路径
                                                 #simulation.explore()方法将会建立一个名为simulation.found
                                                 #状态列表来表示可以找到我们所希望的输出。如过没有找到,则
                                                 #该列表会被置为false,反之为true
    if simulation.found:   #检查是否发现了解决方案
        solution_state = simulation.found[0]
        print(solution_state.posix.dumps(sys.stdin.fileno()))  #打印出angr执行到这个状态时的输入,也就是我们所希望的flag

    else:
        raise Exception('Cannot find')

if __name__ == '__main__':
    main(sys.argv)

可以使用ida打开二进制文件进行地址的查看:
在这里插入图片描述

运行效果:
在这里插入图片描述

01_angr_avoid:

目的:让学习者使用一定的约束来减少运算量,以节省时间

import angr
import sys

def main(argv):
    p = angr.Project('/home/yuan/ctf/angr/angr1/01_angr_avoid')
    initial_state = p.factory.entry_state()
    sm = p.factory.simgr(initial_state)
    
    good_addr = 0x080485e5   #因为一般来讲一个二进制文件执行时是不会只有一个分支语句的
                             #所以为了节省时间和对计算资源的浪费,需要添加约束来避免对一些无用语句的执行
    bad_addr = 0x080485f2    #此处即为输出为“Try again”的地址

    sm.explore(find=good_addr, avoid=bad_addr) #avoid就是.explore()里的第二个参数,也就是不想要执行到这里
    
    if sm.found:
        flag = sm.found[0]
        print(flag.posix.dumps(sys.stdin.fileno()))
    else:
        raise Exception('Cannot find')
if __name__ == '__main__':
        main(sys.argv)

运行效果:
在这里插入图片描述

02_angr_find_condition:

目的:掌握另一种判断输出状态的方法

import angr
p = angr.Project('/home/yuan/ctf/angr/angr2/02_angr_find_condition')
state = p.factory.entry_state()
sm = p.factory.simulation_manager(state)
def good(state):
    return b'Good Job.' in state.posix.dumps(1)  #希望得到的输出
def bad(state):
    return b'Try again.' in state.posix.dumps(1)   #不希望得到的输出
sm.explore(find = good, avoid = bad)
if sm.found:
    find_state = sm.found[0]
    flag = find_state.posix.dumps(0)
    print(str(flag,'utf-8'))
else:
    print("NO!!!!!!!!")

运行效果:
在这里插入图片描述

03_angr_registers:

目的:掌握对输入进寄存器的变量符号化的方法

import angr
import claripy
p = angr.Project('/home/yuan/ctf/angr/angr3/03_angr_symbolic_registers')

init_addr = 0x08048980  #call scanf的下一条指令地址
state = p.factory.blank_state(addr=init_addr)  #创建一个状态,并将该地址赋给它,也就是跳过输入,直接执行下一条指令,此处使用.blank_state()而不再是.entry_state()
#虽然当前版本的angr已经支持scanf多个变量输入,但为了学习angr的另外一种方法,就按这种方法来吧。

#定义三个位向量,即三个输入
p1 = claripy.BVS('p1',32)   #32位寄存器
p2 = claripy.BVS('p2',32)
p3 = claripy.BVS('p3',32)

#将三个输入分别赋给存放输入的三个寄存器
state.regs.eax = p1    #.regs.eax 访问eax这个寄存器
state.regs.ebx = p2
state.regs.edx = p3

#创建一个模拟管理器
sm = p.factory.simulation_manager(state)

#定义函数
def good(state):
    return b'Good Job.' in state.posix.dumps(1)
def bad(state):
    return b'Try again.' in state.posix.dumps(1)

#开始探索
sm.explore(find = good, avoid = bad)

#探索成功时:
if sm.found:
    find_state = sm.found[0]
    flag1 = find_state.solver.eval(p1)        #将探索成功时的第一个输入赋给flag1,下面两个类似
    flag2 = find_state.solver.eval(p2)
    flag3 = find_state.solver.eval(p3)
    print('{:x} {:x} {:x}'.format(flag1,flag2,flag3))
else:
    print('No')

运行效果:
在这里插入图片描述

04_angr_symbolic_stack:

目的:掌握对输入进栈里的变量符号化的方法

import angr
import claripy
import sys
def main(argv):
    p = angr.Project('/home/yuan/ctf/angr/angr4/04_angr_symbolic_stack')

    def good(state):
        return b'Good Job.' in state.posix.dumps(1)
    def bad(state):
        return b'Try again.' in state.posix.dumps(1)
    
    #创建开始状态
    start_addr = 0x08048697  #scanf之后的地址,之所以是这儿,是因为上一行'add  esp,10h'的作用是清理scanf的栈空间
    state = p.factory.blank_state(addr=start_addr)

    #因为跳过了scanf函数,所以我们需要模拟它的整个操作(对栈的操作)
    #state.stack_push(state.regs.ebp)
    state.regs.ebp = state.regs.esp    #初始化ebp、esp
    space = 0x8                         #一个变量占4个空间,所以两个就是8
    state.regs.esp -= space   #模拟scanf时栈的情况(剔除了对空间的浪费,即只开辟了两个变量的空间)
    ps1 = claripy.BVS('ps1',32)       #符号化两个输入
    ps2 = claripy.BVS('ps2',32)
    state.stack_push(ps1)     #将符号化的输入入栈
    state.stack_push(ps2)
    #至此对scanf的模拟过程就完成了
    
    #创建模拟管理器
    simulation = p.factory.simgr(state)
    
    #开始探索
    simulation.explore(find=good,avoid=bad)
    if simulation.found:
        solution_state = simulation.found[0]
        flag1 = solution_state.solver.eval(ps1)
        flag2 = solution_state.solver.eval(ps2)
        print('{} {}'.format(flag1,flag2))
    else:
        print("AAAAAAA")

if __name__ == '__main__':
    main(sys.argv)

运行效果:
在这里插入图片描述

05_angr_symbolic_memory

目的:掌握对输入进内存的变量符号化方法

import angr
import claripy
import sys

def main(argv):
    path = argv[1]
    p = angr.Project(path)

    start_addr = 0x08048601
    state = p.factory.blank_state(addr=start_addr)

    #创建四个位向量,模拟输入
    p1 = claripy.BVS('p1',64)   #一个变量输入8个字符,一个字符8位bit,总共64bit
    p2 = claripy.BVS('p2',64)
    p3 = claripy.BVS('p3',64)
    p4 = claripy.BVS('p4',64)

    #开始对输入进行模拟
    state.memory.store(0x0A1BA1C0,p1)#让四个位向量指向输入在内存中的地址
    state.memory.store(0x0A1BA1C8,p2)
    state.memory.store(0x0A1BA1D0,p3)
    state.memory.store(0x0A1BA1D8,p4)
    #scanf模拟结束

    sm = p.factory.simgr(state) #创建模拟管理器 
    
    def good(state):
        return b'Good Job.' in state.posix.dumps(1)
    def bad(state):
        return b'Try again.' in state.posix.dumps(1)

    sm.explore(find = good,avoid = bad)

    if sm.found:
        solution_state = sm.found[0]
        flag1 = solution_state.solver.eval(p1,cast_to=bytes)
        flag2 = solution_state.solver.eval(p2,cast_to=bytes)
        flag3 = solution_state.solver.eval(p3,cast_to=bytes)
        flag4 = solution_state.solver.eval(p4,cast_to=bytes)
        print("{} {} {} {}".format(flag1.decode('utf-8'),flag2.decode('utf-8'),flag3.decode('utf-8'),flag4.decode('utf-8')))
    else:
        print("NO")

if __name__ == '__main__':
    main(sys.argv)

运行效果:
在这里插入图片描述

06_angr_symbolic_dynamic_memory

目的:对输入进堆空间的变量符号化

import angr
import sys
import claripy
def main(argv):
    path = argv[1]
    p = angr.Project(path)

    start_addr = 0x08048699
    state = p.factory.blank_state(addr=start_addr)

    p0 = claripy.BVS('p0',8*8)
    p1 = claripy.BVS('p1',8*8)


    #print("ESP:",state.regs.esp)   查看当前esp地址,用作开辟堆空间
    fake_p0 =0x7fff0000-0x100      #在堆中开辟的空间的地址,是一个随机地址
    memory_p0 = 0x0ABCC8A4   #存放指向堆中空间的地址信息的地址
    state.memory.store(memory_p0, fake_p0, endness=p.arch.memory_endness)   #angr默认大端存放数据,需要转换为小端存放

    fake_p1=0x7fff0000-0x200
    memory_p1 = 0x0ABCC8AC
    state.memory.store(memory_p1, fake_p1, endness=p.arch.memory_endness)

    state.memory.store(fake_p0,p0)
    state.memory.store(fake_p1,p1)

    sm = p.factory.simgr(state)

    def is_good(state):
        return b'Good Job.' in state.posix.dumps(1)
    def is_bad(state):
        return b'Try again.' in state.posix.dumps(1)

    sm.explore(find=is_good, avoid=is_bad)

    if sm.found:
        solution_state = sm.found[0]
        solution0 = solution_state.se.eval(p0,cast_to=bytes).decode('utf-8')
        solution1 = solution_state.se.eval(p1,cast_to=bytes).decode('utf-8')
        print("{} {}".format(solution0, solution1))
    else:
        print("NO!")


if __name__ == '__main__':
    main(sys.argv)

运行效果:
在这里插入图片描述

后记

先到这里,(#.#)

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值