红绡枫叶 发表于 2013-11-3 00:02

WIN32汇编Crackme(适合新手了解windows消息机制等基础知识)

本帖最后由 红绡枫叶 于 2013-11-3 18:14 编辑

Crackme有以下特点:         1,由于是win32汇编语言编写,反汇编代码几乎和源代码一样,特别适合新手分析.         2,”麻雀虽小,五脏俱全”Crackme以对话框为主窗口(模态),虽然没有自己的消息循环结构(此时是系统内建),但消息处理过程也是很典型的.         3,新手会”惊奇”的发现,搜索不到字符串,==||,但是鉴于程序太小,随便往上翻看就看到了,对!字符串”变成”资源载入使用,一般的软件开发都是这样做的….,没有用到GetWindowText,GetDlgItemText一类的函数来获取文本编辑框的内容….         4,双线程编程.我把消息处理过程与验证过程分开在两个线程里         5,算法比较简单….希望有人把注册机源码贴上来         6,外带一点ReserveMe,请把serial的长度由15改为30及以上…
不久后我将贴上汇编源码…..代码不足之处请不吝指出,谢谢
希望论坛越办越好...
已修改serial最小长度为6.....

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
      .386
      .model flat,stdcall
      option casemap:none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定义
include      windows.inc
include      gdi32.inc
includelib    gdi32.lib
include      user32.inc
includelib    user32.lib
include      kernel32.inc
includelib    kernel32.lib
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;equ 等值定义
DLG_MAIN equ 1
IDC_EDIT equ 2
IDC_STC equ 3
IDC_Button_Try equ 4
IDC_Button_ABOUT equ 5
C_ICO equ 6


szUnRegInfo equ 100
szUnRegCap equ 101
szRegedInfo equ 102
szRegedCap equ 103
szAbout equ 104
szAboutCap equ 105
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段
      .data?
hInstance dd ?
hIcon dd ?
hEdit dd ?
szRegBuff db 100 dup(?)
szInfoBuff db 80 dup(?)
szInfoCapBuff db 20 dup(?)
zRegLenth db ?
boolJudge db ?;全局标志变量
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 代码段
      .code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;注册判断
_RegJudge proc uses ebx esi edi,_lParam
LOCAL CmpLenth: byte      ;局部变量的申明,要特别注意它是用ebp当作指针存储的
pushad
mov ebx,offset szRegBuff
mov ebp,offset szRegBuff ;输入字符缓冲区地址
movzx eax,zRegLenth
movzx edx,zRegLenth;字符长度
.if eax >=6      ;--------------------------------算法区
mov esi,edx
mov ecx,2
div cl
.if ah!=0
    add al,1
    movzx ecx,al
    mov CmpLenth,al
    mov al,byte ptr
    mov byte ptr ,al
    .else
      movzx ecx,al
      mov CmpLenth,al
      sub esi,1
.endif
xor eax,eax
push ebp   ;-------------------注意,ebp入栈,不然等会儿用到局部变量时候会出大问题,当然也要注意堆栈平衡
.while ecx>=1
    movzx edx,byte ptr
    movzx edi,byte ptr
    xor edx,edi
    add eax,edx
    imul eax,ecx
    inc ebx
    dec ebp       ;-----------此处更改了ebp
    dec ecx
.endw

.if eax==102 || eax==345 || eax==235
    mov boolJudge,TRUE
.else
    mov boolJudge,FALSE
.endif
pop ebp ;---------------恢复ebp以便使用局部变量
mov cl,CmpLenth
mov ebx,offset szRegBuff
mov ebp,offset szRegBuff
.while ecx>=1
    movzx edx,byte ptr
    movzx edi,byte ptr
    .if edx==edi
      mov boolJudge,FALSE
      .break
    .endif
    inc ebx
    dec ebp
    dec ecx
.endw
.else
    mov boolJudge,FALSE
.endif    ;---------------------------------------------------------算法区
popad
ret
_RegJudge endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>



; 窗口过程
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ProcWinMain    proc    uses ebx edi esi hWnd,uMsg,wParam,lParam ;hWnd 即为对话框句柄
LOCAL RegThreadId: dword
mov eax,uMsg
.if eax == WM_INITDIALOG
    invoke LoadIcon,hInstance,C_ICO
    mov hIcon,eax
    invoke GetDlgItem,hWnd,IDC_EDIT
    mov hEdit,eax
    invoke SendMessage,hWnd,WM_SETICON,ICON_SMALL,hIcon
.elseif eax == WM_CLOSE
    invoke EndDialog,hWnd,NULL
.elseif eax == WM_COMMAND
    movzx eax,word ptr wParam
      .if eax==IDC_EDIT ;------------文本编辑框消息
            invoke GetDlgItem,hWnd,IDC_EDIT
            mov hEdit,eax
            invoke SendMessage,hEdit,EM_LIMITTEXT,15,NULL
            invoke SendMessage,hEdit,WM_GETTEXT,30,offset szRegBuff
            invoke SendMessage,hEdit,WM_GETTEXTLENGTH,NULL,NULL
            mov zRegLenth,al
            invoke CreateThread,NULL,0,offset _RegJudge,NULL,0,addr RegThreadId;-----新建算法线程
            invoke CloseHandle,eax

      .elseif eax==IDC_Button_Try
            .if boolJudge==FALSE
                invoke LoadString,hInstance,szUnRegInfo,offset szInfoBuff,80
                invoke LoadString,hInstance,szUnRegCap,offset szInfoCapBuff,20
                invoke MessageBoxEx,hWnd,offset szInfoBuff,offset szInfoCapBuff,MB_ICONWARNING,NULL
            .elseif boolJudge==TRUE
                invoke LoadString,hInstance,szRegedInfo,offset szInfoBuff,80
                invoke LoadString,hInstance,szRegedCap,offset szInfoCapBuff,20
                invoke MessageBox,hWnd,offset szInfoBuff,offset szInfoCapBuff,MB_ICONASTERISK
            .endif
      .elseif eax==IDC_Button_ABOUT
            invoke LoadString,hInstance,szAbout,offset szInfoBuff,80
            invoke LoadString,hInstance,szAboutCap,offset szInfoCapBuff,20
            invoke MessageBeep,MB_ICONASTERISK
            invoke MessageBox,hWnd,offset szInfoBuff,offset szInfoCapBuff,MB_DEFBUTTON2
      .endif
               
      
.else
    mov eax,FALSE
    ret
.endif
mov eax,TRUE
ret


_ProcWinMain    endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>


start:      ;程序入口
    invoke GetModuleHandle,NULL
    mov hInstance ,eax
    invoke DialogBoxParam,hInstance,DLG_MAIN,NULL,offset _ProcWinMain,NULL
   
    invoke    ExitProcess,NULL
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
      end    start


我是用户 发表于 2013-11-3 00:30

爆一个,一个全局标志位,CreatThread创建线程,判断此标志位是否为1。

红绡枫叶 发表于 2013-11-3 08:29

本帖最后由 红绡枫叶 于 2013-11-3 10:18 编辑

我是用户 发表于 2013-11-3 00:30 static/image/common/back.gif
爆一个,一个全局标志位,CreatThread创建线程,判断此标志位是否为1。
heheh,了解消息机制最重要.....有兴趣写注册机吗?....(serial最小长度已修改..写注册机请重新下载....)
不知是不是我理解问题...创建新线程是来检测输入的serial的正确与否...并非检测全局标志..

我是用户 发表于 2013-11-3 12:53

本帖最后由 我是用户 于 2013-11-3 12:56 编辑

红绡枫叶 发表于 2013-11-3 08:29 static/image/common/back.gif
heheh,了解消息机制最重要.....有兴趣写注册机吗?....(serial最小长度已修改..写注册机请重新下载....)
...
全局标志位是在你新建的线程里赋值的,没仔细跟,可能是我看错了,不过要让他注册成功的话,只要爆破一个标志位就行了,而且你是当输入框内容改变就创建个线程来判断,如果我输入的速度过快的话,OD会跟死机。

alpha007 发表于 2013-11-4 15:01

我自己手算了一个 : AAAOJJ :lol

把C代码贴出来,以便大家参考:
#include <stdio.h>

typedef unsigned char BYTE;
typedef unsigned long DWORD;

void sub_401000()
{
        BYTE serial[] ={"AAAOJJ"};                // 输入的序列号.
        DWORD serial_len=6;                        // 序列号长度.
       
        BYTE byte_4030D5;                        // 标志, 是最关键的值. 保证这个值是OK的,注册机的目的就达到了. success: 1; failed : 0.
        BYTE Quotient,Remainder;        // serial_len除以2的商和余数.
        BYTE byte_40300B_var_1;                // count_ecx的备份.
        DWORD count_ecx;                        // 等于序列号长度的一半.
        DWORD count_esi;                        // = serial_len - 1; 初始值为指向serial最后一个元素的索引.
        DWORD sum_eax;                       
        DWORD index_ebx;                        // serial数组的头部索引
        DWORD index_esi;                        // serial数组的尾部索引
       
        if(serial_len < 6)
        {
                byte_4030D5 = 0;
                return;
        }
       
        count_esi = serial_len;
        Quotient = serial_len/2;
        Remainder = serial_len%2;
       
        if(Remainder != 0)                // 如果输入的serial字符数为奇数,则将自动在尾部追加一个字符,字符数据值等于serial. 同时count_ecx加1.
        {
                count_ecx = Quotient+1;
                byte_40300B_var_1 = Quotient+1;
                serial = serial;
        }
        else                                        // 如果输入的serial字符数为偶数,则直接计算.
        {
                count_ecx = Quotient;
                byte_40300B_var_1 = Quotient;
                count_esi = serial_len-1;
        }
       
        sum_eax = 0;
       
        index_ebx = 0;
        index_esi = count_esi;
       
        while(count_ecx >= 1)
        {
                sum_eax = ( sum_eax + ( serial^serial )) * count_ecx;   
                index_ebx ++;
                index_esi --;
                count_ecx --;
        }
       
        if( (sum_eax == 102) || (sum_eax == 345)
                || (sum_eax == 235) )
        {
                byte_4030D5 = 1;
        }else{
                byte_4030D5 = 0;
        }
       
        count_ecx = byte_40300B_var_1;
        index_ebx = 0;
        index_esi = count_esi;
       
        while(count_ecx >= 1)
        {
                if(serial != serial)        // serial 正向位置上的数据和反向位置上的数据不能相等!
                {
                        index_ebx ++;
                        index_esi --;
                        count_ecx --;
                }else
                {
                        byte_4030D5 = 0;
                }
        }
}

bambooqj 发表于 2013-11-4 15:30

alpha007 发表于 2013-11-4 18:17

写了一个注册机源码如下:
#include <stdio.h>
#include <windows.h>

typedef long BOOL;
typedef unsigned char BYTE;
typedef unsigned long DWORD;

#define TRUE 1
#define FALSE 0

// 字符对结构体: 保存xor值满足的字符对.
typedef struct tag_one_pair_char
{
        BOOL        valid;
        BYTE        char_01;
        BYTE        char_02;
        void *        next;
}_one_pair_char;

// 序列号参数结构体
typedef struct tag_serial_data
{
        BOOL        valid;
        DWORD        serial_len;
        DWORD        xor_data;
        DWORD        sum_eax;
        DWORD        std_sum_eax;
}_serial_data;

int serial_cnt = 0;

#define SERIAL_DATA_ARRAY_CNT        (30)

_serial_data p_serial_data={0};

_one_pair_char* get_one_pair_char_by_xor_val(DWORD tInputXORVal);
void calculate_serial(DWORD        serial_len,DWORD xor_data,DWORD        sum_eax, DWORD std_sum_eax);

// 打印链表 -- 调试用.
void print_pair_char_list(_one_pair_char* pInputList)
{
        _one_pair_char* pTempPair;
        pTempPair = pInputList;
        while ( (pTempPair != NULL) && (pTempPair->valid == TRUE) )
        {
                printf("=== [%c] [%c] \n",pTempPair->char_01, pTempPair->char_02);
                pTempPair=pTempPair->next;
        }
}

// 释放链表
void free_pair_char_list(_one_pair_char* pInputList)
{
        _one_pair_char* p1;
        _one_pair_char* p2;

        if (NULL == pInputList)        return;

        p1 = pInputList;
       
        while ( NULL != p1 )
        {
                p2 = p1->next;
                free(p1);
                p1 = p2;
        }
}

// 打印序列号--内部精确计算
void print_serial_array()
{
        int i;
        for (i=0; i<SERIAL_DATA_ARRAY_CNT; i++)
        {
                if ( p_serial_data.valid != 0 )
                {
                        /*
                        printf("serial_array[%d]: len:%dxor_data:%dsum_eax:%d std_sum:%d \n", i,
                                p_serial_data.serial_len, p_serial_data.xor_data,
                                p_serial_data.sum_eax, p_serial_data.std_sum_eax);
                        */
                        calculate_serial(
                                p_serial_data.serial_len,
                                p_serial_data.xor_data,
                                p_serial_data.sum_eax,
                                p_serial_data.std_sum_eax);
                }
        }
}

// 序列号字符的可能取值.
const BYTE pConstCharArray[] =
{
        '0','1','2','3','4','5','6','7','8','9',
        'a','b','c','d','e','f','g','h','i','j','k','l','m',
        'n','o','p','q','r','s','t','u','v','w','x','y','z',
        'A','B','C','D','E','F','G','H','I','J','K','L','M',
        'N','O','P','Q','R','S','T','U','V','W','X','Y','Z'
};

// 取得一对满足 异或运算 后的值 ==>> 将所有满足条件的值丢进一个单向链表.
_one_pair_char* get_one_pair_char_by_xor_val(DWORD tInputXORVal)
{
        BOOL        bRet;
        DWORD        i,j;
        BYTE * pTempChar01;
        BYTE * pTempChar02;
        DWORD        pConstCharArrayCnt;
        _one_pair_char *        p_pair_head = NULL;        // 链表头结点.
        _one_pair_char *        p_pair_tail = NULL;        // 链表尾结点.
        _one_pair_char *        p_pair_tmp        = NULL;        // 链表临时结点.

        bRet = FALSE;
        pConstCharArrayCnt= (strlen(pConstCharArray))/(sizeof(pConstCharArray));
       
        for (i=0; i<pConstCharArrayCnt; i++)
        {
                pTempChar01 = pConstCharArray+i;
                for (j=0; j<pConstCharArrayCnt; j++)
                {
                        pTempChar02 = pConstCharArray+j;
                        if (( (*pTempChar01) ^ (*pTempChar02) ) == tInputXORVal)
                        {
                                if ( NULL == p_pair_head )
                                {
                                        p_pair_head = (_one_pair_char *)malloc(sizeof(_one_pair_char));
                                        if (NULL == p_pair_head)
                                        {
                                                MessageBox(NULL, "申请内存失败,程序即将关闭!","Error",MB_OK);
                                                exit(-1);
                                        }
                                        p_pair_head->valid = TRUE;
                                        p_pair_head->char_01 = *pTempChar01;
                                        p_pair_head->char_02 = *pTempChar02;
                                        p_pair_head->next = NULL;
                                        p_pair_tail = p_pair_head;
                                }else{
                                        p_pair_tmp = (_one_pair_char *)malloc(sizeof(_one_pair_char));
                                        if (NULL == p_pair_tmp)
                                        {
                                                MessageBox(NULL, "申请内存失败,程序即将关闭!","Error",MB_OK);
                                                exit(-1);
                                        }
                                        p_pair_tmp->valid = TRUE;
                                        p_pair_tmp->char_01 = *pTempChar01;
                                        p_pair_tmp->char_02 = *pTempChar02;
                                        p_pair_tmp->next = NULL;
                                        p_pair_tail->next = p_pair_tmp;
                                        p_pair_tail = p_pair_tmp;
                                }
                                bRet = TRUE;
                        }
                }
        }
       
        return p_pair_head;
}

// 打印序列号
void print_calculate_serial( _one_pair_char * pNormalPairList, _one_pair_char * pMiddlePairList, DWORD serial_len )
{
        BYTE *        pSerialNumber;
        DWORD        i,j,count_ecx;
        _one_pair_char*        pNormalPair;
        _one_pair_char*        pMiddlePair;

        count_ecx = (serial_len+1)/2;
        pSerialNumber = (BYTE *)malloc(serial_len+1);
       
        pNormalPair=pNormalPairList;

        while( pNormalPair )
        {
                pMiddlePair = pMiddlePairList;
                while( pMiddlePair )
                {
                        for(i=0; i<(count_ecx-1); i++)
                        {
                                pSerialNumber = pNormalPair->char_01;
                                pSerialNumber = pNormalPair->char_02;
                        }
                        pSerialNumber = pMiddlePair->char_01;
                        pSerialNumber = pMiddlePair->char_02;
                        pSerialNumber=0;
                        printf("[%s]\n", pSerialNumber);
                        pMiddlePair = pMiddlePair->next;
                }
                pNormalPair = pNormalPair->next;
        }
       
        if ( NULL != pSerialNumber )
        {
                free(pSerialNumber);
                pSerialNumber = NULL;
        }
}

// 精确计算序列号
void calculate_serial(DWORD        serial_len,DWORD xor_data,DWORD        sum_eax, DWORD std_sum_eax)
{
        DWORD        middle_xor_val;
        DWORD        count_ecx;
        _one_pair_char *        pNormalPairList;
        _one_pair_char *        pMiddlePairList;

        count_ecx = (serial_len+1)/2;
        middle_xor_val = xor_data + (std_sum_eax - sum_eax);
       
               
        pNormalPairList = get_one_pair_char_by_xor_val(xor_data);
        pMiddlePairList = get_one_pair_char_by_xor_val(middle_xor_val);
       
        print_calculate_serial(pNormalPairList, pMiddlePairList, serial_len);

        free_pair_char_list(pNormalPairList);
        free_pair_char_list(pMiddlePairList);

}

// 平均值分析,取得可能的序列号数值.
void sub_401000_ex()
{
        DWORD serial_len;                        // 序列号长度.
        BYTE byte_4030D5;                        // 标志, 是最关键的值. 保证这个值是OK的,注册机的目的就达到了. success: 1; failed : 0.
        BYTE Quotient,Remainder;        // serial_len除以2的商和余数.
        BYTE byte_40300B_var_1;                // count_ecx的备份.
        DWORD count_ecx;                        // 等于序列号长度的一半.
        DWORD count_esi;                        // = serial_len - 1; 初始值为指向serial最后一个元素的索引.
        DWORD sum_eax;                       
        DWORD index_ebx;                        // serial数组的头部索引
        DWORD index_esi;                        // serial数组的尾部索引
        DWORD        std_sum_eax;

        int xor_data;
        serial_len = 10;
       
        // 序列号长度范围, 可自己调整
        for(serial_len=6; serial_len<100; serial_len++)
        {
                count_esi = serial_len;
                Quotient = serial_len/2;
                Remainder = serial_len%2;
                count_ecx = Quotient;
                byte_40300B_var_1 = Quotient;
                count_esi = serial_len-1;
               
                // 序列号数据 每一对数据异或后的取值范围. (目前我们使用平均值来评测,后期再精确定位)
                for( xor_data=0; xor_data<255; xor_data++)
                {
                        sum_eax = 0;
                        index_ebx = 0;
                        index_esi = count_esi;
                        count_ecx = byte_40300B_var_1;

                        while(count_ecx >= 1)
                        {
                                //sum_eax = ( sum_eax + ( serial^serial )) * count_ecx;   
                                sum_eax = ( sum_eax + ( xor_data )) * count_ecx;   
                                index_ebx ++;
                                index_esi --;
                                count_ecx --;
                        }
                       
                        /*
                                我们取值是在合法值的 -5 到 +5 之间,后续再做一些精确调整,就是我们的序列号了。
                                当然,如果你取值范围可以改变,这样可以得到更多的序列号。
                                比如,序列号最内层改变两个参数,可以结果的个位数.
                                如果取值从最内层拓展到外一层,则 *1,*2, *3 。。。
                                文字就写到这里,大家去想吧.. O(∩_∩)O~
                        */
                        if ( (sum_eax>=99 && sum_eax <= 105 && (std_sum_eax=102) )
                                || (sum_eax>=342 && sum_eax <= 348 && (std_sum_eax=345) )
                                || (sum_eax>=232 && sum_eax <= 338 && (std_sum_eax=235) ) )

//                         if( (sum_eax == 102) || (sum_eax == 345)
//                                 || (sum_eax == 235) )
                        {
                                p_serial_data.valid = 1;
                                p_serial_data.serial_len = serial_len;
                                p_serial_data.xor_data = xor_data;
                                p_serial_data.sum_eax = sum_eax;
                                p_serial_data.std_sum_eax = std_sum_eax;
                               
                                serial_cnt++;
                               
                                if(serial_cnt >= SERIAL_DATA_ARRAY_CNT)
                                        break;

                                byte_4030D5 = 1;
                        }else{
                                byte_4030D5 = 0;
                        }
                }
        }

}

void main()
{
        sub_401000_ex();
        print_serial_array();
        getch();
}
页: [1]
查看完整版本: WIN32汇编Crackme(适合新手了解windows消息机制等基础知识)