返回介绍

6.2.1 re XHPCTF2017 dont_panic

发布于 2022-02-28 21:36:25 字数 28988 浏览 890 评论 0 收藏 0

下载文件

题目解析

第一步当然是 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

根据我们的分析(详见注释),密码判断逻辑应该如下:

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,我们针对这一题稍微做一点修改,如下:

#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;
}

主要是修改了两个地方:

// 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

// 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{"。但是最后一次是例外,因为完全匹配成功后直接跳转返回,不会再进行匹配。

和预期结果一样,下面写个脚本来自动化这一过程:

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 脚本就快得多:

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 二进制文件的函数名,这将大大简化我们的分析。

参考资料

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文