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
爆一个,一个全局标志位,CreatThread创建线程,判断此标志位是否为1。
本帖最后由 红绡枫叶 于 2013-11-3 10:18 编辑
我是用户 发表于 2013-11-3 00:30 static/image/common/back.gif
爆一个,一个全局标志位,CreatThread创建线程,判断此标志位是否为1。
heheh,了解消息机制最重要.....有兴趣写注册机吗?....(serial最小长度已修改..写注册机请重新下载....)
不知是不是我理解问题...创建新线程是来检测输入的serial的正确与否...并非检测全局标志..
本帖最后由 我是用户 于 2013-11-3 12:56 编辑
红绡枫叶 发表于 2013-11-3 08:29 static/image/common/back.gif
heheh,了解消息机制最重要.....有兴趣写注册机吗?....(serial最小长度已修改..写注册机请重新下载....)
...
全局标志位是在你新建的线程里赋值的,没仔细跟,可能是我看错了,不过要让他注册成功的话,只要爆破一个标志位就行了,而且你是当输入框内容改变就创建个线程来判断,如果我输入的速度过快的话,OD会跟死机。 我自己手算了一个 : 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;
}
}
} 写了一个注册机源码如下:
#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]