diff --git a/doc/2.2_gdb.md b/doc/2.2_gdb.md index fc42523..c45fe43 100644 --- a/doc/2.2_gdb.md +++ b/doc/2.2_gdb.md @@ -459,140 +459,11 @@ $ yaourt -S peda gdb-peda$ python myrun(100) ``` -下面我们通过一道 CTF 题目来练习一下 PEDA 脚本的编写:[asis-ctf-quals-2014 serial-number re-300](../src/Others/2.2_gdb/serial_number_300) -``` -__int64 __fastcall main(__int64 a1, char **a2, char **a3) -{ - __int64 result; // rax@5 - int v4; // ecx@9 - int v5; // ecx@9 - int v6; // ecx@9 - int v7; // ecx@9 - int v8; // ecx@9 - unsigned __int64 v9; // [sp+8h] [bp-68h]@4 - int v10; // [sp+10h] [bp-60h]@9 - int v11; // [sp+14h] [bp-5Ch]@9 - int v12; // [sp+18h] [bp-58h]@9 - int v13; // [sp+1Ch] [bp-54h]@9 - int v14; // [sp+20h] [bp-50h]@9 - int v15; // [sp+24h] [bp-4Ch]@9 - int v16; // [sp+28h] [bp-48h]@9 - int v17; // [sp+2Ch] [bp-44h]@9 - unsigned __int64 v18; // [sp+38h] [bp-38h]@6 - int v19; // [sp+44h] [bp-2Ch]@4 - _QWORD *v20; // [sp+48h] [bp-28h]@1 - int i; // [sp+54h] [bp-1Ch]@1 - int v22; // [sp+58h] [bp-18h]@1 - int v23; // [sp+5Ch] [bp-14h]@1 - - v23 = 0; - v22 = 1; - v20 = malloc(4uLL); - for ( i = 0; i <= 3; ++i ) - { - v20[i] = malloc(0xCuLL); - *(_DWORD *)(v20[i] + 8LL) = 1; - } - printf("Enter serial number in hex formet (without 0x prefix) : ", a2); - v19 = scanf("%llx", &v9); - if ( v19 > 0 ) - { - v18 = v9; - while ( v9 ) - { - v22 ^= 1u; - if ( *(_DWORD *)*v20 != v22 && v22 ) - { - v14 = v9 & 1; - v9 >>= 1; - v15 = v9 & 1; - v9 >>= 1; - v16 = v9 & 1; - v9 >>= 1; - v17 = v9 & 1; - v9 >>= 1; - v23 = *(_DWORD *)(v20[1] + 4LL) & (*(_DWORD *)(v20[2] + 4LL) == 0) & *(_BYTE *)(v20[3] + 4LL) & (unsigned __int8)v14 & (v15 == 0) & (unsigned __int8)(v16 & v17) & *(_DWORD *)(*v20 + 4LL); - v4 = *(_BYTE *)(v20[1] + 4LL) & (*(_DWORD *)(v20[2] + 4LL) == 0) & (unsigned __int8)(*(_BYTE *)(v20[3] + 4LL) & (v14 | (v15 == 0) | v16 | (v17 == 0))) & (*(_DWORD *)(*v20 + 4LL) == 0) | (*(_DWORD *)(v20[1] + 4LL) == 0) & (*(_DWORD *)(v20[2] + 4LL) == 0) & (unsigned __int8)(*(_BYTE *)(v20[3] + 4LL) & ((v14 == 0) | (v15 == 0) | v16 | v17)) & *(_DWORD *)(*v20 + 4LL) | (*(_DWORD *)(v20[1] + 4LL) == 0) & (*(_DWORD *)(v20[2] + 4LL) == 0) & (unsigned __int8)(*(_BYTE *)(v20[3] + 4LL) & (v14 | v15 | (v16 == 0) | v17)) & (*(_DWORD *)(*v20 + 4LL) == 0) | *(_DWORD *)(*v20 + 4LL) & *(_DWORD *)(v20[1] + 4LL) & *(_DWORD *)(v20[2] + 4LL) & (*(_DWORD *)(v20[3] + 4LL) == 0) & (v14 == 0) & (v15 == 0) & (unsigned __int8)(v16 & v17); - v13 = v4 | *(_DWORD *)(v20[1] + 4LL) & (*(_DWORD *)(v20[2] + 4LL) == 0) & *(_DWORD *)(v20[3] + 4LL) & *(_DWORD *)(*v20 + 4LL); - v5 = *(_BYTE *)(v20[1] + 4LL) & *(_BYTE *)(v20[2] + 4LL) & (*(_DWORD *)(v20[3] + 4LL) == 0) & (unsigned __int8)((v14 == 0) | v15 | (v16 == 0) | v17) & (*(_DWORD *)(*v20 + 4LL) == 0) | (*(_DWORD *)(v20[1] + 4LL) == 0) & *(_BYTE *)(v20[2] + 4LL) & (*(_DWORD *)(v20[3] + 4LL) == 0) & (unsigned __int8)(v14 | (v15 == 0) | v16 | v17) & *(_DWORD *)(*v20 + 4LL) | (*(_DWORD *)(v20[1] + 4LL) == 0) & *(_BYTE *)(v20[2] + 4LL) & (*(_DWORD *)(v20[3] + 4LL) == 0) & (unsigned __int8)((v14 == 0) | v15 | v16 | v17) & (*(_DWORD *)(*v20 + 4LL) == 0) | *(_DWORD *)(*v20 + 4LL) & *(_DWORD *)(v20[1] + 4LL) & (*(_DWORD *)(v20[2] + 4LL) == 0) & (*(_DWORD *)(v20[3] + 4LL) == 0) & (unsigned __int8)v14 & (unsigned __int8)v15 & (unsigned __int8)v16 & (v17 == 0); - v12 = v5 | *(_DWORD *)(v20[1] + 4LL) & *(_DWORD *)(v20[2] + 4LL) & (*(_DWORD *)(v20[3] + 4LL) == 0) & *(_DWORD *)(*v20 + 4LL); - v6 = (*(_DWORD *)(v20[1] + 4LL) == 0) & *(_BYTE *)(v20[2] + 4LL) & (*(_DWORD *)(v20[3] + 4LL) == 0) & (v14 == 0) & (unsigned __int8)v15 & (v17 == 0 && v16 == 0) & *(_DWORD *)(*v20 + 4LL) | *(_DWORD *)(v20[1] + 4LL) & (*(_DWORD *)(v20[3] + 4LL) == 0 && *(_DWORD *)(v20[2] + 4LL) == 0) & *(_DWORD *)(*v20 + 4LL) | *(_BYTE *)(v20[1] + 4LL) & (*(_DWORD *)(v20[2] + 4LL) == 0 && *(_DWORD *)(v20[3] + 4LL) == 0 && (v14 == 0 || v15 == 0 || v17 == 0 || v16 == 0)) & (*(_DWORD *)(*v20 + 4LL) == 0) | *(_DWORD *)(*v20 + 4LL) & (*(_DWORD *)(v20[1] + 4LL) == 0) & (*(_DWORD *)(v20[2] + 4LL) == 0) & (*(_DWORD *)(v20[3] + 4LL) == 0) & (unsigned __int8)v14 & (v15 == 0) & (v16 == 0) & (unsigned __int8)v17; - v11 = *(_BYTE *)(v20[1] + 4LL) & (*(_DWORD *)(v20[2] + 4LL) == 0) & (unsigned __int8)(*(_BYTE *)(v20[3] + 4LL) & (v14 | (v15 == 0) | v16 | (v17 == 0))) & (*(_DWORD *)(*v20 + 4LL) == 0) | (*(_DWORD *)(v20[1] + 4LL) == 0) & (*(_DWORD *)(v20[2] + 4LL) == 0) & *(_BYTE *)(v20[3] + 4LL) & (unsigned __int8)v14 & (unsigned __int8)v15 & (v17 == 0 && v16 == 0) & *(_DWORD *)(*v20 + 4LL) | *(_DWORD *)(v20[1] + 4LL) & *(_DWORD *)(v20[2] + 4LL) & (*(_DWORD *)(v20[3] + 4LL) == 0) & *(_DWORD *)(*v20 + 4LL) | *(_BYTE *)(v20[1] + 4LL) & *(_BYTE *)(v20[2] + 4LL) & (*(_DWORD *)(v20[3] + 4LL) == 0) & (unsigned __int8)((v14 == 0) | v15 | (v16 == 0) | v17) & (*(_DWORD *)(*v20 + 4LL) == 0) | v6 | *(_DWORD *)(v20[1] + 4LL) & (*(_DWORD *)(v20[2] + 4LL) == 0) & *(_DWORD *)(v20[3] + 4LL) & *(_DWORD *)(*v20 + 4LL); - v7 = *(_DWORD *)(v20[1] + 4LL) & (*(_DWORD *)(v20[3] + 4LL) == 0 && *(_DWORD *)(v20[2] + 4LL) == 0) & *(_DWORD *)(*v20 + 4LL) | *(_BYTE *)(v20[1] + 4LL) & (*(_DWORD *)(v20[2] + 4LL) == 0) & (*(_DWORD *)(v20[3] + 4LL) == 0) & (unsigned __int8)(v14 & v15 & v16 & v17) & (*(_DWORD *)(*v20 + 4LL) == 0) | (*(_DWORD *)(v20[1] + 4LL) == 0 && *(_DWORD *)(v20[3] + 4LL) == 0 && *(_DWORD *)(v20[2] + 4LL) == 0) & *(_DWORD *)(*v20 + 4LL) | (*(_DWORD *)(*v20 + 4LL) == 0) & (*(_DWORD *)(v20[1] + 4LL) == 0) & (*(_DWORD *)(v20[2] + 4LL) == 0) & (*(_DWORD *)(v20[3] + 4LL) == 0) & (unsigned __int8)v14 & (v15 == 0) & (unsigned __int8)(v16 & v17); - v8 = *(_DWORD *)(v20[1] + 4LL) & *(_DWORD *)(v20[2] + 4LL) & (*(_DWORD *)(v20[3] + 4LL) == 0) & *(_DWORD *)(*v20 + 4LL) | *(_BYTE *)(v20[1] + 4LL) & *(_BYTE *)(v20[2] + 4LL) & (*(_DWORD *)(v20[3] + 4LL) == 0) & (unsigned __int8)v14 & (v15 == 0) & (unsigned __int8)v16 & (v17 == 0) & (*(_DWORD *)(*v20 + 4LL) == 0) | (*(_DWORD *)(v20[1] + 4LL) == 0) & *(_BYTE *)(v20[2] + 4LL) & (*(_DWORD *)(v20[3] + 4LL) == 0) & *(_DWORD *)(*v20 + 4LL) | (*(_DWORD *)(v20[1] + 4LL) == 0) & *(_BYTE *)(v20[2] + 4LL) & (*(_DWORD *)(v20[3] + 4LL) == 0) & (unsigned __int8)v14 & (v15 == 0 && v17 == 0 && v16 == 0) & (*(_DWORD *)(*v20 + 4LL) == 0) | v7; - v10 = *(_BYTE *)(v20[1] + 4LL) & (*(_DWORD *)(v20[2] + 4LL) == 0) & *(_BYTE *)(v20[3] + 4LL) & (v14 == 0) & (unsigned __int8)v15 & (v16 == 0) & (unsigned __int8)v17 & (*(_DWORD *)(*v20 + 4LL) == 0) | (*(_DWORD *)(v20[1] + 4LL) == 0) & (*(_DWORD *)(v20[2] + 4LL) == 0) & *(_BYTE *)(v20[3] + 4LL) & *(_DWORD *)(*v20 + 4LL) | (*(_DWORD *)(v20[1] + 4LL) == 0) & (*(_DWORD *)(v20[2] + 4LL) == 0) & *(_BYTE *)(v20[3] + 4LL) & (v14 == 0) & (v15 == 0) & (unsigned __int8)v16 & (v17 == 0) & (*(_DWORD *)(*v20 + 4LL) == 0) | v8 | *(_DWORD *)(v20[1] + 4LL) & (*(_DWORD *)(v20[2] + 4LL) == 0) & *(_DWORD *)(v20[3] + 4LL) & *(_DWORD *)(*v20 + 4LL); - sub_40064D((unsigned int)v13, v20[3]); - sub_40064D((unsigned int)v12, v20[2]); - sub_40064D((unsigned int)v11, v20[1]); - sub_40064D((unsigned int)v10, *v20); - } - *(_DWORD *)v20[3] = v22; - *(_DWORD *)v20[2] = v22; - *(_DWORD *)v20[1] = v22; - *(_DWORD *)*v20 = v22; - } - if ( v23 == 1 ) - printf("\nCongratulation! Send \"ASIS_MD5(%llx)\" as the flag!", v18); - else - printf("Sorry! The serial number is incorrect!"); - result = 0LL; - } - else - { - printf("Invalid number."); - result = 0LL; - } - return result; -} -``` -上面是在 IDA Pro 中 F5 的结果,可以看到程序中有非常长的位操作逻辑,如果硬着头皮分析的话会非常困难。下面我们借用 PEDA 强大的能力来解决它,首先简化下上面的代码: -``` -int v9; // serial_number -int v23; // correct_serial - -v23 = 0; - -while (v9) { - v14 = v9 & 1; - v9 >>= 1; - v15 = v9 & 1; - v9 >>= 1; - v16 = v9 & 1; - v9 >>= 1; - v17 = v9 & 1; - v9 >>= 1; - v23 = v23 = *(_DWORD *)(v20[1] + 4LL) & (*(_DWORD *)(v20[2] + 4LL) == 0) & *(_BYTE *)(v20[3] + 4LL) & (unsigned __int8)v14 & (v15 == 0) & (unsigned __int8)(v16 & v17) & *(_DWORD *)(*v20 + 4LL); - (v20, v20[1], v20[2], v20[3]) = very_long_bit_operation_asm((v20, v20[1], v20[2], v20[3]), (v14, v15, v16, v17)); -} - -if (v23 == 1) { - printf("Congratulation!"); -} -``` -大概就是这样,我们用 `very_long_bit_operation_asm()` 函数代替了近千行的位操作,它的参数可以分为两组,`(v20, v20[1], v20[2], v20[3])` 和 `(v14, v15, v16, v17)`,每个组表示 4 比特的变量。所以,无论这个函数是什么操作,都只有 `16 * 16 = 256` 种可能,我们就可以使用暴力的方式破解它。 - -通过设置 `rip` 为循环代码的开始,并在 `` 函数结束处设置断点,我们就可以使代码循环执行了。 -```text -0000000000400768 loc_400768: ; CODE XREF: main+E43 -... -.text:0000000000400788 mov rax, [rbp+var_68] -... -000000000040149C -.text:000000000040149C loc_40149C: ; CODE XREF: main+DC -.text:000000000040149C ; main+E6 -... -00000000004014D8 -.text:00000000004014D8 loc_4014D8: ; CODE XREF: main+C7 -.text:00000000004014D8 mov rax, [rbp+var_68] -``` - -参考 http://blog.ztrix.me/blog/2014/05/10/asis-quals-2014-serial-number-writeup/ - #### 更多资料 http://ropshell.com/peda/ ## GEF/pwndbg -除了 PEDA 外还有一些优秀的 gdb 增强工具,功能大致相同,可以看情况选用。 +除了 PEDA 外还有一些优秀的 gdb 增强工具,特别是增加了一些查看堆的命令,可以看情况选用。 - [GEF](https://github.com/hugsy/gef) - Multi-Architecture GDB Enhanced Features for Exploiters & Reverse-Engineers - [pwndbg](https://github.com/pwndbg/pwndbg) - Exploit Development and Reverse Engineering with GDB Made Easy diff --git a/doc/2.5_radare2.md b/doc/2.5_radare2.md index c20be04..dc43c8f 100644 --- a/doc/2.5_radare2.md +++ b/doc/2.5_radare2.md @@ -22,6 +22,7 @@ - [调试(debugging)](#调试debugging) - [视图模式](#视图模式) - [Web 界面使用](#web-界面使用) +- [cutter GUI](#cutter-gui) - [在 CTF 中的运用](#在-ctf-中的运用) - [更多资源](#更多资源) @@ -1104,6 +1105,25 @@ $ r2 -c=H [filename] 默认地址为 `http://localhost:9090/`,这样你就可以在 Web 中进行操作了,但是我强烈建议你强迫自己使用命令行的操作方式。 +## cutter GUI +cutter 是 r2 官方的 GUI,已经在快速开发中,基本功能已经有了,喜欢界面操作的读者可以试一下(请确保 r2 已经正确安装): +``` +$ yaourt -S qt +``` +``` +$ git clone https://github.com/radareorg/cutter +$ cd cutter +$ mkdir build +$ cd build +$ qmake ../src +$ make +``` +然后就可以运行了: +``` +./cutter +``` + + ## 在 CTF 中的运用 - [IOLI crackme](https://github.com/firmianay/Life-long-Learner/blob/master/binary-security/IOLI-crackme-Writeup.md) - [radare2-explorations-binaries](https://github.com/monosource/radare2-explorations-binaries)