原著:raZZia
翻译:TAE![CCG]
软件 2: Ize 2.04 from Gadgetware
Ize from Gadgetware 是一个聪明得小程序,它放了一双眼睛在你的屏幕上,
它会跟着你的鼠标得,它有输入姓名和注册码得注册功,对付这个软件得策略
仍然和上面一个相同:找出我们输入的数据在内存中的地址。
步骤 1: 运行 Ize。 选择注册并输入名字和注册码,我用的是:“razzia”
和“12345”
步骤 2: 进入 (CTRL-D) Softice 并且在 GetDlgItemTextA 上设置断点。
步骤 3: 离开 SoftIce 并且点击 OK。这将带你回到 Softice。你将回到函数
GetDlgItemTextA 中。按 F11 离开函数,你将看到以下代码:
mov esi, [esp + 0C]
push 00000064
push 0040C3A0 ;<--我们的姓名被存放到内存中的这个地方!
mov edi, [USER32!GetDlgItemTextA] ;<-- edi 载入一个地址 GetDlgItemTextA
push 00004EE9
push esi
call edi ;<-- 执行 GetDlgItemTextA
push 00000064 ;<--
(你应该在这里)
push 0040C210 ;<--我们输入的注册码将被放在这里
push 00004EEA
push esi
call edi ;<-- 再次执行 GetDlgItemTextA
我们看见在这个代码段中函数 GetDlgItemTextA 被呼叫了两次,第一次的Call已经
执行,用 ED 40C3A0 命令我们可以看到我们在内存中的名字。
我们跟着程序来读取输入的注册码把,键入 G 并且回车,现在,我们再一次回到函数
GetDlgItemTextA 中现在按F11离开这里,我们看看内存 40C210 中有啥,哦,是我们
输入的注册码!
现在我们知道我们输入的名字和注册码被放到哪里了,我们把这些记下来!
步骤 4: 好的, 下一步呢?我们已经知道了名字和假注册码被放在哪里了,我们需要
找出程序用这些数据干了什么,通常我们需要下断点来找出程序的那些地方读取了这
些数,可是在这里却不需要。
看看以下代码段:
push 0040C210 ;<--保存我们输入的注册码 (作为下面那个Call的参数)
call 00404490 ;<--这个CALL是干什么的呢?
add esp, 00000004
mov edi, eax ;<-- 保存 EAX (hmmmm)
我们进如Call看看它究竟做了什么,但那是不必的,依你经验来猜猜看这个Call是干什么
的?它计算假注册码放入了 EAX。我们继续按 F10直到我们通过了CAll并且看看 EAX 中
的内容,用 ?EAX 命令,在我这里它显示:00003039 0000012345 "09"。
知道了 EDI 是我们的注册码,那么我们继续:
push 0040C3A0 ;<-- 保存我们输入的名字 (作为下个Call的参数)
push 00409080 ;<-- 保存我们未知的内存地址 (作为下个Call的参数)
call 004043B0 ;<-- 执行我们未知的函数
add esp, 00000008
cmp edi, eax ;<--比较 EDI (我们输入的注册码) 和 EAX (未知)
jne 004018A1 ;<--如果不同就跳
我们看见那个CALL有两个入口参数。一个是我们输入名字的地址,另一个我们还不知道是什么,
但我们可以用ED 409080 找到它。我们看见文本‘Ize’。这个函数使用这两个参数计算正确的
注册码,如果你仅仅想破解它,那么你只需要在Call后面设置断点,然后查看EAX的值就可以了
它将显示出正确的注册码来,但我们想知道它是如何计算出注册码的,所以我们跟踪到函数内部
之后,我们将在那儿试着找到 EAX 的内容。
步骤 5: 一旦进入了有趣的函数你将发现一段相当长的执行过程。对我们来说是不需要的,不需
要列出完整的CALL清单,因为这对我们做注册码来说根本不需要。
但是一旦找出哪一部分是对我们计算注册码所必要的时候,你就应该一步步的跟踪它,并且仔细
的把它记下来!
在做了这些以后,我们发现函数的第一部分计算出一些“Key”,之后这些“key”被保存在内存
中并且带入了函数的第二部分。
函数的第二部分计算出正确的注册码,但这是基于“Key”和我们输入的名字的!
下面的代码是我们作出注册机所必要的:
(在跟踪下面代码之前不要忘了记录,使用到的寄存器是下面几个:EBX指向我们输入名字的第一
个字母,EDX 是 0,EBP 是 0,至于“key”我们说得简单些,它存放在内存地址 0040B828 中,
它最初的值是 0xA4CC )
:00404425 movsx byte ptr edi, [ebx + edx] ;<-- 把名字的第一个字母放入
EDI
:00404429 lea esi, [edx+01] ;<-- ESI 是字母所在的位数 "letter-number"
:0040442C call 00404470 ;<-- 一个Call
:00404431 imul edi, eax ;<-- EDI=EDI*EAX (EAX是上面那个CAll返回的一个值)
:00404434 call 00404470 ;<-- 又Call了
:00404439 mov edx, esi
:0040443B mov ecx, FFFFFFFF
:00404440 imul edi, eax ;<-- EDI=EDI*EAX (EAX是上面那个call返回的一个值)
:00404443 imul edi, esi ;<-- EDI=EDI*ESI (ESI 是字母所在的位数)
:00404446 add ebp, edi ;<-- EBP=EBP+EDI (注意 EBP
最后将是我们正确的注册码)
:00404448 mov edi, ebx ;<--这几行计算我们输入名字的长度
:0040444A sub eax, eax ;<--这几行计算我们输入名字的长度
:0040444C repnz ;<--这几行计算我们输入名字的长度
:0040444D scasb ;<--这几行计算我们输入名字的长度
:0040444E not ecx ;<--这几行计算我们输入名字的长度
:00404450 dec ecx ;<-- ECX 现在已经是我们名字的长度了
:00404451 cmp ecx, esi
:00404453 ja 00404425 ;<-- 如果不是最后一个字母,继续循环
:00404455 mov eax, ebp ;<-- 将 EBP 存入 EAX !!!!
:00404457 pop ebp
:00404458 pop edi
:00404459 pop esi
:0040445A pop ebx
:0040445B ret
去看看那个CALL是干什么的!
:00404470 mov eax, [0040B828] ;<-- "key" 放入 EAX
:00404475 mul eax, eax, 015A4E35 ;<-- EAX=EAX * 15A4E35
:0040447B inc eax
;<-- EAX=EAX + 1
:0040447C mov [0040B828], eax ;<-- 用EAX中的值代替 "key"
:00404481 and eax, 7FFF0000 ;<-- EAX=EAX
&& 7FFF0000
:00404486 shr eax, 10
;<-- EAX=EAX >>10
:00404489 ret
上面的循环代码对我们输入名字的所有字母进行了操作。每个字母计算出了一些值,所有的这些
值相加到 EBP 中,之后这个值放入了 EAX,并且函数返回 EAX,那就是我们要找的,我们要知道
的是 EAX 是如何得到这个值的!
步骤 6: 可以做注册机了,我们把上面那段计算注册码的代码翻译为 C 语言吧!
下面就是注册机代码: (注意:我是一个差劲的 C 程序员 :)
#include <stdio.h>
#include <string.h>
main() {
char Name[100];
int NameLength,Offset;
unsigned long Letter,DummyA;
unsigned long Key = 0xa4cc;
unsigned long Number = 0;
printf("Ize 2.04 crack by razzia\n");
printf("Enter your name: ");
gets(Name);
NameLength=strlen(Name);
for (Offset=0;Offset<NameLength;Offset=Offset+1)
{
Letter=Name[Offset];
DummyA=Key;
DummyA=DummyA*0x15a4e35;
DummyA=DummyA+1;
Key=DummyA;
DummyA=DummyA & 0x7fff0000;
DummyA=DummyA >> 0x10;
Letter=Letter*DummyA;
DummyA=Key;
DummyA=DummyA*0x15a4e35;
DummyA=DummyA+1;
Key=DummyA;
DummyA=DummyA & 0x7fff0000;
DummyA=DummyA >> 0x10;
Letter=Letter*DummyA;
Letter=Letter*(Offset+1);
Number=Number+Letter;
}
printf("\nYour registration number is : %lu\n",Number);
}
- 标 题:再贴一篇,进阶篇,比上面那个难一些!! (6千字)
- 作 者:TAE!
- 时 间:2001-7-19 11:20:48
- 链 接:http://bbs.pediy.com