qwgboy2000 发表于 2007-1-10 21:58:19

菜鸟注册机编写基础教程(WIN汇编版)

标 题: 菜鸟注册机编写基础教程(WIN汇编版)【原创】
作 者: qwgboy2000
时 间: 2007-01-10,21:49
链 接: http://bbs.pediy.com/showthread.php?threadid=37755

【文章标题】: 菜鸟注册机编写基础教程(汇编版)
【文章作者】: qwgboy2000
【作者邮箱】: [email protected]
【作者主页】: 无
【作者QQ号】: 27141459
【软件名称】: DCG_2_2.exe
【软件大小】: 503K
【下载地址】: DCG
【加壳方式】: 无
【保护方式】: Name/Serial
【编写语言】: Delphi
【使用工具】: MASM32、VC60的资源编辑器、OD、WINDOWS计算器
【操作平台】: WINXP
【软件介绍】: DCG出品
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
laomms老大曾经写过《菜鸟注册机编写基础教程》,详细介绍了如何用VB、Dephi、MFC写注册机,相信一定使很多像我一样的菜鸟受益非浅,在此向laomms等无私奉献的牛人们表示感谢。

好了,下面我们一起来看一下如何用WIN32ASM来写注册机呢?
我分为两步走的,第一步:找一个CrackMe分析出算法;第二步:用MASM32写注册机

【第一步:】
首先当然要先找一个CrackMe,于是找了一个CrackMe——DCG_2_2.exe开始了菜鸟用汇编写注册机之路。
首先用PEID查一下DCG_2_2.exe发现DELPHI写的没有加壳,然后用OD载入跑一下发现可以用字符串参考就可以下到断点了,窃喜~~~~~~~~

【详细过程】
    通过字符串参考下断:
    004665DB|.E8 08BBFCFF   call    004320E8
    004665E0|.8B55 EC       mov   edx, dword ptr           ;EDX=name
    004665E3|.66:B9 E14D    mov   cx, 4DE1
    004665E7|.8B45 F8       mov   eax, dword ptr
    004665EA|.E8 41FCFFFF   call    00466230                         ;关键CALL
    004665EF|.8D55 E8       lea   edx, dword ptr
    004665F2|.8B45 FC       mov   eax, dword ptr
    004665F5|.8B80 00030000 mov   eax, dword ptr
    004665FB|.E8 E8BAFCFF   call    004320E8
    00466600|.8B45 E8       mov   eax, dword ptr           ;EAX=Serial
    00466603|.8B55 F4       mov   edx, dword ptr
    00466606|.E8 A1DDF9FF   call    004043AC                         ;真假serial比较,真的EAX返回0
    0046660B|.75 13         jnz   short 00466620
    0046660D|.6A 00         push    0                              ; /Style = MB_OK|MB_APPLMODAL
    0046660F|.68 6C664600   push    0046666C                         ; |valid key
    00466614|.68 6C664600   push    0046666C                         ; |valid key
    00466619|.6A 00         push    0                              ; |hOwner = NULL
    0046661B|.E8 D400FAFF   call    <jmp.&user32.MessageBoxA>      ; \MessageBoxA
   
    //////////////////////////////////////////////
   关键CALL部分:
    00466230/$55            push    ebp
    00466231|.8BEC          mov   ebp, esp
    00466233|.83C4 E4       add   esp, -1C
    00466236|.53            push    ebx
    00466237|.33DB          xor   ebx, ebx
    00466239|.895D E4       mov   dword ptr , ebx
    0046623C|.66:894D F6    mov   word ptr , cx
    00466240|.8955 F8       mov   dword ptr , edx
    00466243|.8945 FC       mov   dword ptr , eax
    00466246|.33C0          xor   eax, eax
    00466248|.55            push    ebp
    00466249|.68 E9624600   push    004662E9
    0046624E|.64:FF30       push    dword ptr fs:
    00466251|.64:8920       mov   dword ptr fs:, esp
    00466254|.66:8B45 F6    mov   ax, word ptr
    00466258|.66:8945 EE    mov   word ptr , ax            ;4DE1H存入
    0046625C|.8B45 08       mov   eax, dword ptr
    0046625F|.E8 3CDDF9FF   call    00403FA0
    00466264|.8B45 F8       mov   eax, dword ptr
    00466267|.E8 F4DFF9FF   call    00404260
    0046626C|.85C0          test    eax, eax
    0046626E|.7E 63         jle   short 004662D3
    00466270|.8945 E8       mov   dword ptr , eax          ;为循环终值(即name长度)
    00466273|.C745 F0 01000>mov   dword ptr , 1            ;为循环变量
    0046627A|>8B45 F8       /mov   eax, dword ptr
    0046627D|.8B55 F0       |mov   edx, dword ptr
    00466280|.8A4410 FF   |mov   al, byte ptr       ;依次读name的每个字符到AL
    00466284|.0FB755 EE   |movzx   edx, word ptr
    00466288|.C1EA 08       |shr   edx, 8                        ;右移8位
    0046628B|.32C2          |xor   al, dl                        ;AL与DL异或
    0046628D|.8845 F5       |mov   byte ptr , al            ;暂存一下,设此结果为A
    00466290|.33C0          |xor   eax, eax
    00466292|.8A45 F5       |mov   al, byte ptr             ;读出暂存的A
    00466295|.66:0345 EE    |add   ax, word ptr          ;AX+
    00466299|.8B55 FC       |mov   edx, dword ptr
    0046629C|.66:F76A 04    |imul    word ptr                 ;*CE6D(CE6D是固定值)
    004662A0|.8B55 FC       |mov   edx, dword ptr
    004662A3|.66:0342 06    |add   ax, word ptr             ;+58BF(58BF是固定值)
    004662A7|.66:8945 EE    |mov   word ptr , ax         ;保存
    004662AB|.8D4D E4       |lea   ecx, dword ptr
    004662AE|.33C0          |xor   eax, eax
    004662B0|.8A45 F5       |mov   al, byte ptr
    004662B3|.BA 02000000   |mov   edx, 2
    004662B8|.E8 831CFAFF   |call    00407F40                        ;把A转成十六进制字符串,例如ASCII为36H,就转化为‘3’‘6’
    004662BD|.8B55 E4       |mov   edx, dword ptr
    004662C0|.8B45 08       |mov   eax, dword ptr
    004662C3|.E8 A0DFF9FF   |call    00404268                        ;连接字符串所转换的字符串,循环结束即为正确的serial
    004662C8|.8B45 08       |mov   eax, dword ptr
    004662CB|.FF45 F0       |inc   dword ptr
    004662CE|.FF4D E8       |dec   dword ptr
    004662D1|.^ 75 A7         \jnz   short 0046627A
    004662D3|>33C0          xor   eax, eax
    004662D5|.5A            pop   edx
    004662D6|.59            pop   ecx
    004662D7|.59            pop   ecx
    004662D8|.64:8910       mov   dword ptr fs:, edx
    004662DB|.68 F0624600   push    004662F0
    004662E0|>8D45 E4       lea   eax, dword ptr
    004662E3|.E8 B8DCF9FF   call    00403FA0
    004662E8\.C3            retn

以上是CrackMe的算法部分总结并转化为我们下面注册机的题目如下:

输入一个name,运算以后输出Serial
运算过程如下
初始数据有3个CE6D,58BF,X=4DE1
1、X>>8 ==> Y
2、依次取name的一个字符与上面的Y异或 ==> S
3、((S+X)*CE6D+58BF)&FFFF ==> X
4、S转化为ASCII码对应的两个字符(例如36H就变成'3''6')连接到Serial后面
4、循环到1、直到所有name的字符取完
直到这里为止第一步已经完成了,下面我们来实现第二步。

【第二步:】
用MASM32环境进行注册机的编写,因为本文面对没有使用过MASM32环境的朋友,所以说的详细(罗嗦)一些,高手可以跳过。
首先我们来准备一下运行环境(建议放弃MASM32简单的IDE环境,改为在命令行下用nmake工具进行代码维护):
为了建立这个环境,需要做下面的工作:
第1步:安装常用软件,包括编辑软件Editplus,MSDN,16进制编辑器hexedit,可视化资源编辑器Resource Workshop,调试工具OD和反汇编软件W32DASM等,如果空间允许的话,最好安装Visual C++,以便使用它集成的资源编辑器。
第2步:选择一个驱动器安装MASM32软件包,安装好的目录是x:\Masm32目录,对读者来说整个软件包中重要的只有3个目录:bin目录中有汇编编译器ml.exe,资源编译器rc.exe和链接器Link.exe等执行文件;include目录中有各种头文件;lib目录中有全部导入库。MASM32没有选择地把安装目录名定为masm32,如果不满意的话,完全可以把这3个关键目录拷贝到别的用户自己命名的目录中,对使用没有任何影响。
第3步:建立源文件目录,由于Win32汇编不再像DOS汇编一样一个项目只有一个asm文件,而是包括asm,rc,makefile和图标等多个文件,如果把多个项目的文件混在同一个目录中将无法分辨,所以必须为每个项目单独建立一个目录,建议把这些目录集中在一个专门放置源程序的目录中,如x:\Source目录。
第4步:由于MASM32软件包中没有nmake.exe文件,所以要单独寻找nmake.exe并拷贝到bin目录中。
第5步:为这个环境建立一个设置环境变量的批处理文件,假设文件名为Var.bat,那么这个文件内容如下:
@echo off
set include=x:\masm32\Include
set lib=x:\masm32\lib
set path=x:\masm32\bin;%path%
echo on

好了环境我们已经准备好了,下面开工开始写注册机
首先注册机要有对话框资源,我们可以用VC60的资源编辑器来完成这个工作,我们要做两个对话框一个是输入Name得出Serial的,一个是“关于注册机”的对话框。
建立好以后保存为Dialog.rc,然后用文本编辑器打开并去掉那些不重要甚至是阻碍我们用MASM32环境来编译的部分。我的Dialog.rc如下:
#include "resource.h"

#define ICO_MAIN 0x1000          //图标,这里值随便定义但是要和ASM里面相同
#define DLG_MAIN 1               //主对话框
#define IDD_ABOUTBOX 2         //关于对话框
#define IDC_STATIC1 11         //编辑框1,我们这里就是输入Name的那个编辑框
#define IDC_STATIC2 12         //编辑框2,我们这里就是得出Serial的那个编辑框

ICO_MAIN         ICON    "DCG_KeyGen.ico"   //定义图标,我们这里用的是DCG标志的图标,你当然可以自己换一个好看的

IDD_ABOUTBOX DIALOG DISCARDABLE193, 180, 234, 69
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU         //定义了关于对话框的很多属性,具体意思不必要太了解,可以在resource.h里面查到
CAPTION "关于 DCG_2_2.exe_KeyGen"                              //对话框标题
FONT 9, "宋体"                                                   //对话框中字的字号、字体
BEGIN                                                            //可以换成 { (如果换了下面也要换)
      ICON            ICO_MAIN,-1,11,14,20,20                      //图标放的位置
      LTEXT         "DCG_2_2.exe_KeyGen 2.0 版",IDC_STATIC,38,10,134,8,   //标签文本
                      SS_NOPREFIX
      DEFPUSHBUTTON   "确定",IDOK,177,7,50,14,WS_GROUP                      //确定按纽
      LTEXT         "by qwgboy2000",IDC_STATIC,39,23,144,12               //标签文本
      LTEXT         "http://www.dcg.org.cn",IDC_STATIC,39,36,153,13       //标签文本
      LTEXT         "[email protected]",IDC_STATIC,39,50,153,13    //标签文本
END                                                            //可以换成 }(如果换了上面也要换)

DLG_MAIN DIALOG 193, 180, 240, 60
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_APPWINDOW                                  //定义了主对话框的很多属性,具体意思不必要太了解,可以在resource.h里面查到
CAPTION "DCG_2_2.exe_KeyGen"                           //主对话框标题
FONT 9, "宋体"                                           //字号、字体
BEGIN                                  //可以换成 { (如果换了下面也要换)
      DEFPUSHBUTTON   "确定",IDOK,180,7,50,19            //确定按纽
      PUSHBUTTON      "关于",IDCANCEL,180,30,50,19         //关于按纽
      LTEXT         "Name:",IDC_STATIC,7,7,30,19         //标签Name
      LTEXT         "Serial:",IDC_STATIC,7,30,30,19      //标签Serial
      EDITTEXT      IDC_STATIC1,58,7,104,17,ES_AUTOHSCROLL               //编辑框1
      EDITTEXT      IDC_STATIC2,57,29,104,17,ES_AUTOHSCROLL | ES_READONLY//编辑框2
END                                    //可以换成 }(如果换了上面也要换)

对话框资源是做好了,其实用VC资源编辑器很容易做,但是作注释却化了我不少时间(拼音打字不容易呀)

下面终于到代码部分了,我们建立了一个Dialog.asm的文件,内容如下:
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Dialog.asm
; 对话框资源使用的模板代码
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 使用 nmake 或下列命令进行编译和链接:
; ml /c /coff Dialog.asm
; rc Dialog.rc
; Link /subsystem:windows Dialog.obj Dialog.res
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
      .386
      .model flat, stdcall
      option casemap :none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include    windows.inc
include    user32.inc
includelibuser32.lib
include    kernel32.inc
includelibkernel32.lib
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Equ 等值定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ICO_MAINequ    1000h;图标,和资源文件里面的对应
DLG_MAINequ    1       ;主对话框
IDD_ABOUTBOXequ    2       ;关于对话框
IDC_STATIC1   equ             11      ;输入Name的编辑框
IDC_STATIC2   equ             12      ;得出Serial的编辑框
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段 , 这里定义的都是全局变量
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                  .data

InforMationdb    "请输入name",0

      .data?

hInstancedd    ?

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 代码段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
      .code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;首先是关于对话框的部分,没有太多要特别解释的地方,
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ProcABOUTprocuses ebx edi esi hWnd,wMsg,wParam,lParam

      moveax,wMsg
      .ifeax == WM_CLOSE
      invokeEndDialog,hWnd,NULL
      .elseifeax == WM_INITDIALOG
      invokeLoadIcon,hInstance,ICO_MAIN
      invokeSendMessage,hWnd,WM_SETICON,ICON_BIG,eax
      .elseifeax == WM_COMMAND
      moveax,wParam
      .ifax == IDOK            ;点确定按纽就退出关于对话框
      invokeEndDialog,hWnd,NULL
      .endif
      .else
      moveax,FALSE
      ret
      .endif
      moveax,TRUE
      ret

_ProcABOUTendp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;这里是主对话框的部分,关键算法就在这里写了
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ProcDlgMainprocuses ebx edi esi hWnd,wMsg,wParam,lParam
local@szName:byte       ;定义局部变量字节型数组,这个看名字就知道是接收name用的了
local@szSerial:byte   ;定义局部变量字节型数组,这个看名字就知道是发Serial用的了
local   @szLength:dword      ;定义一个dword类型的变量
local   @temp:word             ;定义一个word类型的变量
      invoke RtlZeroMemory,addr @szName,sizeof @szName      ;对@szName变量清0
      invoke RtlZeroMemory,addr @szSerial,sizeof @szSerial    ;对@szSerial清0,(为什么要清0呢?因为不清0会出现一些不是我们想要的随机字符)
      moveax,wMsg
      .ifeax == WM_CLOSE
      invokeEndDialog,hWnd,NULL
      .elseifeax == WM_INITDIALOG
      invokeLoadIcon,hInstance,ICO_MAIN
      invokeSendMessage,hWnd,WM_SETICON,ICON_BIG,eax
      .elseifeax == WM_COMMAND
      moveax,wParam
      .ifax == IDCANCEL
                                  invokeDialogBoxParam,hInstance,IDD_ABOUTBOX,NULL,offset _ProcABOUT,NULL   ;点"关于"按纽弹出关于对话框
      .endif
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;紧接着下面就是关键算法部分了
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                        .ifax == IDOK                                                         ;点"确定"按纽
          invokeGetDlgItemText,hWnd,IDC_STATIC1,addr @szName,sizeof @szName;得到编辑框1的内容
                                  mov @szLength,eax                                                    ;得到编辑框1长度放入@szLength
                                  mov @temp,4de1h                                                      ;3个固定值还记得吗?这里先用到一个了放入@temp
          .if @szLength==0                                                   ;如果编辑框1为空
                                  invoke SetDlgItemText,hWnd,IDC_STATIC2,addr InforMation            ;编辑框2的内容变为"请输入name"
                                  .else                                                                ;否则到(核心部分了)
          lea esi,@szSerial                                                    ;@szSerial字符串的首地址给esi(这里不能用mov esi,offset @szSerial,因为@szSerial是局部变量,地址是放在堆栈中的,用offset会提示出错)
          xor ebx,ebx                                                          ;ebx=0
          mov cx,@temp                                                         
          mov ax,cx                                                            ;ax=4de1
          suanfa:shr ax,8                                                      ;循环部分了,ax>>8
                                  lea esi,@szName                                                      ;取@szName首地址
                                  mov dl,                                                   ;依次取Name的字符
                                  xor al,dl                                                            ;^al
                                  mov dl,al                                                            ;暂存
          and al,0fh                                                         ;保留al的后四位
          lea esi,@szSerial                                                    ;取Serial的首地址
          .if al<0ah                                                         ;这个if是把值转化为16进制字符的
          add al,30h
          .else
          add al,37h
          .endif                                                               ;直到这里,就是如果小于10的话就加30H,大于10的话就加37H
          mov ,al                                                 ;上面算出的字符放到Serial的相应位置
          mov al,dl                                                            ;读取暂存
          shr al,4                                                             ;取al前四位
          .if al<0ah                                                         ;同上的if把al内容转换位16进制字符
          add al,30h
          .else
          add al,37h
          .endif
          mov ,al                                                   ;结果保存到Serial的相应位置
          movzx ax,dl                                                          ;零扩展
          add ax,cx                                                            ;+cx
          mov dx,0ce6dh                                                      ;3个固定值的第二个了
          imul dx                                                            ;*固定值ce6dh
          add ax,058bfh                                                      ;+3个固定值的第三个了
          and ax,0ffffh                                                      
          mov cx,ax                                                            ;存入cx,以便循环继续使用
          inc ebx
          cmp ebx,@szLength                                                    ;判断Name的每个字符是不是算完了
          jl suanfa                                                            ;没算完就继续循环算,算完了就好了
                                  invoke SetDlgItemText,hWnd,IDC_STATIC2,addr @szSerial                ;把最终得到的@szSerial送到编辑框2显示出来
                                  .endif
      .endif
      .else
      moveax,FALSE
      ret
      .endif
      moveax,TRUE
      ret

_ProcDlgMainendp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
start:
      invokeGetModuleHandle,NULL
      movhInstance,eax
      invokeDialogBoxParam,hInstance,DLG_MAIN,NULL,offset _ProcDlgMain,NULL
      invokeExitProcess,NULL
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
      endstart

好了Dialog.asm我们也写好了

下面就是编译了,我们来做一个makefile文件,为什么要做一个makefile文件呢?我们上面说了:建议放弃MASM32简单的IDE环境,改为在命令行下用nmake工具进行代码维护
makefile文件内容如下

NAME = Dialog
OBJS = $(NAME).obj
RES= $(NAME).res

LINK_FLAG = /subsystem:windows
ML_FLAG = /c /coff

$(NAME).exe: $(OBJS) $(RES)
    Link $(LINK_FLAG) $(OBJS) $(RES)

.asm.obj:
    ml $(ML_FLAG) $<
.rc.res:
    rc $<

clean:
    del *.obj
    del *.res

好了下面编译一下就可以了,终于完成了,有的人会说怎么那么长呀?真麻烦。其实大多都是框架结构而已。你可以直接照抄就可以了,只要在关键算法那里改成你自己的就好了,这样一想是不是也不难呀,甚至比其他工具写要更简单呢。。。。

祝大家天天进步,最后感谢一下QQ群:老罗汇编中的雅枫大哥,他RP非常不错,请教问题都能耐心给予解答。

--------------------------------------------------------------------------------
【经验总结】
相信不少和我一样的菜鸟要感叹:天了!原来用WIN32ASM来写注册机那么容易!

--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!

                                                       2007年01月10日 下午 09:39:45

wan 发表于 2007-1-11 08:40:17

好文,支持啊:victory:

wzwgp 发表于 2007-1-11 09:23:04

这个要好好学习!

xyyh816 发表于 2007-1-11 21:44:51

您还是菜鸟?晕,高手了,向您学习

maoli0366 发表于 2007-1-13 21:31:54

好啊,看得我眼花了/:D

yang15363 发表于 2007-4-1 13:41:46

好东东,学习一下.

fyxt2033 发表于 2007-4-4 20:16:36

很好的学习材料,谢谢楼主提供

jiaf 发表于 2007-4-5 12:03:48

学习中,感谢

rttw5i 发表于 2007-4-5 18:28:41

iBlueSky 发表于 2007-4-6 13:14:32

不错
收藏备用
谢谢!!
页: [1] 2 3
查看完整版本: 菜鸟注册机编写基础教程(WIN汇编版)