finish 6.6

This commit is contained in:
firmianay 2017-11-23 14:44:22 +08:00
parent 6405dd5a81
commit 493465469d
5 changed files with 539 additions and 1 deletions

View File

@ -260,7 +260,7 @@ int main(int argc, char * argv[])
- 在每条指令之前(`IPOINT_BEFORE`)执行分析函数 `docount()`,功能是对全局变量递增计数。 - 在每条指令之前(`IPOINT_BEFORE`)执行分析函数 `docount()`,功能是对全局变量递增计数。
- 执行完成函数 `Fini()`,输出计数结果到文件。 - 执行完成函数 `Fini()`,输出计数结果到文件。
由于我当前使用的系统和内核版本过新Pin 暂时还未支持,使用时需要加上 `-ifeellucky` 参数,`-o` 参数将运行结果输出到文件。运行程序: 由于我当前使用的系统和内核版本过新Pin 暂时还未支持,使用时需要加上 `-ifeellucky` 参数(在最新的 pin 3.5 中似乎不需要这个参数了)`-o` 参数将运行结果输出到文件。运行程序:
``` ```
[ManualExamples]$ uname -a [ManualExamples]$ uname -a
Linux manjaro 4.11.5-1-ARCH #1 SMP PREEMPT Wed Jun 14 16:19:27 CEST 2017 x86_64 GNU/Linux Linux manjaro 4.11.5-1-ARCH #1 SMP PREEMPT Wed Jun 14 16:19:27 CEST 2017 x86_64 GNU/Linux
@ -417,6 +417,7 @@ Count 152786
#### 参考资料 #### 参考资料
- [A binary analysis, count me if you can](http://shell-storm.org/blog/A-binary-analysis-count-me-if-you-can/) - [A binary analysis, count me if you can](http://shell-storm.org/blog/A-binary-analysis-count-me-if-you-can/)
- [pintool2](https://github.com/sebastiendamaye/pintool2) - [pintool2](https://github.com/sebastiendamaye/pintool2)
- [Pin 3.5 User Guide](https://software.intel.com/sites/landingpage/pintool/docs/97503/Pin/html/)
#### 练习 #### 练习
- [**RE** - picoCTF 2014 - Baleful](../src/Reverse/5.2_baleful) - [**RE** - picoCTF 2014 - Baleful](../src/Reverse/5.2_baleful)

View File

@ -5,6 +5,423 @@
## 题目解析 ## 题目解析
第一步当然是 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}
```
参考资料里的 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) - [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/)

View File

@ -0,0 +1,69 @@
#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;
}

View File

@ -0,0 +1,30 @@
#HXP CTF 2017 - dont_panic 100 pts
#Writeup link : https://rce4fun.blogspot.com/2017/11/hxp-ctf-2017-dontpanic-reversing-100.html
#Souhail Hammou
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))
#flag : hxp{k3eP_C4lM_AnD_D0n't_P4n1c__G0_i5_S4F3}

View File

@ -0,0 +1,21 @@
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))