---
# System prepended metadata

title: angr_ctf刷题小记（&&angr入门？
tags: [CTF, angr, Reverse/逆向]

---

# angr_ctf刷题小记（&&angr入门？

###### tags: `CTF` `Reverse/逆向` `angr`

今天划水的时候发现了一个用来逐步学习angr的题库：[angr_ctf](https://github.com/jakespringer/angr_ctf/)。  
刚好angr写脚本不太熟练，故开始（约等于从零开始的）学习并做下记录 ~~（方便后人踩坑~~ 。

试图每天打卡1-2题吧（水帖实锤(x)。

## 0xFF_一切的最开始

> 环境：win10+wsl(ubuntu 18.04)  
> python相关：python(3.6.9)+angr(9.0.4495)+templite(0.2.1)

- 上面github题库的环境是python2，但angr从8.0开始就放弃了对python2的支持，所以刷题的时候需要对题库脚本进行微调（py2->py3，比如print的东西需要用括号括起来）。
- 安装相关自行谷歌，建议安装angr的时候使用python虚拟环境（virtualenvwrapper）。
- angr理论相关（比如符号执行）在主目录下的文件`SymbolicExecution.pptx`中有说明，超详细！
- 如遇到打开`XX_angr_find`时遇到报错：`Exec format error`，参考[这篇blog](https://blog.csdn.net/fjh1997/article/details/105536828)；安装完qemu以后，每次遇到该error就执行一次`sudo service binfmt-support start`启用服务即可。

先把整个包download下来并解压，可以看到有每一个题目的文件夹（题目生成包，用来生成可执行文件，只需刷题的话大概没用），还有`dist`和`solutions`两个文件夹。

`dist`里有：
1. `XX_xxxx`：每道题的elf。
2. `scaffoldXX.py`：解题脚本挖空范例（题面，需要填空，注释用来解释语句的作用很详细）。

`solutions`里各道题的文件夹里有：
1. `XX_xxxx`：每道题的elf。
2. `scaffoldXX.py`：解题脚本挖空范例（同上）。
3. `solveXX.py`：解题脚本（正确答案=v=）。

我的话直接转到`dist`文件夹里做了（懒得切目录）。

p.s. 具体学写脚本还是得看`scaffoldXX.py`里的注释 或者 [这个系列](https://www.anquanke.com/post/id/212816)，这里只是一个做题记录罢了:/

---

## 0x00_angr_find

用ida打开文件定位到关键分支（“Good Job”）：

![:/](https://i.imgur.com/WonOVDP.png)

把地址0x8048678（输出Good Job的地址）填进print_good_address里，整合得到脚本：
```python=
import angr
import sys

path_to_binary = './00_angr_find'
project = angr.Project(path_to_binary)
initial_state = project.factory.entry_state()
simulation = project.factory.simgr(initial_state)

print_good_address = 0x8048678
simulation.explore(find=print_good_address)

if simulation.found:
    solution_state = simulation.found[0]
    print(solution_state.posix.dumps(sys.stdin.fileno()))
else:
    raise Exception('Could not find the solution')
```

---

## 0x01_angr_avoid

ida里打开，时间很长（，并且会出提示：

![:/](https://i.imgur.com/RjXHAWR.png)

并且analysis完以后按F5还会蹦出这个：

![:/](https://i.imgur.com/1t253Hs.png)

[小小的脑袋里充满了大大的疑惑.jpg]  
只能说真不愧是针对avoid出的题了。

既然没有图形界面（懒得设置）又不能反编译，那就走点小道好了。

shift+F12出strings window，然后双击进到“Good job”。

![:/](https://i.imgur.com/tuUp8Di.png)

查看调用情况。

![:/](https://i.imgur.com/9QnsI2O.png)

![:/](https://i.imgur.com/GajLdrs.png)

在IDA view里定位到函数分支，填地址，over。

avoid同理：

![:/](https://i.imgur.com/u0Zdh65.png)

需要注意的是，反编译maybe_good()函数可以看出，should_succeed必须为1，而should_succeed还被avoid_me()函数调用改为0，所以avoid的地址还得加上avoid_me()函数的地址。

以及，一开始没搜成功（大意了），因为反编译complex_function()以后可以看到这个是必走的，只要在if那里避免转进“try again”就好。

最后的脚本（加了个测时间的）：

```python=
import angr
import sys
import time

t = time.clock()
path_to_binary = './01_angr_avoid'
project = angr.Project(path_to_binary)
initial_state = project.factory.entry_state()
simulation = project.factory.simgr(initial_state)

print_good_address = 0x80485DD
will_not_succeed_address = [0x80485EF,0x804855B,0x80485A8]
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()))
else:
    raise Exception('Could not find the solution')

print('time:',round(time.clock()-t,2),'s')
```

---

## 0x02_angr_find_condition

用ida看ida view发现分支有无限多，但是奇怪的是反编译以后并没有看到这些（迷惑）。

像这个样子的：

![:/](https://i.imgur.com/PWsDF3v.png)

所以根据挖了空的题解脚本的提示填空就好。脚本：

```python=
import angr
import sys
import time

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

t = time.clock()
path_to_binary = './02_angr_find_condition'
project = angr.Project(path_to_binary)
initial_state = project.factory.entry_state()
simulation = project.factory.simgr(initial_state)

simulation.explore(find=is_successful, avoid=should_abort)
if simulation.found:
    solution_state = simulation.found[0]
    print(solution_state.posix.dumps(sys.stdin.fileno()))
else:
    raise Exception('Could not find the solution')

print('time:',round(time.clock()-t,2),'s')
```

一点点坑：

布尔变量那里一开始写的是`return i if stdout_output==b"Good Job." else 0`，后来发现"Good Job."不能跟stdout_output完全匹配（输出stdout_output可以看到是类似于`b'Enter the password: Good Job.\n'`的东西），所以懒得完全匹配直接上in了。

---

## 0x03_angr_symbolic_registers

这题的点在于angr能将数据直接注入到寄存器中（angr强大之处+1。

![:/](https://i.imgur.com/gxTzDfA.png)

查看get_user_input()的反编译窗口没什么作用，我选择反汇编。

![:/](https://i.imgur.com/13IoeqR.png)

可以看到三个输入分别被传入eax，ebx和edx中。