codegate2017-angrybird

0x00:

最近又在看angr了,总结了一下常见的用法以及一些模板…正好这个题目可以用上。

0x01:题目分析

x64的elf文件,运行一下直接退出了:

1
2
3
4
# muhe @ MUHE-PC in /mnt/c/Users/muhe/Desktop [21:25:12]
$ ./angrybird
# muhe @ MUHE-PC in /mnt/c/Users/muhe/Desktop [21:25:15] C:1
$

直接丢进IDA看汇编

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
.text:0000000000400761                 push    rbp
.text:0000000000400762 mov rbp, rsp
.text:0000000000400765 add rsp, 0FFFFFFFFFFFFFF80h
.text:0000000000400769 mov rax, fs:28h
.text:0000000000400772 mov [rbp+var_8], rax
.text:0000000000400776 xor eax, eax
.text:0000000000400778 cmp eax, 0
.text:000000000040077B jz _exit
.text:0000000000400781 mov [rbp+var_70], offset off_606018
.text:0000000000400789 mov [rbp+var_68], offset off_606020
.text:0000000000400791 mov [rbp+var_60], offset off_606028
.text:0000000000400799 mov [rbp+var_58], offset off_606038
.text:00000000004007A1 mov eax, 0
.text:00000000004007A6 call sub_4006F6
.text:00000000004007AB mov [rbp+n], eax
.text:00000000004007AE mov eax, 0
.text:00000000004007B3 call sub_40070C
.text:00000000004007B8 mov eax, 0
.text:00000000004007BD call sub_40072A
.text:00000000004007C2 mov rdx, cs:stdin ; stream
.text:00000000004007C9 mov ecx, [rbp+n]
.text:00000000004007CC lea rax, [rbp+s]
.text:00000000004007D0 mov esi, ecx ; n
.text:00000000004007D2 mov rdi, rax ; s
.text:00000000004007D5 call _fgets
.text:00000000004007DA movzx edx, [rbp+s]
.text:00000000004007DE movzx eax, [rbp+var_4F]
.text:00000000004007E2 xor eax, edx
.text:00000000004007E4 mov [rbp+var_30], al
.text:00000000004007E7 movzx eax, [rbp+var_30]
.text:00000000004007EB cmp al, 0Fh
.text:00000000004007ED jg short loc_400803
.text:00000000004007EF mov edi, offset aMelong ; "melong"
.text:00000000004007F4 call _puts
.text:00000000004007F9 mov edi, 1 ; status
.text:00000000004007FE call _exit

这个cm非常规,前面很多乱七八糟的函数,就是让你执行不到正常逻辑去。如果想要执行到00000000004007C2去,然后去逆向算法什么,需要把前面的一些拦路虎全部patch掉…我开始在做patch一点,调试一点,然后继续patch…后来实在忍不了,太坑了,直接上符号执行算了。

0x02:解决

模板

使用angr符号执行解题可以不从main开始跑,只要指定一个入口就好了

1
2
3
4
5
6
7
8
9
10
import angr

prog = angr.Project('./cm')
#s = prog.factory.blank_state(addr=0x0804864B)
s = prog.factory.entry_state(args=["./cm"])
pg = prog.factory.path_group(s, immutable=False)
path = pg.explore(find=(0x0804864B,))

print path
print pg.found[0].state.se._solver.result.model

不过后面print的部分需要做一点改动…
因为有些题目输入是从命令行参数给的,有些是read那种读取的。

1
2
3
4
5
6
7
.text:0000000000404FAB loc_404FAB:                             ; CODE XREF: main+4834j
.text:0000000000404FAB lea rax, [rbp+s]
.text:0000000000404FAF mov rsi, rax
.text:0000000000404FB2 mov edi, offset format ; "you typed : %s\n"
.text:0000000000404FB7 mov eax, 0
.text:0000000000404FBC call _printf
.text:0000000000404FC1 mov eax, 0

执行到这里0000000000404FC1就可以,不过要使用posix相关的方法去提取输入。

solve.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/usr/bin/env python
# coding=utf-8

import angr

start_addr = 0x00000000004007C2

def main():
prog = angr.Project('angrybird', load_options={"auto_load_libs": False})

#s = prog.factory.entry_state(addr=start_addr)
s = prog.factory.blank_state(addr=start_addr)
path = prog.factory.path(s)
pg = prog.factory.path_group(path, immutable=False)

find = pg.explore(find=(0x0000000000404FC1))

print find
print pg.found[-1].state.posix.dumps(0)

if __name__ == '__main__':
main()

结果

1
2
3
4
(angr) ➜  Desktop python solve.py 
WARNING | 2017-03-04 05:33:08,495 | simuvex.plugins.symbolic_memory | Concretizing symbolic length. Much sad; think about implementing.
<PathGroup with 418 deadended, 4 active, 1 found>
Im_so_cute&pretty_:)� @ �  J   �

0x03:参考与引用

Ysc‘s blog