Win10+OD+PEID
我们开始第一个,先随意输入一个用户名密码:
Name:15pb
Password:123456
点击Check It Baby! 会弹出一个对话框提示信息: Sorry, The Serial is incorrect !
这说明作者检测我们输入错误会弹出提示信息,我们只需要定位到弹出对话框或者字符串位置,往上找到判断代码Nop掉就爆破成功
F9
继续运行F12
暂停,打开调用堆栈我猜测流程可能是这样的,对不对?需要验证一下:
想写注册机的话我们还是要详细分析一下,重新运行程序
程序断下来后,我们先观察参数(Delphi是寄存器传参)
F8
走一遍:0042FA79 |> \8D55 F0 LEA EDX,[LOCAL.4] ; |跳转位置,EDX=username
0042FA7C |. 8B83 DC010000 MOV EAX,DWORD PTR DS:[EBX+0x1DC] ; |
0042FA82 |. E8 D1AFFEFF CALL ; \用户名长度
0042FA87 |. 8B45 F0 MOV EAX,[LOCAL.4] ; eax=name
0042FA8A |. 0FB600 MOVZX EAX,BYTE PTR DS:[EAX] ; AL=name[0]
0042FA8D |. F72D 50174300 IMUL DWORD PTR DS:[0x431750] ; eax=name[0]*0x29
0042FA93 |. A3 50174300 MOV DWORD PTR DS:[0x431750],EAX ; temp=name[0]*0x29
0042FA98 |. A1 50174300 MOV EAX,DWORD PTR DS:[0x431750]
0042FA9D |. 0105 50174300 ADD DWORD PTR DS:[0x431750],EAX ; temp=(name[0]*0x29)*2
0042FAA3 |. 8D45 FC LEA EAX,[LOCAL.1]
0042FAA6 |. BA ACFB4200 MOV EDX,Acid_bur.0042FBAC ; edx=CW
0042FAAB |. E8 583CFDFF CALL Acid_bur.00403708 ; local1=CW
0042FAB0 |. 8D45 F8 LEA EAX,[LOCAL.2]
0042FAB3 |. BA B8FB4200 MOV EDX,Acid_bur.0042FBB8 ; edx=CRACKED
0042FAB8 |. E8 4B3CFDFF CALL Acid_bur.00403708 ; local2=CRACKED
0042FABD |. FF75 FC PUSH [LOCAL.1] ; CW
0042FAC0 |. 68 C8FB4200 PUSH Acid_bur.0042FBC8 ; 看了下可能是个字符串
0042FAC5 |. 8D55 E8 LEA EDX,[LOCAL.6] ; edx=local6=0
0042FAC8 |. A1 50174300 MOV EAX,DWORD PTR DS:[0x431750] ; 咦?这不是我们的首字母加密值吗?
0042FACD |. E8 466CFDFF CALL Acid_bur.00406718 ; Local6=4018
0042FAD2 |. FF75 E8 PUSH [LOCAL.6] ; 4018
0042FAD5 |. 68 C8FB4200 PUSH Acid_bur.0042FBC8 ; 算法相关字符串
0042FADA |. FF75 F8 PUSH [LOCAL.2] ; local2=CRACKED
0042FADD |. 8D45 F4 LEA EAX,[LOCAL.3] ; local3=0 是不是该注意了
0042FAE0 |. BA 05000000 MOV EDX,0x5 ; ??? 没看懂继续走
0042FAE5 |. E8 C23EFDFF CALL Acid_bur.004039AC ; local3=CW-4018-CRACKED 密码出现了
0042FAEA |. 8D55 F0 LEA EDX,[LOCAL.4] ; |
0042FAED |. 8B83 E0010000 MOV EAX,DWORD PTR DS:[EBX+0x1E0] ; |
0042FAF3 |. E8 60AFFEFF CALL ; \strlen
0042FAF8 |. 8B55 F0 MOV EDX,[LOCAL.4] ; EDX=密码
0042FAFB |. 8B45 F4 MOV EAX,[LOCAL.3] ; CW-4018-CRACKED
0042FAFE |. E8 F93EFDFF CALL Acid_bur.004039FC ; 比较密码和计算出来的值
0042FB03 |. 75 1A JNZ SHORT Acid_bur.0042FB1F
可以发现从用户名到密码出现中间有很多CALL,能F8
坚决不F7
,不可能每个CALL都进去看的,如果你见CALL就进,大概率分析一会你都不知道你在哪了,想一想是不是呢?
分析方法总结:
多走几次就会发现,CW和CRACKED是固定不变的,我唯一变得就是中间的数字(如4018)关键函数很明显了对不对,搞明白它是怎么计算的就可以完美破解了
0042FABD |. FF75 FC PUSH [LOCAL.1] ; CW
0042FAC0 |. 68 C8FB4200 PUSH Acid_bur.0042FBC8 ; 看了下可能是个字符串
0042FAC5 |. 8D55 E8 LEA EDX,[LOCAL.6] ; edx=local6=0
0042FAC8 |. A1 50174300 MOV EAX,DWORD PTR DS:[0x431750] ; 咦?这不是我们的首字母加密值吗?
0042FACD |. E8 466CFDFF CALL Acid_bur.00406718 ; Local6=4018
仔细分析,首字母加密值0xFB2换为10进制就是4018,一开始犯错误见CALL就进,分析了老半天,搞了半天才发现其实这个CALL也不用分析的,我们一开始就算出来了
00406718 /$ 83C4 F8 ADD ESP,-0x8
0040671B |. 6A 00 PUSH 0x0
0040671D |. 894424 04 MOV DWORD PTR SS:[ESP+0x4],EAX ; 首字母加密值
00406721 |. C64424 08 00 MOV BYTE PTR SS:[ESP+0x8],0x0
00406726 |. 8D4C24 04 LEA ECX,DWORD PTR SS:[ESP+0x4] ; ecx=首字母加密值
0040672A |. 8BC2 MOV EAX,EDX ; local6=0
0040672C |. BA 44674000 MOV EDX,Acid_bur.00406744 ; %d
00406731 |. E8 8A080000 CALL Acid_bur.00406FC0 ;一开始我跟进去了,哈哈,不用进去
00406736 |. 59 POP ECX
00406737 |. 5A POP EDX
00406738 \. C3 RETN
总结:根据用户名首字母算出一个数,在获得两个固定字符串CW和CRACKED,拼接起来,密码格式:CW-用户名首字母加密值(十进制)-CRACKED
我们用C/C++代码还原一下
int mian()
{
printf("输入用户名(不能小于4位):\r\n");
// 取第一个字符值
int cName = getchar();
cName *= 0x29*2;
printf("密码: CW-%4d-CRACKED\r\n",cName);
system("pause");
return 0;
}
到此第一部分就算破解完成了。
我们开始第二个,先随意输入一个序列号:123456,弹出对话框:Try Again!!
老方法搜索字符串下断点,OD提示我们字符串在数据区,下内存访问断点,重新运行OD,停下后查看调用堆栈
看了下这里调用MessageBox弹出提示信息,说明已经判断完了,这应该不是我们要找的地方,在两个地方下断点后重新运行,继续看调用堆栈,找上一层
我们发现调用只有一处地方,应该就是我们要找的地方了,看一看
JNZ很关键,在它上面的CALL下断点(这个CALL应该就是验证函数)
参数很明显可以看到真正的序列号,试了试,确实是真的
往上翻了翻,F8走一遍,序列号是固定的就是:Hello Dude!