📄 chap3-4.htm.primary
字号:
还不是很好,所以得算算:</span></pre>
<pre><span class="p9"> 100000000 - FFFFFF64 = 9C</span></pre>
<pre><span class="p9">在 SoftICE 用这样的命令:</span></pre>
<pre><span class="p9"> :? 0-FFFFFF64</span></pre>
<pre><span class="p9">100000000 对SoftICE来说太大了,但它还是给出了相同的结果。</span></pre>
<pre><span class="p9">现在是...来看看什么东西躲在EBP-9C那里的时候了...这样输入命令:</span></pre>
<pre><span class="p9"> :d ebp-9c</span></pre>
<pre><span class="p9">数据窗口会显示出一大排数字 ─ 注册码!但是记住我前面说过的...两种注册
方式对应两个注册码....所以你把这些注册码抄下来以后,继续用F10单步运行
....我们会遇到这些代码:</span></pre>
<pre> <span class="p9">> LEA EAX, [EBP-68] ; EAX = EBP-68
LEA ECX, [EBP-34] ; ECX = EBP-34
PUSH EAX ; 保存 EAX
PUSH ECX ; 保存 ECX
> CALL 00403DD0 ; 再次调用子程序
ADD ESP, 08 ; 删除保存的信息
TEST EAX, EAX ; 检查返回结果
JNZ 00402BFF ; 如果非零跳转</span></pre>
<pre><span class="p9">你在EBP-68处找到了什么?不错吧...另一个注册码。</span></pre>
<pre><span class="p9"> :d ebp-68</span></pre>
<pre><span class="p9">我们的练习结束了,希望一切顺利。
</span></pre>
<pre><span class="p9">3.2 Command Line 95 -容易的用户名/注册码方式的注册、注册器
=================================================================
这是一个非常好的例子,注册码的计算也很简单。
</span></pre>
<pre><span class="p9">3.1.1 检查程序
===========================
检查程序以后你知道它是32位的应用程序,要求输入名字和注册码。 让我们开始!</span></pre>
<pre><span class="p9">3.1.2 捕捉代码
===========================
我们象拆解TaskLock那样 ─ 设置断点。我们可以在两个可能性最大的两个函数
都设上断点:GetWindowTextA 和 GetDlgItemTextA. 按下Ctrl+D 进入SoftICE, 然后:</span></pre>
<pre><span class="p9"> :bpx getwindowtexta
:bpx getdlgitemtexta</span></pre>
<pre><span class="p9">接下来进入注册对话框,输入一个名字和一些数字(多数情况下是一个整数),
我是这么写的,然后按OK....</span></pre>
<pre><span class="p9"> Name: ED!SON '96
Code: 12345</span></pre>
<pre><span class="p9">程序在 GetDlgItemTextA 处停住了,就象TaskLock一样。我们按F11回到调用它
的地方。用 Ctrl+Up卷动窗口直到看到这些:</span></pre>
<pre><span class="p9"> MOV ESI, [ESP+0C]
PUSH 1E ; 最大长度
PUSH 0040A680 ; 缓冲地址
PUSH 000003ED ; 控制柄
PUSH ESI ; 对话柄
CALL [User32!GetDlgItemTextA]</span></pre>
<pre><span class="p9">数字40A680引起了我们的注意,看看那里有什么:
:d 40a680</span></pre>
<pre><span class="p9">如果没有我们输入的名字,数据窗口里有些什么呢?好了,我们来研究下面的一 段代码:</span></pre>
<pre><span class="p9"> PUSH 00
PUSH 00
PUSH 000003F6 ; 控制柄
MOV EDI, 0040A680 ; 保存缓冲区地址
PUSH ESI ; 对话柄
CALL [User32!GetDlgItemInt]</span></pre>
<pre><span class="p9">GetDlgItemInt 和 GetDlgItemText差不多,但它从文字框中返回一个整数。
它出在EAX中返回来的,所以单步运行通过这些代码,再来看看寄存器窗....
对我而言是:</span></pre>
<pre><span class="p9"> EAX=00003039</span></pre>
<pre><span class="p9">十六进制数3039是多少? 输入:
:? 3039</span></pre>
<pre><span class="p9">我们得到:</span></pre>
<pre><span class="p9"> 00003039 0000012345 "09"
^ 16进制 ^ 十进制 ^ ASCII</span></pre>
<pre><span class="p9">正如你看到(和已经猜到)的那样,它是你输入的注册码。OK,下面怎么办?让
我们来看下面的代码:</span></pre>
<pre><span class="p9"> MOV [0040A548], EAX ; 返回注册码
MOV EDX, EAX ; 同时保存在DX中
</span></pre>
<pre><span class="p9">3.1.3 计算注册码
==========================
这样注册码就算出来了</span></pre>
<pre><span class="p9"> MOV ECX, FFFFFFFF ; 这几行计算字符长度
SUB EAX, EAX ; .
REPNZ SCASB ; .
NOT ECX ; .
DEC ECX ; ECX <-- 长度
MOVSX EAX, BYTE PTR [0040A680] ; 读入40A680处的一字节
IMUL ECX, EAX ; ECX = ECX * EAX
SHL ECX, 0A ; 左移 0A 次
ADD ECX, 0002F8CC ; 结果加上2F8CC
MOV [0040A664], ECX</span></pre>
<pre><span class="p9">验证合法性....</span></pre>
<pre><span class="p9"> CMP ECX, EDX ; 比较
JZ 00402DA6 ; 如果相同就....</span></pre>
<pre><span class="p9">当你运行到比较这一步时,就可以得到你真正的注册码:</span></pre>
<pre><span class="p9"> :? ecx</span></pre>
<pre><span class="p9">对我而言它是:
000DC0CC 0000901324</span></pre>
<pre><span class="p9">也就是说我的正确的注册码是901324.</span></pre>
<pre><span class="p9">按F5或者Ctrl+D让它运行,然后用正确的注册码(十进制)再来一次。这一次 成功了!
</span></pre>
<pre><span class="p9">4. 为COMMAND LINE 95制作注册器
=========================================
我们把上面计算注册码的代码翻译成C语言程序。 最明了的计算公式就是:</span></pre>
<pre><span class="p9">code=((uppercase_first_char * length_of_string) << 0x0A) + 0x2f8cc;</span></pre>
<pre><span class="p9">注(1): 别忘了一件事 就是把所有字符转成大写
(2): "<< 0x0A" 实际上就是 "乘以 2^10"</span></pre>
<pre><span class="p9">完整的程序就是:</span></pre>
<pre><span class="p9"> #include <string.h>
#include <stdio.h></span></pre>
<pre><span class="p9"> int main()
{
unsigned long code;
unsigned char buffer[0x1e];</span></pre>
<pre><span class="p9"> printf("CommandLine95 Keymaker by ED!SON '96\n");
printf("Enter name: ");
gets(buffer);</span></pre>
<pre><span class="p9"> strupr(buffer);
code = ( ((unsigned long)buffer[0] *
(unsigned long)strlen(buffer))
<< 0x0A) + 0x2f8cc;</span></pre>
<pre><span class="p9"> printf("Your code is: %lu", code);</span></pre>
<pre><span class="p9"> return 0;
}</span></pre>
<pre><span class="p9">爽吧?
</span></pre>
<pre><span class="p9">4. 当程序调用一个函数时,PUSH和CALL这些指令是如何工作的
============================================================================
我们重新来看看TaskLock中的这段代码:</span></pre>
<pre><span class="p9"> PUSH 32 ; 字符串最大长度
PUSH EAX ; 字符缓冲区地址
PUSH 000003F4 ; 控制标识
PUSH DWORD PTR [ESI+1C] ; 对话框柄
CALL [USER32!GetDlgItemTextA] ; 获得字符串</span></pre>
<pre><span class="p9">如果认为是C语言编译出来的话,这个CALL应该是这样:</span></pre>
<pre><span class="p9"> GetDlgItemTextA(hwndDlg, 0x3F4, buffer, 0x32);
^ [ESI+1C] ^ EAX</span></pre>
<pre><span class="p9">PUSH把数据保存在叫做堆栈的地方。每个PUSH把新的数据放在堆栈的顶部,被调
用的子程序就挨个地检查躺在堆栈中的数据,按照定义来使用它们。</span></pre>
<pre><span class="p9">附录</span></pre>
<pre><span class="p9">A. 让SoftICE载入符号
==============================
你可以用exp getwindowtext命令来检查SoftICE是否已经为GetWindowText装入
了符号,象这样:
:exp getwindowtext</span></pre>
<pre><span class="p9">如果你没有得到所有GetWindowText函数的列表,你就得编辑\SIW95\WINICE.DAT,
在"Examples of export symbols that can be included for chicago"这段文字
以后的那些 'exp='的行首去掉';',为了节省内存,选择最重要的几个就可以了:</span></pre>
<pre><span class="p9"> kernel32.dll
user32.dll
gdi32.dll</span></pre>
<pre><span class="p9">编辑完后,重新起动计算机使其生效。
</span></pre>
<pre><span class="p9">B. 函数语法
============================
如果你看看下面的函数声明,对我们上面讲到的函数调用就容易明白了:</span></pre>
<pre><span class="p9">int GetWindowText(int windowhandle, char *buffer, int maxlen); int
GetDlgItemText(int dialoghandle, int controlid, char *buffer,
int maxlen);
int GetDlgItemInt(int dialoghandle, int controlid, int *flag, int type);</span></pre>
<pre><span class="p9">这些函数的详细描述,可参考Windows/Win32编程手册
</span></pre>
<pre><span class="p9">C.</span><span class="p9"> 如何与我联系
================
On IRC (EFNet): In #Ucf96, #Cracking
By e-mail: edison@ccnux.utm.my OR an461165@anon.penet.fi On my
homepage: http://www.geocities.com/SoHo/2680/cracking.html</span></pre>
<pre><span class="p9">======================================================================</span></pre>
<pre><span class="p9">译后记:
花了一个下午的时间(上班时间啊!),译完这篇拆解教程。不知大家看不看
得懂?ED!SON的文章是很浅显易懂的,我担心会让我毛手毛脚地闹出歧义来,
如果真有什么错误的话,帐应该算在我头上(请大家来信指出)。ED!SON的这
篇文章对初学者来说非常值得一读,我就是看完这篇文章以后,马上连续CRACK
了几个程序(就这么快、这么简单!)下次我就把CRACK WINZIP6.2的过程讲讲
吧(WINZIP6.2的注册器已经泛滥成灾了,就当练习练习吧)。欢迎来信交流,
你CRACK了什么程序,别忘了告诉我你用的方法;如果觉得我翻译得还算看得下
去话,就给些鼓励吧。</span></pre>
<pre><span class="p9">CFIDO ID : Jim Tyan
EMAIL : jimtyan@tasteful.com</span></pre>
<pre><span class="p9">田学军 8878888 CALL 29549 jimtyan@tasteful.co</span></pre>
</div>
</div>
</blockquote>
<span class="p9"></span><span class="p9"></span><span class="p9"></span><span class="p9"></span>
<p align="center"><a href="../Catalog.htm"><img src="../image/navtoc.gif" width="84" height="23" border="0"></a><a href="Chap3-3.htm"><img src="../image/Navprev.gif" width="80" height="23" border="0"></a><a href="../chap4/Chap4-1.htm"><img src="../image/navnext.gif" width="83" height="23" border="0"></a></p>
<hr width=735>
<div align="center"><span class="p9"><font size="2"><span class="p9"><font size="2"><span class="p9">Copyright
© 2000-2001 <a href="http://www.pediy.com/">KanXue Studio</a> All Rights
Reserved.</span></font></span></font></span> </div>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -