【文章标题】: 我的第一个keygen
【文章作者】: haithink
【作者邮箱】: haithink@163.com
【软件名称】: song's crackme
【下载地址】: 论坛下载
【加壳方式】: 无壳
【编写语言】: vc++6.0
【使用工具】: OD
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
来论坛很久了,一直没写破文。这几天专注于crackme,花了两天时间终于写出了keygen.
这个crackme比较特别,请往下看。
看图标,MFC,peid,vc++ 6.0,嗯,随便输入点东西,弹出个try again。
od载入吧
GetWindowTextA下断,来到此处,代码我已添加注释。
004016A9 . 50 push eax
004016AA . 68 E9030000 push 3E9 ; ID:1001
004016AF . E8 F38A0000 call 0040A1A7 ; 获取用户名
004016B4 . 8D4C24 04 lea ecx, dword ptr [esp+4]
004016B8 . 51 push ecx
004016B9 . 68 EA030000 push 3EA ; ID:1002
004016BE . 8BCE mov ecx, esi
004016C0 . E8 E28A0000 call 0040A1A7
004016C5 . 6A 00 push 0 ; 下句将ecx中放入指针
004016C7 . 8D4C24 0C lea ecx, dword ptr [esp+C] ; EAX->name,edx->SN
004016CB . E8 3BAB0000 call 0040C20B ; call 40c20b后可将eax->name,SN
004016D0 . 8A08 mov cl, byte ptr [eax]
004016D2 . 33F6 xor esi, esi ; 累加用户名到esi中
004016D4 . 84C9 test cl, cl
004016D6 . 74 0D je short 004016E5
004016D8 > 0FBED1 movsx edx, cl
004016DB . 8A48 01 mov cl, byte ptr [eax+1]
004016DE . 03F2 add esi, edx
004016E0 . 40 inc eax
004016E1 . 84C9 test cl, cl
004016E3 .^ 75 F3 jnz short 004016D8
004016E5 > 6A 00 push 0
004016E7 . 8D4C24 08 lea ecx, dword ptr [esp+8]
004016EB . E8 1BAB0000 call 0040C20B
004016F0 . 8A08 mov cl, byte ptr [eax] ; 累加SN到edx中
004016F2 . 33D2 xor edx, edx
004016F4 . 84C9 test cl, cl
004016F6 . 74 0D je short 00401705
004016F8 > 0FBEC9 movsx ecx, cl
004016FB . 03D1 add edx, ecx
004016FD . 8A48 01 mov cl, byte ptr [eax+1]
00401700 . 40 inc eax
00401701 . 84C9 test cl, cl
00401703 .^ 75 F3 jnz short 004016F8
00401705 > 52 push edx ; 累加的两个和
00401706 . 56 push esi
00401707 . E8 E4FBFFFF call 004012F0 ; 关键算法
这部分比较简单,是些熟悉的API和循环结构,无非是得到用户名,序列号,
算下他们的各自的ASCII值和接下来看关键算法
流程:他虽说搞了个跳转表,但真正做的事不多,先初始化一堆变量后,
就计算了两个约数和,再比较就没啥事了。不过里面还解密了一个字符串。
004012F0 $ 55 push ebp ; 关键算法
004012F1 . 8BEC mov ebp, esp
004012F3 . 83EC 60 sub esp, 60
004012F6 . 53 push ebx
004012F7 . 56 push esi
004012F8 . 57 push edi ; 初始化跳转表
004012F9 . 8D05 DF134000 lea eax, dword ptr [4013DF]
004012FF . 50 push eax
00401300 . 8F45 B0 pop dword ptr [ebp-50]
00401303 . 8D05 E4134000 lea eax, dword ptr [4013E4]
00401309 . 50 push eax
0040130A . 8F45 B4 pop dword ptr [ebp-4C]
0040130D . 8D05 FA134000 lea eax, dword ptr [4013FA]
00401313 . 50 push eax
00401314 . 8F45 B8 pop dword ptr [ebp-48]
00401317 . 8D05 14144000 lea eax, dword ptr [401414]
0040131D . 50 push eax
0040131E . 8F45 BC pop dword ptr [ebp-44]
00401321 . 8D05 1C144000 lea eax, dword ptr [40141C]
00401327 . 50 push eax
00401328 . 8F45 C0 pop dword ptr [ebp-40]
0040132B . 8D05 32144000 lea eax, dword ptr [401432]
00401331 . 50 push eax
00401332 . 8F45 C4 pop dword ptr [ebp-3C]
00401335 . 8D05 78144000 lea eax, dword ptr [401478]
0040133B . 50 push eax
0040133C . 8F45 C8 pop dword ptr [ebp-38]
0040133F . 8D05 DC144000 lea eax, dword ptr [4014DC]
00401345 . 50 push eax
00401346 . 8F45 CC pop dword ptr [ebp-34]
00401349 . 8D05 3E154000 lea eax, dword ptr [40153E]
0040134F . 50 push eax
00401350 . 8F45 D0 pop dword ptr [ebp-30]
00401353 . 8D05 ED144000 lea eax, dword ptr [4014ED]
00401359 . 50 push eax
0040135A . 8F45 D4 pop dword ptr [ebp-2C]
0040135D . 8D05 89144000 lea eax, dword ptr [401489]
00401363 . 50 push eax
00401364 . 8F45 D8 pop dword ptr [ebp-28]
00401367 . 8D05 67144000 lea eax, dword ptr [401467]
0040136D . 50 push eax
0040136E . 8F45 DC pop dword ptr [ebp-24]
00401371 . 8D05 58144000 lea eax, dword ptr [401458]
00401377 . 50 push eax
00401378 . 8F45 E0 pop dword ptr [ebp-20]
0040137B . 8D05 49144000 lea eax, dword ptr [401449]
00401381 . 50 push eax
00401382 . 8F45 E4 pop dword ptr [ebp-1C]
00401385 . 8D05 26144000 lea eax, dword ptr [401426]
0040138B . 50 push eax
0040138C . 8F45 E8 pop dword ptr [ebp-18]
0040138F . 8D05 3C164000 lea eax, dword ptr [40163C]
00401395 . 50 push eax
00401396 . 8F45 EC pop dword ptr [ebp-14]
00401399 . 8D05 4B164000 lea eax, dword ptr [40164B]
0040139F . 50 push eax
004013A0 . 8F45 F0 pop dword ptr [ebp-10]
004013A3 . 8D05 04514100 lea eax, dword ptr [415104]
004013A9 . 50 push eax
004013AA . 8F45 F4 pop dword ptr [ebp-C]
004013AD . 8D05 10514100 lea eax, dword ptr [415110]
004013B3 . 50 push eax
004013B4 . 8F45 F8 pop dword ptr [ebp-8] ; 失败字符串
004013B7 . C705 20814100>mov dword ptr [418120], 0 ; j
004013C1 > 8D35 A0504100 lea esi, dword ptr [4150A0] ; BYTE T1
004013C7 . 0335 20814100 add esi, dword ptr [418120] ; 418120:j
004013CD . 33C0 xor eax, eax
004013CF . 8A06 mov al, byte ptr [esi] ; T1[j]
004013D1 . 8305 20814100>add dword ptr [418120], 1 ; j++,[ebp-50]是一个跳转表:0012f88c处
004013D8 . FFA485 B0FFFF>jmp dword ptr [ebp+eax*4-50] ; DWORD T2
004013DF . E9 7D020000 jmp 00401661 ; 这下面是最后弹出正确或错误对话框
004013E4 . 6A 00 push 0 ; /Style = MB_OK|MB_APPLMODAL
004013E6 . 68 1C514100 push 0041511C ; |hello
004013EB . 68 1C514100 push 0041511C ; |hello
004013F0 . 6A 00 push 0 ; |hOwner = NULL
004013F2 . FF15 44034100 call dword ptr [<&USER32.MessageBoxA>>; \MessageBoxA
004013F8 .^ EB C7 jmp short 004013C1
004013FA . 8D35 A0504100 lea esi, dword ptr [4150A0]
00401400 . 0335 20814100 add esi, dword ptr [418120] ; j
00401406 . 33C0 xor eax, eax
00401408 . 8B06 mov eax, dword ptr [esi] ; T1[j]
0040140A . 50 push eax
0040140B . 8305 20814100>add dword ptr [418120], 4 ; j += 4
00401412 .^ EB AD jmp short 004013C1
00401414 . 8F05 04814100 pop dword ptr [418104]
0040141A .^ EB A5 jmp short 004013C1
0040141C . 8B45 08 mov eax, dword ptr [ebp+8] ; 参数;name和
0040141F . A3 14814100 mov dword ptr [418114], eax ; m
00401424 .^ EB 9B jmp short 004013C1
00401426 . C705 08814100>mov dword ptr [418108], 0 ; t
00401430 .^ EB 8F jmp short 004013C1
00401432 . 8B0D 00814100 mov ecx, dword ptr [418100] ; r
00401438 . 2B0D 08814100 sub ecx, dword ptr [418108] ; t
0040143E . 890D 00814100 mov dword ptr [418100], ecx
00401444 .^ E9 78FFFFFF jmp 004013C1
00401449 . C705 1C814100>mov dword ptr [41811C], 1
00401453 .^ E9 69FFFFFF jmp 004013C1
00401458 . C705 0C814100>mov dword ptr [41810C], 1 ; z
00401462 .^ E9 5AFFFFFF jmp 004013C1
00401467 . 8B15 00814100 mov edx, dword ptr [418100] ; r
0040146D . 8915 18814100 mov dword ptr [418118], edx ; y
00401473 .^ E9 49FFFFFF jmp 004013C1
00401478 . A1 18814100 mov eax, dword ptr [418118] ; y
0040147D . D1E8 shr eax, 1
0040147F . A3 18814100 mov dword ptr [418118], eax ; y/=2;
00401484 .^ E9 38FFFFFF jmp 004013C1
00401489 . EB 0F jmp short 0040149A ;这下面计算约数和了
0040148B > 8B0D 04814100 mov ecx, dword ptr [418104] ; [418104]:n
00401491 . 83C1 01 add ecx, 1
00401494 . 890D 04814100 mov dword ptr [418104], ecx ; n++
0040149A > 8B15 04814100 mov edx, dword ptr [418104] ; n
004014A0 . 3B15 18814100 cmp edx, dword ptr [418118] ; y
004014A6 . 77 2F ja short 004014D7
004014A8 . A1 14814100 mov eax, dword ptr [418114] ; m
004014AD . A3 00814100 mov dword ptr [418100], eax ; r = m
004014B2 . A1 00814100 mov eax, dword ptr [418100]
004014B7 . 33D2 xor edx, edx
004014B9 . F735 04814100 div dword ptr [418104] ; r/n
004014BF . 85D2 test edx, edx ; 是否整除
004014C1 . 75 12 jnz short 004014D5
004014C3 . 8B0D 1C814100 mov ecx, dword ptr [41811C] ; 整除,x,
004014C9 . 030D 04814100 add ecx, dword ptr [418104] ; n
004014CF . 890D 1C814100 mov dword ptr [41811C], ecx ; x = x+n;
004014D5 >^ EB B4 jmp short 0040148B
004014D7 >^ E9 E5FEFFFF jmp 004013C1
004014DC . 8B15 1C814100 mov edx, dword ptr [41811C] ; x
004014E2 . 8915 00814100 mov dword ptr [418100], edx ; r
004014E8 .^ E9 D4FEFFFF jmp 004013C1
004014ED . EB 0D jmp short 004014FC
004014EF > A1 04814100 mov eax, dword ptr [418104] ; n
004014F4 . 83C0 01 add eax, 1
004014F7 . A3 04814100 mov dword ptr [418104], eax ; n++
004014FC > 8B0D 04814100 mov ecx, dword ptr [418104]
00401502 . 3B0D 18814100 cmp ecx, dword ptr [418118] ; y
00401508 . 77 2F ja short 00401539 ;再一次计算约数和
0040150A . 8B15 1C814100 mov edx, dword ptr [41811C] ; x
00401510 . 8915 00814100 mov dword ptr [418100], edx ; r=x
00401516 . A1 00814100 mov eax, dword ptr [418100] ; r
0040151B . 33D2 xor edx, edx
0040151D . F735 04814100 div dword ptr [418104] ; r/n
00401523 . 85D2 test edx, edx
00401525 . 75 10 jnz short 00401537
00401527 . A1 0C814100 mov eax, dword ptr [41810C] ; z
0040152C . 0305 04814100 add eax, dword ptr [418104] ; n
00401532 . A3 0C814100 mov dword ptr [41810C], eax ; z = z + n
00401537 >^ EB B6 jmp short 004014EF
00401539 >^ E9 83FEFFFF jmp 004013C1
0040153E . 8B0D 14814100 mov ecx, dword ptr [418114] ; m
00401544 . 3B0D 0C814100 cmp ecx, dword ptr [41810C] ; z
0040154A . 0F85 B7000000 jnz 00401607
00401550 . 8B15 1C814100 mov edx, dword ptr [41811C] ; x
00401556 . 3B55 0C cmp edx, dword ptr [ebp+C] ; sn和
00401559 . 0F85 A8000000 jnz 00401607 ; 完蛋
0040155F . A1 14814100 mov eax, dword ptr [418114] ; m
00401564 . 2B05 0C814100 sub eax, dword ptr [41810C] ; z
0040156A . A3 00814100 mov dword ptr [418100], eax ; r= m-z(实际上应该是0)
0040156F . C745 AC C1504>mov dword ptr [ebp-54], 004150C1
00401576 . 8B0D 00814100 mov ecx, dword ptr [418100] ; r
0040157C . 8B548D F4 mov edx, dword ptr [ebp+ecx*4-C] ; [ebp - c]已初始化,
00401580 . 8955 A8 mov dword ptr [ebp-58], edx ; 指针指向字符串Aszz6ryxs7
00401583 . 8B45 A8 mov eax, dword ptr [ebp-58] ; loc1
00401586 . 0FBE08 movsx ecx, byte ptr [eax]
00401589 . 83F9 57 cmp ecx, 57 ; 'W',解密后第一个字母是W
0040158C . 74 2A je short 004015B8
0040158E > 8B55 A8 mov edx, dword ptr [ebp-58] ; 应该是解密字符串
00401591 . 0FBE02 movsx eax, byte ptr [edx] ; 解密后Well Done
00401594 . 85C0 test eax, eax
00401596 . 74 20 je short 004015B8
00401598 . 8B4D A8 mov ecx, dword ptr [ebp-58]
0040159B . 0FBE11 movsx edx, byte ptr [ecx]
0040159E . A1 00814100 mov eax, dword ptr [418100] ; r
004015A3 . 83C0 16 add eax, 16
004015A6 . 33D0 xor edx, eax
004015A8 . 8B4D A8 mov ecx, dword ptr [ebp-58]
004015AB . 8811 mov byte ptr [ecx], dl
004015AD . 8B55 A8 mov edx, dword ptr [ebp-58]
004015B0 . 83C2 01 add edx, 1
004015B3 . 8955 A8 mov dword ptr [ebp-58], edx ; loc1++
004015B6 .^ EB D6 jmp short 0040158E
004015B8 > 833D 00814100>cmp dword ptr [418100], 0 ; r
004015BF . 74 14 je short 004015D5
004015C1 . C705 00814100>mov dword ptr [418100], 1 ; r
004015CB . A1 00814100 mov eax, dword ptr [418100]
004015D0 . 8945 A0 mov dword ptr [ebp-60], eax ; loc2
004015D3 . EB 13 jmp short 004015E8
004015D5 > C705 00814100>mov dword ptr [418100], 0 ; r = 0
004015DF . 8B0D 00814100 mov ecx, dword ptr [418100]
004015E5 . 894D A0 mov dword ptr [ebp-60], ecx ; loc2
004015E8 > 8B55 AC mov edx, dword ptr [ebp-54] ; 004150c1
004015EB . A1 00814100 mov eax, dword ptr [418100] ; r
004015F0 . 8B4C85 F4 mov ecx, dword ptr [ebp+eax*4-C]
004015F4 . 890A mov dword ptr [edx], ecx
004015F6 . C745 AC C6504>mov dword ptr [ebp-54], 004150C6
004015FD . 8B55 AC mov edx, dword ptr [ebp-54]
00401600 . 8B45 F4 mov eax, dword ptr [ebp-C]
00401603 . 8902 mov dword ptr [edx], eax
00401605 . EB 30 jmp short 00401637
00401607 > 8B0D 14814100 mov ecx, dword ptr [418114] ; m
0040160D . 2B0D 0C814100 sub ecx, dword ptr [41810C] ; z
00401613 . 890D 00814100 mov dword ptr [418100], ecx ; r
00401619 . C745 A4 C1504>mov dword ptr [ebp-5C], 004150C1
00401620 . 8B55 A4 mov edx, dword ptr [ebp-5C] ; [ebp - 8]开始时初始化了
00401623 . 8B45 F8 mov eax, dword ptr [ebp-8] ; 指向失败字符串
00401626 . 8902 mov dword ptr [edx], eax
00401628 . C745 A4 C6504>mov dword ptr [ebp-5C], 004150C6
0040162F . 8B4D A4 mov ecx, dword ptr [ebp-5C]
00401632 . 8B55 F8 mov edx, dword ptr [ebp-8]
00401635 . 8911 mov dword ptr [ecx], edx ;把成功字符串地址放入跳转表索引
00401637 >^ E9 85FDFFFF jmp 004013C1
0040163C . A1 14814100 mov eax, dword ptr [418114] ; m
00401641 . A3 00814100 mov dword ptr [418100], eax ; r
00401646 .^ E9 76FDFFFF jmp 004013C1
0040164B . A1 44034100 mov eax, dword ptr [<&USER32.Message>
00401650 . 35 88000000 xor eax, 88
00401655 . 35 88000000 xor eax, 88
0040165A . FFD0 call eax
0040165C .^ E9 60FDFFFF jmp 004013C1
00401661 > 5F pop edi
00401662 . 5E pop esi
00401663 . 5B pop ebx
00401664 . 8BE5 mov esp, ebp
00401666 . 5D pop ebp
00401667 . C3 retn
这部分就有点麻烦了,这个crackme搞得有点像虚拟机,他有一个跳转表,一个跳转索引表,一开始我真是有点晕,
动态跟踪并且反汇编后庆幸算法流程还不算长,要不然就真麻烦了。
跳转表索引
004150A0 04 02 02 00 00 00 03 0F 0E 0D 0B 06 0A 07 02 02 .....
004150B0 00 00 00 03 0E 05 0C 0B 06 09 08 02 00 00 00 00 .........
004150C0 02 00 00 00 00 02 00 00 00 00 02 00 00 00 00 10 ............
跳转表
0012F88C DF 13 40 00 E4 13 40 00 FA 13 40 00 14 14 40 00 ?@.?@.?@.@.
0012F89C 1C 14 40 00 32 14 40 00 78 14 40 00 DC 14 40 00 @.2@.x@.?@.
0012F8AC 3E 15 40 00 ED 14 40 00 89 14 40 00 67 14 40 00 >@.?@.?@.g@.
0012F8BC 58 14 40 00 49 14 40 00 26 14 40 00 3C 16 40 00 X@.I@.&@.<@.
0012F8CC 4B 16 40 00 04 51 41 00 10 51 41 00 A8 FE 12 00 K@.QA.QA..
我说说算法流程吧,
这里面变量比较多,初始化他们后,先把用户名ASCII码的和(S)的约数累加起来(约数不解释了吧,我是数学系的哈)这里的约数
不包含自身,然后有把这个和(S1),同前面一样求出所以约数和(S2),如果S2不等于S1那就完蛋了,接下来把S1与序列号和
做比较,不等久完蛋,都等的话就成功了,接着解密字符串,解出来时Well Done,自然是成功了。
如果要爆破的话,当然是在那两个比较的地方。
接下来说注册机
我一开始没认识到S很特殊,直接生成随机串,结果CPU 百分百了几十秒还没出来,于是写了个程序先看看有哪些
S能满足约数和的约数和等于自身。结果50000以内也不过一下若干个
num sum_of_factor
28 28
220 284
284 220
496 496
1184 1210
1210 1184
2620 2924
2924 2620
5020 5564
5564 5020
6232 6368
6368 6232
8128 8128
10744 10856
10856 10744
12285 14595
14595 12285
17296 18416
18416 17296
其中28和496最特别,他们的约数和直接等于自身,其它的都是孪生的。好了
我就从这里面挑前七个做注册机,关键在于生成用户名。关键代码如下
int magic[] = {220,284,496,496,1184,1210,2620,2924};
void keygen(HWND hDlg)
{
BOOL flag = FALSE;
int m,i;
char sName[100];
char sn[100];
int t;
srand(GetTickCount());
memset(sName, 0,50);
memset(sn,0,50);
//生成符合要求的用户名
m = rand()%8;//选取魔数
int quo = magic[m]/0x30;////用户名长度
int res = magic[m]%0x30;
int tmp;
for(i = 0;i < quo;i++)
{
sName[i] = 0x30;
if(res)
{
t = res - (quo-(i+1))*9;
tmp = t > 0 ? t : 0;//最少承担
tmp = (rand()%(10-tmp)) + tmp;//实际承担
tmp = (res > tmp?tmp:res);
sName[i] += tmp;
res -= tmp;
}
}
m = (m%2)?(m-1):(m+1);
quo = magic[m]/0x30;///序列号长度
res = magic[m]%0x30;
for(i = 0;i < quo;i++)
{
sn[i] = 0x30;
if(res)
{
t = res - (quo-(i+1))*9;
tmp = t > 0 ? t : 0;//最少承担
tmp = (rand()%(10-tmp)) + tmp;//实际承担
tmp = (res > tmp?tmp:res);
sn[i] += tmp;
res -= tmp;
}
}
SetDlgItemText(hDlg,IDC_SN,sn);
SetDlgItemText(hDlg,IDC_NAME,sName);
}
我为了方便生成所有数字型的用户名,如果要小写字母型的话,把代码里几个常数改改就行了。大写字母类似,如果
混合型的话就有点麻烦了。
--------------------------------------------------------------------------------
【经验总结】
这个Crackme 考验耐心,他跳得比较厉害,而不是一堆分支或循环结构。流程也不算长,跟出后容易明白作者思路。
后记:一直想写个注册机,先做一个叫cycle,思考了几天,一直想逆出他的算法,一天在精华里看见有人写出来,居然是
穷举,感叹!于是又去看08年腾讯的那个题,钢球问题,算法比较长,本来想打印代码,结果20页,就
对着电脑反汇编,搞了几天大概明白了。信息论里倒是学过钢球问题,看来乌龟大师给出的答案后,深感其功力之
深厚,我就是再写个注册机意义不大,又到国外一个网站下了个crackme,dephi的我从么见过dephi,搞它那个NAG一直没
搞掉,于是看精华,呵呵,一个资源黑客就把它给全搞定了,连注册码都不用输入。又从论坛上下载了这个crackme,终于
搞定,事成之后先向寝室了同学炫了一阵。这个注册机的风格就是仿照乌龟大师的那个,一点generate出来一组用户名
和序列号,看着很爽。第一次写,如有不足之处请指出,谢谢!
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
2010年10月12日 19:19:04
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!