160个CrackMe之001
为了提高自己对反汇编的熟练程度,打算对这160个CrackMe的爆破点及注册算法都分析一下。
需要练手的朋友可以到这里下载,链接: http://pan.baidu.com/s/1c06fNOW 密码: ht4e
废话不多说,进入正题,第一个CrackMe:
运行程序,找到输入用户名和注册码的地方,输入假码,点击注册,弹窗提示错误。
使用OD载入程序,搜索字符串,很快可以找到关键点。
0042FAFE |. E8 F93EFDFF CALL Acid_bur.004039FC 0042FB03 |. 75 1A JNZ SHORT Acid_bur.0042FB1F ; //此处改nop即可爆破 0042FB05 |. 6A 00 PUSH 0 0042FB07 |. B9 CCFB4200 MOV ECX, Acid_bur.0042FBCC ; Congratz !! 0042FB0C |. BA D8FB4200 MOV EDX, Acid_bur.0042FBD8 ; Good job dude =) 0042FB11 |. A1 480A4300 MOV EAX, DWORD PTR DS:[430A48] 0042FB16 |. 8B00 MOV EAX, DWORD PTR DS:[EAX] 0042FB18 |. E8 53A6FFFF CALL Acid_bur.0042A170 0042FB1D |. EB 18 JMP SHORT Acid_bur.0042FB37
需要注意输入用户名的长度需要大于等于4,否则也是注册失败。
0042FA4D |. A1 6C174300 MOV EAX, DWORD PTR DS:[43176C] 0042FA52 |. E8 D96EFDFF CALL Acid_bur.00406930 0042FA57 |. 83F8 04 CMP EAX, 4 0042FA5A |. 7D 1D JGE SHORT Acid_bur.0042FA79 ; //用户名长度检查,此处也可该JMP,无视长度检查 0042FA5C |. 6A 00 PUSH 0 0042FA5E |. B9 74FB4200 MOV ECX, Acid_bur.0042FB74 ; Try Again! 0042FA63 |. BA 80FB4200 MOV EDX, Acid_bur.0042FB80 ; Sorry , The serial is incorect ! 0042FA68 |. A1 480A4300 MOV EAX, DWORD PTR DS:[430A48] 0042FA6D |. 8B00 MOV EAX, DWORD PTR DS:[EAX] 0042FA6F |. E8 FCA6FFFF CALL Acid_bur.0042A170 0042FA74 |. E9 BE000000 JMP Acid_bur.0042FB37 0042FA79 |> 8D55 F0 LEA EDX, DWORD PTR SS:[EBP-10]
下面看一下程序的注册算法,在断首下断点,重新运行,输入假码,点击注册,断了下来。
0042F99D 51 PUSH ECX 0042F99E 51 PUSH ECX 0042F99F 51 PUSH ECX 0042F9A0 51 PUSH ECX 0042F9A1 51 PUSH ECX 0042F9A2 51 PUSH ECX 0042F9A3 53 PUSH EBX 0042F9A4 56 PUSH ESI 0042F9A5 8BD8 MOV EBX,EAX 0042F9A7 33C0 XOR EAX,EAX 0042F9A9 55 PUSH EBP 0042F9AA 68 67FB4200 PUSH Acid_bur.0042FB67 0042F9AF 64:FF30 PUSH DWORD PTR FS:[EAX] 0042F9B2 64:8920 MOV DWORD PTR FS:[EAX],ESP 0042F9B5 C705 50174300 2>MOV DWORD PTR DS:[431750],29 ; //全局变量赋值 0042F9BF 8D55 F0 LEA EDX,DWORD PTR SS:[EBP-10] 0042F9C2 8B83 DC010000 MOV EAX,DWORD PTR DS:[EBX+1DC] 0042F9C8 E8 8BB0FEFF CALL Acid_bur.0041AA58 0042F9CD 8B45 F0 MOV EAX,DWORD PTR SS:[EBP-10] 0042F9D0 E8 DB40FDFF CALL Acid_bur.00403AB0 0042F9D5 A3 6C174300 MOV DWORD PTR DS:[43176C],EAX ; //用户名存放到全局变量中 0042F9DA 8D55 F0 LEA EDX,DWORD PTR SS:[EBP-10] 0042F9DD 8B83 DC010000 MOV EAX,DWORD PTR DS:[EBX+1DC] 0042F9E3 E8 70B0FEFF CALL Acid_bur.0041AA58 0042F9E8 8B45 F0 MOV EAX,DWORD PTR SS:[EBP-10] 0042F9EB 0FB600 MOVZX EAX,BYTE PTR DS:[EAX] ; //取用户名第1位无符号扩展给eax 0042F9EE 8BF0 MOV ESI,EAX 0042F9F0 C1E6 03 SHL ESI,3 ; //左移3位 0042F9F3 2BF0 SUB ESI,EAX ; //减去原先未移位的值 0042F9F5 8D55 EC LEA EDX,DWORD PTR SS:[EBP-14] 0042F9F8 8B83 DC010000 MOV EAX,DWORD PTR DS:[EBX+1DC] 0042F9FE E8 55B0FEFF CALL Acid_bur.0041AA58 0042FA03 8B45 EC MOV EAX,DWORD PTR SS:[EBP-14] 0042FA06 0FB640 01 MOVZX EAX,BYTE PTR DS:[EAX+1] ; //取用户名第2位无符号扩展给eax 0042FA0A C1E0 04 SHL EAX,4 ; //左移4位 0042FA0D 03F0 ADD ESI,EAX ; //加上第一位运算后的结果 0042FA0F 8935 54174300 MOV DWORD PTR DS:[431754],ESI ; //结果保存到全局变量中 0042FA15 8D55 F0 LEA EDX,DWORD PTR SS:[EBP-10] 0042FA18 8B83 DC010000 MOV EAX,DWORD PTR DS:[EBX+1DC] 0042FA1E E8 35B0FEFF CALL Acid_bur.0041AA58 0042FA23 8B45 F0 MOV EAX,DWORD PTR SS:[EBP-10] 0042FA26 0FB640 03 MOVZX EAX,BYTE PTR DS:[EAX+3] ; //取用户名第4位无符号扩展给eax 0042FA2A 6BF0 0B IMUL ESI,EAX,0B ; //ESI = EAX * 0x0B 0042FA2D 8D55 EC LEA EDX,DWORD PTR SS:[EBP-14] 0042FA30 8B83 DC010000 MOV EAX,DWORD PTR DS:[EBX+1DC] 0042FA36 E8 1DB0FEFF CALL Acid_bur.0041AA58 0042FA3B 8B45 EC MOV EAX,DWORD PTR SS:[EBP-14] 0042FA3E 0FB640 02 MOVZX EAX,BYTE PTR DS:[EAX+2] ; //取用户名第三位无符号扩展给eax 0042FA42 6BC0 0E IMUL EAX,EAX,0E ; //EAX = EAX * 0x0E 0042FA45 03F0 ADD ESI,EAX ; //第四位运算后的结果加上第三位运算后的结果 0042FA47 8935 58174300 MOV DWORD PTR DS:[431758],ESI ; //结果保存到全局变量中 0042FA4D A1 6C174300 MOV EAX,DWORD PTR DS:[43176C] 0042FA52 E8 D96EFDFF CALL Acid_bur.00406930 0042FA57 83F8 04 CMP EAX,4 ; //用户名长度与4做比较 0042FA5A 7D 1D JGE SHORT Acid_bur.0042FA79 ; //大于等于则跳走 0042FA5C 6A 00 PUSH 0 0042FA5E B9 74FB4200 MOV ECX,Acid_bur.0042FB74 ; ASCII 54,"ry Again!" 0042FA63 BA 80FB4200 MOV EDX,Acid_bur.0042FB80 ; ASCII 53,"orry , The serial is incorect !" 0042FA68 A1 480A4300 MOV EAX,DWORD PTR DS:[430A48] 0042FA6D 8B00 MOV EAX,DWORD PTR DS:[EAX] 0042FA6F E8 FCA6FFFF CALL <Acid_bur.MessageBox> 0042FA74 E9 BE000000 JMP Acid_bur.0042FB37 0042FA79 8D55 F0 LEA EDX,DWORD PTR SS:[EBP-10] 0042FA7C 8B83 DC010000 MOV EAX,DWORD PTR DS:[EBX+1DC] 0042FA82 E8 D1AFFEFF CALL Acid_bur.0041AA58 0042FA87 8B45 F0 MOV EAX,DWORD PTR SS:[EBP-10] 0042FA8A 0FB600 MOVZX EAX,BYTE PTR DS:[EAX] ; //取用户名第1位无符号扩展给eax 0042FA8D F72D 50174300 IMUL DWORD PTR DS:[431750] ; //EAX = EAX * 0x29 0042FA93 A3 50174300 MOV DWORD PTR DS:[431750],EAX ; //结果保存到全局变量中 0042FA98 A1 50174300 MOV EAX,DWORD PTR DS:[431750] 0042FA9D 0105 50174300 ADD DWORD PTR DS:[431750],EAX ; //[431750] = EAX + EAX 0042FAA3 8D45 FC LEA EAX,DWORD PTR SS:[EBP-4] 0042FAA6 BA ACFB4200 MOV EDX,Acid_bur.0042FBAC 0042FAAB E8 583CFDFF CALL Acid_bur.00403708 0042FAB0 8D45 F8 LEA EAX,DWORD PTR SS:[EBP-8] 0042FAB3 BA B8FB4200 MOV EDX,Acid_bur.0042FBB8 0042FAB8 E8 4B3CFDFF CALL Acid_bur.00403708 0042FABD FF75 FC PUSH DWORD PTR SS:[EBP-4] ; //CW 0042FAC0 68 C8FB4200 PUSH Acid_bur.0042FBC8 ; UNICODE "-" 0042FAC5 8D55 E8 LEA EDX,DWORD PTR SS:[EBP-18] 0042FAC8 A1 50174300 MOV EAX,DWORD PTR DS:[431750] 0042FACD E8 466CFDFF CALL Acid_bur.00406718 ; //将[431750]的内容转成10进制 0042FAD2 FF75 E8 PUSH DWORD PTR SS:[EBP-18] ; //转好10进制的内容入栈 0042FAD5 68 C8FB4200 PUSH Acid_bur.0042FBC8 ; UNICODE "-" 0042FADA FF75 F8 PUSH DWORD PTR SS:[EBP-8] ; //CRACKED 0042FADD 8D45 F4 LEA EAX,DWORD PTR SS:[EBP-C] 0042FAE0 BA 05000000 MOV EDX,5 0042FAE5 E8 C23EFDFF CALL Acid_bur.004039AC ; //拼接CW-转好的10进制-CRACKED 0042FAEA 8D55 F0 LEA EDX,DWORD PTR SS:[EBP-10] 0042FAED 8B83 E0010000 MOV EAX,DWORD PTR DS:[EBX+1E0] 0042FAF3 E8 60AFFEFF CALL Acid_bur.0041AA58 0042FAF8 8B55 F0 MOV EDX,DWORD PTR SS:[EBP-10] ; //假码 0042FAFB 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C] ; //真码 0042FAFE E8 F93EFDFF CALL Acid_bur.004039FC ; //比较call 0042FB03 75 1A JNZ SHORT Acid_bur.0042FB1F ; //关键跳 0042FB05 6A 00 PUSH 0 0042FB07 B9 CCFB4200 MOV ECX,Acid_bur.0042FBCC 0042FB0C BA D8FB4200 MOV EDX,Acid_bur.0042FBD8 0042FB11 A1 480A4300 MOV EAX,DWORD PTR DS:[430A48] 0042FB16 8B00 MOV EAX,DWORD PTR DS:[EAX] 0042FB18 E8 53A6FFFF CALL <Acid_bur.MessageBox> 0042FB1D EB 18 JMP SHORT Acid_bur.0042FB37 0042FB1F 6A 00 PUSH 0 0042FB21 B9 74FB4200 MOV ECX,Acid_bur.0042FB74 ; ASCII 54,"ry Again!" 0042FB26 BA 80FB4200 MOV EDX,Acid_bur.0042FB80 ; ASCII 53,"orry , The serial is incorect !" 0042FB2B A1 480A4300 MOV EAX,DWORD PTR DS:[430A48] 0042FB30 8B00 MOV EAX,DWORD PTR DS:[EAX] 0042FB32 E8 39A6FFFF CALL <Acid_bur.MessageBox>
可以看到,该程序的算法很简单,前面的运算结果并没有用到,只取了用户名的第一位无符号扩展后与0x29相乘,然后自身 + 自身 = 自身 * 2,然后将结果转成10进制,最后拼接CW-结果-CRACKED的形式。
知道了算法,下面可以来写注册机了:
#include <stdio.h> #include <string.h> #include <stdlib.h> int main(int argc, char* argv[]) { char szBuff[32] = {0}; unsigned int nKey = 0; while (1) { printf("请输入用户名: "); scanf("%31s", szBuff); if (strlen(szBuff) < 4) { puts("用户名长度必须大于等于4,请重新输入!");
continue; } nKey = szBuff[0]; nKey *= 0x29; nKey <<= 1; break; } printf("注册码: CW-%d-CRACKED\r\n", nKey); system("pause"); return 0; }