破文一篇
作者:凭凡 (嘿嘿,我更喜欢凭凡这个网名,不过它是今天才注册的,暂时还不能发贴)
时间:2011/7/17
软件:idcrackme2.exe
下载地址:dc4K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6i4N6G2L8$3c8E0j5h3&6F1i4K6u0W2j5$3!0E0i4K6u0r3d9f1c8m8M7X3y4Z5K9i4k6W2i4K6u0r3d9f1c8Q4x3X3c8d9d9g2m8Q4x3V1k6V1j5i4c8S2j5X3q4K6k6g2)9J5c8X3W2V1j5%4u0S2j5$3E0E0k6e0u0Q4x3X3g2*7K9i4l9`.
声明:1.写篇破文很费时的,希望版主给个邀请码~ 如果版主要给的话,请发给我的另一个马甲:凭凡
2.以后尽量不爆破了,分析算法才能真正掌握逆向分析与调试技术。
3.这个CrackMe很简单,没什么技术含量,高手飘过~
od载入,F9运行,发现程序能正常运行,看来这个CrackMe没有AntiDebug。
回到OD,bp GetDlgItemTextA,返回程序输入注册信息:
name:Bermuda
group:WORKGROUP
code:passcode
停在这:
004013E0 /$ 53 push ebx
004013E1 |. 33C0 xor eax, eax
004013E3 |. 56 push esi
004013E4 |. A3 70974000 mov dword ptr [409770], eax
004013E9 |. 57 push edi
004013EA |. BE 01000000 mov esi, 1
004013EF |. 8B4C24 10 mov ecx, dword ptr [esp+10]
004013F3 |. 6A 1E push 1E ; /Count = 1E (30.)
004013F5 |. 68 F8974000 push 004097F8 ; |Buffer = idcrkme2.004097F8
004013FA |. 8935 F0974000 mov dword ptr [4097F0], esi ; |
00401400 |. 68 E8030000 push 3E8 ; |ControlID = 3E8 (1000.)
00401405 |. A3 74974000 mov dword ptr [409774], eax ; |
0040140A |. 51 push ecx ; |hWnd
0040140B |. FF15 58B24000 call dword ptr [<&USER32.GetDlgItemTe>; \GetDlgItemTextA
00401411 |. A3 E8974000 mov dword ptr [4097E8], eax
00401416 |. E8 85FFFFFF call 004013A0 ; strlen(name)<=1E
0040141B |. 8B0D E8974000 mov ecx, dword ptr [4097E8]
00401421 |. 8935 EC974000 mov dword ptr [4097EC], esi
00401427 |. 3BCE cmp ecx, esi
00401429 |. 76 4A jbe short 00401475 ; strlen(name)>1
0040142B |. 8B15 F0974000 mov edx, dword ptr [4097F0]
00401431 |. 8B1D 70974000 mov ebx, dword ptr [409770]
00401437 |> 0FBEBA F79740>/movsx edi, byte ptr [edx+4097F7]
0040143E |. 0FBE82 577040>|movsx eax, byte ptr [edx+407057] ; d 407057 ,在数据窗口可以看见一堆字符,应该是运算表
00401445 |. 0FAFF8 |imul edi, eax
00401448 |. 0FBE86 1F7040>|movsx eax, byte ptr [esi+40701F]
0040144F |. 0FAFF8 |imul edi, eax
00401452 |. 0FAFFA |imul edi, edx
00401455 |. 42 |inc edx
00401456 |. 03DF |add ebx, edi
00401458 |. 46 |inc esi
00401459 |. 893D 74974000 |mov dword ptr [409774], edi
0040145F |. 8915 F0974000 |mov dword ptr [4097F0], edx
00401465 |. 891D 70974000 |mov dword ptr [409770], ebx ; [409770] 存着运算结果
0040146B |. 8935 EC974000 |mov dword ptr [4097EC], esi
00401471 |. 3BF1 |cmp esi, ecx ;ecx=strlen(name)
00401473 |.^ 72 C2 \jb short 00401437
00401475 |> 5F pop edi
00401476 |. 5E pop esi
00401477 |. 5B pop ebx
00401478 \. C3 retn ;返回到4019f8
这段的主要作用就是取名字,然后根据名字和两张运算表进行运算,结果保存在[409770]中。
004019F2 . 56 push esi
004019F3 . E8 E8F9FFFF call 004013E0 ;
004019F8 . 83C4 04 add esp, 4 ;返回到这里
004019FB . 56 push esi
004019FC . E8 7FFAFFFF call 00401480 ;F7跟进,GetGroup
00401A01 . 83C4 04 add esp, 4
00401A04 . A1 E8974000 mov eax, dword ptr [4097E8] ;[4097EB]==strlen(name)
00401A09 . 83F8 03 cmp eax, 3
00401A0C . 73 07 jnb short 00401A15 ; strlen(name) > 3 ,必须跳
00401A0E . 33C0 xor eax, eax
00401A10 . 5F pop edi
00401A11 . 5E pop esi
00401A12 . C2 1000 retn 10
004019FC . E8 7FFAFFFF call 00401480 这个GetGroup的作用也是获得Group并运算,关键是这几句:
004014C9 |> /0FBE9E AF9740>/movsx ebx, byte ptr [esi+4097AF]
004014D0 |. |0FBE86 577040>|movsx eax, byte ptr [esi+407057]
004014D7 |. |0FAFD8 |imul ebx, eax
004014DA |. |0FBE82 1F7040>|movsx eax, byte ptr [edx+40701F]
004014E1 |. |0FAFD8 |imul ebx, eax
004014E4 |. |0FAFDE |imul ebx, esi
004014E7 |. |46 |inc esi
004014E8 |. |03FB |add edi, ebx
004014EA |. |42 |inc edx
004014EB |. |891D 74974000 |mov dword ptr [409774], ebx ;[409774]保存着运算的结果
004014F1 |. |8935 F0974000 |mov dword ptr [4097F0], esi
004014F7 |. |8915 EC974000 |mov dword ptr [4097EC], edx
004014FD |. |3BD1 |cmp edx, ecx
004014FF |.^\72 C8 \jb short 004014C9
strlen(name)>3会跳到:00401A15
00401A15 > \0FAFC0 imul eax, eax
00401A18 . 6A 0A push 0A ; /Count = A (10.)
00401A1A . A3 74974000 mov dword ptr [409774], eax ; |
00401A1F . A1 AC974000 mov eax, dword ptr [4097AC] ; |
00401A24 . 68 90974000 push 00409790 ; |Buffer = idcrkme2.00409790
00401A29 . 0FAF05 749740>imul eax, dword ptr [409774] ; |
00401A30 . 68 EA030000 push 3EA ; |ControlID = 3EA (1002.)
00401A35 . A3 7C974000 mov dword ptr [40977C], eax ; |
00401A3A . 56 push esi ; |hWnd
00401A3B . FF15 58B24000 call dword ptr [<&USER32.GetDlgItemTe>; \GetDlgItemTextA
00401A41 . 68 90974000 push 00409790 ;这个是注册码的保存地址
00401A46 . E8 250F0000 call 00402970 ;_atol,把注册码转为数值~汗,居然这样草草了事~
00401A4B . 83C4 04 add esp, 4
00401A4E . 8B0D A8974000 mov ecx, dword ptr [4097A8] ; idcrkme2.00400000
00401A54 . A3 88974000 mov dword ptr [409788], eax
00401A59 . 51 push ecx ;现在开始应该是真正判断~
00401A5A . 56 push esi
00401A5B . E8 30F8FFFF call 00401290 ;F7跟进
00401A60 . 83C4 08 add esp, 8
00401A63 . 68 B0974000 push 004097B0 ; ASCII "Bosch"
00401A68 . 68 F8974000 push 004097F8 ; ASCII "Bermuda"
00401A6D . E8 5EF8FFFF call 004012D0
00401A72 . 83C4 08 add esp, 8
00401290 /$ A1 9C974000 mov eax, dword ptr [40979C] ;一堆运算,没有实质性突破,直接F4运行到最后那句CALL 00401520里
00401295 |. 8B0D E8974000 mov ecx, dword ptr [4097E8]
0040129B |. 8B5424 08 mov edx, dword ptr [esp+8]
0040129F |. A3 74974000 mov dword ptr [409774], eax
004012A4 |. 8B4424 04 mov eax, dword ptr [esp+4]
004012A8 |. 52 push edx
004012A9 |. 50 push eax
004012AA |. 890D 7C974000 mov dword ptr [40977C], ecx
004012B0 |. C705 A4974000>mov dword ptr [4097A4], 0
004012BA |. E8 61020000 call 00401520 ;F4到这里。F7跟进
00401520 /$ 83EC 10 sub esp, 10
00401523 |. 8B0D 70974000 mov ecx, dword ptr [409770]
00401529 |. 030D AC974000 add ecx, dword ptr [4097AC]
0040152F |. 53 push ebx
00401530 |. 56 push esi
00401531 |. 81F9 FFFFFF7F cmp ecx, 7FFFFFFF
00401537 |. 57 push edi
00401538 |. 76 06 jbe short 00401540
0040153A |. 81E9 FFFFFF7F sub ecx, 7FFFFFFF
00401540 |> 890D 70974000 mov dword ptr [409770], ecx
00401546 |. 390D 88974000 cmp dword ptr [409788], ecx
0040154C 75 63 jnz short 004015B1 ;关键跳,也是爆破点。
0040154E |. 8D4424 0C lea eax, dword ptr [esp+C]
00401552 |. 68 6C844000 push 0040846C ; /Format = "REGISTERED!"
00401557 |. 50 push eax ; |s
00401558 |. FF15 60B24000 call dword ptr [<&USER32.wsprintfA>] ; \wsprintfA
0040155E |. 8D4C24 14 lea ecx, dword ptr [esp+14]
00401562 |. 8B7C24 28 mov edi, dword ptr [esp+28]
00401566 |. 83C4 08 add esp, 8
00401569 |. 51 push ecx ; /Text
0040156A |. 68 EE030000 push 3EE ; |ControlID = 3EE (1006.)
0040156F |. 57 push edi ; |hWnd
00401570 |. FF15 68B24000 call dword ptr [<&USER32.SetDlgItemTe>; \SetDlgItemTextA
00401576 |. 6A 01 push 1 ; /Enable = TRUE
00401578 |. 8B1D 64B24000 mov ebx, dword ptr [<&USER32.GetDlgI>; |USER32.GetDlgItem
0040157E |. 68 EC030000 push 3EC ; |/ControlID = 3EC (1004.)
00401583 |. 57 push edi ; ||hWnd
00401584 |. FFD3 call ebx ; |\GetDlgItem
00401586 |. 50 push eax ; |hWnd
00401587 |. 8B35 54B24000 mov esi, dword ptr [<&USER32.EnableW>; |USER32.EnableWindow
0040158D |. FFD6 call esi ; \EnableWindow
0040158F |. 8B4424 24 mov eax, dword ptr [esp+24]
00401593 |. 6A 00 push 0 ; /lParam = NULL
00401595 |. 68 001B4000 push 00401B00 ; |DlgProc = idcrkme2.00401B00
0040159A |. 57 push edi ; |hOwner
0040159B |. 6A 68 push 68 ; |pTemplate = 68
0040159D |. 50 push eax ; |hInst
0040159E |. FF15 5CB24000 call dword ptr [<&USER32.DialogBoxPar>; \DialogBoxParamA
keygen很简单:(汗~)
#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#include <windows.h>
int main(int argc, char* argv[])
{
//初始化程序
char tmpName[50],realName[51],tmpGroup[50],realGroup[51];
memset(realName,0,sizeof(realName));
memset(realGroup,0,sizeof(realGroup));
printf("\t\t\t\t\tKeyGen\n\t\t\t\t\t\tCracked by 凭凡\n");
printf("Please input your name:\n");
scanf("%s",tmpName);
int namelen=strlen(tmpName);
strcpy(&realName[1],tmpName);
printf("Please input your group:\n");
scanf("%s",tmpGroup);
int grouplen=strlen(tmpGroup);
strcpy(&realGroup[1],tmpGroup);
char name_table2[]="AfQObVwNOankJ5skqJvae3Ae5jdoETu5n02J6Ez85430PNSDAPjDrYgFaze9VDRjq";
char name_table3[]="AEtn5Pnc5AXi1DFlkYqnujsXNmvHdbcrqOoT8aaV5DkaymMRkPkoQ";
DWORD name_result(0),sum(0),i(1),var(0);
for (;i<namelen;i++)
{
var=realName[i]*name_table2[i]*name_table3[i]*i;
sum+=var;
}
name_result=sum;
sum=0;
for (i=1;i<grouplen;i++)
{
var=realGroup[i]*name_table3[i]*name_table2[i]*i;
sum+=var;
}
name_result+=sum;
var=name_result+0x1252;
if(var > 0x7FFFFFFF) var=var-0x7FFFFFFF;
printf("The serial code is :\n%d\n",var);
return 0;
}
生成一下:
Please input your name:
Bermuda
Please input your group:
WORKGROUP
The serial code is :
41275474
验证一下,成功:

总结一下,汗~这个CrackMe算法很简单。它属于那种f(x)==g(y)类型的,按理应该不容易分析算法,它的f(x)比g(x)复习,但是
g(x)由于太过于简单,导致它的算法可能被很轻松地分析出来。我没做太多分析,它的难点就在于识别那些适合给新手练习。
以前搞CrackMe基本都是爆破,懒得分析算法写注册机,直到现在才发现这样做没什么意义。终于下定
决心搞一篇破文,分析算法,写keygen。
[培训]科锐逆向工程师培训第53期2025年7月8日开班!