• 标 题:翻译一篇写注册机的教程!大侠就不要看了 (5千字)
  • 作 者:TAE!
  • 时 间:2001-7-18 22:01:09
  • 链 接:http://bbs.pediy.com

原著:raZZia
翻译:TAE![CCG]
    呵呵,今日闲来无事,碰巧最近对写注册机感兴趣所以翻译了一篇写注册机的教
    程,较简单,不知有没有大侠翻过。有疏漏错误的地方还请各位更正!
工具!
    你需要一个像softice那样的Windows下的调试软件,和一个Dos库C编译器
   

内容!
    在这篇教程中我将告诉你如何做一个注册机,软件用的保护方式是很众所周知的
    输入姓名和注册码的方式,在选择注册后,一个窗口弹了出来,那就是你要输入
    名字和注册码的地方,这儿的对策就是在内存中找出输入的数据,在你继续之前
    你必须确定你已经根据PWD的教程一设置了softice.dat文件
       
软件 1: Scanline Swiftsearch 2.0!
    Swiftsearch 是一个很有用的小工具,你可以用它来在网络中搜索,我将一步步
    的告诉你如何破解它!
   
    步骤 1: 运行程序 :)

    步骤 2: 选择菜单重的“注册”,你将发现一个可以输入姓名和注册码的窗口。

    步骤 3: 进入softice (ctrl-d)

    步骤 4: 我现在将设置一个像GetWindowText(a)和GetDlgItemText(a)这样的断点
    来找到内存中我们刚刚输入的数据。能够被用于这个程序的函数仅仅是GetDlgItemTexta
    (对与错还是你自己试试吧 :)所以,在SoftIce中输入 BPX GetDlgItemTexta
    然后用 g 命令退出SoftIce。

    步骤 5: 现在输入名字和注册码(我使用的是 razzia 和 12345)并且按 OK,这将带
    你回到SoftIce,现在你已经在GetDlgItemTexta函数中了,按 F11离开函数。你应
    该看到下面的代码:
   
    lea eax, [ebp-2C]          ;<--- 我们在找这个位置(?不理解)
    push eax
    push 00000404
    push [ebp+08]
    call [USER32!GetDlgItemTextA]
    mov edi, eax              ;<--- eax 已经指向字符串长度了,并且一会儿
                                      就会被存储到 edi 中了。

    我们看见 EAX 读入了一个内存地址并且作为函数GetDlgItemTextA的一个参数被
    压进了堆栈中,而后函数GetDlgItemTextA准备开始执行了,我们来查看 EBP-2c
    (用 ED EDP-2c)并且可以看见那儿有我们输入的名字,现在我们知道我们的名字
    被存放在内存中的什么地方了,通常应该把这个地址记下来,但我们即将看到,
    那是不必的。
     
    那么,下一步做什么? 现在我们必须跟着程序来读取我们输入的注册码。输入 g 我
    们再次返回softice的时候按F11,你将看到下面的代码:

    push 0000000B
    lea ecx, [ebp-18]        ;<--所以, ebp-18 是存放输入的注册码的地方
    push ecx                 
    push 0000042A
    push [ebp+08]
    call [USER32!GetDlgItemTextA]
    mov ebx, eax              ;<--将字符长度保存在 EBX 中
    test edi, edi            ;<--还记得 EDI 是放我们输入名字长度的地方吗?
    jne 00402FBF             

    我们看见我们输入得注册码被存放在 EBP-18 中了 ,不相信得话可以用ED EBP-18
    查看一下。 通常这个地址也应该记下来,并且我们看见它检查我们的名字长度是
    否是0,如果不是的话,程序将继续。
   
    步骤 6: 那好,现在我们知道我们输入的数据被存放在哪里了。那么,下一步呢?
    现在我们已经知道怎样做了,通常我们应该在内存中设置断点以便于知道程序哪些
    地方读取了这里。但在这个步软件里仅仅需要按住F10,直到呢看见了以下代码:
   
    cmp ebx, 0000000A      ;<--记得 EBX 是放输入注册码长度的地方吗?
    je 00402FDE           

    这两行很重要!它们检查了输入注册码的长度是否等于10。如果不是,那么程序就
    已经认为注册码是错误的了。修改 EBX 或者在寄存器数据窗口修改标志位寄存器(FLAG)
    以便让程序跳转.继续按F10知道呢到达下面的代码处。
    (记住,这可能和你的地址不一样!)

    :00402FDE xor esi, esi        ;<-- 清空 ESI
    :00402FE0 xor eax, eax        ;<-- 清空 EAX
    :00402FE2 test edi, edi
    :00402FE4 jle 00402FF2
    :00402FE6 movsx byte ptr ecx, [ebp + eax - 2C] ;<-- ECX 载入我们输入名字的一个字母.
    :00402FEB add esi, ecx        ;<-- 将字母加到 ESI
    :00402FED inc eax            ;<-- EAX 加1以便得到下一个字母
    :00402FEE cmp eax, edi        ;<-- 取完了吗?
    :00402FF0 jl 00402FE6        ;<-- 如果没有,就去取下一个字母。

    好的,我们看见程序将我们输入名字的所有字母加起来,那么 ESI 就是总和了,让
    我们继续并且找出程序用那个值做什么!

    :00402FF2 push 0000000A
    :00402FF4 lea eax, [ebp-18]  ;<-- 将输入注册码的地址放入 EAX
    :00402FF7 push 00000000
    :00402FF9 push eax            ;<-- 压入 EAX (作为下面一个Call的参数)
    :00402FFA call 00403870      ;<-- 好的,你认为这个Call是干什么的呢?:)
    :00402FFF add esp, 0000000C
    :00403002 cmp eax, esi        ;<-- 嘿!
    :00403004 je 00403020

    我们进入CALL,它最终反回 ESI,并和 EAX 比较.嗯,让我们看看 EAX 是什么。‘? EAX’显示
    00003039 0000012345 "09"

    好极了!那是我们输入的注册码! 那么ESI呢?我们知道,ESI中是我们输入名字
    的所有字母总和!!

    步骤 7: 现在我们知道程序是如何计算注册码的了,我们可以做注册机了!
    但别忘了程序检查了注册码是不是10位!
    一个简单的C程序将计算出这个软件的注册码:

    #include  <stdio.h>
    #include  <string.h>
    main() {
        char Name[100];
        int NameLength,Offset;
        long int Reg = 0, Dummy2 = 10;
        int Dummy = 0;
        int LengtDummy = 1;
        int Lengt , Teller;
        printf("Scanline SwiftSearch 2.0 crack by raZZia.\n");
        printf("Enter your name: ");
        gets(Name);
        NameLength=strlen(Name);

    /* 计算输入的名字字符的总和*/
    /* 并保存到Reg中          */
        for (Offset=0;Offset<NameLength;Offset=Offset+1) {
          Reg=Reg+Name[Offset];
        }

    /* the while lus calculates the lenght of the figure in */
    /* Reg and places it in Lengt                          */
        while (Dummy != 1) {
          if ( Reg < Dummy2 ) {
              Lengt = LengtDummy ; Dummy =1;
          }
              else {
                LengtDummy=LengtDummy + 1; Dummy2=Dummy2*10;
              }
        };

        printf("\nYour registration number is : " );

    /* 收先打印(10-Lengt)次0        */
        Lengt=10-Lengt;
        for (Teller=1;Teller<=Lengt;Teller=Teller+1) printf("0");
    /* 打印注册码                    */
        printf("%lu\n",Reg);
    }