首页 > 逆向调试 > 一个简单的CrackMe分析

一个简单的CrackMe分析

好久没有接触CrackMe,水平也一直很菜,汇编懂一点点,就是静不下心来看东西。这是crackmes.de上面找到的一个简单CrackMe程序,不过原始下载链接已经忘了,下载地址稍后随IDB文件一起给出。这个CrackMe比较有意思,不是通常的Username / Serial的检查,而是直接给出的两个文本框控件,当然具体填什么就需要自己逆向了。

程序名称:MyCrackIt.exe By DevAstatoR
加密信息:无花无壳,Win32 SDK编写
容易程度:★☆☆☆☆
推荐工具:IDA Pro
下载地址:直接下载 迅雷下载

大概分析:根据IDA对程序的反汇编信息,可以知道第一个框需要填入一个数字,通过SendMessage发送WM_GETTEXT的形式获取这个字符串并通过StrToInt()函数转化为数字,获取第二个文本框的信息同样是通过WM_GETTEXT来实现的,但是这个消息的值是通过第一个框的数字计算出来的,可以推出第一个框的字符串为131313(WM_消息的值参考WinUser.h头文件)。接着程序会把第二个文本框得到的字符串进行异或运算作为一个user32.dll中的函数名称,且长度为11。根据程序失败时弹出一个MessageBox,猜想成功时也是弹出MessageBox。正好MessageBoxA位于user32.dll且名字长度为11。后面还有一个所谓的密码(不要求求出),是通过MessageBoxA和131313两个字符串的ASCII值有符号扩展到双字后求余然后再进行异或运算所得。一个比较特别的地方时作者用cdq/idiv求余的方式来得到下标
crackmes.de一个简单的CrackMe分析
IDB文件:

.text:00401019 ; INT_PTR __stdcall DialogFunc(HWND, UINT, WPARAM, LPARAM)
.text:00401019 DialogFunc      proc near               ; DATA XREF: start+3
.text:00401019
.text:00401019 String1         = dword ptr -4Ch
.text:00401019 var_3A          = byte ptr -3Ah
.text:00401019 String2         = byte ptr -28h
.text:00401019 ProcName        = byte ptr -18h
.text:00401019 lParam          = dword ptr -0Ch
.text:00401019 hDlg            = dword ptr  8
.text:00401019 arg_4           = dword ptr  0Ch
.text:00401019 arg_8           = dword ptr  10h
.text:00401019
.text:00401019                 push    ebp
.text:0040101A                 mov     ebp, esp
.text:0040101C                 sub     esp, 4Ch
.text:0040101F                 cmp     [ebp+arg_4], 111h ; WM_COMMAND
.text:00401026                 jnz     short loc_40103B
.text:00401028                 movzx   eax, word ptr [ebp+arg_8] ; LOWORD(wParam)
.text:0040102C                 dec     eax
.text:0040102D                 dec     eax
.text:0040102E                 jz      loc_401194
.text:00401034                 sub     eax, 3E9h       ; Let's Go
.text:00401039                 jz      short loc_401042
.text:0040103B
.text:0040103B loc_40103B:                             ; CODE XREF: DialogFunc+Dj
.text:0040103B                 xor     eax, eax
.text:0040103D                 jmp     locret_4011A2
.text:00401042 ; ---------------------------------------------------------------------------
.text:00401042
.text:00401042 loc_401042:                             ; CODE XREF: DialogFunc+20j
.text:00401042                 push    ebx             ; 比较用户名及序列号
.text:00401043                 push    esi
.text:00401044                 mov     esi, ds:GetDlgItem
.text:0040104A                 push    edi
.text:0040104B                 push    3E8h            ; nIDDlgItem
.text:00401050                 push    [ebp+hDlg]      ; hDlg
.text:00401053                 call    esi ; GetDlgItem ; 获取用户名控件句柄
.text:00401055                 mov     edi, ds:SendMessageA
.text:0040105B                 lea     ecx, [ebp+lParam]
.text:0040105E                 push    ecx             ; lParam -> 缓冲区
.text:0040105F                 push    0Ah             ; wParam -> 字符数
.text:00401061                 push    0Dh             ; Msg -> WM_GETTEXT
.text:00401063                 push    eax             ; hWnd
.text:00401064                 call    edi ; SendMessageA ; 发送WM_GETTEXT
.text:00401066                 push    3EAh            ; nIDDlgItem
.text:0040106B                 push    [ebp+hDlg]      ; hDlg
.text:0040106E                 call    esi ; GetDlgItem ; 获取序列号控件句柄
.text:00401070                 mov     esi, eax
.text:00401072                 lea     eax, [ebp+lParam]
.text:00401075                 push    eax
.text:00401076                 call    ds:StrToIntA    ; 用户名转为数字
.text:0040107C                 lea     ecx, [ebp+ProcName]
.text:0040107F                 push    ecx             ; lParam
.text:00401080                 push    0Ch             ; wParam
.text:00401082                 sub     eax, 200E4h     ; 如果是WM_GETTEXT
.text:00401082                                         ; 则第一个框填131313
.text:00401087                 push    eax             ; Msg
.text:00401088                 push    esi             ; hWnd
.text:00401089                 call    edi ; SendMessageA
.text:0040108B                 mov     esi, offset unk_402078 ; 复制unk_402078的14个字符到String2
.text:00401090                 lea     edi, [ebp+String2]
.text:00401093                 movsd
.text:00401094                 movsd
.text:00401095                 movsd
.text:00401096                 movsw
.text:00401098                 xor     ebx, ebx
.text:0040109A                 xor     esi, esi        ; esi = 0
.text:0040109C                 cmp     [ebp+String2], bl ; 字符串为空?
.text:0040109F                 jz      short loc_4010A8
.text:004010A1
.text:004010A1 loc_4010A1:                             ; CODE XREF: DialogFunc+8Dj
.text:004010A1                 inc     esi             ; 计算String2长度
.text:004010A2                 cmp     [ebp+esi+String2], bl
.text:004010A6                 jnz     short loc_4010A1
.text:004010A8
.text:004010A8 loc_4010A8:                             ; CODE XREF: DialogFunc+86j
.text:004010A8                 xor     ecx, ecx
.text:004010AA
.text:004010AA loc_4010AA:                             ; CODE XREF: DialogFunc+A2j
.text:004010AA                 mov     eax, ecx
.text:004010AC                 cdq                     ; eax扩展为edx:eax
.text:004010AD                 idiv    esi             ; 余数存入edx
.text:004010AF                 mov     al, [ebp+edx+String2] ; 其实就是取字符串的字符
.text:004010B3                 xor     [ebp+ecx+ProcName], al ; 然后与ProcName进行异或运算
.text:004010B7                 inc     ecx
.text:004010B8                 cmp     ecx, 0Bh        ; API名字长度为11
.text:004010BB                 jl      short loc_4010AA
.text:004010BD                 push    offset ModuleName ; "user32"
.text:004010C2                 call    ds:GetModuleHandleA ; API位于user32.dll
.text:004010C8                 cmp     eax, ebx
.text:004010CA                 jz      loc_40116F
.text:004010D0                 lea     ecx, [ebp+ProcName] ; 获取函数地址
.text:004010D3                 push    ecx             ; lpProcName
.text:004010D4                 push    eax             ; hModule
.text:004010D5                 call    ds:GetProcAddress
.text:004010DB                 cmp     eax, ebx
.text:004010DD                 mov     [ebp+arg_8], eax ; arg_8保存API地址
.text:004010E0                 jz      loc_40116F
.text:004010E6                 mov     esi, offset aThePasswordIs ; "The password is: "
.text:004010EB                 lea     edi, [ebp+String1]
.text:004010EE                 movsd
.text:004010EF                 movsd
.text:004010F0                 movsd
.text:004010F1                 movsd
.text:004010F2                 movsw                   ; String1 <- "The password is: \0"
.text:004010F4                 xor     eax, eax
.text:004010F6                 cmp     byte ptr [ebp+lParam], bl ; ebx=0,lParam->第一个文本框字符串
.text:004010F9                 lea     edi, [ebp+var_3A]
.text:004010FC                 stosd
.text:004010FD                 stosd
.text:004010FE                 stosd
.text:004010FF                 stosw
.text:00401101                 stosb                   ; var_3A所指字符串清零
.text:00401102                 mov     esi, offset dword_40204C
.text:00401107                 lea     edi, [ebp+String2]
.text:0040110A                 movsd
.text:0040110B                 movsd
.text:0040110C                 movsd
.text:0040110D                 movsd                   ; 复制dword_40204C到String2
.text:0040110E                 mov     [ebp+arg_4], ebx
.text:00401111                 jz      short loc_40111F
.text:00401113
.text:00401113 loc_401113:                             ; CODE XREF: DialogFunc+104j
.text:00401113                 inc     [ebp+arg_4]     ; 求第一个文本框字符串长度
.text:00401116                 mov     eax, [ebp+arg_4]
.text:00401119                 cmp     byte ptr [ebp+eax+lParam], bl
.text:0040111D                 jnz     short loc_401113
.text:0040111F
.text:0040111F loc_40111F:                             ; CODE XREF: DialogFunc+F8j
.text:0040111F                 xor     esi, esi
.text:00401121                 cmp     [ebp+ProcName], bl
.text:00401124                 jz      short loc_40112D
.text:00401126
.text:00401126 loc_401126:                             ; CODE XREF: DialogFunc+112j
.text:00401126                 inc     esi             ; 求ProcName长度
.text:00401127                 cmp     [ebp+esi+ProcName], bl
.text:0040112B                 jnz     short loc_401126
.text:0040112D
.text:0040112D loc_40112D:                             ; CODE XREF: DialogFunc+10Bj
.text:0040112D                 xor     ecx, ecx
.text:0040112F
.text:0040112F loc_40112F:                             ; CODE XREF: DialogFunc+136j
.text:0040112F                 mov     eax, ecx
.text:00401131                 cdq
.text:00401132                 idiv    esi             ; ProcName长度
.text:00401134                 mov     eax, ecx
.text:00401136                 movsx   edi, [ebp+edx+ProcName] ; 带符号扩展
.text:0040113B                 cdq
.text:0040113C                 idiv    [ebp+arg_4]     ; 第一个文本框字符串长度
.text:0040113F                 movsx   eax, byte ptr [ebp+edx+lParam] ; 带符号扩展
.text:00401144                 cdq
.text:00401145                 idiv    edi
.text:00401147                 xor     [ebp+ecx+String2], dl ; 解密String2
.text:0040114B                 inc     ecx
.text:0040114C                 cmp     ecx, 0Fh
.text:0040114F                 jl      short loc_40112F
.text:00401151                 lea     eax, [ebp+String2]
.text:00401154                 push    eax             ; lpString2
.text:00401155                 lea     eax, [ebp+String1]
.text:00401158                 push    eax             ; lpString1
.text:00401159                 call    ds:lstrcatA     ; 连接字符串
.text:0040115F                 push    ebx
.text:00401160                 push    offset aWellDone_ ; "Well done."
.text:00401165                 lea     eax, [ebp+String1]
.text:00401168                 push    eax
.text:00401169                 push    ebx
.text:0040116A                 call    [ebp+arg_8]     ; 获取到的API
.text:0040116D                 jmp     short loc_401181
.text:0040116F ; ---------------------------------------------------------------------------
.text:0040116F
.text:0040116F loc_40116F:                             ; CODE XREF: DialogFunc+B1j
.text:0040116F                                         ; DialogFunc+C7j
.text:0040116F                 push    ebx             ; uType
.text:00401170                 push    offset Caption  ; "Error!"
.text:00401175                 push    offset Text     ; "Wrong!"
.text:0040117A                 push    ebx             ; hWnd
.text:0040117B                 call    ds:MessageBoxA
.text:00401181
.text:00401181 loc_401181:                             ; CODE XREF: DialogFunc+154j
.text:00401181                 push    3EBh            ; 调用EndDialog结束对话框
.text:00401186                 push    [ebp+hDlg]      ; hDlg
.text:00401189                 call    ds:EndDialog
.text:0040118F                 pop     edi
.text:00401190                 pop     esi
.text:00401191                 pop     ebx
.text:00401192                 jmp     short loc_40119F
.text:00401194 ; ---------------------------------------------------------------------------
.text:00401194
.text:00401194 loc_401194:                             ; CODE XREF: DialogFunc+15j
.text:00401194                 push    2               ; nResult
.text:00401196                 push    [ebp+hDlg]      ; hDlg
.text:00401199                 call    ds:EndDialog
.text:0040119F
.text:0040119F loc_40119F:                             ; CODE XREF: DialogFunc+179j
.text:0040119F                 xor     eax, eax
.text:004011A1                 inc     eax
.text:004011A2
.text:004011A2 locret_4011A2:                          ; CODE XREF: DialogFunc+24j
.text:004011A2                 leave
.text:004011A3                 retn    10h
.text:004011A3 DialogFunc      endp

第二个文本框要填入什么呢?密码又是什么呢?一个C++源代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// Author: 代码疯子
// Blog: http://www.programlife.net/
#include <stdio.h>
#include <string.h>
#include <windows.h>
 
int main(int argc, char **argv)
{
	char chApi[] = {"MessageBoxA"};
	int i = 0;
	BYTE pbXor[] = {0x24, 0x0B, 0x15, 0x1C,
					0x13, 0x0A, 0x04, 0x36,
					0x06, 0x17, 0x2F, 0x64,
					0x64, 0x00};
	for (i = 0; i < strlen(chApi); ++i)
	{
		chApi[i] ^= pbXor[i];
	}
	printf("%s\n", chApi);
 
	BYTE pbSrc[] = {0x7F, 0x52, 0x45, 0x41, 
					0x58, 0x46, 0x5C, 0x5E, 
					0x5E, 0x5F, 0x48, 0x51,
					0x55, 0x52, 0x45, 0x00};
	char chTxt[] = {"131313"};
	for (i = 0; i < 0x0F; ++i)
	{
		DWORD dwA = (DWORD)((signed char)chApi[i%strlen(chApi)]);
		DWORD dwB = (DWORD)((signed char)chTxt[i%strlen(chTxt)]);
		DWORD dwC = dwB % dwA;
		pbSrc[i] ^= (dwC & 0xFF);
	}
 
	printf("%s\n", (char *)pbSrc);
 
	return 0;
}

觉得文章还不错?点击此处对作者进行打赏!


本文地址: 程序人生 >> 一个简单的CrackMe分析
作者:代码疯子(Wins0n) 本站内容如无声明均属原创,转载请保留作者信息与原文链接,谢谢!


更多



分类: 逆向调试 标签:
  1. 本文目前尚无任何评论.
  1. 本文目前尚无任何 trackbacks 和 pingbacks.