分享
 
 
 

教菜鸟写注册机——高级篇

王朝other·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

教菜鸟写注册机——高级篇(注意我这里说的高级只是对偶辈菜鸟来说是难一些)

HEYA,我又来灌喽!还是那个系列的第3位CRACKME。下载:

http://opencrackmes.crackmes.de/ope...ackmes/k4n3.zip

用W32DASM来反,(可以先看后面说明)

代码:

:004011BF 6A45 push 00000045

:004011C1 50 push eax

:004011C2 A4 movsb

* Reference To: USER32.GetDlgItemTextA, Ord:0104h

|

:004011C3 8B3DA8404000 mov edi, dword ptr [004040A8] ;注意这里把地址放在EDI

* Possible Reference to Dialog: DialogID_0065, CONTROL_ID:03E8, ""

|

:004011C9 68E8030000 push 000003E8

:004011CE 51 push ecx

:004011CF FFD7 call edi ;实际是CALL GetDlgItemTextA,得到用户名

:004011D1 8BF0 mov esi, eax

:004011D3 85F6 test esi, esi

:004011D5 0F844B010000 je 00401326

:004011DB 83FE40 cmp esi, 00000040

:004011DE 0F8742010000 ja 00401326

:004011E4 8B4508 mov eax, dword ptr [ebp+08]

:004011E7 8D5594 lea edx, dword ptr [ebp-6C]

:004011EA 6A13 push 00000013

:004011EC 52 push edx

* Possible Reference to Dialog: DialogID_0065, CONTROL_ID:03E9, ""

|

:004011ED 68E9030000 push 000003E9

:004011F2 50 push eax

:004011F3 FFD7 call edi ;再次调用GetDlgItemText,得到注册码

:004011F5 6BC003 imul eax, 00000003 ;EAX是注册码的长度

:004011F8 C1E002 shl eax, 02 ;左移二位

:004011FB 05CD000000 add eax, 000000CD ;加上0CD

:00401200 8945FC mov dword ptr [ebp-04], eax

:00401203 817DFCA5010000 cmp dword ptr [ebp-04], 000001A5;看看计算结果是不是1A5

:0040120A 0F85BC000000 jne 004012CC ;不是就死,可以逆算出(1A5-0CD)>>2=12

:00401210 33C0 xor eax, eax ;即注册码不能小于12h位

:00401212 8A4594 mov al, byte ptr [ebp-6C]

:00401215 84C0 test al, al

:00401217 7413 je 0040122C

:00401219 8D4D94 lea ecx, dword ptr [ebp-6C]

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:0040122A(C)

|

:0040121C 3C30 cmp al, 30

:0040121E 0F82C6000000 jb 004012EA ;注册码每位不能小于30h,即'0'

:00401224 8A4101 mov al, byte ptr [ecx+01]

:00401227 41 inc ecx

:00401228 84C0 test al, al

:0040122A 75F0 jne 0040121C

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:00401217(C)

|

:0040122C E8CFFDFFFF call 00401000 ;这是什么呀?好像很重要哟,进去看看!

:00401231 8D852CFFFFFF lea eax, dword ptr [ebp+FFFFFF2C]

:00401237 50 push eax

:00401238 E843FEFFFF call 00401080 ;转换过程一,跟进

:0040123D 8945FC mov dword ptr [ebp-04], eax

:00401240 E8BBFDFFFF call 00401000 ;还进去不?呀....别打我!

:00401245 8D8D2CFFFFFF lea ecx, dword ptr [ebp+FFFFFF2C]

:0040124B 56 push esi

:0040124C 51 push ecx

:0040124D E8BEFDFFFF call 00401010

:00401252 83C40C add esp, 0000000C

:00401255 33C9 xor ecx, ecx

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:00401284(C)

|

:00401257 8B45FC mov eax, dword ptr [ebp-04] :0040125A 33D2 xor edx, edx |

:0040125C BE1A000000 mov esi, 0000001A |

:00401261 F7F6 div esi |

:00401263 8A941510FFFFFF mov dl, byte ptr [ebp+edx-000000F0]

:0040126A 88540DC8 mov byte ptr [ebp+ecx-38], dl|

:0040126E 8B45FC mov eax, dword ptr [ebp-04] |

:00401271 C1E003 shl eax, 03 |---转换过程二

:00401274 BA45230100 mov edx, 00012345 |

:00401279 F7E8 imul eax |

:0040127B 03C2 add eax, edx |

:0040127D 8945FC mov dword ptr [ebp-04], eax |

:00401280 41 inc ecx |

:00401281 83F912 cmp ecx, 00000012 |

:00401284 72D1 jb 00401257 /

:00401286 E875FDFFFF call 00401000

:0040128B 33C0 xor eax, eax

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:004012A2(C)

|

:0040128D 8A4C0594 mov cl, byte ptr [ebp+eax-6C] :00401291 8A5405C8 mov dl, byte ptr [ebp+eax-38] |

:00401295 80E930 sub cl, 30 |

:00401298 32D1 xor dl, cl |---转换过程三

:0040129A 885405C8 mov byte ptr [ebp+eax-38], dl |

:0040129E 40 inc eax |

:0040129F 83F812 cmp eax, 00000012 |

:004012A2 72E9 jb 0040128D /

:004012A4 E857FDFFFF call 00401000

:004012A9 8D55C8 lea edx, dword ptr [ebp-38]

:004012AC 52 push edx

:004012AD E85EFEFFFF call 00401110 ;转换过程四

:004012B2 E849FDFFFF call 00401000

:004012B7 8D45C8 lea eax, dword ptr [ebp-38]

* Possible StringData Ref from Data Obj ->"KEYGENNING4NEWBIES"

|

:004012BA 6814514000 push 00405114 ;固定字串"KEYGENNING4NEWBIES"

:004012BF 50 push eax ;上面转换而来的字串

:004012C0 E86BFEFFFF call 00401130 ;进行比较

:004012C5 83C40C add esp, 0000000C

:004012C8 85C0 test eax, eax

:004012CA 753C jne 00401308 ;关键跳转

找串式参考,然后向上很容易找到关键跳转。可以发现是对EAX进行判断,在一般情况下这EAX就是上面CALL的返回值了。再看CALL上面有两个PUSH,猜猜是什么?应该是对字符串比较吧。在上面就可以看出405114是一个固定的字串"KEYGENNIG4NEWBIES",动态跟一跟看EAX是啥,果然,也是一个同样长度的字符串。这时几乎可以肯定这个EAX就是我们的用户名和注册码进行某种运算产生的结果。那么我们就跟一跟看:

从前面的方法找到这个函数的开头,开头还是一些初始化的东东,向下看,可以找到一个API:GetDlgItemText这个API从名字猜猜看,就是我们介绍过的GetDlgItem和GetWindowText和“合体”

具体说明请查资料,我不写了。值得一提的是程序把这个CALL的地址先放在EDI里,以后每次调用时只用CALL EDI就行了,这是多次调用同一API时翻译器的优化方法,注意!

调用这个API后返回值是得到的文本的长度,然后在后面对注册码的长度进行一些计算(注释在上面),我们可以反算出注册码的长度为12h位(多于12h位也可以,因为只取前12h位)。

然后就是一个CALL 401000,我直觉感到这是一个重要的CALL,结果跟进去一看:!@#$%,只是把几个寄存器清零了,这告诉我们:直觉会有出错的时候,代码才是检验真理的唯一标准

下面一个CALL 401080,在它前面压入了一个参数正是我们的用户名,我直觉感到这个CALL有问题。跟进看看,这回对了啦:

代码:

* Referenced by a CALL at Address:

|:00401238

|

:00401080 55 push ebp

:00401081 8BEC mov ebp, esp

:00401083 51 push ecx

:00401084 53 push ebx

:00401085 56 push esi

:00401086 57 push edi

* Possible StringData Ref from Data Obj ->"eheh"

|

:00401087 6880504000 push 00405080

:0040108C 6A00 push 00000000

:0040108E E8ADFFFFFF call 00401040 ;这个CALL有问题

:00401093 83C408 add esp, 00000008

:00401096 8BD8 mov ebx, eax

:00401098 E863FFFFFF call 00401000

* Possible StringData Ref from Data Obj ->" is a whore."

|

:0040109D BF70504000 mov edi, 00405070

:004010A2 83C9FF or ecx, FFFFFFFF

:004010A5 33C0 xor eax, eax

:004010A7 F2 repnz

:004010A8 AE scasb

:004010A9 F7D1 not ecx

:004010AB 2BF9 sub edi, ecx

:004010AD 8BF7 mov esi, edi

:004010AF 8B7D08 mov edi, dword ptr [ebp+08]

:004010B2 8BD1 mov edx, ecx

:004010B4 83C9FF or ecx, FFFFFFFF

:004010B7 F2 repnz

:004010B8 AE scasb

:004010B9 8BCA mov ecx, edx

:004010BB 4F dec edi

:004010BC C1E902 shr ecx, 02

:004010BF F3 repz

:004010C0 A5 movsd

:004010C1 8BCA mov ecx, edx

:004010C3 83E103 and ecx, 00000003

:004010C6 F3 repz

:004010C7 A4 movsb

:004010C8 33FF xor edi, edi

:004010CA 33F6 xor esi, esi ;上面这一段是不是有点晕,没关系,只看结果

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:004010F6(C)

|

:004010CC 8B4508 mov eax, dword ptr [ebp+08]

:004010CF 50 push eax ;在这里D eax看看是什么,RoBa is a whore.

:004010D0 56 push esi ;ESI每次加4,从第ESI个字符开始取值

:004010D1 E86AFFFFFF call 00401040 ;还是上面的CALL

:004010D6 8B8E30504000 mov ecx, dword ptr [esi+00405030];这也是一个表,从里面取值

:004010DC 83C408 add esp, 00000008

:004010DF 33CF xor ecx, edi

:004010E1 03C1 add eax, ecx

:004010E3 8945FC mov dword ptr [ebp-04], eax

:004010E6 C145FC07 rol dword ptr [ebp-04], 07 ;ROL是一个“滚动”移位

:004010EA 8B45FC mov eax, dword ptr [ebp-04]

:004010ED 83C604 add esi, 00000004

:004010F0 33D8 xor ebx, eax ;进行一些运算,EBX最初是"eheh"=68656865

:004010F2 47 inc edi

:004010F3 83FE40 cmp esi, 00000040 ;ESI每次加4,所以这是计算10H=16次

:004010F6 7CD4 jl 004010CC ;这里是循环计算

:004010F8 5F pop edi

:004010F9 8BC3 mov eax, ebx

:004010FB 5E pop esi

:004010FC 5B pop ebx

:004010FD 8BE5 mov esp, ebp

:004010FF 5D pop ebp

:00401100 C3 ret

呵呵,别害怕,这是整个程序最复杂的一处运算,过了这儿就简单了

一上来压入了一个"eheh",一个0,然后一个CALL 401040,我跟进。。。。别着急,先带过看返回值是什么?嗯,EAX=68656865。作了这么多练习了,你的“先死”练出来了么?这个EAX怎么这么别扭,就是"eheh"倒过来了呀。'e'=65h,'h'=68h。当然如果没有看出来,跟进一下更保险了

再向下,一个字串" is a whore."(whore什么意思牙,我英语太菜)接下来就是倒来倒去。记住repnz scasb/ repnz movsd这样的计算经常是字符串的计算。我们不算三七二十一先走过这一段看看结果如何。走到4010CF时下D eax。呵呵,是"RoBa is a whore."(到底是什么意思?不是骂我的吧

)。可见上面那一段就是把用户名接上一个" is a whore." 所以,看不懂的计算不妨先跳过去,往往结果却非常明了。

接下来就是一个循环。又用了CALL 401040。这次是从字串"RoBa is a whore."里取值,而第二个参数ESI每次加4,可以看出它是控制从第几个字符开始取。从循环的最后可以看出要算10h次。

每次从字串中取出四个字符放在EAX中后,再从[405030]这个表里从一个值,进行一些计算,把结果与EBX进行XOR,(EBX最初是上面得到的68656865)。这个CALL返回的值就是10H次计算后的EBX。(这一段较乱,也不太好说明,亲自跟一下就会明白,有疑问请看我的注册机是如何实现的。或者直接找我啦)

好了,我们出来喽,往下走,把返回放在[EBP-4],清空一些寄存器,又来到一个循环。(过程二)

代码:

:00401257 8B45FC mov eax, dword ptr [ebp-04] ;最初这里是上面过程一的结果

:0040125A 33D2 xor edx, edx

:0040125C BE1A000000 mov esi, 0000001A

:00401261 F7F6 div esi ;除以1Ah=26

:00401263 8A941510FFFFFF mov dl, byte ptr [ebp+edx-000000F0];根据余数从表中取值

:0040126A 88540DC8 mov byte ptr [ebp+ecx-38], dl ;把取得的值组成一个字串

:0040126E 8B45FC mov eax, dword ptr [ebp-04]

:00401271 C1E003 shl eax, 03

:00401274 BA45230100 mov edx, 00012345

:00401279 F7E8 imul eax

:0040127B 03C2 add eax, edx ;进行一些计算,准备下次再取

:0040127D 8945FC mov dword ptr [ebp-04], eax

:00401280 41 inc ecx ;ECX是循环变量

:00401281 83F912 cmp ecx, 00000012 ;共计算12h=18次

:00401284 72D1 jb 00401257

先讲下DIV除法运算。它把商放在EAX,余数放在EDX。在这里我们可以看到除以1Ah即26。[ebp-F0]看看是啥,哈哈是一个字符表"ABCDEFGHIJKLMNOPQRSTUVWXYZ"。根据除得的余数从这个表中取出一个字符,(恰好除以26)。然后把取出的字符放在[ebp+ecx-38]这个地方,因为ECX是递增的,这样就形成了一个新串。对后面的计算也有一点要说明。imul eax这句,是两个32位的数相乘,这样结果会是64位,结果的高32位放在EDX,低32放入EAX,一定要注意!

下面我们来到过程三:

代码:

:0040128D 8A4C0594 mov cl, byte ptr [ebp+eax-6C] ;循环取假注册码

:00401291 8A5405C8 mov dl, byte ptr [ebp+eax-38] ;循环取过程二的结果字串

:00401295 80E930 sub cl, 30

:00401298 32D1 xor dl, cl

:0040129A 885405C8 mov byte ptr [ebp+eax-38], dl

:0040129E 40 inc eax ;EAX是循环变量

:0040129F 83F812 cmp eax, 00000012 ;还是18位

:004012A2 72E9 jb 0040128D

又一个循环,EAX是循环变量,[EBP-38]记得是什么,就是过程二得到的那个新串。[EBP-6C]呢,在很远的上面,就是我们的假注册码。用EAX控制每次取一个字符,然后(假码的字符-30h) XOR 新串的字符,生成的新的新串还放在[EBP-38].

好了,先别晕,下面还有:

lea edx,[EBP-38]。这时EDX是过程三产生的新串了,又压进去,然后CALL 401110。跟进过程四:

代码:

:00401110 8B4C2404 mov ecx, dword ptr [esp+04] ;[ESP+4]就是上面PUSH来的字串啦

:00401114 33C0 xor eax, eax

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:00401122(C)

|

:00401116 8A1408 mov dl, byte ptr [eax+ecx] ;依次取过程三产生的新串

:00401119 32D0 xor dl, al ;与循环变量XOR

:0040111B 881408 mov byte ptr [eax+ecx], dl ;放好结果

:0040111E 40 inc eax

:0040111F 83F812 cmp eax, 00000012 ;EAX为循环变量,计算12H=18次

:00401122 72F2 jb 00401116

:00401124 C3 ret

这个比较简单吧。CHEERS!最终结果终于出来了,然后判断这个最终结果是不是一个固定字串。当然我们的胡乱输入得不到字串"KEYGENNING4NEWBIES"的。那么应该怎么办呢?过程一和过程二都是对用户名的计算,这两步是不可逆的。也就是说从用户名N算出一个新串K,我们不能从K算出N来(我以为是这样,即使可逆应该也十分复杂)可以表示成 F12(N)=K。然后新串K和注册码S都参考计算,又得出一个新串K'。这是过程三,这个计算可逆(不明白?我在最后有说明)。F3(K,S)=K'。再从K'得到一个K''(过程四,也是可逆的)。最后判断这个K''是不是等于固定字串,即判断是否F4(K')=K''="KEYGENNING4NEWBIES"。

我们写注册机时呢,既然过程一和二(F12)不可逆,我们把它照抄下来得到K,然后可以从"KEYGENNING4NEWBIES"反算(过程四的逆运算)F4'("KEYGENNING4NEWBIES")=K''。最后F2可逆,所以可以求出F3'(K,K')=S。这样就根据用户名求出了注册码S。

(不知各位看懂没有,我自己都说晕了,这种符号表示真麻烦。其实只要想一想就发现很简单的。)

注册机:(C,写得很烂,各位将就)

代码:

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

void main()

{

unsigned int iEAX,iEBX,i;

char st[]="KEYGENNING4NEWBIES";

char alpha[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ"; //过程二用到的表

char name[70]={0};

int st1[]={

0x12,0x5C,0x34,0x22,0xAB,0x9D,0x54,0x00,

0xDD,0x84,0xAE,0x66,0x31,0x78,0x73,0xCF //过程一用到的表

};

char st2[20]={0};

char password[20]={0};

printf("Please input your name:");

scanf("%s",name);

strcat(name," is a whore.");

iEBX=0x68656865;

for (i=0;i<16;i++)

{

iEAX=(name[i*4])|(name[i*4+1]<<8)|

(name[i*4+2]<<16)|(name[i*4+3]<<24);

iEAX+=(st1[i]^i);

iEAX=(iEAX<<7)|(iEAX>>25); //我用这个表示ROL

iEBX^=iEAX;

} //过程一

iEAX=iEBX;

for (i=0;i<0x12;i++)

{

int k=iEAX%26;

st2[i]=alpha[k];

__asm

{

mov eax,iEAX

shl eax,3

mov edx,12345h

imul eax

add eax,edx

mov iEAX,eax

} //用了汇编

} //过程二

for (i=0;i<18;i++)

st[i]=st[i]^i; //过程四的逆运算

for (i=0;i<18;i++)

{

password[i]=st2[i]^st[i];

password[i]+=0x30;

} //过程三的逆运算,得到注册码

printf("Your Serial number is:\n%s\n",password);

printf("Keygen by RoBa\nEnjoy Cracking!\n");

}

一个可用的用户名:RoBa

注册码::98D34M<N9?:AH85F

这个CRACKME设计有点缺陷,算出的注册码有可能是不可显示字符。开始我以为是我注册机错了,可把字符串粘贴过去以后是正确的。

一点说明:过程二的那个乘法我前面说了,其实结果是64位的,而高级语言里表示64位真的很麻烦,我只知道C里面有一个__int64,但程序老是出错,不得已加进了一段汇编,简单几句就解决了,可见汇编决不能丢掉

还有过程三和过程四为什么可逆,我想各位菜鸟同胞搞不清的可能就是异或。我可以明确的告诉大家,XOR运算是可逆的,逆运算仍然是XOR。下面我来证明:因为XOR是按位计算,所以只要一个二进制位的XOR可逆,那么整个数的计算也就可逆。来看

当A=0,B=0时,C=A XOR B=0,那么A=C XOR B=0,B=C XOR A=0

当A=0,B=1时,C=A XOR B=1,那么A=C XOR B=0,B=C XOR A=1

当A=1,B=0时,C=A XOR B=1,那么A=C XOR B=1,B=C XOR A=0

当A=1,B=1时,C=A XOR B=0,那么A=C XOR B=1,B=C XOR A=1

我说的对吧?

后记:这个CRACKME单从注册算法来说算是比较复杂的了,能够达到大部分共享软件的水平(某些采用密码学算法的BT除外)。对于新手来说可能会有些吃力(写破文更费劲),但如果能够弄明白的话,相信你已经能够搞定很大一部分软件的算法了。

当然,在具体的软件保护中不光是要解开算法,PE文件知识、壳的知识等也非常重要。(我正学脱壳,已经能脱UPX,ASPack了,呵呵,是不是很白痴。。。)让我们一起努力吧。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有