吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 3966|回复: 6
收起左侧

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

[复制链接]
红绡枫叶 发表于 2013-11-3 00:02
CM是什么?Crackme是什么?这是什么东西?楼主发的什么?
他们都是一些公开给别人尝试破解的小程序,制作 Crackme 的人可能是程序员,想测试一下自己的软件保护技术,也可能是一位 Cracker,想挑战一下其它 Cracker 的破解实力,也可能是一些正在学习破解的人,自己编一些小程序给自己破解,KeyGenMe是要求别人做出它的 keygen (序号产生器), ReverseMe 要求别人把它的算法做出逆向分析, UnpackMe 是要求别人把它成功脱壳,本版块禁止回复非技术无关水贴。

本帖最后由 红绡枫叶 于 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 [ebx+1]
    mov byte ptr [ebp+edx],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 [ebx]
    movzx edi,byte ptr [ebp+esi]
    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 [ebx]
    movzx edi,byte ptr [ebp+esi]
    .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


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册[Register]

x

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

我是用户 发表于 2013-11-3 00:30
爆一个,一个全局标志位,CreatThread创建线程,判断此标志位是否为1。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册[Register]

x
 楼主| 红绡枫叶 发表于 2013-11-3 08:29
本帖最后由 红绡枫叶 于 2013-11-3 10:18 编辑
我是用户 发表于 2013-11-3 00:30
爆一个,一个全局标志位,CreatThread创建线程,判断此标志位是否为1。

heheh,了解消息机制最重要.....有兴趣写注册机吗?....(serial最小长度已修改..写注册机请重新下载....)
不知是不是我理解问题...创建新线程是来检测输入的serial的正确与否...并非检测全局标志..

我是用户 发表于 2013-11-3 12:53
本帖最后由 我是用户 于 2013-11-3 12:56 编辑
红绡枫叶 发表于 2013-11-3 08:29
heheh,了解消息机制最重要.....有兴趣写注册机吗?....(serial最小长度已修改..写注册机请重新下载....)
...

全局标志位是在你新建的线程里赋值的,没仔细跟,可能是我看错了,不过要让他注册成功的话,只要爆破一个标志位就行了,而且你是当输入框内容改变就创建个线程来判断,如果我输入的速度过快的话,OD会跟死机。
alpha007 发表于 2013-11-4 15:01
我自己手算了一个 : AAAOJJ

把C代码贴出来,以便大家参考:
[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[1]. 同时count_ecx加1.
	{
		count_ecx = Quotient+1;
		byte_40300B_var_1 = Quotient+1;
		serial[serial_len] = serial[1];
	}
	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[index_ebx]^serial[index_esi] )  ) * 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[index_ebx] != serial[index_esi])	// serial 正向位置上的数据和反向位置上的数据不能相等!
		{
			index_ebx ++;
			index_esi --;
			count_ecx --;
		}else
		{
			byte_4030D5 = 0;
		}
	}
}
头像被屏蔽
bambooqj 发表于 2013-11-4 15:30
提示: 作者被禁止或删除 内容自动屏蔽
alpha007 发表于 2013-11-4 18:17
写了一个注册机源码如下:
[C] 纯文本查看 复制代码
#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[SERIAL_DATA_ARRAY_CNT]={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[i].valid != 0 )
		{
			/*
			printf("serial_array[%d]: len:%d  xor_data:%d  sum_eax:%d std_sum:%d \n", i, 
				p_serial_data[i].serial_len, p_serial_data[i].xor_data, 
				p_serial_data[i].sum_eax, p_serial_data[i].std_sum_eax);
			*/
			calculate_serial(
				p_serial_data[i].serial_len, 
				p_serial_data[i].xor_data, 
				p_serial_data[i].sum_eax, 
				p_serial_data[i].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[0]));
	
	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[i] = pNormalPair->char_01;
				pSerialNumber[serial_len-i-1] = pNormalPair->char_02;
			}
			pSerialNumber[i] = pMiddlePair->char_01;
			pSerialNumber[serial_len-i-1] = pMiddlePair->char_02;
			pSerialNumber[serial_len]=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[index_ebx]^serial[index_esi] )  ) * 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[serial_cnt].valid = 1;
				p_serial_data[serial_cnt].serial_len = serial_len;
				p_serial_data[serial_cnt].xor_data = xor_data;
				p_serial_data[serial_cnt].sum_eax = sum_eax;
				p_serial_data[serial_cnt].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();
}

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册[Register]

x
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 22:11

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表