└文章标题┐:一个取磁盘卷序列号CrackMe简单分析
└破文作者┐:-=>大菜<=-我啦`
└破解对象┐:附件中..
└下载地址┐:附件中..
└对象大小┐:不知
└加壳方式┐:upx
└保护方式┐:序列号
└编写语言┐:delphi
└使用工具┐:od
└破解平台┐:D版XP
└破解声明┐:西西```Crack真好玩也!"
----------------------------------------------------------------------------------
└破解过程┐:
这个东东算法一点都不难,主要是取磁盘卷序列号,刚开始得到注册码时还不知道那个字符串从哪算出来滴咧,哦呵呵,无意中让偶看到一个函数,呵`-`没提示信息的CrackMe,我们找到correct!这个成功字串:
00444BEC /. 55 push ebp //断在这里
00444BED |. 8BEC mov ebp, esp
00444BEF |. 33C9 xor ecx, ecx
00444BF1 |. 51 push ecx
00444BF2 |. 51 push ecx
00444BF3 |. 51 push ecx
00444BF4 |. 51 push ecx
00444BF5 |. 51 push ecx
00444BF6 |. 51 push ecx
00444BF7 |. 51 push ecx
00444BF8 |. 53 push ebx
00444BF9 |. 56 push esi
00444BFA |. 57 push edi
00444BFB |. 8BF8 mov edi, eax
00444BFD |. 33C0 xor eax, eax
00444BFF |. 55 push ebp
00444C00 |. 68 EB4C4400 push 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 [ebp-4]
00444C0E |. 8B87 D0020000 mov eax, dword ptr [edi+2D0]
00444C14 |. E8 87F1FDFF call 00423DA0 //取注册名
00444C19 |. 8B45 FC mov eax, dword ptr [ebp-4] //注册名到eax
00444C1C |. E8 3FEFFBFF call 00403B60 //取注册名长度
00444C21 |. 83F8 03 cmp eax, 3 //和3比较
00444C24 |. 7D 15 jge short 00444C3B //小于3出错
00444C26 |. 6A 00 push 0 ; /Arg1 = 00000000
00444C28 |. 66:8B0D FC4C4>mov cx, word ptr [444CFC] ; |
00444C2F |. B2 01 mov dl, 1 ; |
00444C31 |. B8 084D4400 mov eax, 00444D08 ; |name must be more than 2 characters!
00444C36 |. E8 E5F9FFFF call 00444620 ; \crackme8.00444620
00444C3B |> 8B45 FC mov eax, dword ptr [ebp-4]
00444C3E |. E8 1DEFFBFF call 00403B60 //取注册名长度
00444C43 |. 8BD8 mov ebx, eax //长度传到ebx
00444C45 |. 85DB test ebx, ebx
00444C47 |. 7E 29 jle short 00444C72
00444C49 |. BE 01000000 mov esi, 1 //1传到esi,用于指针偏移
00444C4E |> 8D4D E8 /lea ecx, dword ptr [ebp-18]
00444C51 |. 8B45 FC |mov eax, dword ptr [ebp-4]
00444C54 |. 0FB64430 FF |movzx eax, byte ptr [eax+esi-1] //取注册名各个字符
00444C59 |. BA 02000000 |mov edx, 2
00444C5E |. E8 BD2EFCFF |call 00407B20 //注册名字符依次格式化为大写十六进制字符串
00444C63 |. 8B55 E8 |mov edx, dword ptr [ebp-18]
00444C66 |. 8D45 F8 |lea eax, dword ptr [ebp-8]
00444C69 |. E8 FAEEFBFF |call 00403B68 //每次都连接起来
00444C6E |. 46 |inc esi //指针偏移1,指向下一个字符
00444C6F |. 4B |dec ebx //计数器减一
00444C70 |.^ 75 DC \jnz short 00444C4E //ebx不为0就跳上去
00444C72 |> 8D55 F0 lea edx, dword ptr [ebp-10]
00444C75 |. A1 48784400 mov eax, dword ptr [447848]
00444C7A |. E8 712EFCFF call 00407AF0 //这个call,经过之后在堆栈中可以看到算好的磁盘卷序列号
00444C7F |. 8D45 F4 lea eax, dword ptr [ebp-C]
00444C82 |. 8B55 F8 mov edx, dword ptr [ebp-8] //上面连接起来的注册名的字符串到edx
00444C85 |. E8 EEECFBFF call 00403978
00444C8A |. 8D45 EC lea eax, dword ptr [ebp-14]
00444C8D |. 8B4D F4 mov ecx, dword ptr [ebp-C]
00444C90 |. 8B55 F0 mov edx, dword ptr [ebp-10]
00444C93 |. E8 14EFFBFF call 00403BAC //把算好的磁盘卷序列号和算好的注册名字符串连起来,就是注册码了
00444C98 |. 8D55 E4 lea edx, dword ptr [ebp-1C]
00444C9B |. 8B87 D4020000 mov eax, dword ptr [edi+2D4]
00444CA1 |. E8 FAF0FDFF call 00423DA0
00444CA6 |. 8B45 E4 mov eax, dword ptr [ebp-1C] //假码到eax
00444CA9 |. 8B55 EC mov edx, dword ptr [ebp-14] //真码到edx
00444CAC |. E8 BFEFFBFF call 00403C70 //对比一下
00444CB1 |. 75 15 jnz short 00444CC8 //相等不跳,直接到下面提示
00444CB3 |. 6A 00 push 0 ; /Arg1 = 00000000
00444CB5 |. 66:8B0D FC4C4>mov cx, word ptr [444CFC] ; |
00444CBC |. B2 02 mov dl, 2 ; |
00444CBE |. B8 384D4400 mov eax, 00444D38 ; |correct!
00444CC3 |. E8 58F9FFFF call 00444620 ; \crackme8.00444620
**********************************************************************************************
下面是取磁盘卷序列的地方,我看到的函数是GetVolumeInformationA(获取与一个磁盘卷有关的信息).
f2得新载入,下断bp GetVolumeInformationA,断在7c827052处,alt+f9返回一下,到达GetVolumeInformationA调用的下一条语句,记下地址
00444B1B |. 6A 00 push 0 ; /pFileSystemNameSize = NULL //记下这个地址
00444B1D |. 6A 00 push 0 ; |pFileSystemNameBuffer = NULL
00444B1F |. 8D45 F0 lea eax, dword ptr [ebp-10] ; |
00444B22 |. 50 push eax ; |pFileSystemFlags
00444B23 |. 8D45 F4 lea eax, dword ptr [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 [ebp-110] ; |
00444B33 |. 50 push eax ; |VolumeNameBuffer
00444B34 |. 68 E84B4400 push 00444BE8 ; |c:\
00444B39 |. E8 2A15FCFF call <jmp.&KERNEL32.GetVolumeInformat>; \GetVolumeInformationA //就是这个函数
00444B3E |. 8B06 mov eax, dword ptr [esi] //返回到这里
f2重新载入后下断在00444b1b处,f9运行断下了:
00444B1B |. 6A 00 push 0 ; /pFileSystemNameSize = NULL
(指明lpFileSystemNamebuffer参数的大小,这里是null)
00444B1D |. 6A 00 push 0 ; |pFileSystemNameBuffer = NULL
(指定一个缓冲区,用于装载文件系统的名称,这里是null)
00444B1F |. 8D45 F0 lea eax, dword ptr [ebp-10] ; |
00444B22 |. 50 push eax ; |pFileSystemFlags
(一个标记,用不上)
00444B23 |. 8D45 F4 lea eax, dword ptr [ebp-C] ; |
00444B26 |. 50 push eax ; |pMaxFilenameLength
(指定一个变量,用于装载文件名每一部分的长度)
00444B27 |. 56 push esi ; |pVolumeSerialNumber
(用于装载磁盘卷序列号的变量)->**就是这个参数**
这个参数的返回值在esi这个指针中
00444B28 |. 68 00010000 push 100 ; |MaxVolumeNameSize = 100 (256.)
(指明volumenamebuffer的长度)
00444B2D |. 8D85 F0FEFFFF lea eax, dword ptr [ebp-110] ; |
00444B33 |. 50 push eax ; |VolumeNameBuffer
00444B34 |. 68 E84B4400 push 00444BE8 ; |c:\
(欲取信息的那个卷的根目录,这里是c盘)
00444B39 |. E8 2A15FCFF call <jmp.&KERNEL32.GetVolumeInformat>; \GetVolumeInformationA
f8通过那个函数之后,esi所指向的就是我们要的磁盘卷序列号了,因为在lpvolumeserialnumber这个参数前,esi这个指针进栈(参数是通过堆栈来传递的),好...
00444B3E |. 8B06 mov eax, dword ptr [esi] //磁盘卷序列号到eax
00444B40 |. 03C0 add eax, eax //磁盘卷序列号*2
00444B42 |. 8BF0 mov esi, eax //结果传到esi
00444B44 |. 8D95 ECFEFFFF lea edx, dword ptr [ebp-114]
00444B4A |. 8BC6 mov eax, esi
00444B4C |. E8 9F2FFCFF call 00407AF0 //结果格式化成字符串
00444B51 |. 8B95 ECFEFFFF mov edx, dword ptr [ebp-114]
00444B57 |. 8B83 E8020000 mov eax, dword ptr [ebx+2E8]
00444B5D |. E8 6EF2FDFF call 00423DD0
00444B62 |. 8D55 F8 lea edx, dword ptr [ebp-8]
00444B65 |. 8B83 E8020000 mov eax, dword ptr [ebx+2E8]
00444B6B |. E8 30F2FDFF call 00423DA0
00444B70 |. 8D45 FC lea eax, dword ptr [ebp-4]
00444B73 |. 8B55 F8 mov edx, dword ptr [ebp-8]
00444B76 |. 8A52 03 mov dl, byte ptr [edx+3] //取出其第四位
00444B79 |. E8 0AEFFBFF call 00403A88
00444B7E |. 8B45 FC mov eax, dword ptr [ebp-4]
00444B81 |. E8 D62FFCFF call 00407B5C //第四位变为数值,并不是asc,而是文本数值
00444B86 |. F7EE imul esi //esi(经过运算的磁盘序列号)*第四位的文本数值
00444B88 |. 8D0440 lea eax, dword ptr [eax+eax*2] //再*2再加上自己,结果传到eax
00444B8B |. A3 48784400 mov dword ptr [447848], eax
00444B90 |. 8D95 E8FEFFFF lea edx, dword ptr [ebp-118]
00444B96 |. A1 48784400 mov eax, dword ptr [447848]
00444B9B |. E8 502FFCFF call 00407AF0
00444BA0 |. 8B95 E8FEFFFF mov edx, dword ptr [ebp-118]
00444BA6 |. B8 4C784400 mov eax, 0044784C
00444BAB |. E8 84EDFBFF call 00403934
00444BB0 |. 33C0 xor eax, eax
00444BB2 |. 5A pop edx
00444BB3 |. 59 pop ecx
00444BB4 |. 59 pop ecx
00444BB5 |. 64:8910 mov dword ptr fs:[eax], edx
00444BB8 |. 68 E24B4400 push 00444BE2
00444BBD |> 8D85 E8FEFFFF lea eax, dword ptr [ebp-118]
00444BC3 |. BA 02000000 mov edx, 2
00444BC8 |. E8 37EDFBFF call 00403904
00444BCD |. 8D45 F8 lea eax, dword ptr [ebp-8]
00444BD0 |. BA 02000000 mov edx, 2
00444BD5 |. E8 2AEDFBFF call 00403904
00444BDA \. C3 retn
这样就得出了我先前所不知道的那串字符了
总结:
每位注册名的十六进制asc都格式化成字符串连接起来
用GetVolumeInformation函数取得磁盘序列号,是C盘的,测试过了,程序放在D盘下也没有影响.再格式化成字符串,取出其第四位,变为数值,原磁盘序列号乘以2,再乘以第四位数值,再*2再乘以第四位数值的结果,最后格式化成字符串
注册名字符串连接到磁盘序列字符串后面就是注册码了
name:jiangwu55
key :-1670752386A69616E6777753535
C++注册机:(其它机子没测试过)
#include <windows.h>
#include <stdio.h>
#include <iostream.h>
main()
{
int len=0,i,num=0;
char name[100],code[100],c[]="c:\\";
unsigned long VolumeSerialNumber=0;
memset(name,0,100);//数组全0,免乱码
cout<<"Your Name:";
cin>>name;
len=strlen(name);
if(len<=2)
cout<<"name nust be more than 2 characters!"<<endl;
else
{
GetVolumeInformation(c,NULL,NULL,&VolumeSerialNumber,NULL,0,NULL,NULL); //取磁盘卷序列号
i=VolumeSerialNumber*2;//---------------
sprintf(code,"%u",i); //
const char a=code[3]; //计算磁盘卷序列号
i*=atoi(&a); //
i=i*2+i;//-------------------------------
num=i;
memset(c,0,sizeof(c)); //数组全0,免乱码
memset(code,0,100); //数组全0,免乱码
for(i=0;i<len;i++) //算出name的asc连接后的字符串
{
sprintf(c,"%X",name[i]);
strcat(code,c);
memset(c,0,sizeof(c));
}
memset(name,0,100); //数组全0,免乱码
sprintf(name,"%d",num); //格式化所算出来的磁盘信息
strcat(name,code); //得到注册码
cout<<"Your code:"<<name<<endl; //输出code
getchar();
}
}
----------------------------------------------------------------------------------
└经验总结┐:
呵呵``Crack也不难嘛,至少这个是这样!^-^
----------------------------------------------------------------------------------
└版权声明┐ 本文原创于看雪软件安全论坛, 转载请注明作者并保持文章的完整, 谢谢!
2007年5月3日 9:40:19
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)