好了我们来到关键地方喽:
代码:
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040111C(C)
|
:0040110C 0FBE840D48FFFFFF movsx eax, byte ptr [ebp+ecx-000000B8]
:00401114 41 inc ecx
:00401115 33C1 xor eax, ecx
:00401117 03D8 add ebx, eax
:00401119 3B4DD8 cmp ecx, dword ptr [ebp-28]
:0040111C 75EE jne 0040110C
呵呵,是不是又晕了?[ebp+ecx-B8]这是啥呀?别着急,车到山前必有路。先 d ebp+ecx-B8看看,哟,不还是咱们的用户名吗?:D 怎么回事?好好想想,ecx现在是0,[ebp-B8]和[ebp+FFFFFF48](记得不?放用户名的地址)不是一回事嘛!(不明白的去补习一下负数的表示方法,我也不知道为什么W32DASM有时候非把-B8写成FFFFFF48)
再仔细看看,movsx eax,byte ptr [ebp+ecx-000000B8],注意是byte ptr,即以字节的方式读取(就是说每次读出一个字符),而且又加上了个ecx。如果你破解多了的话,应该立刻就明白:关键的地方到了。
这是一个很典型的循环结构,看出来没?ecx就是循环变量了,每执行一次会从用户名中取一个字符,然后ecx加1,这样[ebp+ecx-B8]就指向用户名的下一个字符了。对取出来的字符与循环变量进行XOR运算,把结果累加到EBX。然后循环变量与[ebp-28]也就是用户名长度比较,如果不等于的话也就是还没取完,就返回上去继续取用户名的下一个字符。这样直到取完为止。
代码:
:0040111E 6BC006 imul eax, 00000006 ;EAX其实是上面最后一轮计算的结果,乘6
:00401121 C1E307 shl ebx, 07 ;EBX是几轮计算累加起来的结果,左移7位
:00401124 03C3 add eax, ebx ;加起来
:00401126 8945C8 mov dword ptr [ebp-38], eax
:00401129 FF75C8 push [ebp-38] ;上面的结果,作为一个参数
* Possible StringData Ref from Data Obj ->"%lX"
|
:0040112C 6838B44000 push 0040B438 ;"%lX"有点眼熟哟
:00401131 8D8D80FEFFFF lea ecx, dword ptr [ebp+FFFFFE80]
:00401137 51 push ecx ;这是什么呢?
:00401138 E8873D0000 call 00404EC4
:0040113D 83C40C add esp, 0000000C
前面几句是继续上面的计算,把EAX*6和EBX左移7位的值加进来,然后结果复制到[ebp-38]这个局部变量里作为下面CALL的一个参数,接着[ebp+FFFFFE80]作第二个参数,然后又一个CALL,还是那样,先别着急跟进去,前后看看有没有可疑之处:
第一个参数[ebp-38],没什么好说的,上面计算的结果。第二个参数指向"%lX",这个字串写过C语言的都有印象吧,就是在printf里把一个数字按照大写的16进制方式显示出来所用的标识符,比方说把一个数字255转换成字串“FF”。(在WinAPI里叫wsprintf)第三个参数是什么呢?前面这种形式见多了吧,猜猜!
我们验证一下前面猜想是否正确,我用"RoBa"上面算出来的结果是46430,也就是16进制的B55E,我们跟过这个CALL看看结果如何?什么,结果在哪?聪明的你还没想到吗,上面那第三个参数[ebp+FFFFFE80]就是结果的地址呀。怎么样不出所料吧。
(其实从40113D这一句add esp,C也能看出来,因为在函数外平衡堆栈的只有这个一个参数数目不定的函数。引申一下,看不懂没关系啦:D )
接着看啦:
代码:
:00401140 8D8580FEFFFF lea eax, dword ptr [ebp+FFFFFE80];眼熟吗,刚才的转换结果呀
:00401146 50 push eax ;EAX指向上面转换得到的字符串
:00401147 8D95E4FEFFFF lea edx, dword ptr [ebp+FFFFFEE4];这个很早了,向前面找找是啥
:0040114D 52 push edx ;EDX指向我们输入的假注册码
* Reference To: KERNEL32.lstrcmpA, Ord:0000h
|
:0040114E E8339C0000 Call 0040AD86
:00401153 85C0 test eax, eax
:00401155 750D jne 00401164 ;关键跳转哟
哈哈,lstrcmp,什么意思不用我说了吧,当然是STRingCoMPare字符串比较啦。把计算的结果与前面输入的假码比较,相等就OK了。好了,现在把上面的完整的代码过一遍,怎么样,写个注册机不难吧?
代码:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
void main()
{
int EAX=0,EBX=0,len;
char name[50]={0};
char password[50]={0};
printf("Please input your name:");
scanf("%s",name);
len=strlen(name);
for (int i=0;i<len;i++)
{
EAX=name[i]^(i+1);
EBX+=EAX;
}
EAX*=6;
EBX<<=7;
EAX+=EBX;
printf("Your password is: %lX\n",EAX);
printf("KeyGen by RoBa Enjoy Cracking,Newbies!\n");
}
简单的C程序哟,你也可以用你熟悉的语言写一个。
后记:
这是一个简单的CRACKME,本来三言两语就能解决的,被我啰啰嗦嗦说了这么一大堆,就是希望能把问题真正地说明白了,希望通过这篇文章让你发现,破解软件乃至写注册机并不是多么困难的事,只要坚持下去,谁都有成为高手的那一天,也希望高手们能够抽时间发一些适合较低水平的文章或者至少对发这种文章的新手多多鼓励。上一页 [1] [2] [3]