第13课 注册算法进阶.docx
《第13课 注册算法进阶.docx》由会员分享,可在线阅读,更多相关《第13课 注册算法进阶.docx(20页珍藏版)》请在冰豆网上搜索。
![第13课 注册算法进阶.docx](https://file1.bdocx.com/fileroot1/2023-1/8/c4a0527c-3ebb-4993-af07-d42979132f97/c4a0527c-3ebb-4993-af07-d42979132f971.gif)
第13课注册算法进阶
第13课注册算法进阶
[例1]目标程序:
easy1.exe。
0167:
004014FC8D45FCLEAEAX,[EBP-04]
0167:
004014FFE814040000CALL00401918
0167:
004015048B5594MOVEDX,[EBP-6C]
0167:
004015070FBE0C10MOVSXECX,BYTE[EAX+EDX]//依次取name中的字符
0167:
0040150B014DA0ADD[EBP-60],ECX//累加到ebp-60中
0167:
0040150EFF4594INCDWORD[EBP-6C]//计数
0167:
004015118D45FCLEAEAX,[EBP-04]
0167:
00401514E8DDE10000CALL0040F6F6
0167:
004015193B4594CMPEAX,[EBP-6C]
0167:
0040151C7FDEJG004014FC//如果没取完,就跳转,形成循环
上面程序的功能是将所有输入的name字符累加起来,以我输入的”TAE”为例,程序每次取一个字符然后将他们相加,就像这样:
”T”的ascii码为0x54,”A”的ascii码为0x41,”E”的ascii码为0x45,”!
”的ascii码为0x21,所以0x54+0x41+0x45+0x21=0xFB,结果就是0xFB,现在还没有结束,请看下面程序对这个0xFB的操作:
0167:
0040151E6955A032130000IMULEDX,[EBP-60],1332
0167:
004015258955A0MOV[EBP-60],EDX
0167:
00401528694DA032130000IMULECX,[EBP-60],1332
0167:
0040152F894DA0MOV[EBP-60],ECX
0167:
004015326945A032130000IMULEAX,[EBP-60],1332
0167:
004015398945A0MOV[EBP-60],EAX
0167:
0040153C8145A04A0F0000ADDDWORD[EBP-60],0F4A
大家能看懂上面的程序吗?
其实就是用0xFB连续乘三次0x1332,然后用这个结果加上0x0F4A,经过这样的计算就得到了你的注册码了
0167:
004015438B5598MOVEDX,[EBP-68]
0167:
004015463B55A0CMPEDX,[EBP-60]//”ebp-60”中保存正确注册码
0167:
004015490F8571010000JNZNEAR004016C0//判断注册码是否正确,不同的话就跳到出错提示了
0167:
0040154F66C745C05000MOVWORD[EBP-40],50
0167:
004015558D45E8LEAEAX,[EBP-18]
0167:
004015588B55A0MOVEDX,[EBP-60]
我得到的注册码:
Name:
TAE!
Sn:
-1861903902
下面给出easy1的keymake的算法注册机(keygen.rek):
.const
.data
szHomePagedb"",0
szEmaildb"mailto:
fpx425@",0
szErrMessdb"请输入姓名!
",0
szBufferdb50dup(0)
szHexdb"%ld",0
.code
movesi,eax
invokelstrlen,esi
movecx,eax
xoredx,edx
xorebx,ebx
xoreax,eax
n1:
movbl,byteptr[esi+eax]
addedx,ebx
inceax
cmpecx,eax
jgn1
moveax,edx
imuleax,eax,1332h
imuleax,eax,1332h
imuleax,eax,1332h
addeax,0F4Ah
invokewsprintf,addrszBuffer,addrszHex,eax
leaeax,szBuffer
注意其中红字标出的部分。
[例2]目标程序nullz的第1、2关。
大家看到了吧,是分三六九等的,一起来试试,先来个最简单的吧!
方法一:
工具:
WinHex
过程:
用前面教过的方法,一试就出来,不信请看
看到了吗?
qJT62aWfviq0P57JGs2FelQkX这个就是注册码,什么?
不信?
我有证据,请看!
还有一种方法就是直接用W32DASM反汇编即可!
如图:
是不是更简单?
呵呵,好的,我们进入下一层!
开始,如图:
出现错误提示?
肯定的了,让我们来一步步分析它,这次光用WINHEX和W32DASM可就不管用了,要动用“动态分析软件”了,例如使用ollydbg。
过程:
:
00401AE48D4C247Cleaecx,dwordptr[esp+7C]
:
00401AE86A33push00000033
:
00401AEA51pushecx
:
00401AEB68ED030000push000003ED
:
00401AF08BCBmovecx,ebx
*ReferenceTo:
MFC42.Ordinal:
0C1A,Ord:
0C1Ah
|
:
00401AF2E8E7100000Call00402BDE
:
00401AF78D542414leaedx,dwordptr[esp+14]
:
00401AFB52pushedx
*ReferenceTo:
KERNEL32.lstrlenA,Ord:
02A1h
|
:
00401AFCFF1500404000Calldwordptr[00404000]
:
00401B028BF0movesi,eax
:
00401B0483FE05cmpesi,00000005-------------比较用户名是否大于5位
:
00401B077311jnb00401B1A -------------小于就出现错误信息
:
00401B096A40push00000040
*PossibleStringDataReffromDataObj->"CrackMe"
|
:
00401B0B6804514000push00405104
*PossibleStringDataReffromDataObj->"UserNamemusthaveatleast5"
->"characters."
|
:
00401B1068D8504000push004050D8
:
00401B15E9BA000000jmp00401BD4
*Referencedbya(U)nconditionalor(C)onditionalJumpatAddress:
|:
00401B07(C)
|
:
00401B1AB801000000moveax,00000001----给EAX赋值为1,做为计数器
:
00401B1F33FFxoredi,edi------------EDI清零,做储数器
:
00401B213BF0cmpesi,eax
:
00401B237211jb00401B36
*Referencedbya(U)nconditionalor(C)onditionalJumpatAddress:
|:
00401B34(C)
|
:
00401B250FBE4C0414movsxecx,byteptr[esp+eax+14]---------
提取你输入用户名的第二位的十六进制
:
00401B2A03CFaddecx,edi
ECX=ECX+EDI
:
00401B2C0FAFC8imulecx,eax
ECX=ECX*EAX
:
00401B2F40inceax
EAX+1
:
00401B308BF9movedi,ecx
EDI=ECX
:
00401B323BC6cmpeax,esi
:
00401B3476EFjbe00401B25 形成循环
以我输入的名字lllufh为例
l的十六进制6C、u的十六进制75、f的十六进制66、h的十六进制68
计算过程如下:
初始化:
EDX=0EAX=1
第一次循环:
1.ecx=6c
2.ecx=ecx+edi=6c
3.ecx=ecx*eax=6c
4.eax=eax+1=2
5.edi=ecx=6c
第二次循环:
1.ecx=6c
2.ecx=ecx+edi=d8
3.ecx=ecx*eax=1b0
4.eax=eax+1=3
5.edi=ecx=1b0
第三次循环:
1.ecx=75
2.ecx=ecx+edi=225
3.ecx=ecx*eax=66f
4.eax=eax+1=4
5.edi=ecx=66f
第四次循环:
1.ecx=66
2.ecx=ecx+edi=6d5
3.ecx=ecx*eax=1b54
4.eax=eax+1=5
5.edi=ecx=1b54
第五次循环:
1.ecx=68
2.ecx=ecx+edi=1bbc
3.ecx=ecx*eax=8aac
4.eax=eax+1=6
5.edi=ecx=8aac
第六次循环:
1.ecx=0
2.ecx=ecx+edi=8aac
3.ecx=ecx*eax=34008
4.eax=eax+1=7
5.edi=ecx=34008
循环结束.
*Referencedbya(U)nconditionalor(C)onditionalJumpatAddress:
|:
00401B23(C)
|
:
00401B3633C9xorecx,ecx--------ecx清零做计数器
:
00401B3885F6testesi,esi
:
00401B3A7620jbe00401B5C
*Referencedbya(U)nconditionalor(C)onditionalJumpatAddress:
|:
00401B5A(C)
|第二次计算开始。
:
00401B3C0FBE6C0C14movsxebp,byteptr[esp+ecx+14]
提取用户名的第一位
:
00401B418BC7moveax,edi
//eax=edi
:
00401B4333D2xoredx,edx
//edx清零
:
00401B45F7F5divebp
//eax=eax/ebp商进EAX,余数进EDX
:
00401B4733D2xoredx,edx
//edx清零
:
00401B49BD0A000000movebp,0000000A
//ebp=0xA
:
00401B4EF7F5divebp
//eax=ex/ebp商进EAX,余数进EDX
:
00401B5080C230adddl,30
//edx=edx+0x30
:
00401B5388540C48movbyteptr[esp+ecx+48],dl
//把EDX的值赋到字符串中
:
00401B5741incecx
ecx=ecx+1
:
00401B583BCEcmpecx,esi
:
00401B5A72E0jb00401B3C形成循环
接着以我输入的名字lllufh为例继续计算:
第一次循环:
1.ebp=6c
2.eax=edi=34008
3.edx=0
4.eax=eax/ebp=7b4edx=18
5.edx=0
6.ebp=a
7.eax=eax/ebp=c5edx=02
8.edx=02+30=32
9.[esp+ecx+48]=32
10.ecx=ecx+1=1
因为我输入的用户名的都三位都一样,所以第二次、第三次循环的值也都是一样的
第四次循环:
1.ebp=75
2.eax=edi=34008
3.edx=0
4.eax=eax/ebp=71cedx=3c
5.edx=0
6.ebp=a
7.eax=eax/ebp=b6edx=0
8.edx=0+30=30
9.[esp+ecx+48]=30
10.ecx=ecx+1=4
第五次循环:
1.ebp=66
2.eax=edi=34008
3.edx=0
4.eax=eax/ebp=828edx=18
5.edx=0
6.ebp=a
7.eax=eax/ebp=0edx=08
8.edx=8+30=38
9.[esp+ecx+48]=38
11.ecx=ecx+1=5
第六次循环:
1.ebp=68
2.eax=edi=34008
3.edx=0
4.eax=eax/ebp=800edx=08
5.edx=0
6.ebp=a
7.eax=eax/ebp=ccedx=08
8.edx=8+30=38
9.[esp+ecx+48]=38
11.ecx=ecx+1=6
跳出循环。
依次把六次循环的余数提出,为222088,这就是注册码喽!
晕,又不信,自己看图吧!
*Referencedbya(U)nconditionalor(C)onditionalJumpatAddress:
|:
00401B3A(C)
|
:
00401B5C8D542448leaedx,dwordptr[esp+48]-----这里是真码
:
00401B608D44247Cleaeax,dwordptr[esp+7C]----这里是假码
:
00401B6452pushedx
:
00401B6550pusheax
*ReferenceTo:
KERNEL32.lstrcmpA,Ord:
0295h
|
:
00401B66FF1508404000Calldwordptr[00404008]
:
00401B6C85C0testeax,eax
:
00401B6E7550jne00401BC0
:
00401B706870434000push00404370
:
00401B758D4C2414leaecx,dwordptr[esp+14]
*ReferenceTo:
MFC42.Ordinal:
0219,Ord:
0219h
|
:
00401B79E85A100000Call00402BD8
*PossibleStringDataReffromDataObj->"
DifficultyLEVEL-2Completed!
"
下面给出nullz的第2关的keymake的算法注册机(keygen.rek):
.const
.data
szHomePagedb"",0
szEmaildb"mailto:
fpx425@",0
szErrMessdb"请输入姓名!
",0
szBufferdb50dup(0)
szHexdb"%d",0
lendd0
.code
movesi,eax
invokelstrlen,esi
movlen,eax
moveax,1
xoredi,edi
n1:
movsxecx,byteptr[esi+eax]
addecx,edi
imulecx,eax
inceax
movedi,ecx
cmpeax,len
jben1
xorecx,ecx
n2:
movsxebp,byteptr[esi+ecx]
moveax,edi
xoredx,edx
divebp
xoredx,edx
movebp,0Ah
divebp
adddl,30h
movbyteptr[szBuffer+ecx],dl
incecx
cmpecx,len
jbn2
leaeax,szBuffer
以上基本上来自程序的反汇编代码:
注意其中的红字部分,我第一次编译没通过,就是因为数字后面没加h。
[例3]目标程序nullz的第3关。
该第三阶段了,可是一个比上一个要难哟,睁大眼睛仔细看呀!
什么?
和第二个一样?
别急呀,外表一样,芯可不一样喽,跟我一步步来吧!
:
00401C728D4C2414leaecx,dwordptr[esp+14]
:
00401C7651pushecx
:
00401C7768ED030000push000003ED
:
00401C7C8BCFmovecx,edi
*ReferenceTo:
MFC42.Ordinal:
0C19,Ord:
0C19h
|
:
00401C7EE8670F0000Call00402BEA
:
00401C838B6C2418movebp,dwordptr[esp+18]
ebp=0x650088以后计算用
:
00401C878B55F8movedx,dwordptr[ebp-08]
为用户名个数
:
00401C8A83FA05cmpedx,00000005
进行比较
:
00401C8D7D11jge00401CA0
不能小于5位
:
00401C8F6A40push00000040
*PossibleStringDataReffromDataObj->"CrackMe"
|
:
00401C916804514000push00405104
*PossibleStringDataReffromDataObj->"UserNamemusthaveatleast5"
->"characters."
|
:
00401C9668D8504000push004050D8
:
00401C9BE9E2000000jmp00401D82
*Referencedbya(U)nconditionalor(C)onditionalJumpatAddress:
|:
00401C8D(C)
|
:
00401CA033C0xoreax,eax
//eax清零
:
00401CA23BD3cmpedx,ebx
//比较是否输入注册码
:
00401CA47E3Cjle00401CE2
//没有则出错
:
00401CA6B901000000movecx,00000001
//ecx=1
:
00401CAB33FFxoredi,edi
//edi清零
:
00401CAD2BCDsubecx,ebp
//ecx=ecx-ebp
:
00401CAF894C241Cmovdwordptr[esp+1C],ecx
//把ecx的值放入[esp+1c]中
*Referencedbya(U)nconditionalor(C)onditionalJumpatAddress:
|:
00401CDA(C)
|
计算注册码过程开始:
:
00401CB30FBE5C0500movsxebx,byteptr[ebp+eax]
//依次提取用户名第一位的十六进制
:
00401CB88D4C0500leaecx,dwordptr[ebp+eax]
//ecx=ebp+eax
:
00401CBC03F3addesi,ebx
//esi=esi+ebx
:
00401CBE8BD8movebx,eax
//ebx=ebx+eax
:
00401CC0C1E308shlebx,08
//ebx左移三位
:
00401CC333F3xoresi,ebx
//esi=esixorebx
:
00401CC58B5C241Cmovebx,dwordptr[esp+1C]
//ebx=[esp+1c]
:
00401CC903D9addebx,ecx
//ebx=ebx+ecx
:
00401CCB8BCFmovecx,edi
//ecx=edi
:
00401CCD0FAFF3imulesi,ebx
//esi=esi*ebx
:
00401CD0F7D1notecx
//ecx取反
:
00401CD20FAFF1imulesi,ecx
//esi=esi*ecx
:
00401CD540inceax
//eax=eax+1
:
00401CD603FAaddedi,edx
//edi=edi+edx
:
00401CD83BC2cmpeax,edx
:
00401CDA7CD7jl00401CB3
形成循环
:
00401CDC8B7C2420movedi,dwordptr[esp+20]
:
00401CE033DBxorebx,ebx
*Referencedbya(U)nconditionalor(C)onditionalJumpatAddress:
|:
00401CA4(C)
|
:
00401CE256pushesi
:
00401CE38D542414leaedx,dwordptr[esp+14]
*PossibleStringDataReffromDataObj->"%lu"
|
:
00401CE7682C514000push0040512C
:
00401CEC52pushedx
*ReferenceTo:
MFC42.Ordinal:
0B02,Ord:
0B02h
|
:
00401CEDE8F20E0000Call00402BE4
:
00401CF28B74241Cmovesi,dwordptr[esp+1C]---------这里就是真码了