新CrackMe160之041 - crackme.2
与旧版032相同
- 运行程序有个提示界面阻挡了去路, 看来是要先把这个界面干掉, 提示信息说是需要reg.dat那我们就创建一个, 果然不再提示了直接进入到主界面了
既然是去NAG, 那我们直接跳过这个文件验证, 004383EC处改为 jmp 00438428, 搞定~
主界面什么作用都没有, 我们也把它当作NAG干掉吧, 因为程序是delphi写的, 我们这里需要了解delphi窗体的加载原理, 在delphi中, 第一个创建的窗体就是第一个加载的, 所以我们找到窗体的创建在哪里, OD中, 00438447, 00438459, 00438471, 三处即为三个窗体创建, 用IDR来分析更容易看出来
EntryPoint
004383DC push ebp
004383DD mov ebp,esp
004383DF add esp,0FFFFFFF4
004383E2 mov eax,4382E4
004383E7 call @InitExe
>004383EC jmp 00438428
004383EE nop
004383EF nop
004383F0 nop
004383F1 mov eax,43A760; gvar_0043A760:TFileRec
004383F6 call @Assign
004383FB mov edx,80
00438400 mov eax,43A760; gvar_0043A760:TFileRec
00438405 call @ResetFile
0043840A call IOResult
0043840F test eax,eax
>00438411 je 00438428
00438413 push 0
00438415 push 4384A0; 'Missing!'
0043841A push 4384AC; 'Hey, where is my little Reg.dat\rI love it so much that I can't\rlive without it. Return it back! Arrgh!'
0043841F push 0
00438421 call user32.MessageBoxA
>00438426 jmp 00438488
00438428 mov eax,[00439A90]; ^Application:TApplication
0043842D mov eax,dword ptr [eax]
0043842F call TApplication.Initialize
00438434 mov ecx,dword ptr ds:[439B0C]; ^gvar_0043A758:TForm1
0043843A mov eax,[00439A90]; ^Application:TApplication
0043843F mov eax,dword ptr [eax]
00438441 mov edx,dword ptr ds:[4380C8]; TForm1
00438447 call TApplication.CreateForm
0043844C mov ecx,dword ptr ds:[439B20]; ^gvar_0043A728:TForm2
00438452 mov eax,[00439A90]; ^Application:TApplication
00438457 mov eax,dword ptr [eax]
00438459 mov edx,dword ptr ds:[4379C0]; TForm2
0043845F call TApplication.CreateForm
00438464 mov ecx,dword ptr ds:[439A6C]; ^gvar_0043A750:TForm3
0043846A mov eax,[00439A90]; ^Application:TApplication
0043846F mov eax,dword ptr [eax]
00438471 mov edx,dword ptr ds:[437F38]; TForm3
00438477 call TApplication.CreateForm
0043847C mov eax,[00439A90]; ^Application:TApplication
00438481 mov eax,dword ptr [eax]
00438483 call TApplication.Run
00438488 call @Halt0
那我们就把TForm1 和 TForm2的地址互换一下, 即让程序先创建TForm2, 在OD中我们找到下面这四行,
00438434 mov ecx,dword ptr ds:[439B0C]; ^gvar_0043A758:TForm1
00438441 mov edx,dword ptr ds:[4380C8]; TForm1
0043844C mov ecx,dword ptr ds:[439B20]; ^gvar_0043A728:TForm2
00438459 mov edx,dword ptr ds:[4379C0]; TForm2
将它们改为
00438434 mov ecx,dword ptr ds:[439B20]; ^gvar_0043A758:TForm2
00438441 mov edx,dword ptr ds:[4379C0]; TForm2
0043844C mov ecx,dword ptr ds:[439B0C]; ^gvar_0043A728:TForm1
00438459 mov edx,dword ptr ds:[4380C8]; TForm1
保存, 第二个NAG也去掉了
-
暴力破解, 4个选择框的change事件都到00437BD8这个方法来验证数据, 我们就下断点跟踪, 首先, 判断name长度有没有5位, 记录这边关键跳位置004383EC, 然后一路向下我们看到了算法, 看到了很多对比, 我们都先不管, 一直执行到最后的关键跳00437CC9, 这时我们4位数是乱选的, 到这边就跳过了, , 本次调试就结束了, 说明, 不跳过就是成功分支, 所以我们让第一次判断直接跳入成功分支, 将004383EC改为jmp 00437CCB, 保存测试~ 随便选择一个数ok亮起, 暴破完成~
-
正常破解, 由上一步, 我们进入00437BD8这个方法详细分析, 用户名输入abcde, 太长也没用, 程序只取了0234这4位来验证的, 验证码第一位选1, 即当前为1, 0, 0, 0, 单步跟踪, 到00437C16处, 取用户名第一位a=97, 除于10 = 9, 同理得到其它3位为c/10=9, d/10=10, e/10=10, 4位取值计算完成, 进入校验环节, 分别判断计算结算有没有大于10的, 有的话继续除于10, 接着与输入的4位验证码进行对比, 由此, 算法就已经清晰了, 做了正反向计算, c代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "string.h"
int main(){
while(1==1){
char rlt[5] = {0};
char user[20] = {0};
printf("请选择 1.用户名(5~20位) 2.系列号(4位数字): ");
int inp;
scanf("%d",&inp);
if(inp == 2){
printf("请输入系列号(4位): ");
scanf("%s", rlt);
int len = strlen(rlt);
if(len != 4){
printf("系列号必须为4位");
continue;
}
int a,i,j;
srand((unsigned int)time(0));
for(i=0,j=0; i<4; i++,j++){
a = rlt[i] - 0x30; //字符数字转整形数字
if(a == 1) { a = 10; }
if(a == 0) { a = 1; } else //不可见符号
if(a == 2) { a = 21; } else //不可见符号
if(a == 3) { a = 30 + rand() % 8 + 2; } else //0~7 +2 = 2~9
if(a >= 4 && a <= 10) { //40~109 可见符号
a *= 10;
a += rand() % 10; //0~9
}
user[j] = a;
if(i == 0){ j++; }
}
user[1]='?'; //第二位任意
printf("用户名为: %d,%d,%d,%d=%s\n", user[0],user[2],user[3],user[4],user);
} else {
printf("请输入用户名(5~20位): ");
scanf("%s", user);
int len = strlen(user);
if(len < 5){
printf("用户名长度小于5位");
continue;
}
int i, j, a = 0;
for(i=0,j=0; i<5; i++,j++){
a = user[i] / 10;
while(a >= 10){ a = a / 10; }
rlt[j] = a+0x30; //整形数字转字符数字
if(i == 0) i++;
}
printf("系列号为: %s\n", rlt);
}
}
return 0;
}
运行示例:
请输入用户名(5~20位): abcde
系列号为: 9911
注意: 用户名输入完后就算当前系列号是对的, 也需要改变一下再改回来OK按钮才会亮起
使用的工具连接(工具有点多有点大,可以先下OD,其它的后面慢慢下) 点击前往下载
下面是我的OD的界面布局,我觉得这4个是最常用的界面,其它的我基本上没用到~