黑客风云——风云网络
设为首页 加入收藏 我要投稿 网站地图

您现在的位置: 黑客风云 >> 黑客文章 >> 黑客进阶 >> 软件破解 >> 正文
·完美空间提供500M免费AS04-10·企业安全之YY内网准入以04-09
·企业安全之意识与策略04-09·剑走偏锋:IIS漏洞利用04-09
·我来免费网提供100M免费04-09·1122mb.com提供20G超大免04-08
·映像劫持与反劫持技术04-07·让所有"暴力删除工具"无04-07
·入侵88red系统的详细过程04-07·Sql Injection脚本注入终04-07
·vbs+delphi 反弹后门生成04-07·飞讯网提供100MB免费PHP04-07
·突破SQL注入攻击时输入框04-04·结合内核和病毒技术的最04-04
·Real Player rmoc3260.d04-04·亿万网络今月最后为您提04-04
·php+mysql 5 sql inject04-03·Real Player rmoc3260.d04-03
·oblog文件下载漏洞04-03·免费啦提供1G-2G免费全能04-03
·完全解析网页后门和挂马04-02·一句话开3389(只测试过04-02
·萧萧免费空间网提供100M04-02·谷道免费空间网提供1G免04-01
·从本地入手解决双线路由03-31·sablog 1.6 多个跨站漏洞03-31
·富文本编辑器的跨站脚本03-31·Cookie注入是怎样产生的03-31
[推荐]教菜鸟写注册机
      ★★★★★

教菜鸟写注册机

文章整理发布:黑客风云 文章来源:www.05112.com 更新时间:2006-12-27 9:32:48

我先给各位补一点课,就是对函数的调用。除了一些DELPHI程序之外,对函数参数的传递大都用堆栈来完成,简单地说就是把函数的各个参数先PUSH进去,然后再CALL这个函数。在函数内部呢,一般[ebp+8]是第一个参数,[ebp+C]是第二个参数,每次多加4依此类推。而函数内部的局部变量常用[ebp-4][ebp-8]...等等。(原因讲起来有点复杂,先记住就行了)函数的返回值在EAX里。

一般来说,软件的判断注册部分都是一个函数,在函数开头最经典的两句就是

push ebp
mov ebp,esp

这和堆栈处理有关,我们菜鸟先不用太明白,知道这通常是一个函数的开始就行了。向上找找有没有丫,找到了没有,在最上面哪(我上面没有列出来)。如果你想完整地判断它的算法的话,一般从这里开始就行了。在这个程序中前面都是一些初始化之类的东东,所以我把前面一部分省略了。(这也是破解时的原则,不要在无关紧要的地方费功夫,在高级语言中,代码有很大部分是机器自动生成的,电脑一行行写代码不知道累,人脑一行行读代码怎么受得了?你的脑袋是几GHz的CPU?常见有些没有破解经验的汇编高手,完全懂得每行代码的意思,就是找不到关键的地方,原来他跟了半天都是在API里转,白做无用功了。)

好了,现在可以动态调试了。我们在开头这里下个断点,一步步向下看,出现了一个CALL GetDlgItem,我们来看一看函数说明(手头一份这个是必需的)

HWND GetDlgItem(
    HWND hDlg,  // handle of dialog box
    int nIDDlgItem   // identifier of control
   );

呵呵,简单的说这个函数就是让程序确定一个对话框上的控件,第一个参数是对话框的句柄,第二个参数是对话框上某个控件的ID,函数会返回该控件的句柄,这样在下面就可以用这个句柄来操作了。看程序:

代码:
* Possible Reference to Dialog: DialogID_0001, CONTROL_ID:0066, ""                                   | :00401085 6A66                    push 00000066    ;控件ID :00401087 53                      push ebx    ;对话框句柄 * Reference To: USER32.GetDlgItem, Ord:0000h                                   | :00401088 E8159C0000              Call 0040ACA2
看见第一行没有,DialogID_0001,CONTROL_ID:0066,压进去了一个66作为第二个参数:控件ID(注意API调用是从右至左,也就是最后面一个参数先PUSH),用 资源查看工具 看看ID为66的是甚么呀,呵呵就是那个输入用户名的文本框嘛。好了,现在我们有文本框的句柄了,存在EAX里。接着向下看,又一个API,是GetWindowText。看看说明:

int GetWindowText(
    HWND hWnd,  // handle of window or control with text
    LPTSTR lpString,  // address of buffer for text
    int nMaxCount   // maximum number of characters to copy
   );

从名字也能猜出来了,这个函数就是得到一个窗口类控件的文本。第一个参数是该控件的句柄,第二个是存放得到的文本的缓冲区的地址,第三个参数设定取文本的最大长度。看程序:
代码:
:0040108D 6A64                    push 00000064    ;最大长度 :0040108F 8D9548FFFFFF            lea edx, dword ptr [ebp+FFFFFF48];把[ebp+FFFFFF48]先放在EDX里 :00401095 52                      push edx    ;缓冲区地址[ebp+FFFFFF48] :00401096 50                      push eax    ;EAX?是上面那个API的返回值呀,控件句柄 * Reference To: USER32.GetWindowTextA, Ord:0000h                                   | :00401097 E8129C0000              Call 0040ACAE
好了,现在 D ebp+FFFFFF48 看看,是不是输入的用户名?(说明,在OLLY或SICE里这个是[ebp-B8]的形式,其实是一样的)

下面有类似的操作,只是控件ID成了68,可想而知就是得到注册码了,注册码放在[ebp+FFFFFEE4]。

呵呵,继续,到了这么几句:
代码:
:004010BD 8D8548FFFFFF            lea eax, dword ptr [ebp+FFFFFF48] :004010C3 50                      push eax :004010C4 E867050000              call 00401630
这是干甚么牙?要不要进4010C4这个CALL 401630看看?且慢!我前面说过了,不要在无关紧要的地方费力,(啪!一个鸡蛋扔上来:谁知道这里是不是重要啊?)别急嘛,一般来说,先粗略地跟一遍,试着猜猜CALL的作用。如果发现返回值很可疑,再跟进细看也不迟。(这就需要一定的“直觉”了,英文叫“Sence”,台湾老大叫“触机”或者“先死:D”,别担心,破解得多了自然会有这种感觉,这种感觉很难说出来,有时候一见那种阵势就知道关键地方到了)

又扯远了,我们回来看代码。一个CALL,前面有PUSH EAX,很明显是CALL的参数了。(见我前面的说明)看看EAX:lea eax,dword ptr [ebp+FFFFFF48]。[ebp+FFFFFF48]还有没有印象?对了,就是前面API调用中放用户名的地址呀。过了这里后D eax,呵呵不就是咱们的用户名吗,我输入的是“RoBa”,带过这个CALL后看看EAX是什么,嗯~~~~是4。想到什么了?没有?没关系咱们继续看下面:
代码:
:004010C9 59                      pop ecx :004010CA 8945D8                  mov dword ptr [ebp-28], eax  ;记住,上面的返回结果在[ebp-28] :004010CD 8D95E4FEFFFF            lea edx, dword ptr [ebp+FFFFFEE4] :004010D3 52                      push edx :004010D4 E857050000              call 00401630

又是一个CALL 401630,和上面一样的。看看它的参数EDX,[ebp+FFFFFEE4]呵就是假注册码呀,我输的是'87654321',返回值EAX=8,发现什么没有?对,这个CALL就是求一个字符串的长度嘛,要是跟进去又给费不少时间。向下:
代码:
:004010F0 837DD803                cmp dword ptr [ebp-28], 00000003 :004010F4 7E7B                    jle 00401171 :00401102 837DD832                cmp dword ptr [ebp-28], 00000032 :00401106 7D69                    jge 00401171

还记得[ebp-28]是什么吗?对,就是用户名的长度,这几句的意思就很明显了,用户名的长度必须大于3小于32h,不然就跳到401171去了,你可以跟过去看看是什么,呵呵是用户名不符合要求之类的提示。

好了我们来到关键地方喽:
代码:
* 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  #include  #include  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
简单的C程序哟,你也可以用你熟悉的语言写一个。

后记:

这是一个简单的CRACKME,本来三言两语就能解决的,被我啰啰嗦嗦说了这么一大堆,就是希望能把问题真正地说明白了,希望通过这篇文章让你发现,破解软件乃至写注册机并不是多么困难的事,只要坚持下去,谁都有成为高手的那一天,也希望高手们能够抽时间发一些适合较低水平的文章或者至少对发这种文章的新手多多鼓励。Enjoy Cracking,Newbies!

上一页  [1] [2] 

文章录入:cainiaowang    责任编辑:cainiaowang 
  • 上一篇文章:

  • 下一篇文章:
  • 【字体: 】【发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
    VIP 专 区
    Copyright @2006 黑客风云 ●业务联系:QQ 联系怪人 联系奇人 Email:给怪人发邮件 给奇人发邮件
    ICP备案:冀06009886