分析cbex crackme#1
crackme就是“破解我”的意思,它们都是一些公开用作破解练习的小程序
下载地址:https://github.com/idea-oss/example-/tree/main/01/06/bin
-
运行程序
点击确定后,然后几出错了
-
用od打开调试
用之前的方法找到入口函数
-
代码分析
#这里是给messagebox()函数传参,并调用
PUSH 0 ; /Style = MB_OK|MB_APPLMODAL
PUSH abexcm1-.00402000 ; |Title = "abex' 1st crackme"
PUSH abexcm1-.00402012 ; |Text = "Make me think your HD is a CD-Rom."
PUSH 0 ; |hOwner = NULL
CALL <JMP.&USER32.MessageBoxA> ; \MessageBoxA
#给getdrivetype()函数传参并调用,getdrivetype() api,获取c驱动的类型(大部分返回的是HDD类型)
PUSH abexcm1-.00402094 ; /RootPathName = "c:\"
CALL <JMP.&KERNEL32.GetDriveTypeA> ; \GetDriveTypeA 返回值(eax)是三(drive_fixed)
INC ESI ;inc esi为自加一操作,esi的值为0
DEC EAX ;dec为自减一操作,所以eax变成了2
JMP SHORT abexcm1-.00401021 ;无用操作,就是跳到下一行代码处
INC ESI
INC ESI
DEC EAX
CMP EAX,ESI ;比较eax,esi
JE SHORT abexcm1-.0040103D ;若上面比较的值相等就跳转40103D,否则就向下执行命令
PUSH 0 ; /Style = MB_OK|MB_APPLMODAL
PUSH abexcm1-.00402035 ; |Title = "Error"
PUSH abexcm1-.0040203B ; |Text = "Nah... This is not a CD-ROM Drive!"
PUSH 0 ; |hOwner = NULL
CALL <JMP.&USER32.MessageBoxA> ; \MessageBoxA
JMP SHORT abexcm1-.00401050
PUSH 0 ; |/Style = MB_OK|MB_APPLMODAL
PUSH abexcm1-.0040205E ; ||Title = "YEAH!"
PUSH abexcm1-.00402064 ; ||Text = "Ok, I really think that your HD is a CD-ROM! :p"
PUSH 0 ; ||hOwner = NULL
CALL <JMP.&USER32.MessageBoxA> ; |\MessageBoxA
CALL <JMP.&KERNEL32.ExitProcess> ; \ExitProcess
指令 | 说明 |
---|---|
push | 入栈操作 |
call | 调用指定位置的函数 |
inc | 值加1 |
dec | 值减1 |
jmp | 跳转到指定地址 |
cmp | 比较给定的两个操作数与sub命令类似,但是操作数的值不会改变,仅改变eflags寄存器(若两个操作数的值一致,sub结果为0,zf被置为1) |
je | 条件跳转指令(jump if equal) 若zf为1,则跳转 |
- 破解
在如下位置,按空格
将JE条件跳转指令改成JMP无条件跳转即可
copy to executable
然后运行修改后的程序
破解成功
栈帧
栈帧在程序中用于声明局部变量、调用函数。栈帧就是利用EBP(栈帧指针,请注意不是ESP)寄存器访问栈内部局部变量、参数函数返回地址等手段ESP承担着栈顶指针的作用,而EBP寄存器则负责行使栈帧指针的职能。程序运行中,ESP寄存器的值随时变化,访问栈中函数的局部变量、参数时,若以ESP值为基准编写程序会十分困难,并且也很难使CPU引用到准确的地址。所以,调用某函数时,先要把用作基准点(函数起始地址)的ESP值保存到EBP并维持在函数内部。这样,无论ESP的值如何变化,以EBP的值为基准能够安全访问到相关函数的局部变量、参数、返回地址,这就是EBP寄存器作为栈帧指针的作用
栈帧对应的汇编代码
push ebp ;函数开始,使用ebp前先把已有的值保存到栈中
mov ebp,esp ;保存当前esp到ebp中
......
mov esp,ebp ;将函数的起始地址返回到esp中
pop ebp ;函数返回前弹出保存在栈中的ebp值
retn ;函数终止