# 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 #include #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 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 -- ... */ /* ===================================================================== */ 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/)