• 标 题:注册机写作教学。奉贤给想加入CCG和BCG的朋友。 (11千字)
  • 作 者:LL[CCG]
  • 时 间:2001-10-21 23:18:55
  • 链 接:http://bbs.pediy.com

前些天在论坛看到有人问软件的算法是如何看懂的 ??注册机是如何写出来的??有感于目前看雪教学中没有这方面的内容(对于不是明码比较的注册机工具就都没有办法了)。于是这篇文章出炉了.由于我对编程方面的技术实在是那个。所以拉来了halfbit(云观)老哥。让他帮忙写ASM,VC的注册机。我自己来写VB的。
本文的目的是通过一个简单的CRACKME的破解来说一下算法的分析和注册机的写作(针对于NAME/SERIAL保护的)。奉献给想加入BCG和CCG的破解爱好者。我尽量写的详细点。如有不明之处请发信到llmen@sina.com
工具:调试器一个(我用的是TRW2000)。编程工具一个。iceClock。

技术要求:熟悉基本的汇编指令。调试器的运用。编程基础(什么 ??你说你不会。。。。那就去找一本书了。一般看完前4章就可以了。由于能力原因只给出了VB,VC,ASM的注册机原代码。)

目标:http://www.cracknow.com/crackme/figugegl.1.zip    2KB。伪装者那里的。加了自己写的壳,入口点是0040147B。
选目标可让我费了些工夫。一开始halfbit让我找个软件,可是我没找到简单点的。才想到CRACKME,又小又简单。可是手头只有CCG和BCG的考试CRACKME。不过为了生命安全着想我还是用别的吧。:)
废话说完了,现在我们开始。

启动TRW2000和CRACKME。输入姓名:liuliu,注册码:98765,用HMEMCPY做断点。点下CHECK。断下来,用PMODULE回到程序领空。跟踪的时候要注意寄存器EAX,EBX,ECX,EDX,ESI,EDI的变化。用D命令查看内容。
:0040132B E80C020000              call 0040153C                               
:00401330 89C6                    mov esi, eax                                  我们在这里,
:00401332 83FE05                  cmp esi, 00000005                            比较姓名长度是不是小于5 。
这里看看ESI里的数值。是6。我的姓名输入是liuliu。长度是6。所以是比较长度。你问为什么知道是姓名长度 ??经验啦。你不知道是比较什么可以改变一下NAME或SERIAL的长度看看。   
:00401335 7D04                    jge 0040133B                                  不小就跳
:00401337 31C0                    xor eax, eax
:00401339 EB44                    jmp 0040137F                                  小于就挂。
:0040133B 6A14                    push 00000014
:0040133D 8D45D6                  lea eax, dword ptr [ebp-2A]
:00401340 50                      push eax             
:00401341 6A66                    push 00000066
:00401343 53                      push ebx
:00401344 E8F3010000              call 0040153C                                这个是取SERIAL的长度。
:00401349 09C0                    or eax, eax                                  看看EAX是不是0,也就是是不是注册码没有输入。
:0040134B 7432                    je 0040137F                                  是0就挂
:0040134D 31FF                    xor edi, edi                                  EDI变0,用来做计数器。
:0040134F EB15                    jmp 00401366                                  跳到算法开始。
:00401351 0FBE443DD6              movsx eax, byte ptr [ebp+edi-2A]              这是姓名第一个字符入EAX。看看EAX里的数值。是6C。l的ASCII码就是6C。所以我找到地方了。:)
:00401356 0FBE543DEB              movsx edx, byte ptr [ebp+edi-15]              这里是注册码第一个字符入EDX。看看EDX的数值。是39。9的ASCII码就是39。
:0040135B 29FA                    sub edx, edi                                  用注册码第一个字符的ASCII码减去EDI(现在为零)。EDX=69。
:0040135D 39D0                    cmp eax, edx                                  比较EAX和EDX是否相等。当然不等了EAX=6C,EDX=39。
:0040135F 7404                    je 00401365                                  相等就继续。跳(这里用r fl z强行跳过。)
:00401361 31C0                    xor eax, eax
:00401363 EB1A                    jmp 0040137F                                  不等就挂。
 
:00401365 47                      inc edi                                      计数器EDI加1。

:00401366 39F7                    cmp edi, esi                                  比较EDI是否等于ESI(姓名长度),也就是注册码是否计算完毕。
:00401368 7CE7                    jl 00401351                                  相等就结束。不等继续。到这里第一次循环结束。第一位注册码验证完毕。在0040135D这里是关键的比较。以后的几次循环算法是一样的,只是数值不同。算法弄的差不多了。后面总结一下。
:0040136A 6A00                    push 00000000
:0040136C 6848204000              push 00402048
:00401371 6850204000              push 00402050
:00401376 53                      push ebx
:00401377 E8E4010000              call 00401560                                注册成功!
算法总结:程序的流程是这样子的
1,比较输入姓名的长度是不是小于5。
2,比较注册码是不是没有输入。
3,算法开始,第1位注册码要等于第1位姓名的ASCII码6C-0(EDI的值)。注册码第1位为l(ASCII码为6C)
            第2位注册码要等于第2位姓名的ASCII码69-1。注册码第2位为h
            第3位注册码要等于第3位姓名的ASCII码75-2。注册码第3位为s。依次类推。
            NAME:liuliu                              SERIAL:lhsiep
到这里算法分析完毕。注册码也出来了。程序计算的流程也弄明白了。用你熟悉的编程语言来模仿一下程序作个注册机。
VB的注册机。
先介绍一下里面用到的一般书上没有的函数。我用的是VB6。0企业版。
LEN() 返回字符串的长度。
ASC()返回字符的ASCII码,VB返回的是10进制的。
MID()返回参数指定的字符。用法:MID(目标字符串,开始的位数,取字符的个数)
STRING()把数字转换为字符。如:A=STRING(76)此时A=“L”。
启动VB6,新建一个工程。在FORM上加两个LABLE控件。然后加两个TEXTBOX控件。一个COMMANDBUTTON控件。
TEXT1。TEXT用来获取NAME,TEXT2。TEXT用来输出SERIAL。
在COMMAND1控件的CLICK事件里如下代码:
Private Sub Command1_Click()
Dim a, b, c, d, e                '变量声明。VB不用特别声明变量的类型。多简单。:)
text2.text="姓名不要小于5位"     
a = Text1.Text                  'a=输入的姓名
b = Len(a)                      'b=姓名的长度
c = 1                          '设一个计数器,类似于程序中的EDI。
If b < 5 Then GoTo a:          '判断姓名长度。小于5就什么也不做。
Do                              ’循环语句,用来计算注册码。
d = Mid(a, c, 1)               
d = Asc(d)
d = d + 1 - c
d = String(1, d)
e = e & d
c = c + 1
Loop While c <= b
Text2.Text = e                  '输出注册码。         
a:
End Sub 
然后用P-CODE编译。才12KB。
VC的注册机
先用APPWIZARD做一个默认的DIALOG BASED。然后删掉上面的东西。加入两个EDITBOX,一个BUTTON。
EDITBOX1用来获得NAME,EDITBOX2用来输出SERIAL。
用CLASSWIZARD加入EDITBOX1的MEMBER m_name.EDITBOX2的MEMBER m_key.
用CLASSWIZARD在BUTTON1的BN_CLICKED事件加个函数OnButton1()
加入如下代码:
void CLLDlg::OnButton1()
{
    // TODO: Add your control notification handler code here
    UpdateData(TRUE);
    m_key        = "";
    char * pName= m_name.GetBuffer(0);

    if(m_name.GetLength() < 5)MessageBox("name必须大于5个字母", "error", MB_OK);
    else{
        for(int n=0;n<=m_name.GetLength();n++)
        {
            m_key += *(pName+n)-n;
        }
        UpdateData(FALSE);
    };
    m_name.ReleaseBuffer();
    
}
用RELEASE编译。
下面是汇编的。我实在是没能力加上步骤。。。请参考iczelion的win32asm教程。
; ml /c /coff /Cp LL.asm
; link /SUBSYSTEM:WINDOWS /LIBPATH:d:\masm32\lib LL
.386
.model flat,stdcall
option casemap:none
WinMain proto :DWORD,:DWORD,:DWORD,:DWORD

include d:\masm32\include\windows.inc
include d:\masm32\include\user32.inc
include d:\masm32\include\kernel32.inc
includelib d:\masm32\lib\user32.lib
includelib d:\masm32\lib\kernel32.lib

.data
ClassName db "SimpleWinClass",0
AppName  db "LL asm",0
MenuName db "FirstMenu",0
ButtonClassName db "button",0
ButtonText db "get key",0
EditClassName db "edit",0
TestString db "Wow! I'm in an edit box now",0
name5        db "name必须大于5个字母",0    ;LL add
msgError    db "error",0            ;LL add

.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
hwndButton HWND ?
hwndEdit HWND ?
keyBuffer db 100 dup(?)        ;LL add
buffer db 512 dup(?)                    ; buffer to store the text retrieved from the edit box

.const
ButtonID equ 1                                ; The control ID of the button control
EditID equ 2                                    ; The control ID of the edit control
IDM_HELLO equ 1
IDM_CLEAR equ 2
IDM_GETTEXT equ 3
IDM_EXIT equ 4

.code
start:
    invoke GetModuleHandle, NULL
    mov    hInstance,eax
    invoke GetCommandLine
    mov CommandLine,eax
    invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
    invoke ExitProcess,eax

WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
    LOCAL wc:WNDCLASSEX
    LOCAL msg:MSG
    LOCAL hwnd:HWND
    mov  wc.cbSize,SIZEOF WNDCLASSEX
    mov  wc.style, CS_HREDRAW or CS_VREDRAW
    mov  wc.lpfnWndProc, OFFSET WndProc
    mov  wc.cbClsExtra,NULL
    mov  wc.cbWndExtra,NULL
    push  hInst
    pop  wc.hInstance
    mov  wc.hbrBackground,COLOR_BTNFACE+1
    mov  wc.lpszMenuName,OFFSET MenuName
    mov  wc.lpszClassName,OFFSET ClassName
    invoke LoadIcon,NULL,IDI_APPLICATION
    mov  wc.hIcon,eax
    mov  wc.hIconSm,eax
    invoke LoadCursor,NULL,IDC_ARROW
    mov  wc.hCursor,eax
    invoke RegisterClassEx, addr wc
    invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR ClassName, \
                        ADDR AppName, WS_OVERLAPPEDWINDOW,\
                        CW_USEDEFAULT, CW_USEDEFAULT,\
                        300,200,NULL,NULL, hInst,NULL
    mov  hwnd,eax
    invoke ShowWindow, hwnd,SW_SHOWNORMAL
    invoke UpdateWindow, hwnd
    .WHILE TRUE
        invoke GetMessage, ADDR msg,NULL,0,0
        .BREAK .IF (!eax)
        invoke TranslateMessage, ADDR msg
        invoke DispatchMessage, ADDR msg
    .ENDW
    mov    eax,msg.wParam
    ret
WinMain endp

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
    .IF uMsg==WM_DESTROY
        invoke PostQuitMessage,NULL
    .ELSEIF uMsg==WM_CREATE
        invoke CreateWindowEx,WS_EX_CLIENTEDGE, ADDR EditClassName,NULL,\
                        WS_CHILD or WS_VISIBLE or WS_BORDER or ES_LEFT or\
                        ES_AUTOHSCROLL,\
                        50,35,200,25,hWnd,8,hInstance,NULL
        mov  hwndEdit,eax
        invoke SetFocus, hwndEdit
        invoke CreateWindowEx,NULL, ADDR ButtonClassName,ADDR ButtonText,\
                        WS_CHILD or WS_VISIBLE or BS_DEFPUSHBUTTON,\
                        75,70,140,25,hWnd,ButtonID,hInstance,NULL
        mov  hwndButton,eax
    .ELSEIF uMsg==WM_COMMAND
        mov eax,wParam
        .IF lParam==0
            .IF ax==IDM_HELLO
                invoke SetWindowText,hwndEdit,ADDR TestString
            .ELSEIF ax==IDM_CLEAR
                invoke SetWindowText,hwndEdit,NULL
;*******************************************************************************
            .ELSEIF  ax==IDM_GETTEXT
                invoke GetWindowText,hwndEdit,ADDR buffer,512    ;获得name串
        mov    ebx,0
        .WHILE byte ptr [buffer+ebx]!=0
            mov    al,[buffer+ebx]
            sub    al,bl
            mov    [keyBuffer+ebx],al            ;变换后放入key串
            inc    ebx;
        .ENDW
        .IF ebx<5
            invoke MessageBox,NULL,offset name5, offset msgError,MB_OK
        .ELSE
            invoke MessageBox,NULL,offset keyBuffer,ADDR AppName,MB_OK      ;显示key串
        .ENDIF
;**********************************************************************************
        .ELSE
                invoke DestroyWindow,hWnd
            .ENDIF
        .ELSE
            .IF ax==ButtonID
                shr eax,16
                .IF ax==BN_CLICKED
                    invoke SendMessage,hWnd,WM_COMMAND,IDM_GETTEXT,0
                .ENDIF
            .ENDIF
        .ENDIF
    .ELSE
        invoke DefWindowProc,hWnd,uMsg,wParam,lParam
        ret
    .ENDIF
    xor    eax,eax
    ret
WndProc endp
end start
到这里这篇文章就差不多了。有些遗憾的是没有DELPHI的原代码。因为没见到懂DELPHI的人。小楼,AJJ看到这个后能不能把DELPHI的注册机也加上呀。我知道的懂DELPHI的只有你们两个。:)
                                                                              LL[CCG] & halfbit[CCG]

  • 标 题:TC的注册机~~~ (596字)
  • 作 者:伪装者[CCG]
  • 时 间:2001-10-22 0:00:39

#include "stdio.h"
main()
{
unsigned char a[80];
int d,i;
unsigned long s;
start:printf("*********-={ figugegl }=- Crackme #1*********\nThis keygen is made by Pretender\nPlease input your name  : ");
gets(a);
d=strlen(a);
if(d<5) {printf("Your user name must longer than 4 letters!!please re-input\n");goto start;}
printf("Your Register code is  : ");
for(i=0;i<d;i++)
printf("%c",a[i]-i);

printf("\n *****************************      ---    ---    ---\n *Welcome to WWW.CRACKNOW.COM*      /      /      / --\n *****************************      ---    ---    --/\n");
}

  • 标 题:我抛砖引玉来个DELPHI的。 (577字)
  • 作 者:ljh3146[BCG]
  • 时 间:2001-10-28 11:20:07

procedure TForm1.BitBtn1Click(Sender: TObject);
var
a,c,e:string;  //定义A,C,E为字符型,
b,d:integer;  //定义B,D为数值型。

begin
a:=edit1.Text;    //让A的值等于EDIT1的值。
  if length(a)<5 then  //LENGTH()相当于VB中的LEN(),如果注册名小于则报错。
    showmessage('注册名不能小于五位!')
  else
  begin
    for  b:=1 to length(a) do  ’循环语句,用来计算注册码。
    begin
      d:=ord(a[b]); 
      d:=d+1-b;     
      c:=chr(d);
      e:=e+c;
    end;
    end;
edit2.Text:=e;
end;

只是将LL大侠的VB版改为DELPHI的了,:)
我试了还行。