前几天写了使用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;
}