能力值:
( LV2,RANK:10 )
|
-
-
2 楼
由于空闲时间也不是很多,不一定天天更新,只是当自己将一个crackme完全从头到尾做完后就来更新一下,也大致看了下,crackme2007专辑中有些是有壳的,所以目前只做那些没有加壳的,尽量要求自己先自己做一遍,当不明白的时候在结合教程来做,等完全分析清楚算法后,自己再独立写出注册机来,说到编程方面我也是个菜鸟,可能写出来的代码一点都不符合规范,但我目前的目标是能实现功能就行了。先贴一个前几天做的一个练习。
CrackMe 2007 序列号->逍遥风->ACG TRIAL 分析
下载地址大家自己找。
0040127D . BF 06214000 MOV EDI,crcme1.00402106
00401282 . 33DB XOR EBX,EBX ; 上面函数取注册码,之后将放用户名的地址送入EDI
00401284 . 33C0 XOR EAX,EAX
00401286 > 8A1F MOV BL,BYTE PTR DS:[EDI] ; 取用户名的每一位的ascii
00401288 . 80FB 20 CMP BL,20 ; 格式判断,如果ascii吗小于20则是非打印字符,就跳走
0040128B . 0F82 95000000 JB crcme1.00401326
00401291 . 03C3 ADD EAX,EBX ; 累加用户名的每一位ascii码
00401293 . 47 INC EDI ; 指向下一位用户名的字符
00401294 . 803F 00 CMP BYTE PTR DS:[EDI],0 ; 是否到用户名最后一位,是否是0
00401297 .^ 75 ED JNZ SHORT crcme1.00401286
00401299 . C1C0 03 ROL EAX,3 ; 用户名ascii码之和循环左移3位,相当于乘以8
0040129C . 35 A5150500 XOR EAX,515A5 ; 再和0x515A5异或,后压栈保存
004012A1 . 50 PUSH EAX
004012A2 . 33C0 XOR EAX,EAX
004012A4 . 33DB XOR EBX,EBX
004012A6 . 33FF XOR EDI,EDI
004012A8 . BE 2E214000 MOV ESI,crcme1.0040212E ; 注册码送入ESI
004012AD > B8 0A000000 MOV EAX,0A ; EAX赋值0A,结合后面看是作为乘数
004012B2 . 8A1E MOV BL,BYTE PTR DS:[ESI] ; 循环取注册吗的每一位
004012B4 . 85DB TEST EBX,EBX ; 此处是判断是否循环判断完了,是则跳出循环
004012B6 . 74 15 JE SHORT crcme1.004012CD ; 因为在后面并没有判断结束循环的语句,而常用的ECX也没有减一的操作
004012B8 . 80FB 30 CMP BL,30 ; 判断注册码是否是数字,分别判断是否小于0和大宇9,是则非数字
004012BB . 72 69 JB SHORT crcme1.00401326
004012BD . 80FB 39 CMP BL,39
004012C0 . 7F 64 JG SHORT crcme1.00401326
004012C2 . 83EB 30 SUB EBX,30 ; 注册码的ASCII码减0x30,得出的值就是十进制的数字值
004012C5 . 0FAFF8 IMUL EDI,EAX
004012C8 . 03FB ADD EDI,EBX ; edi=edi*0A+十进制的注册码值,edi初值是0
004012CA . 46 INC ESI
004012CB .^ EB E0 JMP SHORT crcme1.004012AD
004012CD > 81F7 CA870000 XOR EDI,87CA ; 注册码循环计算出的值和0x87CA异或
004012D3 . 8BDF MOV EBX,EDI
004012D5 . 58 POP EAX ; 出栈的值是之前用户名循环计算出的值
004012D6 . 03C3 ADD EAX,EBX ; 将用户名和注册码循环计算出的结果相加
004012D8 . 35 E7970700 XOR EAX,797E7
004012DD . 85C0 TEST EAX,EAX
004012DF 75 45 JNZ SHORT crcme1.00401326
004012E1 . 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL
004012E3 . 68 1B204000 PUSH crcme1.0040201B ; |-=ACG=- T h e B e s t -=ACG=-
004012E8 . 68 77204000 PUSH crcme1.00402077 ; |Text = "Yeah You Did It!!!
Czyli nareszczie ci si?uda硂
Teraz mo縠sz przy彻czy?si?do ACG"
004012ED . FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hOwner
004012F0 . E8 5D010000 CALL <JMP.&USER32.MessageBox>; \MessageBoxA
其中这段循环的作用是把字符转换为数字,比如输入136608,经执行这段循环后就变成数字的136608,只不过调试时看到的是16进制。
004012AD > /B8 0A000000 MOV EAX,0A ; EAX赋值0A,结合后面看是作为乘数
004012B2 . |8A1E MOV BL,BYTE PTR DS:[ESI] ; 循环取注册吗的每一位
004012B4 . |85DB TEST EBX,EBX ; 此处是判断是否循环判断完了,是则跳出循环如果取到的是0则表明已经到字符处的末尾
004012B6 . |74 15 JE SHORT crcme1.004012CD ; 因为在后面并没有判断结束循环的语句,而常用的ECX也没有减一的操作
004012B8 . |80FB 30 CMP BL,30 ; 判断注册码是否是数字,分别判断是否小于0和大宇9,是则非数字
004012BB . |72 69 JB SHORT crcme1.00401326
004012BD . |80FB 39 CMP BL,39
004012C0 . |7F 64 JG SHORT crcme1.00401326
004012C2 . |83EB 30 SUB EBX,30 ; 注册码的ASCII码减0x30,得出的值就是十进制的数字值
004012C5 . |0FAFF8 IMUL EDI,EAX
004012C8 . |03FB ADD EDI,EBX ; edi=edi*0A+十进制的注册码值,edi初值是0
004012CA . |46 INC ESI
004012CB .^\EB E0 JMP SHORT crcme1.004012AD
比如136608,,这样计算就得出数字的136608,第0位是1,第一位是3,第二位是6。。。。。
((((((0*10+1)*10+3)*10+6)*10+6)*10+0)*10+8=136608
这段也是想了好久才搞明白的。还有上面的那句TEST EBX,EBX,如果取得的是字符最后一个空字符则表明已经取完,就跳出循环。
改程序在开始还有一个验证KEY文件的过程,只是如果没有找到就直接进入程序,如果找到的话就弹出一个提示框,key文件名是:ACG.key
内容必须是12个字符,“ACG The Best”
00401012 |. 68 6B234000 PUSH crcme1.0040236B ; |ACG.key
00401017 |. E8 84040000 CALL <JMP.&KERNEL32.CreateFileA> ; \CreateFileA
0040101C |. 83F8 FF CMP EAX,-1
0040101F |. 0F84 59010000 JE crcme1.0040117E
00401025 |. A3 73234000 MOV DWORD PTR DS:[402373],EAX
0040102A |. 6A 00 PUSH 0 ; /pFileSizeHigh = NULL
0040102C |. FF35 73234000 PUSH DWORD PTR DS:[402373] ; |hFile = NULL
00401032 |. E8 51040000 CALL <JMP.&KERNEL32.GetFileSize> ; \GetFileSize
00401037 |. 83F8 0C CMP EAX,0C
0040103A |. 0F85 3E010000 JNZ crcme1.0040117E
00401040 |. 6A 0C PUSH 0C ; /MemSize = C (12.)
00401042 |. 6A 00 PUSH 0 ; |Flags = GMEM_FIXED
00401044 |. E8 39040000 CALL <JMP.&KERNEL32.GlobalAlloc> ; \GlobalAlloc
00401049 |. A3 7B234000 MOV DWORD PTR DS:[40237B],EAX
0040104E |. 6A 00 PUSH 0 ; /pOverlapped = NULL
00401050 |. 68 77234000 PUSH crcme1.00402377 ; |pBytesRead = crcme1.00402377
00401055 |. 6A 0C PUSH 0C ; |BytesToRead = C (12.)
00401057 |. FF35 7B234000 PUSH DWORD PTR DS:[40237B] ; |Buffer = NULL
0040105D |. FF35 73234000 PUSH DWORD PTR DS:[402373] ; |hFile = NULL
00401063 |. E8 14040000 CALL <JMP.&KERNEL32.ReadFile> ; \ReadFile
00401068 |. 8B3D 7B234000 MOV EDI,DWORD PTR DS:[40237B]
0040106E |. 33DB XOR EBX,EBX
00401070 |. 8A1F MOV BL,BYTE PTR DS:[EDI]
00401072 |. 80F3 1B XOR BL,1B
00401075 |. C1C3 02 ROL EBX,2
00401078 |. 81F3 68010000 XOR EBX,168
0040107E |. 85DB TEST EBX,EBX
00401080 |. 0F85 F8000000 JNZ crcme1.0040117E
循环取出文件的内容,依次判断是否是那12个字符,过程是:取出的字符和1B异或,在左移2位,相当于*4。然后和一个值判断是否相等,
比如上面的判断值168,逆过来就是(0X168/4) XOR 1B = 41,其ASCII值为A。
算法:用户名的每位ASCII码累加,累加和*8再和0X515A5异或得到一个值A
输入的注册码要是数字,将其转为数值后和0X87CA异或得到值B
将A+B得到C,C再和0X797E7异或后是否是0来判断注册码是否正确。
所以逆推:C=0X797E7,B=0X797E7-A,
注册码=(0X797E7-A)XOR 0X87CA
C语言实现注册过程如下:
int main(void)
{
char sn[20]={"pediy"};
int i;
int sum=0;
for (i=0;i<20;i++)
{
sum=sum+sn[i]; //求用户名的ascii吗累加
}
sum=sum*8; //累加和*8
sum=sum ^ 0X515A5; //在和这个值异或
sum=(0x797E7-sum)^0x87CA; //计算出注册码。
printf("%d\n",sum);
getchar();
return 0;
}
|
能力值:
( LV2,RANK:10 )
|
-
-
3 楼
谢谢分享谢谢分享
|
能力值:
( LV2,RANK:10 )
|
-
-
4 楼
支持分享
|
能力值:
( LV2,RANK:10 )
|
-
-
5 楼
感谢分享。。。。
|
能力值:
( LV2,RANK:10 )
|
-
-
6 楼
CrackMe 2007->序列号->逍遥分->Splish CrackMe 分析和注册机
这个比较简单,刚开始先做简单的比较好,这个的注册码不是唯一的,组合很多。
查找字符串后找到关键断点,分析如下:共分成2部分
0040135D |> \6A 20 PUSH 20 ; /字符串长度
0040135F |. 68 15324000 PUSH CrackMe0.00403215 ; |字符存放的地址
00401364 |. FF35 90344000 PUSH DWORD PTR DS:[403490] ; |hWnd = 0009029A (class='Edit',parent=0007024A)
0040136A |. E8 BB030000 CALL <JMP.&USER32.GetWindowTextA> ; \取文本框字符
0040136F |. 8D05 53134000 LEA EAX,DWORD PTR DS:[401353] ; 将【401353】的内容送EAX,从字符串看应该是要找的
00401375 |. 8D1D 15324000 LEA EBX,DWORD PTR DS:[403215] ; 将刚才输入的机器号送EBX
0040137B |> 8038 00 /CMP BYTE PTR DS:[EAX],0
0040137E |. 74 0C |JE SHORT CrackMe0.0040138C ; 依次取出每一位,按位比较是否相等,不等就跳走
00401380 |. 8A08 |MOV CL,BYTE PTR DS:[EAX] ; 重新输入改采记下的那个字符串"HardCoded",提示成功
00401382 |. 8A13 |MOV DL,BYTE PTR DS:[EBX]
00401384 |. 38D1 |CMP CL,DL
00401386 |. 75 4A |JNZ SHORT CrackMe0.004013D2 ; 此处为爆破点。
00401388 |. 40 |INC EAX
00401389 |. 43 |INC EBX
0040138A |.^ EB EF \JMP SHORT CrackMe0.0040137B
0040138C |> EB 2F JMP SHORT CrackMe0.004013BD
0040138E |. 43 6F 6E 67 7>ASCII "Congratulations,"
0040139E |. 20 79 6F 75 2>ASCII " you got the har"
004013AE |. 64 20 63 6F 6>ASCII "d coded serial",0
004013BD |> 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL
004013BF |. 68 0A304000 PUSH CrackMe0.0040300A ; |Splish, Splash
004013C4 |. 68 8E134000 PUSH CrackMe0.0040138E ; |Congratulations, you got the hard coded serial
004013C9 |. 6A 00 PUSH 0 ; |hOwner = NULL
004013CB |. E8 78030000 CALL <JMP.&USER32.MessageBoxA> ; \MessageBoxA
004013D0 |. EB 13 JMP SHORT CrackMe0.004013E5
004013D2 |> 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL
004013D4 |. 68 0A304000 PUSH CrackMe0.0040300A ; |Splish, Splash
004013D9 |. 68 67304000 PUSH CrackMe0.00403067 ; |Sorry, please try again.
004013DE |. 6A 00 PUSH 0 ; |hOwner = NULL
004013E0 |. E8 63030000 CALL <JMP.&USER32.MessageBoxA> ; \MessageBoxA
004013E5 |> 61 POPAD
第一部分结果:输入“HardCoded”后成功。
第二部分具体分析如下:
同样根据字符串找点关键断点:
004015E4 /$ 55 PUSH EBP
004015E5 |. 8BEC MOV EBP,ESP
004015E7 |. 6A 20 PUSH 20 ; /Count = 20 (32.)
004015E9 |. 68 42324000 PUSH CrackMe0.00403242 ; |【403242】存放取得的注册码
004015EE |. FF75 0C PUSH DWORD PTR SS:[EBP+C] ; |hWnd
004015F1 |. E8 34010000 CALL <JMP.&USER32.GetWindowTextA> ; \GetWindowTextA
004015F6 |. 85C0 TEST EAX,EAX
004015F8 |. 0F84 95000000 JE CrackMe0.00401693
004015FE |. A3 67344000 MOV DWORD PTR DS:[403467],EAX ; 将注册码的长度送【403467】
00401603 |. 6A 0B PUSH 0B ; /Count = B (11.)
00401605 |. 68 36324000 PUSH CrackMe0.00403236 ; |【403236】存放取得的注册名
0040160A |. FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hWnd
0040160D |. E8 18010000 CALL <JMP.&USER32.GetWindowTextA> ; \GetWindowTextA
00401612 |. 85C0 TEST EAX,EAX
00401614 |. 74 68 JE SHORT CrackMe0.0040167E
00401616 |. A3 63344000 MOV DWORD PTR DS:[403463],EAX ; 注册名长度送【403463】
0040161B |. 33C9 XOR ECX,ECX
0040161D |. 33DB XOR EBX,EBX
0040161F |. 33D2 XOR EDX,EDX ; 寄存器置0
00401621 |. 8D35 36324000 LEA ESI,DWORD PTR DS:[403236] ; 取注册名存放地址
00401627 |. 8D3D 58324000 LEA EDI,DWORD PTR DS:[403258]
0040162D |. B9 0A000000 MOV ECX,0A ; ECX赋初值0x0A
00401632 |> 0FBE041E /MOVSX EAX,BYTE PTR DS:[ESI+EBX] ; 循环取出注册名的每一位字符送EAX
00401636 |. 99 |CDQ
00401637 |. F7F9 |IDIV ECX ; 除0x0A
00401639 |. 33D3 |XOR EDX,EBX ; 余数和EBX异或,EBX初始值为0,下次循环后就会变化
0040163B |. 83C2 02 |ADD EDX,2 ; 异或后的值在+2
0040163E |. 80FA 0A |CMP DL,0A ; 判断DL是否小于A,小于则将edx送【403258】地址
00401641 |. 7C 03 |JL SHORT CrackMe0.00401646 ; 不小于A则先将DL减去A在送【403258】
00401643 |. 80EA 0A |SUB DL,0A
00401646 |> 88141F |MOV BYTE PTR DS:[EDI+EBX],DL ; EBX是循环计数值,从0开始累加
00401649 |. 43 |INC EBX
0040164A |. 3B1D 63344000 |CMP EBX,DWORD PTR DS:[403463] ; 循环结束标志判断,当注册名取完后则推出循环
00401650 |.^ 75 E0 \JNZ SHORT CrackMe0.00401632
00401652 |. 33C9 XOR ECX,ECX
00401654 |. 33DB XOR EBX,EBX
00401656 |. 33D2 XOR EDX,EDX ; 寄存器置零
00401658 |. 8D35 42324000 LEA ESI,DWORD PTR DS:[403242] ; 取注册码
0040165E |. 8D3D 4D324000 LEA EDI,DWORD PTR DS:[40324D]
00401664 |. B9 0A000000 MOV ECX,0A ; 赋初值0A
00401669 |> 0FBE041E /MOVSX EAX,BYTE PTR DS:[ESI+EBX] ; 取出注册码的每一位
0040166D |. 99 |CDQ
0040166E |. F7F9 |IDIV ECX ; 除0A
00401670 |. 88141F |MOV BYTE PTR DS:[EDI+EBX],DL ; 注册码ascii码除0x0A的余数
00401673 |. 43 |INC EBX
00401674 |. 3B1D 67344000 |CMP EBX,DWORD PTR DS:[403467]
0040167A |.^ 75 ED \JNZ SHORT CrackMe0.00401669
0040167C |. EB 2A JMP SHORT CrackMe0.004016A8
0040167E |> 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL
00401680 |. 68 0A304000 PUSH CrackMe0.0040300A ; |Splish, Splash
00401685 |. 68 A0304000 PUSH CrackMe0.004030A0 ; |Please enter your name.
0040168A |. 6A 00 PUSH 0 ; |hOwner = NULL
0040168C |. E8 B7000000 CALL <JMP.&USER32.MessageBoxA> ; \MessageBoxA
00401691 |. EB 62 JMP SHORT CrackMe0.004016F5
00401693 |> 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL
00401695 |. 68 0A304000 PUSH CrackMe0.0040300A ; |Splish, Splash
0040169A |. 68 B8304000 PUSH CrackMe0.004030B8 ; |Please enter your serial number.
0040169F |. 6A 00 PUSH 0 ; |hOwner = NULL
004016A1 |. E8 A2000000 CALL <JMP.&USER32.MessageBoxA> ; \MessageBoxA
004016A6 |. EB 4D JMP SHORT CrackMe0.004016F5
004016A8 |> 8D35 4D324000 LEA ESI,DWORD PTR DS:[40324D] ; 注册码每位循环计算出的值
004016AE |. 8D3D 58324000 LEA EDI,DWORD PTR DS:[403258] ; 注册名每位循环计算出的值
004016B4 |. 33DB XOR EBX,EBX
004016B6 |> 3B1D 63344000 /CMP EBX,DWORD PTR DS:[403463] ; 循环结束判断语句,【403463】存放注册名长度,看来根据这个值来决定循环次数
004016BC |. 74 0F |JE SHORT CrackMe0.004016CD
004016BE |. 0FBE041F |MOVSX EAX,BYTE PTR DS:[EDI+EBX] ; 分别比较每一位
004016C2 |. 0FBE0C1E |MOVSX ECX,BYTE PTR DS:[ESI+EBX]
004016C6 |. 3BC1 |CMP EAX,ECX
004016C8 |. 75 18 |JNZ SHORT CrackMe0.004016E2 ; 不同则调到失败提示窗口
004016CA |. 43 |INC EBX
004016CB |.^ EB E9 \JMP SHORT CrackMe0.004016B6
004016CD |> 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL
004016CF |. 68 0A304000 PUSH CrackMe0.0040300A ; |Splish, Splash
004016D4 |. 68 42304000 PUSH CrackMe0.00403042 ; |Good job, now keygen it.
004016D9 |. 6A 00 PUSH 0 ; |hOwner = NULL
004016DB |. E8 68000000 CALL <JMP.&USER32.MessageBoxA> ; \MessageBoxA
算法总结:
先根据输入的注册名计算出一个值,取注册名的每一位后的ASCII码除以A,余数和当前的循环计数值异或,异或后的值加2,在判断得出的值是否小于0xA,不小于的话要先减去0xA,将此值保存。此值记作A
循环取出注册码的每位ascii码除以0xA,将余数保存,此值记作B, 最后取注册名的长度,循环比较值A和值B的每一位是否相等,循环次数是注册名的长度,看来注册码长度不能小于注册名的长度,否则这部比较不会通过的。
注册机源码:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
char name[]={"pediy"};
printf("注册名:%s\n",name);
char sn[20];
int i,namelen;
namelen=strlen(name);
for (i=0;i<namelen;i++)
{
name[i]=name[i]%0x0A; //取余数
name[i]=name[i]^i; //余数和当前循环的i值异或
name[i]=name[i]+0x02; // 异或后的结果加+2
if (name[i]>=0x0A)
{
name[i]=name[i]-0x0A;// 如果上面得的值大于0xA,就减去0xA。
}
}
printf("注册码:");
for (i=0;i<namelen;i++)
{
sn[i]=0x7*0x0A+name[i]; //逆算处真码,此处是0x07是随便取的,这样算出的
printf("%c",sn[i]); //主要是字母,也可以用其他值,因为注册码不唯一。
} //注册码后面可以是任何值都可以验证过,因为之比较与注册名相同的注册码,后面的不比较。
printf("\n\n");
getchar();
return 0;
}
|
能力值:
( LV2,RANK:10 )
|
-
-
7 楼
这是这几天做的练习中的一个,直接从练习笔记中考过来的。。
这几天也想找个免费软件试试,结果脱壳不会,看来要一步一步的来,还是继续我的crackme。
CrackMe2007->序列号->逍遥风->Bad Sector CrackMe
00401139 $ 6A 32 PUSH 32 ; /Count = 32 (50.)
0040113B . 68 F3204000 PUSH Crackme1.004020F3 ; |Buffer = Crackme1.004020F3
00401140 . 68 C8000000 PUSH 0C8 ; |ControlID = C8 (200.)
00401145 . FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hWnd
00401148 . E8 DE000000 CALL <JMP.&USER32.GetDlgItemTextA> ; \GetDlgItemTextA
0040114D . 83F8 00 CMP EAX,0 ; 判断用户名是否为空,空则跳走
00401150 . 0F84 99000000 JE Crackme1.004011EF
00401156 . 83F8 04 CMP EAX,4 ; 判断用户名是否小于4,小则跳走
00401159 . 0F82 90000000 JB Crackme1.004011EF
0040115F . 33C9 XOR ECX,ECX
00401161 . 33DB XOR EBX,EBX
00401163 . 33F6 XOR ESI,ESI
00401165 . 8945 FC MOV DWORD PTR SS:[EBP-4],EAX ; 【EBP-4】中存放用户名的长度
00401168 > 0FBE81 F32040>MOVSX EAX,BYTE PTR DS:[ECX+4020F3] ; 取得用户名的一位字符
0040116F . 83F8 20 CMP EAX,20 ; 判断取出的字符是否是空格
00401172 . 74 07 JE SHORT Crackme1.0040117B
00401174 . 6BC0 04 IMUL EAX,EAX,4 ; 取出的字符ASCII吗乘以4送入EAX
00401177 . 03D8 ADD EBX,EAX ; 在EBX中累加刚才的乘积
00401179 . 8BF3 MOV ESI,EBX ; 乘机保存到ESI
0040117B > 41 INC ECX ; 计数器累加
0040117C . 3B4D FC CMP ECX,DWORD PTR SS:[EBP-4] ; 判断是否用户名取完了,
0040117F .^ 75 E7 JNZ SHORT Crackme1.00401168 ; 没有到用户名末尾则继续,否则往下执行
00401181 . 83FE 00 CMP ESI,0 ; 如果根据用户名计算出的结果是0则跳走
00401184 . 74 69 JE SHORT Crackme1.004011EF
00401186 . BB 89476500 MOV EBX,654789 ; 将0x654789送给EBX
0040118B > 0FBE81 F22040>MOVSX EAX,BYTE PTR DS:[ECX+4020F2] ; 从用户名的最后一位开始取字符
00401192 . 4B DEC EBX ; 刚才送的那个值减一
00401193 . 6BC3 02 IMUL EAX,EBX,2 ; 减一后的值乘以2送入EAX
00401196 . 03D8 ADD EBX,EAX ; EAX和EBX相加;也就是(654789-1)*2+(654789-1)
00401198 . 4B DEC EBX ; 上面计算的结果减一
00401199 . 49 DEC ECX ; 计数器减一
0040119A .^ 75 EF JNZ SHORT Crackme1.0040118B
0040119C . 56 PUSH ESI ; /<%lu>
0040119D . 53 PUSH EBX ; |<%lX>
0040119E . 68 C7204000 PUSH Crackme1.004020C7 ; |BS-%lX-%lu
004011A3 . 68 BB214000 PUSH Crackme1.004021BB ; |s = Crackme1.004021BB
004011A8 . E8 6C000000 CALL <JMP.&USER32.wsprintfA> ; \wsprintfA
算法:用户名至少4位,分别根据用户名顺序和倒叙计算出一个值,在计算下就是注册码,具体看上面的注释和下面的注册机源码。。
顺序计算是将每位的ascii码累加;倒叙是现在ebx附一个初值,之后减一,在和顺序时计算的值*2等计算,然后按格式输出即可。
一组正确的注册码:pediy BS-6022E527-2156
#include <stdio.h>
int main(void)
{
//这个crackme的注册码格式:BS-6022E527-2156,用户名不能低于4位。
char name[20]={"abcdef"};
int sn1; //从第一个字符开始依次取用户名中的每个字符乘以4的累加值放于此。
int sn2; //从最后一个字符倒叙取用户名,循环计算结果存放处。
int i;
int ebx,esi,eax;
ebx=0;
esi=0;
eax=0;
sn1=0;
sn2=0;
for (i=0;i<20;i++)
{
sn2=sn2+name[i]*4;
}
esi=sn1;
ebx=0x654789;
for (i=19;i>=0;i--)
{
if (name[i]>0x0) //若是字符为空则不进入循环累计。
{
ebx=ebx-1;
eax=ebx*2;
ebx=ebx+eax;
ebx--;
}
}
sn1=ebx;
printf("用户名:%s\n",name);
printf("注册码:BS-%lX-%lu\n",sn1,sn2);
getchar();
return 0;
}
|
能力值:
( LV2,RANK:10 )
|
-
-
8 楼
不错,想到就做,慢慢就熟练了!
|
能力值:
( LV2,RANK:10 )
|
-
-
9 楼
CrackMe 2007->序列号->逍遥风->Trsh—CrackMe 分析和注册机
重要的是先自己做几遍,实在不行再看教程。
004010D3 . 6A 50 PUSH 50 ; /Count = 50 (80.)
004010D5 . 68 B0344000 PUSH tsrh-cra.004034B0 ; |Buffer = tsrh-cra.004034B0
004010DA . 68 DE000000 PUSH 0DE ; |ControlID = DE (222.)
004010DF . FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hWnd
004010E2 . E8 43020000 CALL <JMP.&USER32.GetDlgItemTextA> ; \GetDlgItemTextA
004010E7 . 83F8 05 CMP EAX,5 ; 取注册名并判断长度是否大于等于5位,否则跳走
004010EA . 7D 26 JGE SHORT tsrh-cra.00401112
004010EC . B8 66354000 MOV EAX,tsrh-cra.00403566
004010F1 . E8 05020000 CALL tsrh-cra.004012FB
004010F6 . 6A 40 PUSH 40 ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
004010F8 . 68 52354000 PUSH tsrh-cra.00403552 ; |Title = "TSRh CrackMe *Easy*"
004010FD . 68 00304000 PUSH tsrh-cra.00403000 ; |Text = "Kill this Nag!!!"
00401102 . 6A 00 PUSH 0 ; |hOwner = NULL
00401104 . E8 27020000 CALL <JMP.&USER32.MessageBoxA> ; \MessageBoxA
00401109 . 33C0 XOR EAX,EAX
0040110B . 5E POP ESI
0040110C . 5F POP EDI
0040110D . 5B POP EBX
0040110E . C9 LEAVE
0040110F . C2 1000 RETN 10
00401112 > E8 DC000000 CALL tsrh-cra.004011F3 ; 关键call,跟进,格式化字符串:trsh-“7D3+注册名长度的十进制”
00401117 . 6A 50 PUSH 50 ; /Count = 50 (80.)
00401119 . 68 90314000 PUSH tsrh-cra.00403190 ; |Buffer = tsrh-cra.00403190
0040111E . 68 4D010000 PUSH 14D ; |ControlID = 14D (333.)
00401123 . FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hWnd
00401126 . E8 FF010000 CALL <JMP.&USER32.GetDlgItemTextA> ; \GetDlgItemTextA
0040112B . A1 90314000 MOV EAX,DWORD PTR DS:[403190] ; 取注册码字符,存放于【403190】处并赋值给eax
00401130 . 3D 74737268 CMP EAX,68727374 ; 比较注册码的前4个字符是否是:0x68727374
00401135 . 75 23 JNZ SHORT tsrh-cra.0040115A
00401137 . 05 20320000 ADD EAX,3220 ; EAX赋值+0x3220,注册码前4为字符值加3220
0040113C . 50 PUSH EAX
0040113D . 33C0 XOR EAX,EAX
0040113F . E8 EA000000 CALL tsrh-cra.0040122E ; 关键call,跟进
00401144 . 58 POP EAX
00401145 . 85C0 TEST EAX,EAX
00401147 . 74 11 JE SHORT tsrh-cra.0040115A
00401149 . 33C2 XOR EAX,EDX
0040114B . 8BD0 MOV EDX,EAX
0040114D . 8BF0 MOV ESI,EAX
0040114F . 33C0 XOR EAX,EAX
00401151 . E8 31010000 CALL tsrh-cra.00401287 ; 比较结果
00401156 . 84C0 TEST AL,AL
00401158 . 75 1F JNZ SHORT tsrh-cra.00401179 ; 此处跳走就完蛋
0040115A > B8 85354000 MOV EAX,tsrh-cra.00403585
0040115F . E8 97010000 CALL tsrh-cra.004012FB
关键call根进
0040122E /$ 56 PUSH ESI
0040122F |. 68 20334000 PUSH tsrh-cra.00403320 ; /String = "tsrh-2008-CZYXY"
00401234 |. E8 1B010000 CALL <JMP.&KERNEL32.lstrlenA> ; \lstrlenA
00401239 |. 8B3D 14354000 MOV EDI,DWORD PTR DS:[403514] ; 【403514】存放的是注册名的长度,取出送EDI
0040123F |. BE 01000000 MOV ESI,1
00401244 |. 8BC8 MOV ECX,EAX ; EAX是取得的格式字符“tsrh-2008-”的长度,送ECX
00401246 |> B8 B0344000 MOV EAX,tsrh-cra.004034B0 ; ASCII "pediy"
0040124B |. 0FB64406 FF MOVZX EAX,BYTE PTR DS:[ESI+EAX-1] ; 依次取出注册名的每位字符
00401250 |. 04 0C ADD AL,0C ; 和0x0C相加
00401252 |. 0FB6D0 MOVZX EDX,AL ; 相加后的值送EDX
00401255 |. 83EA 11 SUB EDX,11 ; 相加后的值减0X11
00401258 |. 03D0 ADD EDX,EAX
0040125A |. 2BD1 SUB EDX,ECX
0040125C |. 33C2 XOR EAX,EDX
0040125E |. 50 PUSH EAX ; /<%X>
0040125F |. 68 18354000 PUSH tsrh-cra.00403518 ; |Format = "%X"
00401264 |. 8D81 20334000 LEA EAX,DWORD PTR DS:[ECX+403320] ; |
0040126A |. 50 PUSH EAX ; |s
0040126B |. E8 A8000000 CALL <JMP.&USER32.wsprintfA> ; \wsprintfA
00401270 |. 83C4 0C ADD ESP,0C
00401273 |. 68 20334000 PUSH tsrh-cra.00403320 ; /String = "tsrh-2008-CZYXY"
00401278 |. E8 D7000000 CALL <JMP.&KERNEL32.lstrlenA> ; \lstrlenA
0040127D |. 8BC8 MOV ECX,EAX
0040127F |. 46 INC ESI
00401280 |. 4F DEC EDI
00401281 |.^ 75 C3 JNZ SHORT tsrh-cra.00401246
00401283 |. 33C0 XOR EAX,EAX
00401285 |. 5E POP ESI
00401286 \. C3 RETN
00401287 /$ 53 PUSH EBX
00401288 |. BE 01000000 MOV ESI,1 ; ESI赋给值1
0040128D |> B8 B0344000 /MOV EAX,tsrh-cra.004034B0 ; ASCII "pediy"
00401292 |. 0FB64406 FF |MOVZX EAX,BYTE PTR DS:[ESI+EAX-1]
00401297 |. 85C0 |TEST EAX,EAX ; 判断是否取完注册码,取完则跳出循环
00401299 |. 74 34 |JE SHORT tsrh-cra.004012CF
0040129B |. 40 |INC EAX ; 注册名每位先加1
0040129C |. BA 20334000 |MOV EDX,tsrh-cra.00403320 ; ASCII "tsrh-2008-CZYXY"
004012A1 |. 0FB65416 0B |MOVZX EDX,BYTE PTR DS:[ESI+EDX+B]
004012A6 |. 33C2 |XOR EAX,EDX
004012A8 |> 83F8 41 |/CMP EAX,41 ; 小于“A”则加0x8
004012AB |. 7D 05 ||JGE SHORT tsrh-cra.004012B2
004012AD |. 83C0 08 ||ADD EAX,8
004012B0 |.^ EB F6 |\JMP SHORT tsrh-cra.004012A8
004012B2 |> 83F8 5A |/CMP EAX,5A ; 大于0x5A则减0x3
004012B5 |. 7E 05 ||JLE SHORT tsrh-cra.004012BC
004012B7 |. 83E8 03 ||SUB EAX,3
004012BA |.^ EB F6 |\JMP SHORT tsrh-cra.004012B2
004012BC |> 83C6 09 |ADD ESI,9
004012BF |. BB 20334000 |MOV EBX,tsrh-cra.00403320 ; ASCII "tsrh-2008-CZYXY"
004012C4 |. 89041E |MOV DWORD PTR DS:[ESI+EBX],EAX
004012C7 |. 83EE 08 |SUB ESI,8
004012CA |. 83FE 10 |CMP ESI,10
004012CD |.^ 75 BE \JNZ SHORT tsrh-cra.0040128D
004012CF |> 33C0 XOR EAX,EAX
004012D1 |. 5B POP EBX
004012D2 |. E8 01000000 CALL tsrh-cra.004012D8
004012D7 \. C3 RETN
算法:用户名必须大于=5,其他具体看注册机源码
注册机:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
//初步试了下好像用户名输入的是数字计算出来的不对,
//所以下面的最好输入字母且不能低于5位。。
//注册码的第二部分是0x7D3+用户名的长度,第一部分必须是“tsrh-”
int main(void)
{
char name[]={"pediy"};
int i;
int namelen;
char temp[20]; //存放一个中间计算过程
char temp2[20];//存放注册码的第三部分
printf("注册名:%s\n",name);
for (i=0;i<20;i++)
{
temp[i]='\0'; temp2[i]='\0';
}
namelen=strlen(name);
for (i=0;i<namelen;i++)
{
// printf("%lX",(((name[i]+0x0C)*2-0x11)-0x0A-i)^(name[i]+0x0C)); //计算注册码中间的一个call,在根据这个结果计算真正的注册码
int a;
a=(((name[i]+0x0C)*2-0x11)-0x0A-i)^(name[i]+0x0C);
if (i==1)
{
itoa(a,temp,16);
}
}
if (islower(temp[0]))
{
temp[0]-=32;
}
for (i=0;i<namelen;i++)
{
name[i]++;
if (i==0)
{
name[i]=name[i]^temp[0];
}
else
{
name[i]=name[i]^0x00;
}
while (name[i]<0x41)
{
name[i]+=0x8;
}
while (name[i]>0x5A)
{
name[i]-=3;
}
temp2[i]=name[i];
}
printf("\n\n");
printf("注册码:tsrh-");
printf("%d-",0x7D3+namelen);
printf("%s",temp2);
printf("\n\n");
getchar();
return 0;
}
|
能力值:
( LV2,RANK:10 )
|
-
-
10 楼
CrackMe 2007->序列号->逍遥风->Salazan’s KeyGenMe#001 分析
查找字符串,很容易找到断点,输入注册名:pediy,注册码:12345678901234567890123456789
0045618C |. 64:FF30 PUSH DWORD PTR FS:[EAX]
0045618F |. 64:8920 MOV DWORD PTR FS:[EAX],ESP
00456192 |. 8D55 FC LEA EDX,DWORD PTR SS:[EBP-4]
00456195 |. 8B83 F8020000 MOV EAX,DWORD PTR DS:[EBX+2F8]
0045619B |. E8 90CDFDFF CALL SalazanK.00432F30 ; 取输入的注册名,结果在【EBP-4】
004561A0 |. 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4]
004561A3 |. E8 58E3FAFF CALL SalazanK.00404500
004561A8 |. 83F8 03 CMP EAX,3 ; 判断注册名长度是否小于3,小则跳走
004561AB |. 7C 1B JL SHORT SalazanK.004561C8
004561AD |. 8D55 F8 LEA EDX,DWORD PTR SS:[EBP-8]
004561B0 |. 8B83 FC020000 MOV EAX,DWORD PTR DS:[EBX+2FC]
004561B6 |. E8 75CDFDFF CALL SalazanK.00432F30 ; 取输入的注册码,放于【EBP-8】中
004561BB |. 8B45 F8 MOV EAX,DWORD PTR SS:[EBP-8]
004561BE |. E8 3DE3FAFF CALL SalazanK.00404500
004561C3 |. 83F8 03 CMP EAX,3 ; 判断是否大于等于3,如果小于3则提示错误
004561C6 |. 7D 0C JGE SHORT SalazanK.004561D4
004561C8 |> B8 58624500 MOV EAX,SalazanK.00456258 ; Min. 3 char in name/serial!
004561CD |. E8 3E6BFDFF CALL SalazanK.0042CD10
004561D2 |. EB 53 JMP SHORT SalazanK.00456227
004561D4 |> 8D55 F4 LEA EDX,DWORD PTR SS:[EBP-C]
004561D7 |. 8B83 FC020000 MOV EAX,DWORD PTR DS:[EBX+2FC]
004561DD |. E8 4ECDFDFF CALL SalazanK.00432F30 ; 取输入的注册码
004561E2 |. 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C]
004561E5 |. E8 2EFBFFFF CALL SalazanK.00455D18 ; 关键call要跟进
004561EA |. 84C0 TEST AL,AL
004561EC 74 1F JE SHORT SalazanK.0045620D ; 此处改成JNE既可以爆破
004561EE |. 8B83 00030000 MOV EAX,DWORD PTR DS:[EBX+300]
004561F4 |. 8B80 08020000 MOV EAX,DWORD PTR DS:[EAX+208]
004561FA |. 33D2 XOR EDX,EDX
004561FC |. E8 73EDFFFF CALL SalazanK.00454F74
00456201 |. BA 7C624500 MOV EDX,SalazanK.0045627C ; Congr! You are real cracker!
关键call根进后分析:
00455DD1 |. 33D2 XOR EDX,EDX
00455DD3 |> 8B4D F4 /MOV ECX,DWORD PTR SS:[EBP-C]
00455DD6 |. 0FB64C11 FF |MOVZX ECX,BYTE PTR DS:[ECX+EDX-1]
00455DDB |. 03D9 |ADD EBX,ECX
00455DDD |. 42 |INC EDX
00455DDE |. 48 |DEC EAX
00455DDF |.^ 75 F2 \JNZ SHORT SalazanK.00455DD3 ; 注册码的1-5位的ascii码累加
00455DE1 |> 81FB 8D010000 CMP EBX,18D ; 累加和是否是0x18D
00455DE7 |. 75 04 JNZ SHORT SalazanK.00455DED
00455DE9 |. C645 E3 01 MOV BYTE PTR SS:[EBP-1D],1 ; 【EBP-1D】置1
00455DED |> 33DB XOR EBX,EBX
00455DEF |. 8B45 F0 MOV EAX,DWORD PTR SS:[EBP-10]
00455DF2 |. E8 09E7FAFF CALL SalazanK.00404500
00455DF7 |. 85C0 TEST EAX,EAX
00455DF9 |. 7C 11 JL SHORT SalazanK.00455E0C
00455DFB |. 40 INC EAX
00455DFC |. 33D2 XOR EDX,EDX
00455DFE |> 8B4D F0 /MOV ECX,DWORD PTR SS:[EBP-10]
00455E01 |. 0FB64C11 FF |MOVZX ECX,BYTE PTR DS:[ECX+EDX-1]
00455E06 |. 03D9 |ADD EBX,ECX
00455E08 |. 42 |INC EDX
00455E09 |. 48 |DEC EAX
00455E0A |.^ 75 F2 \JNZ SHORT SalazanK.00455DFE
00455E0C |> 81FB 8C010000 CMP EBX,18C ; 7--11位的ascii码相加后是否等于0x18C
00455E12 |. 75 04 JNZ SHORT SalazanK.00455E18
00455E14 |. C645 E2 01 MOV BYTE PTR SS:[EBP-1E],1 ; 【EBP-1E】置1
00455E18 |> 33DB XOR EBX,EBX
00455E1A |. 8B45 EC MOV EAX,DWORD PTR SS:[EBP-14]
00455E1D |. E8 DEE6FAFF CALL SalazanK.00404500
00455E22 |. 85C0 TEST EAX,EAX
00455E24 |. 7C 11 JL SHORT SalazanK.00455E37
00455E26 |. 40 INC EAX
00455E27 |. 33D2 XOR EDX,EDX
00455E29 |> 8B4D EC /MOV ECX,DWORD PTR SS:[EBP-14]
00455E2C |. 0FB64C11 FF |MOVZX ECX,BYTE PTR DS:[ECX+EDX-1]
00455E31 |. 03D9 |ADD EBX,ECX
00455E33 |. 42 |INC EDX
00455E34 |. 48 |DEC EAX
00455E35 |.^ 75 F2 \JNZ SHORT SalazanK.00455E29
00455E37 |> 81FB 90010000 CMP EBX,190 ; 13--17位ascii码累加
00455E3D |. 75 04 JNZ SHORT SalazanK.00455E43
00455E3F |. C645 E1 01 MOV BYTE PTR SS:[EBP-1F],1 ; 【EBP-1F】置1
00455E43 |> 33DB XOR EBX,EBX
00455E45 |. 8B45 E8 MOV EAX,DWORD PTR SS:[EBP-18]
00455E48 |. E8 B3E6FAFF CALL SalazanK.00404500
00455E4D |. 85C0 TEST EAX,EAX
00455E4F |. 7C 11 JL SHORT SalazanK.00455E62
00455E51 |. 40 INC EAX
00455E52 |. 33D2 XOR EDX,EDX
00455E54 |> 8B4D E8 /MOV ECX,DWORD PTR SS:[EBP-18]
00455E57 |. 0FB64C11 FF |MOVZX ECX,BYTE PTR DS:[ECX+EDX-1]
00455E5C |. 03D9 |ADD EBX,ECX
00455E5E |. 42 |INC EDX
00455E5F |. 48 |DEC EAX
00455E60 |.^ 75 F2 \JNZ SHORT SalazanK.00455E54
00455E62 |> 81FB 88010000 CMP EBX,188 ; 19--23位ascii码累加
00455E68 |. 75 04 JNZ SHORT SalazanK.00455E6E
00455E6A |. C645 E0 01 MOV BYTE PTR SS:[EBP-20],1 ; 【EBP-20】置1
00455E6E |> 33DB XOR EBX,EBX
00455E70 |. 8B45 E4 MOV EAX,DWORD PTR SS:[EBP-1C]
00455E73 |. E8 88E6FAFF CALL SalazanK.00404500
00455E78 |. 85C0 TEST EAX,EAX
00455E7A |. 7C 11 JL SHORT SalazanK.00455E8D
00455E7C |. 40 INC EAX
00455E7D |. 33D2 XOR EDX,EDX
00455E7F |> 8B4D E4 /MOV ECX,DWORD PTR SS:[EBP-1C]
00455E82 |. 0FB64C11 FF |MOVZX ECX,BYTE PTR DS:[ECX+EDX-1]
00455E87 |. 03D9 |ADD EBX,ECX
00455E89 |. 42 |INC EDX
00455E8A |. 48 |DEC EAX
00455E8B |.^ 75 F2 \JNZ SHORT SalazanK.00455E7F
00455E8D |> 81FB 86010000 CMP EBX,186 ; 25--29位ascii码累加
00455E93 |. 75 04 JNZ SHORT SalazanK.00455E99
00455E95 |. C645 DF 01 MOV BYTE PTR SS:[EBP-21],1 ; 【EBP-21】置1
00455E99 |> 8A45 E3 MOV AL,BYTE PTR SS:[EBP-1D]
00455E9C |. 2245 E2 AND AL,BYTE PTR SS:[EBP-1E]
00455E9F |. 74 18 JE SHORT SalazanK.00455EB9
00455EA1 |. 807D E1 00 CMP BYTE PTR SS:[EBP-1F],0
00455EA5 |. 74 12 JE SHORT SalazanK.00455EB9
00455EA7 |. 807D E0 00 CMP BYTE PTR SS:[EBP-20],0
00455EAB |. 74 0C JE SHORT SalazanK.00455EB9
00455EAD |. 807D DF 00 CMP BYTE PTR SS:[EBP-21],0
00455EB1 |. 74 06 JE SHORT SalazanK.00455EB9
00455EB3 |. C645 FB 01 MOV BYTE PTR SS:[EBP-5],1
00455EB7 |. EB 04 JMP SHORT SalazanK.00455EBD
00455EB9 |> C645 FB 00 MOV BYTE PTR SS:[EBP-5],0
00455EBD |> 33C0 XOR EAX,EAX
00455EBF |. 5A POP EDX
00455EC0 |. 59 POP ECX
00455EC1 |. 59 POP ECX
00455EC2 |. 64:8910 MOV DWORD PTR FS:[EAX],EDX
00455EC5 |. 68 E75E4500 PUSH SalazanK.00455EE7
00455ECA |> 8D45 E4 LEA EAX,DWORD PTR SS:[EBP-1C]
00455ECD |. BA 05000000 MOV EDX,5
00455ED2 |. E8 95E3FAFF CALL SalazanK.0040426C
00455ED7 |. 8D45 FC LEA EAX,DWORD PTR SS:[EBP-4]
00455EDA |. E8 69E3FAFF CALL SalazanK.00404248
00455EDF \. C3 RETN
算法:注册码和用户名没有关系,注册码位数必须是29位,注册码的6 、12、18、24位可以是任意字符,其他的要分成5组,每组的ascii码累加和分别是:0x18D 0x18C 0x190 0x188 0x186 。下面注册机代码中先根据每组的和算出平均值,最后一位取累加和减去前四位的和,也就是每组都是前4位相同,最后一位不同而已。
[ATTACH]45996[/ATTACH]
这是关键call跟进后发现里面有好多call调用,执行到下面的循环累加过程时,查看堆栈的结果,应该是将29位注册码分成5部分,第一部分1—5位。第二部分:7-11位,第三部分:13-17位,第四部分:19—23位,第五部分:25-29位。29位中去掉了4位,每部分有5位。
注册机代码:这个只是个参考而已。。
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(void)
{ //注册名和计算没有关系,所以直接打印出注册码,
//本来这个注册码组合就非常多,只是练习随便算出一个结果就行了。
char sn[29];
int i;
//以下只是结果中的一种情况
//前4位我取一样的值,第五位取判断累加和的值减去前4位的和。
for (i=0;i<5;i++) //第一组结果
{
sn[i]=0x18D/5;
if (i==4)
{
sn[i]=0x18D-0x18D/5*4;//每组的第五位的值
}
}
for (i=6;i<11;i++) //第二组结果
{
sn[i]=0x18C/5;
if (i==10)
{
sn[i]=0x18C-0x18C/5*4;//每组的第五位的值
}
}
for (i=12;i<17;i++) //第三组结果
{
sn[i]=0x190/5;
if (i==16)
{
sn[i]=0x190-0x190/5*4;//每组的第五位的值
}
}
for (i=18;i<23;i++) //第四组结果
{
sn[i]=0x188/5;
if (i==22)
{
sn[i]=0x188-0x188/5*4;//每组的第五位的值
}
}
for (i=24;i<29;i++) //第五组结果
{
sn[i]=0x186/5;
if (i==28)
{
sn[i]=0x186-0x186/5*4;//每组的第五位的值
}
}
sn[5]='-'; sn[11]='-'; sn[17]='-'; sn[23]='-';
for (i=0;i<29;i++)
{
printf("%c",sn[i]);
}
printf("\n\n");
getchar();
return 0;
}
|
能力值:
( LV2,RANK:10 )
|
-
-
11 楼
支持楼主!学习
|
能力值:
( LV2,RANK:10 )
|
-
-
12 楼
来学习的,需要研究一下
|
能力值:
( LV2,RANK:10 )
|
-
-
13 楼
CrackMe 2007->序列号->逍遥风->CZG CrackMe 分析
这个比较简单,但是当逆推计算公式时感觉很麻烦,后来就想直接照搬计算注册码的语句,之前看到论坛上有说明如何把汇编直接考到程序中,但当时也没仔细看,于是有了下面的代码,定义变量时用汇编中的各个寄存器和堆栈的名字,贴一个正确的注册码:pediy 3272156575
004015C5 |. /EB 09 JMP SHORT ECrackMe.004015D0
004015C7 |> |8B55 E0 /MOV EDX,DWORD PTR SS:[EBP-20] ; 这个循环是计算注册码的关键代码
004015CA |. |83C2 01 |ADD EDX,1
004015CD |. |8955 E0 |MOV DWORD PTR SS:[EBP-20],EDX
004015D0 |> \8B45 E0 MOV EAX,DWORD PTR SS:[EBP-20]
004015D3 |. 3B45 E4 |CMP EAX,DWORD PTR SS:[EBP-1C]
004015D6 |. 7D 42 |JGE SHORT ECrackMe.0040161A
004015D8 |. 8B4D E0 |MOV ECX,DWORD PTR SS:[EBP-20]
004015DB |. 51 |PUSH ECX ; /Arg1
004015DC |. 8D4D EC |LEA ECX,DWORD PTR SS:[EBP-14] ; |
004015DF |. E8 1C030000 |CALL ECrackMe.00401900 ; \这个call是依次循环取出输入注册名的每一位送到AL
004015E4 |. 0FBED0 |MOVSX EDX,AL
004015E7 |. 8B45 F0 |MOV EAX,DWORD PTR SS:[EBP-10]
004015EA |. 03C2 |ADD EAX,EDX
004015EC |. 8945 F0 |MOV DWORD PTR SS:[EBP-10],EAX
004015EF |. 8B4D E0 |MOV ECX,DWORD PTR SS:[EBP-20]
004015F2 |. C1E1 08 |SHL ECX,8
004015F5 |. 8B55 F0 |MOV EDX,DWORD PTR SS:[EBP-10]
004015F8 |. 33D1 |XOR EDX,ECX
004015FA |. 8955 F0 |MOV DWORD PTR SS:[EBP-10],EDX
004015FD |. 8B45 E0 |MOV EAX,DWORD PTR SS:[EBP-20]
00401600 |. 83C0 01 |ADD EAX,1
00401603 |. 8B4D E4 |MOV ECX,DWORD PTR SS:[EBP-1C]
00401606 |. 0FAF4D E0 |IMUL ECX,DWORD PTR SS:[EBP-20]
0040160A |. F7D1 |NOT ECX
0040160C |. 0FAFC1 |IMUL EAX,ECX
0040160F |. 8B55 F0 |MOV EDX,DWORD PTR SS:[EBP-10]
00401612 |. 0FAFD0 |IMUL EDX,EAX
00401615 |. 8955 F0 |MOV DWORD PTR SS:[EBP-10],EDX ; 此时EDX中的值的10进制数就是正确的注册码。
00401618 |.^ EB AD \JMP SHORT ECrackMe.004015C7 ; 后面的注册码比较函数就不在仔细跟了。
0040161A |> 8B45 F0 MOV EAX,DWORD PTR SS:[EBP-10]
0040161D |. 50 PUSH EAX ; 下面这句是格式输出 %lu格式
0040161E |. 68 54404000 PUSH ECrackMe.00404054 ; %lu
00401623 |. 8D4D DC LEA ECX,DWORD PTR SS:[EBP-24]
00401626 |. 51 PUSH ECX
00401627 |. E8 52070000 CALL <JMP.&MFC42.#2818>
这个比较简单,但是当逆推计算公式时感觉很麻烦,后来就想直接照搬计算注册码的语句,之前看到论坛上有说明如何把汇编直接考到程序中,但当时也没仔细看,于是有了下面的代码,定义变量时用汇编中的各个寄存器和堆栈的名字,这样可以把那个循环中的每一句都替换,最后输出edx的值,刚开始输出时用的是“%d”,结果发现是负数,后来跟踪了好久发现计算的都是对的,后来查看edx寄存器发现如果是有符号数的话就是输出的值,如果是无符号时就是正确的注册码了。后来改成printf("注册码:%lu\n",ebp10);后就正确了, 之前是printf("注册码:%lu\n",ebp10),真是疏忽呀。
贴一个正确的注册码:pediy 3272156575
#include <stdlib.h>
#include <stdio.h>
#include <string>
int main(void)
{
char name[]={"pediy"};
unsigned int ebp1c,ebp20,ebp10;
unsigned int eax,ecx,edx,i;
ebp20=0;
ebp10=0x081276345;
ebp1c=strlen(name);
for (i=0;i<ebp1c;i++)
{
eax=name[i];//以下并不是汇编语句,只是定义的变量是汇编中的一些名字,
edx=eax; //具体的每一句是和上面的那个计算注册码循环中的代码一一对应。
eax=ebp10;
eax=eax+edx;
ebp10=eax;
ecx=ebp20;
ecx=ecx*0x100;
edx=ebp10;
edx=edx^ecx;
ebp10=edx;
eax=ebp20;
eax++;
ecx=ebp1c;
ecx=ecx*ebp20;
ecx=~ecx;
eax=eax*ecx;
edx=ebp10;
edx=edx*eax;
ebp10=edx;
ebp20++;
}
printf("注册名:%s\n",name);
printf("注册码:%lu\n",ebp10);
getchar();
return 0;
}
|
能力值:
( LV2,RANK:10 )
|
-
-
14 楼
楼主不像是新手呀!
|
能力值:
( LV2,RANK:10 )
|
-
-
15 楼
CrackMe 2007->序列号->逍遥风->lnn1123 CrackMe0.11 算法分析
这个分析不是很难,可是后来在写注册机时怎么也没有写出来,后来又看了几遍论坛上的原帖,里面也没有这方面的分析,也没有给出一个注册码来,没办法,这次只能修改程序爆破了,,爆破的语句在下面分析中写出了。
00401112 . 6A 28 PUSH 28 ; /Count = 28 (40.)
00401114 . 8D45 BC LEA EAX,DWORD PTR SS:[EBP-44] ; |
00401117 . 50 PUSH EAX ; |Buffer
00401118 . FF35 04304000 PUSH DWORD PTR DS:[403004] ; |hWnd = NULL
0040111E . E8 5B010000 CALL <JMP.&user32.GetWindowTextA> ; \GetWindowTextA
00401123 . 8D75 BC LEA ESI,DWORD PTR SS:[EBP-44] ; 【EBP-44】保存输入用户名
00401126 . AC LODS BYTE PTR DS:[ESI]
00401127 . 3C 00 CMP AL,0 ; 判断用户名是否是空,
00401129 . 75 11 JNZ SHORT Crack.0040113C
0040112B . FF35 04304000 PUSH DWORD PTR DS:[403004] ; /hWnd = NULL
00401131 . E8 60010000 CALL <JMP.&user32.SetFocus> ; \SetFocus
00401136 . 33C0 XOR EAX,EAX
00401138 . C9 LEAVE
00401139 . C2 1000 RETN 10
0040113C > 8D45 BC LEA EAX,DWORD PTR SS:[EBP-44] ; 用户名不是空到这里,将用户名送EAX
0040113F . 50 PUSH EAX
00401140 . E8 6F010000 CALL Crack.004012B4 ; 关键call,根据用户名计算出一个值。返回在ECX中
00401145 . 8D45 BC LEA EAX,DWORD PTR SS:[EBP-44]
00401148 . 50 PUSH EAX ; /String
00401149 . E8 60010000 CALL <JMP.&kernel32.lstrlenA> ; \取输入用户名的长度
0040114E . 8BF8 MOV EDI,EAX ; 用户名长度送EDI,用作循环次数
00401150 . 8BC8 MOV ECX,EAX ; ECX也是用户名长度
00401152 . BB 01000000 MOV EBX,1 ; EBX赋初值1
00401157 . 33D2 XOR EDX,EDX ; EDX置零
00401159 . EB 1C JMP SHORT Crack.00401177
0040115B > 4F DEC EDI ; 循环计数值减一。初值是用户名的长度
0040115C . 36:0FB6542F B>MOVZX EDX,BYTE PTR SS:[EDI+EBP-44] ; 从用户名的末位开始读字符
00401162 . 33D3 XOR EDX,EBX ; 于EBX异或
00401164 . 0FAFD3 IMUL EDX,EBX ; 再与EBX相乘
00401167 . 83C3 05 ADD EBX,5
0040116A . 3115 24304000 XOR DWORD PTR DS:[403024],EDX
00401170 . C105 24304000>ROL DWORD PTR DS:[403024],5 ; 和【403024】异或后再乘以0x20
00401177 > 0BFF OR EDI,EDI ; 判断是否循环结束
00401179 .^ 75 E0 JNZ SHORT Crack.0040115B
0040117B . A1 24304000 MOV EAX,DWORD PTR DS:[403024]
00401180 . 8945 FC MOV DWORD PTR SS:[EBP-4],EAX ; 将【403024】的值放入【EBP-4】中保存
00401183 . 33C0 XOR EAX,EAX
00401185 . 6A 28 PUSH 28 ; /Count = 28 (40.)
00401187 . 8D85 3CFFFFFF LEA EAX,DWORD PTR SS:[EBP-C4] ; |
0040118D . 50 PUSH EAX ; |Buffer
0040118E . FF35 08304000 PUSH DWORD PTR DS:[403008] ; |hWnd = NULL
00401194 . E8 E5000000 CALL <JMP.&user32.GetWindowTextA> ; \取输入的注册码
00401199 . 33C9 XOR ECX,ECX
0040119B . 33DB XOR EBX,EBX ; ECX EBX置零
0040119D > 36:0FB69429 3>MOVZX EDX,BYTE PTR SS:[ECX+EBP-C4] ; 循环取出注册码的每一位
004011A6 . 03DA ADD EBX,EDX
004011A8 . 6BDB 10 IMUL EBX,EBX,10 ; 先累加后再乘以0x10
004011AB . 41 INC ECX
004011AC . 3BC8 CMP ECX,EAX ; 判断是否循环结束
004011AE .^ 75 ED JNZ SHORT Crack.0040119D
004011B0 . 3B5D FC CMP EBX,DWORD PTR SS:[EBP-4] ; 上面上次计算的结果比较是否相等,相等则成功。
004011B3 . 74 15 JE SHORT Crack.004011CA ;此处修改成JMP 后既可以爆破。
004011B5 . 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL
004011B7 . 68 30304000 PUSH Crack.00403030 ; |Crackme V 0.11
004011BC . 68 54304000 PUSH Crack.00403054 ; |NO,try again
004011C1 . 6A 00 PUSH 0 ; |hOwner = NULL
004011C3 . E8 C2000000 CALL <JMP.&user32.MessageBoxA> ; \MessageBoxA
004011C8 . EB 32 JMP SHORT Crack.004011FC
004011CA > 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL
004011CC . 68 30304000 PUSH Crack.00403030 ; |Crackme V 0.11
004011D1 . 68 3F304000 PUSH Crack.0040303F ; |Register successful!
004011D6 . 6A 00 PUSH 0 ; |hOwner = NULL
004011D8 . E8 AD000000 CALL <JMP.&user32.MessageBoxA> ; \MessageBoxA
|
能力值:
( LV4,RANK:50 )
|
-
-
16 楼
路过。。。。。
|
能力值:
( LV2,RANK:10 )
|
-
-
17 楼
这个不错的,谢谢楼主分享。
|
能力值:
( LV2,RANK:10 )
|
-
-
18 楼
CrackMe 2007->序列号->逍遥风->moon’s KGme #1 分析和注册机
这个脱壳很顺利,之后查找字符串,到以下位置。这个cm很简单,分析如下。
00447EB0 |. 55 PUSH EBP
00447EB1 |. 68 A17F4400 PUSH 123.00447FA1
00447EB6 |. 64:FF30 PUSH DWORD PTR FS:[EAX]
00447EB9 |. 64:8920 MOV DWORD PTR FS:[EAX],ESP
00447EBC |> 8D55 F0 /LEA EDX,DWORD PTR SS:[EBP-10]
00447EBF |. 8B86 D0020000 |MOV EAX,DWORD PTR DS:[ESI+2D0]
00447EC5 |. E8 36C2FDFF |CALL 123.00424100 ; 取输入的用户名放于【EBP-10】
00447ECA |. 8B55 F0 |MOV EDX,DWORD PTR SS:[EBP-10]
00447ECD |. 8D45 FC |LEA EAX,DWORD PTR SS:[EBP-4]
00447ED0 |. E8 EFBCFBFF |CALL 123.00403BC4
00447ED5 |. 8B45 FC |MOV EAX,DWORD PTR SS:[EBP-4]
00447ED8 |. E8 DFBCFBFF |CALL 123.00403BBC ; 取输入的用户名长度
00447EDD |. 83F8 06 |CMP EAX,6 ; 判断是否大于等于6位,小于6的话重复上面循环
00447EE0 |.^ 7C DA \JL SHORT 123.00447EBC ; 将输入注册名复制后追加到原注册名后
00447EE2 |. 8D45 F8 LEA EAX,DWORD PTR SS:[EBP-8]
00447EE5 |. BA B87F4400 MOV EDX,123.00447FB8 ; xxxxxx
00447EEA |. E8 E5BAFBFF CALL 123.004039D4
00447EEF |. BB 01000000 MOV EBX,1
00447EF4 |> 8D45 F8 /LEA EAX,DWORD PTR SS:[EBP-8]
00447EF7 |. E8 90BEFBFF |CALL 123.00403D8C
00447EFC |. 8B55 FC |MOV EDX,DWORD PTR SS:[EBP-4]
00447EFF |. 8A541A FF |MOV DL,BYTE PTR DS:[EDX+EBX-1] ; 依次取出注册名每一位,循环6次,所以只取前6位
00447F03 |. 80C2 05 |ADD DL,5 ; 注册名每位字符加5
00447F06 |. 885418 FF |MOV BYTE PTR DS:[EAX+EBX-1],DL ; 保存到这个地址。用于后面比较
00447F0A |. 43 |INC EBX
00447F0B |. 83FB 07 |CMP EBX,7
00447F0E |.^ 75 E4 \JNZ SHORT 123.00447EF4
00447F10 |. 8D45 F4 LEA EAX,DWORD PTR SS:[EBP-C]
00447F13 |. BA C87F4400 MOV EDX,123.00447FC8 ; Hey, u r realy good!\n\rSend ur solution to moon.86@gmx.de!
00447F18 |. E8 B7BAFBFF CALL 123.004039D4
00447F1D |. 8D55 EC LEA EDX,DWORD PTR SS:[EBP-14]
00447F20 |. 8B86 EC020000 MOV EAX,DWORD PTR DS:[ESI+2EC]
00447F26 |. E8 F9C4FFFF CALL 123.00444424
00447F2B |. 8B55 EC MOV EDX,DWORD PTR SS:[EBP-14] ; 取输入的注册码
00447F2E |. 8B45 F8 MOV EAX,DWORD PTR SS:[EBP-8] ; 取计算出的真码
00447F31 |. E8 96BDFBFF CALL 123.00403CCC ; 比较注册码函数
00447F36 |. 75 26 JNZ SHORT 123.00447F5E ; 此处是爆破位置。
00447F38 |. 6A 00 PUSH 0
00447F3A |. 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C]
00447F3D |. E8 3EBEFBFF CALL 123.00403D80
00447F42 |. 8BD0 MOV EDX,EAX
00447F44 |. B9 04804400 MOV ECX,123.00448004 ; Yeah, u got it!
算法看代码中的注释。
[B]一组正确的注册码:pediy ujin~u[/B]
#include <stdlib.h>
#include <stdio.h>
#include <string>
int main(void)
{ //注册名注意最好是数字和字母,且字母不能是小写z,否则
//计算出的注册码可能不容易输入,因为注册码是根据注册名每位
//的ascii码加5得到的,而小写z和其后面的ascii码+5后会大于128.
//注册名会单独保存一个位置且是6位,如果注册名大于6位则计算时只取
//前6位计算,如果不够6位,则赋值输入的注册名并和输入的注册名合并,直到》=6位后就进入计算过程。
char Name[]={"pediy"};
const int n=6;
int i;
char RegName[n];
int NameLen=strlen(Name);
if (NameLen>=n)
{
for (i=0;i<6;i++)
RegName[i]=Name[i];
}
else
{ int j=0;
for (i=0;i<6;i++)
{
if (j>NameLen-1)
{
j=0;
}
RegName[i]=Name[j];
j++;
}
}
printf("注册名:%s\n",Name);
printf("注册码:");
for (i=0;i<6;i++)
{
RegName[i]=RegName[i]+0x5;
printf("%c",RegName[i]);
}
getchar();
return 0;
}
|
能力值:
( LV2,RANK:10 )
|
-
-
19 楼
CrackMe 2007->序列号->逍遥风->Prolixe-KeygenMe#1 分析和注册机
这个CM分析了下算法,虽然计算注册码的call很好确定,但是要跟进去里面的call还有不少,后来就反复的试了好多次,主要用猜测的方法,同时要注意查看内存和堆栈的变化,比如在进入一个call前肯定要传参数,有时也要传入返回值保存的地方,所以主要查看call前面的几个语句的地址,F8不过call后在查看堆栈后的变化来猜测该call的功能,后来分析出计算注册码的过程(这步并没有在call里面,可以直接看到),计算出后有小写字母的话就转换大些等这些操作就是通过执行call后的变化猜出来的。
注册码分3部分,首尾部分是固定的字符,中间的字符数和输入的用户名位数相同,具体看代码。
00407FAD |. 50 PUSH EAX ; |Buffer
00407FAE |. 68 E8030000 PUSH 3E8 ; |ControlID = 3E8 (1000.)
00407FB3 |. 53 PUSH EBX ; |hWnd
00407FB4 |. E8 97C6FFFF CALL <JMP.&user32.GetDlgItemTextA> ; \取输入的用户名,存放在【EBP-104】
00407FB9 |. 6A 1E PUSH 1E ; /Count = 1E (30.)
00407FBB |. 8D85 FCFDFFFF LEA EAX,DWORD PTR SS:[EBP-204] ; |
00407FC1 |. 50 PUSH EAX ; |Buffer
00407FC2 |. 68 E9030000 PUSH 3E9 ; |ControlID = 3E9 (1001.)
00407FC7 |. 53 PUSH EBX ; |hWnd
00407FC8 |. E8 83C6FFFF CALL <JMP.&user32.GetDlgItemTextA> ; \取输入的注册码,存放于【EBP-204】
00407FCD |. 80BD FCFDFFFF>CMP BYTE PTR SS:[EBP-204],0 ; 注册码是否是空?空则提示错误
00407FD4 |. 75 17 JNZ SHORT Keygen去.00407FED
00407FD6 |. 6A 40 PUSH 40 ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
00407FD8 |. 68 0C814000 PUSH Keygen去.0040810C ; |Error
00407FDD |. 68 14814000 PUSH Keygen去.00408114 ; |Enter a Serial
00407FE2 |. 53 PUSH EBX ; |hOwner
00407FE3 |. E8 88C6FFFF CALL <JMP.&user32.MessageBoxA> ; \MessageBoxA
00407FE8 |. E9 B9000000 JMP Keygen去.004080A6
00407FED |> 80BD FCFEFFFF>CMP BYTE PTR SS:[EBP-104],0 ; 用户名是否为空?空则提示错误
00407FF4 |. 75 17 JNZ SHORT Keygen去.0040800D
00407FF6 |. 6A 40 PUSH 40 ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
00407FF8 |. 68 0C814000 PUSH Keygen去.0040810C ; |Error
00407FFD |. 68 24814000 PUSH Keygen去.00408124 ; |Enter a Name
00408002 |. 53 PUSH EBX ; |hOwner
00408003 |. E8 68C6FFFF CALL <JMP.&user32.MessageBoxA> ; \MessageBoxA
00408008 |. E9 99000000 JMP Keygen去.004080A6
0040800D |> 8D85 F8FDFFFF LEA EAX,DWORD PTR SS:[EBP-208]
00408013 |. 8D95 FCFEFFFF LEA EDX,DWORD PTR SS:[EBP-104] ; 用户名送EAX
00408019 |. B9 00010000 MOV ECX,100
0040801E |. E8 19B8FFFF CALL Keygen去.0040383C
00408023 |. 8B85 F8FDFFFF MOV EAX,DWORD PTR SS:[EBP-208]
00408029 |. 8D55 FC LEA EDX,DWORD PTR SS:[EBP-4]
0040802C |. E8 E3FDFFFF CALL Keygen去.00407E14 ; 关键call,计算出注册码
00408031 |. 8D85 F4FDFFFF LEA EAX,DWORD PTR SS:[EBP-20C]
00408037 |. 8D95 FCFDFFFF LEA EDX,DWORD PTR SS:[EBP-204]
0040803D |. B9 00010000 MOV ECX,100
00408042 |. E8 F5B7FFFF CALL Keygen去.0040383C
00408047 |. 8B95 F4FDFFFF MOV EDX,DWORD PTR SS:[EBP-20C]
0040804D |. 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4]
00408050 |. E8 EBB8FFFF CALL Keygen去.00403940 ; 比较注册码
00408055 75 2F JNZ SHORT Keygen去.00408086 ; 修改此处可以爆破。
贴出一组正确的注册码:用户名:123 注册码:HZF-RQX-GFD
#include <stdlib.h>
#include <stdio.h>
#include <string>
int main(void)
{
char name[]={"123"};
//感觉这个CM的算法有些问题,当输入一些字符,比如有些小写字母
//计算出来的就不一定对,主要原因应该是计算的超出了ASCII的范围。
//比如我用pediy做用户名,计算出来的就不能用。
//注册码必须以“HZF-”开始,以"-GDF"结束,中间的字符是下面计算的结果。
int namelen=strlen(name);
int ebx,ecx,edx,edi,i;
printf("注册名:%s\n",name);
ebx=1;
for (i=0;i<namelen;i++)
{
edi=name[i];
edx=edi;
ecx=ebx+5;
edx=edx^ecx;
edx=edx+edi;
edx=edx+0x0A;
ebx=ebx+1;
if (edx>=0x61 && edx<=0x7A)
{
edx=edx-0x20; //小写转换成大写,其他字符不变。
}
name[i]=edx; //用name数组保存计算的结果。
}
printf("注册码:HZF-%s-GFD\n",name);
getchar();
return 0;
}
|
能力值:
( LV2,RANK:10 )
|
-
-
20 楼
CrackMe 2007->序列号->逍遥风->Olivers CrackMe 分析
这个crackme分析起来不是很难,但就是很麻烦,中间对字符处理了不下5次。在注册码比较过程中采用的是明码,所以可以直接看到真正的注册码。由于编程水平不行,目前没有写出注册机,等以后再说。具体如下:
输入用户名:abcdef,注册码:123456 注册名必须大于等于6位。
第一步操作是将用户名倒序后得以字符串记作A; 此时为:fedcba
第二步操作是将用户名的N-1位字符分别取出,A的每一位分别转换成10进制,之后组成第二个字符串,用户名的第一位是a,A的第一个字符f的10进制是103,这样就组成a103,依次类推,最终得到字符B:a103b101c100d99e98,
第三步操作是字符串B的首位和末尾除外的字符进行一次重复操作,如B中“a”和“最后的8”不进行操作,得的结果是记作C:
103b101c100d99e9
110033bb110011cc110000dd9999ee99=C
第四步操作是将C 的每一位字符的ASCII码转换成10进制但是最后一位不进行操作。得到的结果记作:D即:
110033bb110011cc110000dd9999ee9
494948485151989849494848494999994949484848481001005757575710110157
第五步操作是从D的第三位开始取字符,并且每次间隔3位,知道D中的字符取到最后或者取得字符数达到0x30位。取出的字符记作:E
485199484949481
第六步操作是从D的第3位开始取字符,从E中取字符,将取出的2个字符分别转换成10进制的数字,然后求2个数相减的绝对值,之后用这个绝对值修改对应的E值,,D值每次循环都累加3,E的每次循环累加1。 直到将E中的每个值就修改完,此时得到的值就是真正的注册码。
001748175151013
00430CA2 |. 33DB XOR EBX,EBX ; EBX置零,用于下面的循环赋初值
00430CA4 |. 8D55 FC LEA EDX,DWORD PTR SS:[EBP-4]
00430CA7 |. 8B86 DC010000 MOV EAX,DWORD PTR DS:[ESI+1DC]
00430CAD |. E8 669FFEFF CALL <ocrackme.取字符文本> ; 取输入的用户名,存于ebp-4
00430CB2 |. 8D55 F8 LEA EDX,DWORD PTR SS:[EBP-8]
00430CB5 |. 8B86 E0010000 MOV EAX,DWORD PTR DS:[ESI+1E0]
00430CBB |. E8 589FFEFF CALL <ocrackme.取字符文本> ; 取输入的注册码,存于ebp-8
00430CC0 |. 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4] ; 用户名送EAX
00430CC3 |. E8 702CFDFF CALL <ocrackme.取字符串长度> ; 用户名长度
00430CC8 |. 83F8 06 CMP EAX,6 ; 是否大于等于6位
00430CCB |. 7D 0F JGE SHORT ocrackme.00430CDC
00430CCD |. B8 F40E4300 MOV EAX,ocrackme.00430EF4 ; Name must be at least 6 Characters long
00430CD2 |. E8 65DEFFFF CALL ocrackme.0042EB3C
00430CD7 |. E9 E8010000 JMP ocrackme.00430EC4
00430CDC |> 837D F8 00 CMP DWORD PTR SS:[EBP-8],0 ; 注册码是否是空。
00430CE0 |. 75 34 JNZ SHORT ocrackme.00430D16
00430CE2 |. B8 240F4300 MOV EAX,ocrackme.00430F24 ; Enter a Serial #
00430CE7 |. E8 50DEFFFF CALL ocrackme.0042EB3C
00430CEC |. E9 D3010000 JMP ocrackme.00430EC4
00430CF1 |> 8B45 FC /MOV EAX,DWORD PTR SS:[EBP-4] ; 取得输入的注册码
00430CF4 |. E8 3F2CFDFF |CALL <ocrackme.取字符串长度> ; 计算注册码长度,在返回值EAX中
00430CF9 |. 2BC3 |SUB EAX,EBX
00430CFB |. 8B55 FC |MOV EDX,DWORD PTR SS:[EBP-4] ; 注册码送EDX
00430CFE |. 8A5402 FF |MOV DL,BYTE PTR DS:[EDX+EAX-1] ; 从最后一位开始取注册码的每个字符
00430D02 |. 8D45 E4 |LEA EAX,DWORD PTR SS:[EBP-1C]
00430D05 |. E8 562BFDFF |CALL ocrackme.00403860
00430D0A |. 8B55 E4 |MOV EDX,DWORD PTR SS:[EBP-1C] ; 这个循环倒叙取出注册码并保存到一个位置。可由堆栈ebp-c中看出
00430D0D |. 8D45 F4 |LEA EAX,DWORD PTR SS:[EBP-C]
00430D10 |. E8 2B2CFDFF |CALL ocrackme.00403940
00430D15 |. 43 |INC EBX
00430D16 |> 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4] ; 输入的注册码送EAX
00430D19 |. E8 1A2CFDFF |CALL <ocrackme.取字符串长度> ; 取输入的注册码长度
00430D1E |. 3BD8 |CMP EBX,EAX ; 是否已到注册码最后
00430D20 |.^ 7C CF \JL SHORT ocrackme.00430CF1 ; 未到最后则继续循环
00430D22 |. BB 01000000 MOV EBX,1
00430D27 |. EB 36 JMP SHORT ocrackme.00430D5F
00430D29 |> FF75 EC /PUSH DWORD PTR SS:[EBP-14] ; 这个循环是顺序取每个字符,并得到每个字符的十进制数
00430D2C |. 8D45 E4 |LEA EAX,DWORD PTR SS:[EBP-1C] ; 在ebp-14中存放,取得位数是字符长度减一
00430D2F |. 8B55 FC |MOV EDX,DWORD PTR SS:[EBP-4]
00430D32 |. 8A541A FF |MOV DL,BYTE PTR DS:[EDX+EBX-1]
00430D36 |. E8 252BFDFF |CALL ocrackme.00403860
00430D3B |. FF75 E4 |PUSH DWORD PTR SS:[EBP-1C]
00430D3E |. 8D55 E0 |LEA EDX,DWORD PTR SS:[EBP-20]
00430D41 |. 8B45 F4 |MOV EAX,DWORD PTR SS:[EBP-C]
00430D44 |. 0FB64418 FF |MOVZX EAX,BYTE PTR DS:[EAX+EBX-1]
00430D49 |. E8 2A5AFDFF |CALL ocrackme.00406778
00430D4E |. FF75 E0 |PUSH DWORD PTR SS:[EBP-20]
00430D51 |. 8D45 EC |LEA EAX,DWORD PTR SS:[EBP-14]
00430D54 |. BA 03000000 |MOV EDX,3
00430D59 |. E8 9A2CFDFF |CALL ocrackme.004039F8
00430D5E |. 43 |INC EBX
00430D5F |> 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4]
00430D62 |. E8 D12BFDFF |CALL <ocrackme.取字符串长度>
00430D67 |. 3BD8 |CMP EBX,EAX
00430D69 |.^ 7C BE \JL SHORT ocrackme.00430D29
00430D6B |. BB 01000000 MOV EBX,1
00430D70 |. 8D45 F4 LEA EAX,DWORD PTR SS:[EBP-C]
00430D73 |. E8 4429FDFF CALL ocrackme.004036BC
00430D78 |. EB 4D JMP SHORT ocrackme.00430DC7
00430D7A |> 8D45 DC /LEA EAX,DWORD PTR SS:[EBP-24]
00430D7D |. 8B55 EC |MOV EDX,DWORD PTR SS:[EBP-14] ; 这个循环是将上面ebp-14中的字符去掉首尾和最后一位后,
00430D80 |. 8A141A |MOV DL,BYTE PTR DS:[EDX+EBX] ; 每个字符在重复一遍,比如字符:a102b101,结果就是:110022bb1100
00430D83 |. 8850 01 |MOV BYTE PTR DS:[EAX+1],DL
00430D86 |. C600 01 |MOV BYTE PTR DS:[EAX],1
00430D89 |. 8D55 DC |LEA EDX,DWORD PTR SS:[EBP-24]
00430D8C |. 8D45 D8 |LEA EAX,DWORD PTR SS:[EBP-28]
00430D8F |. E8 581AFDFF |CALL ocrackme.004027EC
00430D94 |. 8D45 D4 |LEA EAX,DWORD PTR SS:[EBP-2C]
00430D97 |. 8B55 EC |MOV EDX,DWORD PTR SS:[EBP-14]
00430D9A |. 8A141A |MOV DL,BYTE PTR DS:[EDX+EBX]
00430D9D |. 8850 01 |MOV BYTE PTR DS:[EAX+1],DL
00430DA0 |. C600 01 |MOV BYTE PTR DS:[EAX],1
00430DA3 |. 8D55 D4 |LEA EDX,DWORD PTR SS:[EBP-2C]
00430DA6 |. 8D45 D8 |LEA EAX,DWORD PTR SS:[EBP-28]
00430DA9 |. B1 02 |MOV CL,2
00430DAB |. E8 0C1AFDFF |CALL ocrackme.004027BC
00430DB0 |. 8D55 D8 |LEA EDX,DWORD PTR SS:[EBP-28]
00430DB3 |. 8D45 F0 |LEA EAX,DWORD PTR SS:[EBP-10]
00430DB6 |. E8 212BFDFF |CALL ocrackme.004038DC
00430DBB |. 8D45 F4 |LEA EAX,DWORD PTR SS:[EBP-C]
00430DBE |. 8B55 F0 |MOV EDX,DWORD PTR SS:[EBP-10]
00430DC1 |. E8 7A2BFDFF |CALL ocrackme.00403940
00430DC6 |. 43 |INC EBX
00430DC7 |> 8B45 EC MOV EAX,DWORD PTR SS:[EBP-14]
00430DCA |. E8 692BFDFF |CALL <ocrackme.取字符串长度>
00430DCF |. 48 |DEC EAX
00430DD0 |. 3BD8 |CMP EBX,EAX
00430DD2 |.^ 7C A6 \JL SHORT ocrackme.00430D7A
00430DD4 |. BB 01000000 MOV EBX,1
00430DD9 |. 8D45 EC LEA EAX,DWORD PTR SS:[EBP-14]
00430DDC |. E8 DB28FDFF CALL ocrackme.004036BC
00430DE1 |. EB 1C JMP SHORT ocrackme.00430DFF
00430DE3 |> 8D55 E4 /LEA EDX,DWORD PTR SS:[EBP-1C] ; 这个循环是将上见的重复后的字符每位的ASCII码值转换为10进制保存,但最后一位不转换
00430DE6 |. 8B45 F4 |MOV EAX,DWORD PTR SS:[EBP-C]
00430DE9 |. 0FB64418 FF |MOVZX EAX,BYTE PTR DS:[EAX+EBX-1]
00430DEE |. E8 8559FDFF |CALL ocrackme.00406778
00430DF3 |. 8B55 E4 |MOV EDX,DWORD PTR SS:[EBP-1C]
00430DF6 |. 8D45 EC |LEA EAX,DWORD PTR SS:[EBP-14]
00430DF9 |. E8 422BFDFF |CALL ocrackme.00403940
00430DFE |. 43 |INC EBX
00430DFF |> 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C]
00430E02 |. E8 312BFDFF |CALL <ocrackme.取字符串长度>
00430E07 |. 3BD8 |CMP EBX,EAX
00430E09 |.^ 7C D8 \JL SHORT ocrackme.00430DE3
00430E0B |. BB 03000000 MOV EBX,3
00430E10 |. 8D45 F4 LEA EAX,DWORD PTR SS:[EBP-C]
00430E13 |. E8 A428FDFF CALL ocrackme.004036BC
00430E18 |. 83FB 30 CMP EBX,30
00430E1B |. 7D 22 JGE SHORT ocrackme.00430E3F
00430E1D |> 8D45 E4 /LEA EAX,DWORD PTR SS:[EBP-1C]
00430E20 |. 8B55 EC |MOV EDX,DWORD PTR SS:[EBP-14]
00430E23 |. 8A541A FF |MOV DL,BYTE PTR DS:[EDX+EBX-1]
00430E27 |. E8 342AFDFF |CALL ocrackme.00403860
00430E2C |. 8B55 E4 |MOV EDX,DWORD PTR SS:[EBP-1C]
00430E2F |. 8D45 F4 |LEA EAX,DWORD PTR SS:[EBP-C]
00430E32 |. E8 092BFDFF |CALL ocrackme.00403940
00430E37 |. 83C3 03 |ADD EBX,3
00430E3A |. 83FB 30 |CMP EBX,30
00430E3D |.^ 7C DE \JL SHORT ocrackme.00430E1D
00430E3F |> BB 01000000 MOV EBX,1
00430E44 |. EB 5B JMP SHORT ocrackme.00430EA1
00430E46 |> 8B45 FC /MOV EAX,DWORD PTR SS:[EBP-4]
00430E49 |. E8 EA2AFDFF |CALL <ocrackme.取字符串长度>
00430E4E |. 03C3 |ADD EAX,EBX
00430E50 |. 8B55 EC |MOV EDX,DWORD PTR SS:[EBP-14]
00430E53 |. 8A5402 FD |MOV DL,BYTE PTR DS:[EDX+EAX-3]
00430E57 |. 8D45 E4 |LEA EAX,DWORD PTR SS:[EBP-1C]
00430E5A |. E8 012AFDFF |CALL ocrackme.00403860 ; 将DL从复制到一个地方
00430E5F |. 8B45 E4 |MOV EAX,DWORD PTR SS:[EBP-1C]
00430E62 |. E8 4159FDFF |CALL ocrackme.004067A8 ; 取得DL的十进制值,在eax
00430E67 |. 50 |PUSH EAX
00430E68 |. 8D45 E4 |LEA EAX,DWORD PTR SS:[EBP-1C]
00430E6B |. 8B55 F4 |MOV EDX,DWORD PTR SS:[EBP-C] ; 第五个字符串送EDX
00430E6E |. 8A541A FF |MOV DL,BYTE PTR DS:[EDX+EBX-1] ; 依次取出每一位
00430E72 |. E8 E929FDFF |CALL ocrackme.00403860
00430E77 |. 8B45 E4 |MOV EAX,DWORD PTR SS:[EBP-1C] ; DL的值复制到其他地方
00430E7A |. E8 2959FDFF |CALL ocrackme.004067A8 ; 也转换成10进制
00430E7F |. 5A |POP EDX
00430E80 |. 2BC2 |SUB EAX,EDX
00430E82 |. 99 |CDQ
00430E83 |. 33C2 |XOR EAX,EDX
00430E85 |. 2BC2 |SUB EAX,EDX
00430E87 |. 8D55 E8 |LEA EDX,DWORD PTR SS:[EBP-18]
00430E8A |. E8 E958FDFF |CALL ocrackme.00406778
00430E8F |. 8D45 F4 |LEA EAX,DWORD PTR SS:[EBP-C]
00430E92 |. E8 712CFDFF |CALL ocrackme.00403B08
00430E97 |. 8B55 E8 |MOV EDX,DWORD PTR SS:[EBP-18]
00430E9A |. 8A12 |MOV DL,BYTE PTR DS:[EDX]
00430E9C |. 885418 FF |MOV BYTE PTR DS:[EAX+EBX-1],DL
00430EA0 |. 43 |INC EBX
00430EA1 |> 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C]
00430EA4 |. E8 8F2AFDFF |CALL <ocrackme.取字符串长度>
00430EA9 |. 3BD8 |CMP EBX,EAX
00430EAB |.^ 7E 99 \JLE SHORT ocrackme.00430E46
00430EAD |. 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C]
00430EB0 |. 8B55 F8 MOV EDX,DWORD PTR SS:[EBP-8]
00430EB3 |. E8 902BFDFF CALL ocrackme.00403A48 ; 真假注册码比较
00430EB8 |. 75 0A JNZ SHORT ocrackme.00430EC4 ; 修改此处可以爆破
00430EBA |. B8 400F4300 MOV EAX,ocrackme.00430F40 ; You Got It!!! :)
00430EBF |. E8 78DCFFFF CALL ocrackme.0042EB3C
|
能力值:
( LV2,RANK:10 )
|
-
-
21 楼
CrackMe 2007->序列号->逍遥风->ThrawN的CrackMe 分析
输入注册名和注册码后无反应,后来发现不输入注册名时会提示字符要在2个字符以上,就查找这个字符串提示,来到关键断点处,注册名不能低于3个字符。
00444BFB |. 8BF8 MOV EDI,EAX
00444BFD |. 33C0 XOR EAX,EAX
00444BFF |. 55 PUSH EBP
00444C00 |. 68 EB4C4400 PUSH UP8.00444CEB
00444C05 |. 64:FF30 PUSH DWORD PTR FS:[EAX]
00444C08 |. 64:8920 MOV DWORD PTR FS:[EAX],ESP
00444C0B |. 8D55 FC LEA EDX,DWORD PTR SS:[EBP-4]
00444C0E |. 8B87 D0020000 MOV EAX,DWORD PTR DS:[EDI+2D0]
00444C14 |. E8 87F1FDFF CALL UP8.00423DA0 ; 取输入的用户名,【EBP-4】
00444C19 |. 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4]
00444C1C |. E8 3FEFFBFF CALL UP8.00403B60 ; 取用户名长度
00444C21 |. 83F8 03 CMP EAX,3 ; 判断用户名长度是否大于等于3
00444C24 |. 7D 15 JGE SHORT UP8.00444C3B
00444C26 |. 6A 00 PUSH 0 ; /Arg1 = 00000000
00444C28 |. 66:8B0D FC4C4>MOV CX,WORD PTR DS:[444CFC] ; |
00444C2F |. B2 01 MOV DL,1 ; |
00444C31 |. B8 084D4400 MOV EAX,UP8.00444D08 ; |Name must be more than 2 characters!
00444C36 |. E8 E5F9FFFF CALL UP8.00444620 ; \UP8.00444620
00444C3B |> 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4] ; 用户名送EAX
00444C3E |. E8 1DEFFBFF CALL UP8.00403B60 ; 该call返回用户名长度
00444C43 |. 8BD8 MOV EBX,EAX
00444C45 |. 85DB TEST EBX,EBX
00444C47 |. 7E 29 JLE SHORT UP8.00444C72
00444C49 |. BE 01000000 MOV ESI,1 ; ESI赋初值1
00444C4E |> 8D4D E8 /LEA ECX,DWORD PTR SS:[EBP-18]
00444C51 |. 8B45 FC |MOV EAX,DWORD PTR SS:[EBP-4] ; 用户名送EAX
00444C54 |. 0FB64430 FF |MOVZX EAX,BYTE PTR DS:[EAX+ESI-1] ; 取出用户名的每一位字符
00444C59 |. BA 02000000 |MOV EDX,2 ; EDX赋值0x2
00444C5E |. E8 BD2EFCFF |CALL UP8.00407B20 ; 从堆栈中可知是该call会是EBP-18等于上面取得的字符ascii码
00444C63 |. 8B55 E8 |MOV EDX,DWORD PTR SS:[EBP-18]
00444C66 |. 8D45 F8 |LEA EAX,DWORD PTR SS:[EBP-8]
00444C69 |. E8 FAEEFBFF |CALL UP8.00403B68 ; 将取出的每个字符的ASCII码合并
00444C6E |. 46 |INC ESI
00444C6F |. 4B |DEC EBX
00444C70 |.^ 75 DC \JNZ SHORT UP8.00444C4E
00444C72 |> 8D55 F0 LEA EDX,DWORD PTR SS:[EBP-10]
00444C75 |. A1 48784400 MOV EAX,DWORD PTR DS:[447848] ; 将【447848】的值送给EAX。
00444C7A |. E8 712EFCFF CALL UP8.00407AF0 ; 该call将EAX的值转换成有符号十进制表示%d
00444C7F |. 8D45 F4 LEA EAX,DWORD PTR SS:[EBP-C]
00444C82 |. 8B55 F8 MOV EDX,DWORD PTR SS:[EBP-8]
00444C85 |. E8 EEECFBFF CALL UP8.00403978 ; 将根据用户名字符计算的结果存于ebp-C
00444C8A |. 8D45 EC LEA EAX,DWORD PTR SS:[EBP-14]
00444C8D |. 8B4D F4 MOV ECX,DWORD PTR SS:[EBP-C]
00444C90 |. 8B55 F0 MOV EDX,DWORD PTR SS:[EBP-10]
00444C93 |. E8 14EFFBFF CALL UP8.00403BAC ; 将上面转换的十进制数和上面的结果按字符方式合并成一个
00444C98 |. 8D55 E4 LEA EDX,DWORD PTR SS:[EBP-1C]
00444C9B |. 8B87 D4020000 MOV EAX,DWORD PTR DS:[EDI+2D4]
00444CA1 |. E8 FAF0FDFF CALL UP8.00423DA0 ; 取出输入的假的注册码
00444CA6 |. 8B45 E4 MOV EAX,DWORD PTR SS:[EBP-1C]
00444CA9 |. 8B55 EC MOV EDX,DWORD PTR SS:[EBP-14]
00444CAC |. E8 BFEFFBFF CALL UP8.00403C70 ; 比较真假注册码是否相同
00444CB1 |. 75 15 JNZ SHORT UP8.00444CC8 ; 修改此处可以爆破
00444CB3 |. 6A 00 PUSH 0 ; /Arg1 = 00000000
00444CB5 |. 66:8B0D FC4C4>MOV CX,WORD PTR DS:[444CFC] ; |
00444CBC |. B2 02 MOV DL,2 ; |
00444CBE |. B8 384D4400 MOV EAX,UP8.00444D38 ; |Correct!
00444CC3 |. E8 58F9FFFF CALL UP8.00444620 ; \UP8.00444620
上面【447848】的值计算方法是:先取C:盘的序列号,再乘以2, 得值A,将A转换成10进制,取其第四位的数字和A相乘,得值B,B再乘以3的值就是送入【447848】的值。
反汇编分析如下:
00444B18 |. 64:8920 MOV DWORD PTR FS:[EAX],ESP
00444B1B |. 6A 00 PUSH 0 ; /pFileSystemNameSize = NULL
00444B1D |. 6A 00 PUSH 0 ; |pFileSystemNameBuffer = NULL
00444B1F |. 8D45 F0 LEA EAX,DWORD PTR SS:[EBP-10] ; |
00444B22 |. 50 PUSH EAX ; |pFileSystemFlags
00444B23 |. 8D45 F4 LEA EAX,DWORD PTR SS:[EBP-C] ; |
00444B26 |. 50 PUSH EAX ; |pMaxFilenameLength
00444B27 |. 56 PUSH ESI ; |pVolumeSerialNumber
00444B28 |. 68 00010000 PUSH 100 ; |MaxVolumeNameSize = 100 (256.)
00444B2D |. 8D85 F0FEFFFF LEA EAX,DWORD PTR SS:[EBP-110] ; |
00444B33 |. 50 PUSH EAX ; |VolumeNameBuffer
00444B34 |. 68 E84B4400 PUSH UP8.00444BE8 ; |c:\
00444B39 |. E8 2A15FCFF CALL <JMP.&KERNEL32.GetVolumeInformation>; \GetVolumeInformationA
00444B3E |. 8B06 MOV EAX,DWORD PTR DS:[ESI] ; 取的的c:\序列号送EAX
00444B40 |. 03C0 ADD EAX,EAX ; 序列号乘以2
00444B42 |. 8BF0 MOV ESI,EAX
00444B44 |. 8D95 ECFEFFFF LEA EDX,DWORD PTR SS:[EBP-114]
00444B4A |. 8BC6 MOV EAX,ESI
00444B4C |. E8 9F2FFCFF CALL UP8.00407AF0 ; 将序列号转换成10进制表示。
00444B51 |. 8B95 ECFEFFFF MOV EDX,DWORD PTR SS:[EBP-114] ; EBP-114中就是转换成的10进制
00444B57 |. 8B83 E8020000 MOV EAX,DWORD PTR DS:[EBX+2E8]
00444B5D |. E8 6EF2FDFF CALL UP8.00423DD0 ; 再将10进制数转换成字符串保存
00444B62 |. 8D55 F8 LEA EDX,DWORD PTR SS:[EBP-8]
00444B65 |. 8B83 E8020000 MOV EAX,DWORD PTR DS:[EBX+2E8]
00444B6B |. E8 30F2FDFF CALL UP8.00423DA0
00444B70 |. 8D45 FC LEA EAX,DWORD PTR SS:[EBP-4]
00444B73 |. 8B55 F8 MOV EDX,DWORD PTR SS:[EBP-8]
00444B76 |. 8A52 03 MOV DL,BYTE PTR DS:[EDX+3] ; 十进制数的第4位送DL,从0开始的话就是第三位
00444B79 |. E8 0AEFFBFF CALL UP8.00403A88
00444B7E |. 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4]
00444B81 |. E8 D62FFCFF CALL UP8.00407B5C ; 取出并转换成数字,
00444B86 |. F7EE IMUL ESI ; 将上面序列号乘以2后的值再乘以转换成10进制数的第四位。
00444B88 |. 8D0440 LEA EAX,DWORD PTR DS:[EAX+EAX*2] ; 再乘以0x3
00444B8B |. A3 48784400 MOV DWORD PTR DS:[447848],EAX ; 将结果送入【447848】,用于后面注册码的计算
贴出一组正确的注册码:用户名“pediy”,注册码是:“-1670752387065646979”
算法见注册机中注释
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <windows.h>
int sn();
int main(void)
{
//这个的算法也很简单,注册码是由2个字符串合并得到的,第一个字符串
//是先求出c盘的序列号并*2,得值A,将A转换成10进制取第四位数字和A相乘后再乘以0x3所得的值按10进制输出。
//第二部分是将输入的用户名的每个字符的ASCII码(16进制表示)转换成字符串
//如用户名“pediy”,注册码是:“-1670752387065646979”
char name[]={"pediy"};
printf("注册名:%s\n",name);
printf("注册码:%d",sn()); //输出根据序列号计算出的值。
int namelen=strlen(name);
int i;
for (i=0;i<namelen;i++) //此处就不转换成字符串了,直接打印输出。
{
printf("%LX",name[i]); //此处必须是“X”,因为小写的得到的注册码是错误的
}
printf("\n\n");
getchar();
return 0;
}
int sn() //取硬盘序列号并计算出一个值
{
char pathName[]={"c:\\"};
char vName[255];
char fName[255];
unsigned long int Serial;
GetVolumeInformation(pathName,vName,255,&Serial,0,0,fName,255);
Serial=Serial*2; //序列号*2
char buffer[255];
itoa(Serial,buffer,10);//转换成10进制
char n=buffer[3]-0x30; //取其第三位,得的值是该数字的ascii码-0x30
Serial=Serial*n; //和上面的数字相乘
Serial=Serial*0x3; //再乘以3
return Serial;
}
|
能力值:
( LV2,RANK:10 )
|
-
-
22 楼
谢谢楼主分享。
|
能力值:
( LV2,RANK:10 )
|
-
-
23 楼
CrackMe 2007->序列号->逍遥风->DTC。CrackMe10 分析
查找字符串,来到以下地方,分析如下:脱壳用论坛上的软件脱的
0040119B . 6A 33 PUSH 33 ; /Count = 33 (51.)
0040119D . 68 2C624000 PUSH keygenme.0040622C ; |Buffer = keygenme.0040622C
004011A2 . 68 D1070000 PUSH 7D1 ; |ControlID = 7D1 (2001.)
004011A7 . FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hWnd
004011AA . E8 AF010000 CALL <JMP.&user32.GetDlgItemTextA> ; \取输入的用户名
004011AF . 6BC0 05 IMUL EAX,EAX,5 ; 用户名长度*0x5;
004011B2 . 3D FA000000 CMP EAX,0FA ; 是否大于等于0x0FA
004011B7 . 0F87 89000000 JA keygenme.00401246 ; 是否小于等于0x1E,即用户名长度大于5小于50;
004011BD . 83F8 1E CMP EAX,1E
004011C0 . 0F82 80000000 JB keygenme.00401246
004011C6 . 6A 00 PUSH 0 ; /IsSigned = FALSE
004011C8 . 6A 00 PUSH 0 ; |pSuccess = NULL
004011CA . 68 D2070000 PUSH 7D2 ; |ControlID = 7D2 (2002.)
004011CF . FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hWnd
004011D2 . E8 81010000 CALL <JMP.&user32.GetDlgItemInt> ; \GetDlgItemInt
004011D7 . A3 5F624000 MOV DWORD PTR DS:[40625F],EAX ; 取注册码输入框中的值,看来一定要输入数字
004011DC . 68 2C624000 PUSH keygenme.0040622C
004011E1 . E8 C2000000 CALL keygenme.004012A8 ; 关键call跟进。
004011E6 . 803D 63624000>CMP BYTE PTR DS:[406263],1 ; 关键call中会对【406263】设置个标志,在这判断
004011ED . 74 43 JE SHORT keygenme.00401232 ; 若为“1”就跳到失败处,否则成功。
关键算法call跟进后如下:
004012A8 /$ 55 PUSH EBP
004012A9 |. 8BEC MOV EBP,ESP
004012AB |. 803D B4124000>CMP BYTE PTR DS:[4012B4],0CC
004012B2 |. 74 53 JE SHORT keygenme.00401307
004012B4 |. 33C0 XOR EAX,EAX
004012B6 |. 33C9 XOR ECX,ECX
004012B8 |. 803D D4124000>CMP BYTE PTR DS:[4012D4],0CC
004012BF |. 74 46 JE SHORT keygenme.00401307
004012C1 |. 33D2 XOR EDX,EDX
004012C3 |. 8B55 08 MOV EDX,DWORD PTR SS:[EBP+8] ; EDX是输入的用户名
004012C6 |> 8A02 /MOV AL,BYTE PTR DS:[EDX] ; 依次取出注册名的每一个字符送入AL
004012C8 |. 84C0 |TEST AL,AL ; 字符是否取完?
004012CA |. 74 08 |JE SHORT keygenme.004012D4 ; 取完则跳出循环
004012CC |. 03C8 |ADD ECX,EAX
004012CE |. C1C1 08 |ROL ECX,8
004012D1 |. 42 |INC EDX
004012D2 |.^ EB F2 \JMP SHORT keygenme.004012C6
004012D4 |> 83F1 02 XOR ECX,2
004012D7 |. 83E9 50 SUB ECX,50
004012DA |. 81F1 37130000 XOR ECX,1337
004012E0 |. 56 PUSH ESI
004012E1 |. 66:8B35 79614>MOV SI,WORD PTR DS:[406179]
004012E8 |. 66:03CE ADD CX,SI
004012EB |. 803D FA124000>CMP BYTE PTR DS:[4012FA],0CC
004012F2 |. 74 13 JE SHORT keygenme.00401307
004012F4 |. 5E POP ESI
004012F5 |. A1 5F624000 MOV EAX,DWORD PTR DS:[40625F] 【40625f】存放的是先前取得的注册码,是一个16进制数字。
004012FA |. 3BC1 CMP EAX,ECX
004012FC |. 75 04 JNZ SHORT keygenme.00401302
004012FE |. 33C0 XOR EAX,EAX
00401300 |. EB 0E JMP SHORT keygenme.00401310
00401302 |> 33C0 XOR EAX,EAX
00401304 |. 40 INC EAX
00401305 |. EB 10 JMP SHORT keygenme.00401317
00401307 |> C605 63624000>MOV BYTE PTR DS:[406263],1
0040130E |. EB 07 JMP SHORT keygenme.00401317
00401310 |> C605 63624000>MOV BYTE PTR DS:[406263],0
00401317 |> C9 LEAVE
00401318 \. C2 0400 RETN 4
算法:用户名长度大于5小于50位,注册码必须是数字,根据用户名计算出一个值,然后和输入的注册码比较,相等就在一个位置置0,不相等就置1,然后判断该位置的值。
做这个的时候要用到循环移位,但是c语言中的移位运算符并不是循环移位的,后来在网上搜到一个代码
假设移位的数字在ecx中:
if (ecx & 0x80000000)
{
ecx=ecx<<1;
ecx=ecx | 0x01;
}
else
ecx=ecx<<1;
}
一组正确的注册码:abcdef 1690755840
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <windows.h>
int main(void)
{
char name[]={"abcdef"};
int i,j,namelen;
unsigned long int ecx,eax;
eax=0;
ecx=0;
namelen=strlen(name);
for (i=0;i<namelen;i++)
{
eax=name[i];
ecx=ecx+eax;
for (j=0;j<8;j++)
{
if (ecx & 0x80000000) //循环左移一位运算,
{
ecx=ecx<<1;
ecx=ecx | 0x01;
}
else
ecx=ecx<<1;
}
}
ecx=ecx^0x2;
ecx=ecx-0x50;
ecx=ecx^0x1337;
ecx=ecx+0x07DA;
printf("注册名:%s\n",name);
printf("注册码:%d\n",ecx);
printf("\n\n");
getchar();
return 0;
}
|
能力值:
( LV2,RANK:10 )
|
-
-
24 楼
CrackMe 2007->序列号->逍遥风->Rith—CrackMe1 分析
一组正确的注册码:ABCDEF f6d2bh
不知这个cm有问题还是程序有问题,还是我分析的不彻底,有人知道的话请指出。计算出来的值如果超过0x7F的话就是错误的注册码,全部都小于0x7F时才正确,也就是超过了ascii表的范围显示出来的就不正确。注册名不能小于5位,注册码和注册名位数要相同,取出注册名的每一位和固定字串中的每一位后计算出一个值。
0040159A . 56 PUSH ESI
0040159B . 8BF1 MOV ESI,ECX
0040159D . 57 PUSH EDI
0040159E . 68 48304000 PUSH Rith_Cra.00403048 ; 31415926535897932384
004015A3 . 8D4C24 14 LEA ECX,DWORD PTR SS:[ESP+14]
004015A7 . 897424 1C MOV DWORD PTR SS:[ESP+1C],ESI
004015AB . E8 FA020000 CALL <JMP.&MFC42.#537>
004015B0 . 6A 01 PUSH 1
004015B2 . 8BCE MOV ECX,ESI
004015B4 . C74424 28 000>MOV DWORD PTR SS:[ESP+28],0
004015BC . E8 E3020000 CALL <JMP.&MFC42.#6334>
004015C1 . 8B7E 60 MOV EDI,DWORD PTR DS:[ESI+60] ; 取得用户名,送EDI
004015C4 . 8B5F F8 MOV EBX,DWORD PTR DS:[EDI-8] ; 用户名长度送EBX
004015C7 . 83FB 05 CMP EBX,5 ; EBX中用户名长度不能小于5
004015CA . 7C 7E JL SHORT Rith_Cra.0040164A
004015CC . 8B46 64 MOV EAX,DWORD PTR DS:[ESI+64] ; 注册码送EAX
004015CF . 894424 14 MOV DWORD PTR SS:[ESP+14],EAX
004015D3 . 3958 F8 CMP DWORD PTR DS:[EAX-8],EBX ; 比较用户名长度和注册码长度
004015D6 . 75 72 JNZ SHORT Rith_Cra.0040164A ; 不等就跳走
004015D8 . 83FB 14 CMP EBX,14 ; 用户名长度是否大于0x14,是否大于20位
004015DB . 7F 6D JG SHORT Rith_Cra.0040164A
004015DD . 33C9 XOR ECX,ECX
004015DF . 85DB TEST EBX,EBX
004015E1 . 7E 54 JLE SHORT Rith_Cra.00401637
004015E3 . 8B7424 10 MOV ESI,DWORD PTR SS:[ESP+10] ; 取字串“31415926535897932384”
004015E7 > 8A040F MOV AL,BYTE PTR DS:[EDI+ECX] ; 逐位取出用户名
004015EA . 0FBE2C31 MOVSX EBP,BYTE PTR DS:[ECX+ESI] ; 逐位取出刚才字串中的字符
004015EE . 0FBEC0 MOVSX EAX,AL
004015F1 . 99 CDQ
004015F2 . F7FD IDIV EBP
004015F4 . 8BC2 MOV EAX,EDX ; 2个字符ascii码相除
004015F6 . D1E0 SHL EAX,1 ; 商值乘以0x2,左移一位相当于*2
004015F8 . 83F8 7B CMP EAX,7B
004015FB . 7E 03 JLE SHORT Rith_Cra.00401600
004015FD . 83E8 1A SUB EAX,1A ; 若大于0x7B,就减去0x1A
00401600 > 83F8 41 CMP EAX,41
00401603 . 7D 09 JGE SHORT Rith_Cra.0040160E
00401605 . BA 82000000 MOV EDX,82 ; 是否小于0x41,小的话就0x82-该值
0040160A . 2BD0 SUB EDX,EAX
0040160C . 8BC2 MOV EAX,EDX
0040160E > 83F8 5B CMP EAX,5B
00401611 . 7E 12 JLE SHORT Rith_Cra.00401625
00401613 . 83F8 61 CMP EAX,61 ; 若<=0x5B 且 >=0x61 就跳到下面
00401616 . 7D 0D JGE SHORT Rith_Cra.00401625
00401618 . 99 CDQ
00401619 . BD 0A000000 MOV EBP,0A
0040161E . F7FD IDIV EBP
00401620 . 83C2 30 ADD EDX,30
00401623 . 8BC2 MOV EAX,EDX
00401625 > 8B5424 14 MOV EDX,DWORD PTR SS:[ESP+14]
00401629 . 38040A CMP BYTE PTR DS:[EDX+ECX],AL
0040162C . 75 1C JNZ SHORT Rith_Cra.0040164A
0040162E . 41 INC ECX
0040162F . 3BCB CMP ECX,EBX
00401631 .^ 7C B4 JL SHORT Rith_Cra.004015E7
00401633 . 8B7424 18 MOV ESI,DWORD PTR SS:[ESP+18]
00401637 > 6A 00 PUSH 0
00401639 . 68 34304000 PUSH Rith_Cra.00403034 ; Congratulations!
0040163E . 68 20304000 PUSH Rith_Cra.00403020 ; Well done cracker!
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <windows.h>
int main(void)
{
char name[]={"ABCDEF"};
//不知这个cm有问题还是程序有问题,计算出来的值如果超过0x7F的话就是错误
//的注册码,全部都小于0x7F时才正确,也就是超过了ascii表的范围。
//注册名不能小于5位,注册码和注册名位数要相同,取出注册名的每一位和
//固定字串中的每一位后计算出一个值。
printf("注册名:%s\n",name);
printf("注册名:");
char table[]={"31415926535897932384"};
int i,j,namelen,tablelen;
int eax,ebx,ecx,edx,ebp;
namelen=strlen(name);
tablelen=strlen(table);
for (i=0;i<namelen;i++)
{
eax=name[i];
ebp=table[i];
edx=0;
edx=eax % ebp;
eax=edx;
eax=eax*0x2;
if (eax>0x7B)
{
eax=eax-0x1A;
}
if (eax<0x41)
{
eax=0x82-eax;
}
if (eax>0x5B )
{
if (eax<0x61)
{
edx=0;
ebp=0x0A;
edx=eax % ebp;
edx=edx+0x30;
eax=edx;
}
}
printf("%c",eax);
}
printf("\n\n");
getchar();
return 0;
}
|
能力值:
( LV2,RANK:10 )
|
-
-
25 楼
CrackMe 2007->序列号->逍遥风->CodeFantasy CrackMe 分析
OD载入程序,用“超级字符串查找”发现有注册成功的提示,下断点,跟踪如下:
00408DDC |> \68 FF000000 PUSH 0FF ; /Count = FF (255.); Case 3EA of switch 00408DBB
00408DE1 |. 68 9CA24000 PUSH CodeFant.0040A29C ; |Buffer = CodeFant.0040A29C
00408DE6 |. 68 F2030000 PUSH 3F2 ; |ControlID = 3F2 (1010.)
00408DEB |. 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8] ; |
00408DEE |. 50 PUSH EAX ; |hWnd
00408DEF |. E8 68B9FFFF CALL <JMP.&user32.GetDlgItemTextA> ; \取用户名
00408DF4 |. 8D45 B4 LEA EAX,DWORD PTR SS:[EBP-4C]
00408DF7 |. BA 9CA24000 MOV EDX,CodeFant.0040A29C
00408DFC |. B9 FF000000 MOV ECX,0FF
00408E01 |. E8 6AAAFFFF CALL CodeFant.00403870
00408E06 |. 837D B4 00 CMP DWORD PTR SS:[EBP-4C],0 ; 用户名不为空
00408E0A |. 0F84 9E000000 JE CodeFant.00408EAE
00408E10 |. 68 FF000000 PUSH 0FF ; /Count = FF (255.)
00408E15 |. 68 9CA34000 PUSH CodeFant.0040A39C ; |Buffer = CodeFant.0040A39C
00408E1A |. 68 F3030000 PUSH 3F3 ; |ControlID = 3F3 (1011.)
00408E1F |. 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8] ; |
00408E22 |. 50 PUSH EAX ; |hWnd
00408E23 |. E8 34B9FFFF CALL <JMP.&user32.GetDlgItemTextA> ; \取输入的注册码
00408E28 |. 8D45 AC LEA EAX,DWORD PTR SS:[EBP-54]
00408E2B |. BA 9CA24000 MOV EDX,CodeFant.0040A29C
00408E30 |. B9 FF000000 MOV ECX,0FF
00408E35 |. E8 36AAFFFF CALL CodeFant.00403870
00408E3A |. 8B45 AC MOV EAX,DWORD PTR SS:[EBP-54]
00408E3D |. 8D55 B0 LEA EDX,DWORD PTR SS:[EBP-50]
00408E40 |. E8 23FCFFFF CALL CodeFant.00408A68 ; 关键call,根据用户名计算一个值
00408E45 |. 8B45 B0 MOV EAX,DWORD PTR SS:[EBP-50]
00408E48 |. 50 PUSH EAX
00408E49 |. 8D45 A8 LEA EAX,DWORD PTR SS:[EBP-58]
00408E4C |. BA 9CA34000 MOV EDX,CodeFant.0040A39C
00408E51 |. B9 FF000000 MOV ECX,0FF
00408E56 |. E8 15AAFFFF CALL CodeFant.00403870
00408E5B |. 8B55 A8 MOV EDX,DWORD PTR SS:[EBP-58]
00408E5E |. 58 POP EAX
00408E5F |. E8 84ABFFFF CALL CodeFant.004039E8
00408E64 |. 75 48 JNZ SHORT CodeFant.00408EAE
00408E66 |. 6A 40 PUSH 40 ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
00408E68 |. 68 AC8F4000 PUSH CodeFant.00408FAC ; |注册提示
00408E6D |. 68 B88F4000 PUSH CodeFant.00408FB8 ; |恭喜您,注册码正确!
00408E72 |. 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8] ; |
00408E75 |. 50 PUSH EAX ; |hOwner
00408E76 |. E8 19B9FFFF CALL <JMP.&user32.MessageBoxA> ; \MessageBoxA
注册码计算的关键call就不贴了,计算过程如下:分别取出用户名的每一位,其ascii码值+0xA,并转换成16进制表示,且16进制的字母用大写表示,把用户名的所有字符都转换完后就得到了注册码。如:pediy 对应的注册码:7A6F6E7383 p的ascii值0x70 加上0xA 得0x7A,以此类推,y的ascii码:0x79,加0xA后是0x83;
注册机:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char name[]={"pediy"};
int i;
int namelen=strlen(name);
printf("注册名:%s\n",name);
printf("注册码:");
for (i=0;i<namelen;i++)
{
printf("%X",name[i]+0xA);
}
getchar();
return 0;
}
|
|
|