mirror of
https://github.com/nganhkhoa/CTF-All-In-One.git
synced 2024-12-25 11:41:16 +07:00
434 lines
23 KiB
Markdown
434 lines
23 KiB
Markdown
# 6.2.1 re XHPCTF2017 dont_panic
|
||
|
||
- [题目解析](#题目解析)
|
||
- [参考资料](#参考资料)
|
||
|
||
|
||
[下载文件](../src/writeup/6.2.1_re_xhpctf2017_dont_panic)
|
||
|
||
## 题目解析
|
||
第一步当然是 file 啦:
|
||
```
|
||
$ file dont_panic
|
||
dont_panic: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, stripped
|
||
```
|
||
64 位,静态编译,而且 stripped。
|
||
|
||
看一下段吧:
|
||
```
|
||
$ readelf -S dont_panic
|
||
There are 13 section headers, starting at offset 0xfa388:
|
||
|
||
Section Headers:
|
||
[Nr] Name Type Address Offset
|
||
Size EntSize Flags Link Info Align
|
||
[ 0] NULL 0000000000000000 00000000
|
||
0000000000000000 0000000000000000 0 0 0
|
||
[ 1] .text PROGBITS 0000000000401000 00001000
|
||
000000000007ae40 0000000000000000 AX 0 0 16
|
||
[ 2] .rodata PROGBITS 000000000047c000 0007c000
|
||
0000000000033f5b 0000000000000000 A 0 0 32
|
||
[ 3] .typelink PROGBITS 00000000004b0080 000b0080
|
||
0000000000000b4c 0000000000000000 A 0 0 32
|
||
[ 4] .itablink PROGBITS 00000000004b0bd0 000b0bd0
|
||
0000000000000038 0000000000000000 A 0 0 8
|
||
[ 5] .gosymtab PROGBITS 00000000004b0c08 000b0c08
|
||
0000000000000000 0000000000000000 A 0 0 1
|
||
[ 6] .gopclntab PROGBITS 00000000004b0c20 000b0c20
|
||
0000000000044d5d 0000000000000000 A 0 0 32
|
||
[ 7] .noptrdata PROGBITS 00000000004f6000 000f6000
|
||
0000000000002608 0000000000000000 WA 0 0 32
|
||
[ 8] .data PROGBITS 00000000004f8620 000f8620
|
||
0000000000001cf0 0000000000000000 WA 0 0 32
|
||
[ 9] .bss NOBITS 00000000004fa320 000fa310
|
||
000000000001a908 0000000000000000 WA 0 0 32
|
||
[10] .noptrbss NOBITS 0000000000514c40 000fa310
|
||
00000000000046a0 0000000000000000 WA 0 0 32
|
||
[11] .note.go.buildid NOTE 0000000000400fc8 00000fc8
|
||
0000000000000038 0000000000000000 A 0 0 4
|
||
[12] .shstrtab STRTAB 0000000000000000 000fa310
|
||
0000000000000073 0000000000000000 0 0 1
|
||
```
|
||
我们发现一些奇怪的东西,`.gosymtab`、`.gopclantab`,Google 一下才知道,它其实是一个用 Go 语言编写的程序。好吧,运行它:
|
||
```
|
||
$ ./dont_panic
|
||
usage: ./dont_panic flag
|
||
$ ./dont_panic abcd
|
||
Nope.
|
||
```
|
||
```
|
||
$ xxd -g1 dont_panic | grep Nope.
|
||
000a5240: 3e 45 72 72 6e 6f 45 72 72 6f 72 4e 6f 70 65 2e >ErrnoErrorNope.
|
||
$ objdump -d dont_panic | grep a524b
|
||
47ba23: 48 8d 05 21 98 02 00 lea 0x29821(%rip),%rax # 0x4a524b
|
||
```
|
||
字符串“Nope.”应该是判断错误时的输出,我们顺便找到了使用它的地址为 `0x47ba23`,接下来在去 r2 里看吧,经过一番搜索,找到了最重要的函数 `fcn.0047b8a0`:
|
||
```
|
||
[0x0047ba23]> pdf @ fcn.0047b8a0
|
||
/ (fcn) fcn.0047b8a0 947
|
||
| fcn.0047b8a0 ();
|
||
| ; JMP XREF from 0x0047bc4e (fcn.0047b8a0)
|
||
| .-> 0x0047b8a0 64488b0c25f8. mov rcx, qword fs:[0xfffffffffffffff8]
|
||
| : 0x0047b8a9 488d442490 lea rax, [rsp - 0x70]
|
||
| : 0x0047b8ae 483b4110 cmp rax, qword [rcx + 0x10] ; [0x10:8]=-1 ; 16
|
||
| ,==< 0x0047b8b2 0f8691030000 jbe 0x47bc49
|
||
| |: 0x0047b8b8 4881ecf00000. sub rsp, 0xf0
|
||
| |: 0x0047b8bf 4889ac24e800. mov qword [local_e8h], rbp
|
||
| |: 0x0047b8c7 488dac24e800. lea rbp, [local_e8h] ; 0xe8 ; 232
|
||
| |: 0x0047b8cf 488b05f2ec07. mov rax, qword [0x004fa5c8] ; [0x4fa5c8:8]=0
|
||
| |: 0x0047b8d6 4883f802 cmp rax, 2 ; 2
|
||
| ,===< 0x0047b8da 0f8530020000 jne 0x47bb10
|
||
| ||: ; JMP XREF from 0x0047bc3d (fcn.0047b8a0)
|
||
| .----> 0x0047b8e0 488b05d9ec07. mov rax, qword [0x004fa5c0] ; [0x4fa5c0:8]=0
|
||
| :||: 0x0047b8e7 488b0ddaec07. mov rcx, qword [0x004fa5c8] ; [0x4fa5c8:8]=0
|
||
| :||: 0x0047b8ee 4883f901 cmp rcx, 1 ; 1
|
||
| ,=====< 0x0047b8f2 0f8611020000 jbe 0x47bb09
|
||
| |:||: 0x0047b8f8 488b4810 mov rcx, qword [rax + 0x10] ; [0x10:8]=-1 ; 16
|
||
| |:||: 0x0047b8fc 48894c2450 mov qword [local_50h], rcx
|
||
| |:||: 0x0047b901 488b4018 mov rax, qword [rax + 0x18] ; [0x18:8]=-1 ; 24
|
||
| |:||: 0x0047b905 4889442448 mov qword [local_48h], rax
|
||
| |:||: 0x0047b90a 4883f82a cmp rax, 0x2a ; '*' ; 42 ; 判断密码长度是否大于 42
|
||
| ,======< 0x0047b90e 0f8c0f010000 jl 0x47ba23 ; 若小于,失败
|
||
| ||:||: 0x0047b914 31d2 xor edx, edx
|
||
| ||:||: 0x0047b916 31db xor ebx, ebx
|
||
| ||:||: 0x0047b918 4889542438 mov qword [local_38h], rdx ; 密码字符串 provided_flag 的下标 i
|
||
| ||:||: 0x0047b91d 885c2436 mov byte [local_36h], bl
|
||
| ||:||: 0x0047b921 4839c2 cmp rdx, rax ; 比较下标 i 与密码长度
|
||
| ,=======< 0x0047b924 7d72 jge 0x47b998 ; 若大于或等于,成功
|
||
| |||:||: ; JMP XREF from 0x0047b996 (fcn.0047b8a0)
|
||
| --------> 0x0047b926 0fb63411 movzx esi, byte [rcx + rdx] ; 循环终点
|
||
| |||:||: 0x0047b92a 4080fe80 cmp sil, 0x80 ; 128
|
||
| ========< 0x0047b92e 0f83a0010000 jae 0x47bad4
|
||
| |||:||: 0x0047b934 400fb6f6 movzx esi, sil
|
||
| |||:||: 0x0047b938 488d7a01 lea rdi, [rdx + 1] ; 1 ; 下标 + 1
|
||
| |||:||: ; JMP XREF from 0x0047bb04 (fcn.0047b8a0) ; 密码逐位判断逻辑
|
||
| --------> 0x0047b93c 48897c2440 mov qword [local_40h], rdi
|
||
| |||:||: 0x0047b941 01f3 add ebx, esi
|
||
| |||:||: 0x0047b943 885c2437 mov byte [local_37h], bl ; bl 代表 provided_flag[i]
|
||
| |||:||: 0x0047b947 881c24 mov byte [rsp], bl
|
||
| |||:||: 0x0047b94a e811feffff call fcn.0047b760 ; 该函数会对 bl 做一些处理
|
||
| |||:||: 0x0047b94f 0fb6442408 movzx eax, byte [local_8h] ; [0x8:1]=255 ; 8 ; eax 是上面函数的返回值,即 mapanic(provided_flag[i])
|
||
| |||:||: 0x0047b954 488b4c2438 mov rcx, qword [local_38h] ; [0x38:8]=-1 ; '8' ; 56
|
||
| |||:||: 0x0047b959 4883f92a cmp rcx, 0x2a ; '*' ; 42 ; 判断 rcx 是否大于等于 0x2a
|
||
| ========< 0x0047b95d 0f836a010000 jae 0x47bacd ; 如果大于或等于,跳转
|
||
| |||:||: 0x0047b963 488d15f6a807. lea rdx, 0x004f6260 ; 读入 constant_binary_blob
|
||
| |||:||: 0x0047b96a 0fb60c0a movzx ecx, byte [rdx + rcx] ; ecx 代表 constant_binary_blob[i]
|
||
| |||:||: 0x0047b96e 38c8 cmp al, cl ; 比较 mapanic(provided_flag[i]) 和 constant_binary_blob[i]
|
||
| ========< 0x0047b970 0f85ad000000 jne 0x47ba23 ; 如果不等于,失败
|
||
| |||:||: 0x0047b976 488b442448 mov rax, qword [local_48h] ; [0x48:8]=-1 ; 'H' ; 72
|
||
| |||:||: 0x0047b97b 488b4c2450 mov rcx, qword [local_50h] ; [0x50:8]=-1 ; 'P' ; 80
|
||
| |||:||: 0x0047b980 488b542440 mov rdx, qword [local_40h] ; [0x40:8]=-1 ; '@' ; 64
|
||
| |||:||: 0x0047b985 0fb65c2437 movzx ebx, byte [local_37h] ; [0x37:1]=255 ; '7' ; 55
|
||
| |||:||: 0x0047b98a 4889542438 mov qword [local_38h], rdx
|
||
| |||:||: 0x0047b98f 885c2436 mov byte [local_36h], bl
|
||
| |||:||: 0x0047b993 4839c2 cmp rdx, rax
|
||
| ========< 0x0047b996 7c8e jl 0x47b926 ; 循环起点
|
||
| |||:||: ; JMP XREF from 0x0047b924 (fcn.0047b8a0)
|
||
| `-------> 0x0047b998 488d05d5c902. lea rax, 0x004a8374 ; "Seems like you got a flag." ; 成功
|
||
| ||:||: 0x0047b99f 48898424a800. mov qword [local_a8h], rax
|
||
| ||:||: 0x0047b9a7 48c78424b000. mov qword [local_b0h], 0x1c ; [0x1c:8]=-1 ; 28
|
||
| ||:||: 0x0047b9b3 48c744245800. mov qword [local_58h], 0
|
||
| ||:||: 0x0047b9bc 48c744246000. mov qword [local_60h], 0
|
||
| ||:||: 0x0047b9c5 488d05b4e300. lea rax, 0x00489d80
|
||
| ||:||: 0x0047b9cc 48890424 mov qword [rsp], rax
|
||
| ||:||: 0x0047b9d0 488d8c24a800. lea rcx, [local_a8h] ; 0xa8 ; 168
|
||
| ||:||: 0x0047b9d8 48894c2408 mov qword [local_8h], rcx
|
||
| ||:||: 0x0047b9dd e80efff8ff call fcn.0040b8f0
|
||
| ||:||: 0x0047b9e2 488b442410 mov rax, qword [local_10h] ; [0x10:8]=-1 ; 16
|
||
| ||:||: 0x0047b9e7 488b4c2418 mov rcx, qword [local_18h] ; [0x18:8]=-1 ; 24
|
||
| ||:||: 0x0047b9ec 4889442458 mov qword [local_58h], rax
|
||
| ||:||: 0x0047b9f1 48894c2460 mov qword [local_60h], rcx
|
||
| ||:||: 0x0047b9f6 488d442458 lea rax, [local_58h] ; 0x58 ; 'X' ; 88
|
||
| ||:||: 0x0047b9fb 48890424 mov qword [rsp], rax
|
||
| ||:||: 0x0047b9ff 48c744240801. mov qword [local_8h], 1
|
||
| ||:||: 0x0047ba08 48c744241001. mov qword [local_10h], 1
|
||
| ||:||: 0x0047ba11 e84a8effff call fcn.00474860
|
||
| ||:||: 0x0047ba16 48c704240000. mov qword [rsp], 0
|
||
| ||:||: 0x0047ba1e e88d1efeff call fcn.0045d8b0
|
||
| ||:||: ; JMP XREF from 0x0047b90e (fcn.0047b8a0)
|
||
| ||:||: ; JMP XREF from 0x0047b970 (fcn.0047b8a0)
|
||
| -`------> 0x0047ba23 488d05219802. lea rax, 0x004a524b ; "Nope." ; 失败
|
||
| |:||: 0x0047ba2a 488984248800. mov qword [local_88h], rax
|
||
| |:||: 0x0047ba32 48c784249000. mov qword [local_90h], 5
|
||
| |:||: 0x0047ba3e 48c784249800. mov qword [local_98h], 0
|
||
| |:||: 0x0047ba4a 48c78424a000. mov qword [local_a0h], 0
|
||
| |:||: 0x0047ba56 488d0523e300. lea rax, 0x00489d80
|
||
| |:||: 0x0047ba5d 48890424 mov qword [rsp], rax
|
||
| |:||: 0x0047ba61 488d84248800. lea rax, [local_88h] ; 0x88 ; 136
|
||
| |:||: 0x0047ba69 4889442408 mov qword [local_8h], rax
|
||
| |:||: 0x0047ba6e e87dfef8ff call fcn.0040b8f0
|
||
| |:||: 0x0047ba73 488b442410 mov rax, qword [local_10h] ; [0x10:8]=-1 ; 16
|
||
| |:||: 0x0047ba78 488b4c2418 mov rcx, qword [local_18h] ; [0x18:8]=-1 ; 24
|
||
| |:||: 0x0047ba7d 488984249800. mov qword [local_98h], rax
|
||
| |:||: 0x0047ba85 48898c24a000. mov qword [local_a0h], rcx
|
||
| |:||: 0x0047ba8d 488d84249800. lea rax, [local_98h] ; 0x98 ; 152
|
||
| |:||: 0x0047ba95 48890424 mov qword [rsp], rax
|
||
| |:||: 0x0047ba99 48c744240801. mov qword [local_8h], 1
|
||
| |:||: 0x0047baa2 48c744241001. mov qword [local_10h], 1
|
||
| |:||: 0x0047baab e8b08dffff call fcn.00474860
|
||
| |:||: 0x0047bab0 48c704240100. mov qword [rsp], 1
|
||
| |:||: 0x0047bab8 e8f31dfeff call fcn.0045d8b0
|
||
| |:||: 0x0047babd 488bac24e800. mov rbp, qword [local_e8h] ; [0xe8:8]=-1 ; 232
|
||
| |:||: 0x0047bac5 4881c4f00000. add rsp, 0xf0
|
||
| |:||: 0x0047bacc c3 ret
|
||
| |:||: ; JMP XREF from 0x0047b95d (fcn.0047b8a0)
|
||
| --------> 0x0047bacd e8ee8dfaff call fcn.004248c0
|
||
| |:||: 0x0047bad2 0f0b ud2
|
||
| |:||: ; JMP XREF from 0x0047b92e (fcn.0047b8a0)
|
||
| --------> 0x0047bad4 48890c24 mov qword [rsp], rcx
|
||
| |:||: 0x0047bad8 4889442408 mov qword [local_8h], rax
|
||
| |:||: 0x0047badd 4889542410 mov qword [local_10h], rdx
|
||
| |:||: 0x0047bae2 e869b8fcff call fcn.00447350
|
||
| |:||: 0x0047bae7 8b742418 mov esi, dword [local_18h] ; [0x18:4]=-1 ; 24
|
||
| |:||: 0x0047baeb 488b7c2420 mov rdi, qword [local_20h] ; [0x20:8]=-1 ; 32
|
||
| |:||: 0x0047baf0 488b442448 mov rax, qword [local_48h] ; [0x48:8]=-1 ; 'H' ; 72
|
||
| |:||: 0x0047baf5 488b4c2450 mov rcx, qword [local_50h] ; [0x50:8]=-1 ; 'P' ; 80
|
||
| |:||: 0x0047bafa 488b542438 mov rdx, qword [local_38h] ; [0x38:8]=-1 ; '8' ; 56
|
||
| |:||: 0x0047baff 0fb65c2436 movzx ebx, byte [local_36h] ; [0x36:1]=255 ; '6' ; 54
|
||
| ========< 0x0047bb04 e933feffff jmp 0x47b93c
|
||
| |:||: ; JMP XREF from 0x0047b8f2 (fcn.0047b8a0)
|
||
| `-----> 0x0047bb09 e8b28dfaff call fcn.004248c0
|
||
| :||: 0x0047bb0e 0f0b ud2
|
||
| :||: ; JMP XREF from 0x0047b8da (fcn.0047b8a0)
|
||
| :`---> 0x0047bb10 488d054c9802. lea rax, 0x004a5363 ; "usage:"
|
||
| : |: 0x0047bb17 4889442478 mov qword [local_78h], rax
|
||
| : |: 0x0047bb1c 48c784248000. mov qword [local_80h], 6
|
||
| : |: 0x0047bb28 488d056a9602. lea rax, 0x004a5199 ; "flag"
|
||
| : |: 0x0047bb2f 4889442468 mov qword [local_68h], rax
|
||
| : |: 0x0047bb34 48c744247004. mov qword [local_70h], 4
|
||
| : |: 0x0047bb3d 488dbc24b800. lea rdi, [local_b8h] ; 0xb8 ; 184
|
||
| : |: 0x0047bb45 0f57c0 xorps xmm0, xmm0
|
||
| : |: 0x0047bb48 4883c7f0 add rdi, 0xfffffffffffffff0
|
||
| : |: 0x0047bb4c 48896c24f0 mov qword [rsp - 0x10], rbp
|
||
| : |: 0x0047bb51 488d6c24f0 lea rbp, [rsp - 0x10]
|
||
| : |: 0x0047bb56 e8851afdff call fcn.0044d5e0
|
||
| : |: 0x0047bb5b 488b6d00 mov rbp, qword [rbp]
|
||
| : |: 0x0047bb5f 488d051ae200. lea rax, 0x00489d80
|
||
| : |: 0x0047bb66 48890424 mov qword [rsp], rax
|
||
| : |: 0x0047bb6a 488d4c2478 lea rcx, [local_78h] ; 0x78 ; 'x' ; 120
|
||
| : |: 0x0047bb6f 48894c2408 mov qword [local_8h], rcx
|
||
| : |: 0x0047bb74 e877fdf8ff call fcn.0040b8f0
|
||
| : |: 0x0047bb79 488b442410 mov rax, qword [local_10h] ; [0x10:8]=-1 ; 16
|
||
| : |: 0x0047bb7e 488b4c2418 mov rcx, qword [local_18h] ; [0x18:8]=-1 ; 24
|
||
| : |: 0x0047bb83 48898424b800. mov qword [local_b8h], rax
|
||
| : |: 0x0047bb8b 48898c24c000. mov qword [local_c0h], rcx
|
||
| : |: 0x0047bb93 488b052eea07. mov rax, qword [0x004fa5c8] ; [0x4fa5c8:8]=0
|
||
| : |: 0x0047bb9a 488b0d1fea07. mov rcx, qword [0x004fa5c0] ; [0x4fa5c0:8]=0
|
||
| : |: 0x0047bba1 4885c0 test rax, rax
|
||
| :,===< 0x0047bba4 0f8698000000 jbe 0x47bc42
|
||
| :||: 0x0047bbaa 48894c2408 mov qword [local_8h], rcx
|
||
| :||: 0x0047bbaf 488d05cae100. lea rax, 0x00489d80
|
||
| :||: 0x0047bbb6 48890424 mov qword [rsp], rax
|
||
| :||: 0x0047bbba e831fdf8ff call fcn.0040b8f0
|
||
| :||: 0x0047bbbf 488b442410 mov rax, qword [local_10h] ; [0x10:8]=-1 ; 16
|
||
| :||: 0x0047bbc4 488b4c2418 mov rcx, qword [local_18h] ; [0x18:8]=-1 ; 24
|
||
| :||: 0x0047bbc9 48898424c800. mov qword [local_c8h], rax
|
||
| :||: 0x0047bbd1 48898c24d000. mov qword [local_d0h], rcx
|
||
| :||: 0x0047bbd9 488d05a0e100. lea rax, 0x00489d80
|
||
| :||: 0x0047bbe0 48890424 mov qword [rsp], rax
|
||
| :||: 0x0047bbe4 488d4c2468 lea rcx, [local_68h] ; 0x68 ; 'h' ; 104
|
||
| :||: 0x0047bbe9 48894c2408 mov qword [local_8h], rcx
|
||
| :||: 0x0047bbee e8fdfcf8ff call fcn.0040b8f0
|
||
| :||: 0x0047bbf3 488b442418 mov rax, qword [local_18h] ; [0x18:8]=-1 ; 24
|
||
| :||: 0x0047bbf8 488b4c2410 mov rcx, qword [local_10h] ; [0x10:8]=-1 ; 16
|
||
| :||: 0x0047bbfd 48898c24d800. mov qword [local_d8h], rcx
|
||
| :||: 0x0047bc05 48898424e000. mov qword [local_e0h], rax
|
||
| :||: 0x0047bc0d 488d8424b800. lea rax, [local_b8h] ; 0xb8 ; 184
|
||
| :||: 0x0047bc15 48890424 mov qword [rsp], rax
|
||
| :||: 0x0047bc19 48c744240803. mov qword [local_8h], 3
|
||
| :||: 0x0047bc22 48c744241003. mov qword [local_10h], 3
|
||
| :||: 0x0047bc2b e8308cffff call fcn.00474860
|
||
| :||: 0x0047bc30 48c704240100. mov qword [rsp], 1
|
||
| :||: 0x0047bc38 e8731cfeff call fcn.0045d8b0
|
||
| `====< 0x0047bc3d e99efcffff jmp 0x47b8e0
|
||
| ||: ; JMP XREF from 0x0047bba4 (fcn.0047b8a0)
|
||
| `---> 0x0047bc42 e8798cfaff call fcn.004248c0
|
||
| |: 0x0047bc47 0f0b ud2
|
||
| |: ; JMP XREF from 0x0047b8b2 (fcn.0047b8a0)
|
||
| `--> 0x0047bc49 e872f3fcff call fcn.0044afc0
|
||
\ `=< 0x0047bc4e e94dfcffff jmp fcn.0047b8a0
|
||
```
|
||
根据我们的分析(详见注释),密码判断逻辑应该如下:
|
||
```C
|
||
for (int i=0; i<length(provided_flag[i]); i++) {
|
||
if (main_mapanic(provided_flag[i]) != constant_binary_blob[i]) {
|
||
badboy();
|
||
exit();
|
||
}
|
||
goodboy();
|
||
}
|
||
```
|
||
|
||
如果要硬着头皮调试的话当然也可以,但我们这里采取暴力破解的办法。还记得章节 5.2 里说的 pin 吗,”由于程序具有循环、分支等结构,每次运行时执行的指令数量不一定相同,于是我们可是使用 Pin 来统计执行指令的数量,从而对程序进行分析”。这里就是这样,程序对输入的密码逐位判断,如果错误,就跳出来,所以根据我们密码正确字节数的不同,程序会执行有明显差异的次数。我们还讲过一个官方示例 inscount0.cpp,我们针对这一题稍微做一点修改,如下:
|
||
```C
|
||
#include <iostream>
|
||
#include <fstream>
|
||
#include "pin.H"
|
||
|
||
ofstream OutFile;
|
||
|
||
// The running count of instructions is kept here
|
||
// make it static to help the compiler optimize docount
|
||
static UINT64 icount = 0;
|
||
|
||
// This function is called before every instruction is executed
|
||
VOID docount(void *ip) {
|
||
if ((long int)ip == 0x0047b96e) icount++; // 0x0047b960: compare mapanic(provided_flag[i]) with constant_binary_blob[i]
|
||
}
|
||
|
||
// Pin calls this function every time a new instruction is encountered
|
||
VOID Instruction(INS ins, VOID *v)
|
||
{
|
||
// Insert a call to docount before every instruction, no arguments are passed
|
||
INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)docount, IARG_INST_PTR, IARG_END); // IARG_INST_PTR: Type: ADDRINT. The address of the instrumented instruction.
|
||
}
|
||
|
||
KNOB<string> KnobOutputFile(KNOB_MODE_WRITEONCE, "pintool",
|
||
"o", "inscount.out", "specify output file name");
|
||
|
||
// This function is called when the application exits
|
||
VOID Fini(INT32 code, VOID *v)
|
||
{
|
||
// Write to a file since cout and cerr maybe closed by the application
|
||
OutFile.setf(ios::showbase);
|
||
OutFile << "Count " << icount << endl;
|
||
OutFile.close();
|
||
}
|
||
|
||
/* ===================================================================== */
|
||
/* Print Help Message */
|
||
/* ===================================================================== */
|
||
|
||
INT32 Usage()
|
||
{
|
||
cerr << "This tool counts the number of dynamic instructions executed" << endl;
|
||
cerr << endl << KNOB_BASE::StringKnobSummary() << endl;
|
||
return -1;
|
||
}
|
||
|
||
/* ===================================================================== */
|
||
/* Main */
|
||
/* ===================================================================== */
|
||
/* argc, argv are the entire command line: pin -t <toolname> -- ... */
|
||
/* ===================================================================== */
|
||
|
||
int main(int argc, char * argv[])
|
||
{
|
||
// Initialize pin
|
||
if (PIN_Init(argc, argv)) return Usage();
|
||
|
||
OutFile.open(KnobOutputFile.Value().c_str());
|
||
|
||
// Register Instruction to be called to instrument instructions
|
||
INS_AddInstrumentFunction(Instruction, 0);
|
||
|
||
// Register Fini to be called when the application exits
|
||
PIN_AddFiniFunction(Fini, 0);
|
||
|
||
// Start the program, never returns
|
||
PIN_StartProgram();
|
||
|
||
return 0;
|
||
}
|
||
```
|
||
主要是修改了两个地方:
|
||
```C
|
||
// This function is called before every instruction is executed
|
||
VOID docount(void *ip) {
|
||
if ((long int)ip == 0x0047b96e) icount++; // 0x0047b960: compare mapanic(provided_flag[i]) with constant_binary_blob[i]
|
||
}
|
||
```
|
||
该函数会在每条指令执行之前被调用,判断是否是我们需要的 `0x0047b96e` 地址处的指令。
|
||
|
||
然后由于函数 docount 需要一个参数,所以 Instruction 函数也要修改,加入指令的地址 `IARG_INST_PTR`:
|
||
```C
|
||
// Pin calls this function every time a new instruction is encountered
|
||
VOID Instruction(INS ins, VOID *v)
|
||
{
|
||
// Insert a call to docount before every instruction, no arguments are passed
|
||
INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)docount, IARG_INST_PTR, IARG_END); // IARG_INST_PTR: Type: ADDRINT. The address of the instrumented instruction.
|
||
}
|
||
```
|
||
|
||
好,接下来 make 并执行。其实我们是知道 flag 结构的,”hxp{...}“ ,总共 42 个字节。
|
||
```
|
||
$ cp dont_panic.cpp source/tools/MyPintool
|
||
[MyPinTool]$ make obj-intel64/dont_panic.so TARGET=intel64
|
||
[MyPinTool]$ ../../../pin -t obj-intel64/dont_panic.so -o inscount.out -- ~/dont_panic "hxp{aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}" ; cat inscount.out
|
||
Nope.
|
||
Count 5
|
||
```
|
||
注意,这里的 5 是执行次数,匹配正确的个数是 5-1=4,即 "hxp{"。但是最后一次是例外,因为完全匹配成功后直接跳转返回,不会再进行匹配。
|
||
|
||
和预期结果一样,下面写个脚本来自动化这一过程:
|
||
```Python
|
||
import os
|
||
|
||
def get_count(flag):
|
||
os.system("../../../pin -t obj-intel64/dont_panic.so -o inscount.out -- ~/dont_panic " + "\"" + flag + "\"")
|
||
with open("inscount.out") as f:
|
||
count = int(f.read().split(" ")[1])
|
||
return count
|
||
|
||
charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-+*'"
|
||
|
||
flag = list("hxp{aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}")
|
||
count = 0
|
||
while count != 42:
|
||
for i in range(4, 41): # only compare "a" in "hex{}"
|
||
for c in charset:
|
||
flag[i] = c
|
||
# print("".join(flag))
|
||
count = get_count("".join(flag))
|
||
if count == i+2:
|
||
break
|
||
print("".join(flag))
|
||
```
|
||
可惜就是速度有点慢,大概跑了一个小时吧。。。
|
||
```
|
||
hxp{k3eP_C4lM_AnD_D0n't_P4n1c__G0_i5_S4F3}
|
||
```
|
||
```
|
||
$ ./dont_panic "hxp{k3eP_C4lM_AnD_D0n't_P4n1c__G0_i5_S4F3}"
|
||
Seems like you got a flag...
|
||
```
|
||
|
||
参考资料里的 gdb 脚本就快得多:
|
||
```Python
|
||
import gdb
|
||
|
||
CHAR_SUCCESS = 0x47B976
|
||
NOPE = 0x47BA23
|
||
gdb.execute("set pagination off")
|
||
gdb.execute("b*0x47B976") #Success for a given character
|
||
gdb.execute("b*0x47BA23") #Block displaying "Nope"
|
||
charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-+*{}'"
|
||
flag = list('A'*42) #junk
|
||
for i in range(0,len(flag)) :
|
||
for c in charset:
|
||
flag[i] = c
|
||
# the number of times we need to hit the
|
||
# success bp for the previous correct characters
|
||
success_hits = i
|
||
gdb.execute("r " + '"' + "".join(flag) + '"')
|
||
while success_hits > 0 :
|
||
gdb.execute('c')
|
||
success_hits -= 1
|
||
#we break either on success or on fail
|
||
rip = int(gdb.parse_and_eval("$rip"))
|
||
if rip == CHAR_SUCCESS:
|
||
break #right one. To the next character
|
||
if rip == NOPE: #added for clarity
|
||
continue
|
||
print("".join(flag))
|
||
```
|
||
|
||
在最后一篇参考资料里,介绍了怎样还原 Go 二进制文件的函数名,这将大大简化我们的分析。
|
||
|
||
|
||
## 参考资料
|
||
- [Pin Tutorial](http://www.ic.unicamp.br/~rodolfo/mo801/04-PinTutorial.pdf)
|
||
- [Reversing GO binaries like a pro](https://rednaga.io/2016/09/21/reversing_go_binaries_like_a_pro/)
|
||
- [HXP CTF 2017 - "dont_panic" Reversing 100 Writeup](http://rce4fun.blogspot.com/2017/11/hxp-ctf-2017-dontpanic-reversing-100.html)
|
||
- [write-up for dont_panic](http://eternal.red/2017/dont_panic-writeup/)
|