【破文标题】Crackme 06-07 的详解
【难度级别】初入门的新手
【下载地址】见附件
【破解工具】OD,peid
【加壳方式】无壳
【保护方式】无Anti-debug
【破解声明】本人破解很菜,此CrackMe算是入门级的,希望以此作为一些简单的案例,给我室友以及才开始接触逆向的各位兄弟,希望大家有所收获,如果不出意外这是一个长期的学习笔记,请大家多多指教。
【前文连接】http://bbs.pediy.com/showthread.php?t=139076
【备 注】
1.老手勿看。
2.开学了,事情好多呀
首先,我们来个温柔点的。拖入Peid查看之后,发现程序没有加壳,VC6.0编译的。通过查看导入表,我们果断用OD载入,然后对GetDlgItemTextA下断点,将程序跑起来,随便输入用户名和密码,我们来到0x4010dc。我们可以看到这是对输入的用户名和密码进行提取:
[SIZE="4"]
004010C8 . 8B3D 98404000 MOV EDI,DWORD PTR DS:[<&USER32.GetDlgIte>; USER32.GetDlgItemTextA
004010CE . 53 PUSH EBX
004010CF . 8B5C24 38 MOV EBX,DWORD PTR SS:[ESP+38]
004010D3 . 6A 1E PUSH 1E ; /Count = 1E (30.)
004010D5 . 56 PUSH ESI ; |Buffer
004010D6 . 68 EA030000 PUSH 3EA ; |ControlID = 3EA (1002.)
004010DB . 53 PUSH EBX ; |hWnd
004010DC . FFD7 CALL EDI ; \GetDlgItemTextA
004010DE . 6A 0A PUSH 0A ; /Count = A (10.)
004010E0 . 55 PUSH EBP ; |Buffer
004010E1 . 68 EB030000 PUSH 3EB ; |ControlID = 3EB (1003.)
004010E6 . 53 PUSH EBX ; |hWnd
004010E7 . FFD7 CALL EDI ; \GetDlgItemTextA
004010E9 . 8BFE MOV EDI,ESI ; 用户名字符串存入0x922FA0(长度最长为0x1E)
004010EB . 83C9 FF OR ECX,FFFFFFFF ; 密码字符串存入0x922F70(长度最长为0xA)
[/SIZE]
[SIZE=4]
// 程序正向.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "resource.h"
int fun(HWND hwnd);
int CALLBACK DialogMainProc(HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
);
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// TODO: Place code here.
DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_DIALOG_MAIN), NULL, DialogMainProc,NULL);
return 0;
}
int CALLBACK DialogMainProc(HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
switch (uMsg)
{
case WM_COMMAND:
if (wParam == IDC_BUTTON_OK)
{
fun(hwndDlg);
}
break;
case WM_CLOSE:
EndDialog(hwndDlg, NULL);
break;
case WM_DESTROY:
EndDialog(hwndDlg, NULL);
break;
default:
return 0;
}
return 1;
}
int fun(HWND hwnd)
{
char file_old_string[20];
char string_final[] = {0xd0,0x20,0x35,0x34,0xc0,0x30,0x57,0x5e,0x40,0x50,0xbd,0x58};
char our_input[20];
int i;
int bl;
int addr;
char *p_char;
int *p_int;
int *p_int_2;
int temp;
DWORD sum;
char cl;
HANDLE file_handle;
/*for (i = 6; i > 0; i--) //对原始文件字符串的前6个字符进行处理
{
bl = file_old_string[6 - i];
bl = bl + i;
bl = bl ^ file_old_string[6 - i];
file_old_string[6 - i] = bl;
}*/
file_handle = CreateFile("blaad.xxx", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,NULL);
if (file_handle == INVALID_HANDLE_VALUE)
{
MessageBox(hwnd, "sorry", "no", MB_OK);
return 0;
}
ReadFile(file_handle, file_old_string, 12, &sum, NULL);
if (sum != 12)
{
MessageBox(hwnd, "sorry", "no", MB_OK);
return 0;
}
GetDlgItemText(hwnd, IDC_EDIT_INPUT, our_input, 13);
p_char = &file_old_string[6];
p_int = (int *)(p_char - 6);
temp = *p_int;
temp = temp - 0xa;
temp = temp & 0xffff;
p_int = (int *)p_char;
*p_int = *p_int ^ temp;
p_int = (int *)(p_char - 4);
temp = *p_int;
temp = temp - 0x9;
temp = temp & 0xffff;
p_int = (int *)(p_char+2);
*p_int = *p_int ^ temp;
p_int = (int *)(p_char - 2);
temp = *p_int;
temp = temp - 0x5;
temp = temp & 0xffff;
p_int = (int *)(p_char+4);
*p_int = *p_int ^ temp;
for (i = 0; i < 12; i++)
{
file_old_string[i] ^= (i+1);
}
p_int_2 = (int *)file_old_string;
p_int = (int *)our_input;
cl = file_old_string[8];
for (i = 0; i < 3; i++)
{
temp = *(p_int_2+i);
*(p_int+i) ^= temp;
p_char = (char *)(p_int+i);
*p_char += cl;
*(p_int+i) &= 0xfffff0f0;
}
if (strncmp(our_input, string_final,12) == 0)
{
MessageBox(hwnd, "yes", "Ok", MB_OK);
return 1;
}
return 0;
}[/SIZE]
[SIZE="4"]
// 注册机.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "resource.h"
int CALLBACK test( HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
);
void fun_1(HWND hwnd);
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// TODO: Place code here.
DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_DIALOG_MAIN),NULL, test,NULL);
return 0;
}
void fun_1(HWND hwnd)
{
char our_input[20]; //= {"888888888888"};
char file_string[20];
char final_string[20] = {0xd0,0x20,0x35,0x34,0xc0,0x30,0x57,0x5e,0x40,0x50,0xbd,0x58};
char file_name[] = {"blaad.xxx"};
char temp_ch;
DWORD tmp;
char i;
char *p_char;
int *p_int;
int temp;
HANDLE file;
GetDlgItemText(hwnd,IDC_EDIT_INPUT,our_input,13);
for (i = 1; i < 120; i++)
{
temp_ch = our_input[8] ^ i;
temp_ch = temp_ch + i;
temp_ch &= 0xf0;
if (temp_ch == 0x40)
{
file_string[8] = i;
break;
}
}
final_string[0] -= i;
final_string[4] -= i;
for (i = 0; i < 12; i++)
{
if (i == 8)
{
continue;
}
file_string[i] = our_input[i] ^ final_string[i];
}
for (i = 0; i < 12; i++)
{
file_string[i] ^= (i+1);
}
p_char = &file_string[6];
p_int = (int *)(p_char - 6);
temp = *p_int;
temp = temp - 0xa;
temp = temp & 0xffff;
p_int = (int *)p_char;
*p_int = *p_int ^ temp;
p_int = (int *)(p_char - 4);
temp = *p_int;
temp = temp - 0x9;
temp = temp & 0xffff;
p_int = (int *)(p_char+2);
*p_int = *p_int ^ temp;
p_int = (int *)(p_char - 2);
temp = *p_int;
temp = temp - 0x5;
temp = temp & 0xffff;
p_int = (int *)(p_char+4);
*p_int = *p_int ^ temp;
file = (HANDLE)CreateFile(file_name, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
WriteFile(file,file_string,12,&tmp,NULL);
CloseHandle(file);
}
int CALLBACK test(HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
switch (uMsg)
{
case WM_COMMAND:
if (wParam == IDC_BUTTON_OK)
{
fun_1(hwndDlg);
}
break;
case WM_DESTROY:
EndDialog(hwndDlg, 0);
break;
case WM_CLOSE:
EndDialog(hwndDlg, 0);
break;
default:
return 0;
}
return 1;
}
[/SIZE]
004010F0 . 8B1D 9C404000 MOV EBX,DWORD PTR DS:[<&USER32.MessageBoxA>] ; USER32.MessageBoxA
004010F6 . F2:AE REPNE SCAS BYTE PTR ES:[EDI]
004010F8 . F7D1 NOT ECX
004010FA . 49 DEC ECX
004010FB . 83F9 03 CMP ECX,3 ; 判断用户名长度是否大于等于3,如果小于3则失败
004010FE . 73 0F JNB SHORT prova2.0040110F
00401100 . 6A 40 PUSH 40 ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
00401102 . 68 DC504000 PUSH prova2.004050DC ; |Title = ">:-("
00401107 . 68 A8504000 PUSH prova2.004050A8 ; |Text = "You have to input a name of minimum 3 characters"
0040110C . 50 PUSH EAX ; |hOwner => NULL
0040110D . FFD3 CALL EBX ; \MessageBoxA
0040110F > 8BFD MOV EDI,EBP
00401111 . 83C9 FF OR ECX,FFFFFFFF
00401114 . 33C0 XOR EAX,EAX
00401116 . F2:AE REPNE SCAS BYTE PTR ES:[EDI]
00401118 . F7D1 NOT ECX
0040111A . 49 DEC ECX
0040111B . 83F9 03 CMP ECX,3
0040111E . 73 1E JNB SHORT prova2.0040113E ; 判断密码长度是否大于等于3,如果小于3则失败
00401120 . 6A 40 PUSH 40
00401122 . 68 DC504000 PUSH prova2.004050DC ; ASCII ">:-("
00401127 . 68 6C504000 PUSH prova2.0040506C ; ASCII "You have to input a serial number of minimum 3 characters"
0040112C . 50 PUSH EAX
0040112D . FFD3 CALL EBX ; MessageBoxA
0040112F . 5B POP EBX
00401130 . 5F POP EDI
00401131 . 5E POP ESI
00401132 . B8 01000000 MOV EAX,1
00401137 . 5D POP EBP
00401138 . 83C4 24 ADD ESP,24
0040113B . C2 1000 RETN 10
0040113E > 8BFE MOV EDI,ESI
00401140 . 83C9 FF OR ECX,FFFFFFFF
00401143 . 33C0 XOR EAX,EAX
00401145 . F2:AE REPNE SCAS BYTE PTR ES:[EDI]
00401147 . F7D1 NOT ECX
00401149 . 49 DEC ECX
0040114A . 83F9 03 CMP ECX,3 ; 用户名字符串长度必须大于等于3
0040114D . 0F82 8A000000 JB prova2.004011DD
00401153 . 8BFD MOV EDI,EBP
00401155 . 83C9 FF OR ECX,FFFFFFFF
00401158 . F2:AE REPNE SCAS BYTE PTR ES:[EDI]
0040115A . F7D1 NOT ECX
0040115C . 49 DEC ECX
0040115D . 83F9 03 CMP ECX,3
00401160 . 72 7B JB SHORT prova2.004011DD ; 密码字符串长度必须大于等于3
00401162 . 8BFE MOV EDI,ESI
00401164 . 83C9 FF OR ECX,FFFFFFFF
00401167 . 33DB XOR EBX,EBX
00401169 . F2:AE REPNE SCAS BYTE PTR ES:[EDI]
0040116B . F7D1 NOT ECX
0040116D . 49 DEC ECX
0040116E . 74 27 JE SHORT prova2.00401197
00401170 . 8D6C24 14 LEA EBP,DWORD PTR SS:[ESP+14] ; ebp(0x12FA64)字符串: 0123456789:;<=>?@ABCDEFGHIJKL
00401174 . 8BD6 MOV EDX,ESI ; 这里需要注意一下
00401176 . 2BEE SUB EBP,ESI ; edx的初始值为esi,而ebp先减去esi然后又加上edx,实际上还是为ebp原来的值
00401178 > 8A042A MOV AL,BYTE PTR DS:[EDX+EBP] ; 这里,通过edx的增加来实现一个循环的操作:将那串字符串中的字符依次放入AL中
0040117B . 8A0A MOV CL,BYTE PTR DS:[EDX] ; 依次取出输入的用户名字符串中的字符放入CL
0040117D . 32C8 XOR CL,AL ; CL与AL进行异或
0040117F . 43 INC EBX ; ebx表示现在已经处理的字符个数
00401180 . 880A MOV BYTE PTR DS:[EDX],CL ; 异或之后的结果放入原来的用户字符串中
00401182 . 8BFE MOV EDI,ESI
00401184 . 83C9 FF OR ECX,FFFFFFFF
00401187 . 33C0 XOR EAX,EAX
00401189 . 42 INC EDX
0040118A . F2:AE REPNE SCAS BYTE PTR ES:[EDI] ; 获取用户名字符串的长度
0040118C . F7D1 NOT ECX
0040118E . 49 DEC ECX
0040118F . 3BD9 CMP EBX,ECX ; 判断用户名字符串是否处理完毕
00401191 .^ 72 E5 JB SHORT prova2.00401178 ; 处理完毕之后才跳出循环
00401193 . 8B6C24 10 MOV EBP,DWORD PTR SS:[ESP+10]
00401197 > 8BFE MOV EDI,ESI
00401199 . 83C9 FF OR ECX,FFFFFFFF
0040119C . 33C0 XOR EAX,EAX
0040119E . 33DB XOR EBX,EBX
004011A0 . F2:AE REPNE SCAS BYTE PTR ES:[EDI]
004011A2 . F7D1 NOT ECX
004011A4 . 49 DEC ECX
004011A5 . 74 21 JE SHORT prova2.004011C8 ; 如果密码长度为1,则成功=.=(显然这是不可能滴)
004011A7 . 8BD6 MOV EDX,ESI
004011A9 . 2BEE SUB EBP,ESI ; 这里和前面是一个道理
004011AB > 8A02 MOV AL,BYTE PTR DS:[EDX] ; 这里依次取出前面处理之后的用户名字符串
004011AD . 84C0 TEST AL,AL
004011AF . 74 3B JE SHORT prova2.004011EC ; 失败
004011B1 . 3A042A CMP AL,BYTE PTR DS:[EDX+EBP] ; 密码字符串要和前面处理了的用户名字符串匹配
004011B4 . 75 36 JNZ SHORT prova2.004011EC ; 如果不匹配则失败
004011B6 . 43 INC EBX
004011B7 . 8BFE MOV EDI,ESI
004011B9 . 83C9 FF OR ECX,FFFFFFFF
004011BC . 33C0 XOR EAX,EAX
004011BE . 42 INC EDX
004011BF . F2:AE REPNE SCAS BYTE PTR ES:[EDI]
004011C1 . F7D1 NOT ECX
004011C3 . 49 DEC ECX
004011C4 . 3BD9 CMP EBX,ECX
004011C6 .^ 72 E3 JB SHORT prova2.004011AB ; 判断是否处理完毕
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)