一个简单的CrackMe分析
来源:互联网 发布:一洋电商软件 编辑:程序博客网 时间:2024/05/22 00:23
http://www.programlife.net/simple-crack-me-analysis.html
好久没有接触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求余的方式来得到下标。
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分析
Copyed From 程序人生
Home Page:http://www.programlife.net
Source URL:http://www.programlife.net/simple-crack-me-analysis.html
- 一个简单的CrackMe分析
- 一个简单的CrackMe分析
- 一个CrackMe的分析
- 一个Crackme的简单Code
- 一个简单CrackMe分析+keyGen编写
- 一个简单的linux crackme的逆向
- 一个简单的linux crackme的逆向
- 一个含有crc32算法的CrackMe分析
- 简单的crackme
- CrackMe的算法分析
- crackMe的逆向分析
- 解密一个简单的keyfile保护的CrackMe
- 一个简单的crackme,程序是由.Net编写的
- 一个CrackMe核心代码的不完整分析
- CrackMe技术等级自测3级一个CrackMe分析
- 某道简单的crackme
- 简单CrackMe分析(样本名:ReverseMe)
- 170608 逆向-CrackMe之018和一个简单的论坛CM
- 数据库sql一些常考基础命令
- 如何编写自己单向链表(c语言)
- 来传智播客学到的第一天
- 哈希分布与一致性哈希算法简介
- ios开发HTML5
- 一个简单的CrackMe分析
- HTML5续
- vm虚拟机安装dos6.22
- 实习日志(6):Flex显示Servlet所传值
- 编译器对switch case结构的优化
- CrackMe技术等级自测3级一个CrackMe分析
- hdu 1074 Doing Homework
- iOS开发icon图片尺寸大小官方说明
- 关联规则学习-序列模式挖掘