IOLI-crackme0x06-0x09 writeup


前几天写了使用Radare2并用3中方法来解决crackme0x00, 然后紧接着第二天
就写了另外5个writeup, 如果认真看会发现那几个crackme的分析也是一开始
走了很多弯路, 但玩多了也就熟悉了. 趁热打铁, 把最后几关也过一过.

本文所使用的crackmes都来自IOLI-crackme.

crackme0x06

虽然隔了几天, 但r2打开反汇编时还是发现结构和差不多,
先看main函数:

[0x08048607]> pdf @ sym.main ;-- main: / (fcn) sym.main 99 | sym.main (int arg_10h); | ; var int local_78h @ ebp-0x78 | ; arg int arg_10h @ ebp+0x10 | ; var int local_4h @ esp+0x4 | ; DATA XREF from 0x08048417 (entry0) | 0x08048607 55 push ebp | 0x08048608 89e5 mov ebp, esp | 0x0804860a 81ec88000000 sub esp, 0x88 | 0x08048610 83e4f0 and esp, 0xfffffff0 | 0x08048613 b800000000 mov eax, 0 | 0x08048618 83c00f add eax, 0xf | 0x0804861b 83c00f add eax, 0xf | 0x0804861e c1e804 shr eax, 4 | 0x08048621 c1e004 shl eax, 4 | 0x08048624 29c4 sub esp, eax | 0x08048626 c70424638704. mov dword [esp], str.IOLI_Crackme_Level_0x06 ; [0x8048763:4]=0x494c4f49 ; "IOLI Crackme Level 0x06\n" | 0x0804862d e886fdffff call sym.imp.printf ; int printf(const char *format) | 0x08048632 c704247c8704. mov dword [esp], str.Password: ; [0x804877c:4]=0x73736150 ; "Password: " | 0x08048639 e87afdffff call sym.imp.printf ; int printf(const char *format) | 0x0804863e 8d4588 lea eax, [local_78h] | 0x08048641 89442404 mov dword [local_4h], eax | 0x08048645 c70424878704. mov dword [esp], 0x8048787 ; [0x8048787:4]=0x7325 | 0x0804864c e847fdffff call sym.imp.scanf ; int scanf(const char *format) | 0x08048651 8b4510 mov eax, dword [arg_10h] ; [0x10:4]=-1 ; 16 | 0x08048654 89442404 mov dword [local_4h], eax | 0x08048658 8d4588 lea eax, [local_78h] | 0x0804865b 890424 mov dword [esp], eax | 0x0804865e e825ffffff call sym.check | 0x08048663 b800000000 mov eax, 0 | 0x08048668 c9 leave \ 0x08048669 c3 ret :> ps @ 0x8048787 %s

local_4h还是scanf输入的用户密码, 但这里值得一提的是arg_10h这个地址(ebp+0x10),
我们知道main函数接受2个参数int main(int argc, char *argv[]), 其中argc对应ebp+8,
argv对于ebp+12, 而返回地址在ebp+4, 那么ebp+16又是啥? 第三个参数? 其实这是GCC编译器的一个
特性, 第三个参数envp也是一个字符串指针, 表示的是环境变量的值, 所以这里main函数相当于
int main(int argc, char *argv[], char *envp[]), 只不过前两个参数并未用到.

接下来分析check函数. 对于流程比较复杂的程序, 我们可以在视图模式中按p键切换到极简试图,
然后按TAB,Shift+TAB键切换不同的代码块(Basic Block), 如下所示:

check接受两个参数, 第一个为输入字符串, 第二个为字符串指针. 伪代码如下:

void check(char *input, char *envp[]) { int i; char local_dh[2]; int local_8h = 0; for(i = 0; i < strlen(input); i++) { local_dh[0] = input[i]; local_dh[1] = 0; sscanf(local_dh, "%d", local_4h); local_8h += local_4h; if (local_8h == 0x10) { parell(input, envp); } } printf("Password Incorrect!\n"); return; }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpxfdx.html