0x0 环境
——————–
环境:
系统:Windows 10
工具:IDA 7.X
——————–
0x1 跑起来
程序界面如下, 要求输入账号CTFHUB得到正确的解码。随便输入Key点击Try弹出对话框显示字符串“Wrong Code!Try Again!”

0x2 IDA分析
载入IDA搜索字符串可以明显的发现有错误和正确的明文字符串。

引用错误字符串处然后图形显示能够发现错误和正确的消息提示都在一个函数里面。

而提示正确还是错误为一处就是这个JZ了

这个函数有些长,躲个懒可以直接F5。整理精简下这个逻辑明显就是按钮事件回调了。手写过win32窗口程序的Hellword都能立马看出来。要分析解码方法的逻辑就在0x111这个case就行。
LRESULT __stdcall sub_401109(HWND hWndParent, UINT Msg, WPARAM wParam, LPARAM lParam)
{
switch ( Msg )
{
case 2u:
PostQuitMessage(0);
break;
case 1u:
/.....................
break;
case 0x111u:
if ( wParam == 3 )
{
//................
if ( v17 != v15 )
goto LABEL_35;
}
MessageBoxA(0, aSerialIsCorrec, aGoodCracker, 0);
}
else
{
LABEL_35:
MessageBoxA(0, Text, Caption, 0);
}
//................
}
break;
//................
}
return 0;
}
0x3 分析解码逻辑
.text:00401220 case_111: ; CODE XREF: sub_401109+1C↑j
.text:00401220 cmp [ebp+Msg], 111h
.text:00401227 jnz loc_4013BB
.text:0040122D mov eax, [ebp+wParam]
.text:00401230 cmp ax, 3
.text:00401234 jnz fun_end
.text:0040123A shr eax, 10h
.text:0040123D or ax, ax
.text:00401240 jnz fun_end1
.text:00401246 xor eax, eax
.text:00401248 push 28h ; '(' ; cchMax
.text:0040124A push offset name_buf ; lpString
.text:0040124F push 2 ; nIDDlgItem
.text:00401251 push [ebp+hWndParent] ; hDlg
.text:00401254 call GetDlgItemTextA ; 取name的字符串
.text:00401259 test al, al
.text:0040125B jz Sorry ;
.text:00401261 cmp al, 20h ; ' '
.text:00401263 jg Name_can_be_max_32 ; name的长度不能超过0x20个字节
.text:00401269 cmp al, 5
.text:0040126B jl ame_must_be_min_5 ; name的长度不能低于5个字节
.text:00401271 lea ebx, name_buf
.text:00401277 xor ecx, ecx
.text:00401279 mov al, 5
.text:0040127B xor edx, edx
.text:0040127D do_while: ; CODE XREF: sub_401109+19B↓j
.text:0040127D mov cl, [edx+ebx]
.text:00401280 xor cl, 29h
.text:00401283 add cl, al ; name_buf[i] ^ 0x29 + i
.text:00401285 cmp cl, 41h ; 'A'
.text:00401288 jl short loc_4012A6
.text:0040128A cmp cl, 5Ah ; 'Z'
.text:0040128D jg short loc_4012A6 ; if (name_buf[i] ^ 0x29 + i) < 'A' || (name_buf[i] ^ 0x29 + i) > 'Z'
.text:0040128D ; jmp loc_4012A6;
.text:0040128F loc_40128F: ; CODE XREF: sub_401109+1A1↓j
.text:0040128F mov name_dec_buf[edx], cl ; cl 的值取决于上面那个跳转
.text:00401295 mov (name_dec_buf+1)[edx], 0
.text:0040129C inc dl ; index += 1;
.text:0040129E dec al ; al -= 1;
.text:004012A0 cmp al, 0
.text:004012A2 jz short do_while_break ; 这个循环只会循环五次
.text:004012A4 jmp short do_while
.text:004012A6 loc_4012A6: ; CODE XREF: sub_401109+17F↑j
.text:004012A6 ; sub_401109+184↑j
.text:004012A6 mov cl, 52h ; 'R'
.text:004012A8 add cl, al ; cl = 0x52 + i;
.text:004012AA jmp short loc_40128F ; cl 的值取决于上面那个跳转
.text:004012AC do_while_break: ; CODE XREF: sub_401109+199↑j
.text:004012AC xor edx, edx
.text:004012AE mov eax, 5
.text:004012B3 do_while_2: ; CODE XREF: sub_401109+1D4↓j
.text:004012B3 mov cl, [edx+ebx]
.text:004012B6 xor cl, 27h
.text:004012B9 add cl, al
.text:004012BB add cl, 1 ; name_buf[i] ^ 0x27 + i + 1
.text:004012BE cmp cl, 41h ; 'A'
.text:004012C1 jl short loc_4012DF
.text:004012C3 cmp cl, 5Ah ; 'Z'
.text:004012C6 jg short loc_4012DF ; if (name_buf[i] ^ 0x27 + i + 1) < 'A' || (name_buf[i] ^ 0x27 + i + 1) > 'Z'
.text:004012C6 ; jmp loc_4012DF;
.text:004012C8 loc_4012C8: ; CODE XREF: sub_401109+1DA↓j
.text:004012C8 mov (name_dec_buf+5)[edx], cl ; cl 的值取决于上面那个跳转
.text:004012CE mov (name_dec_buf+6)[edx], 0
.text:004012D5 inc dl ; ndex += 1;
.text:004012D7 dec al ; al -= 1;
.text:004012D9 cmp al, 0
.text:004012DB jz short do_while2_break ; 这个循环只会循环五次
.text:004012DD jmp short do_while_2
.text:004012DF loc_4012DF: ; CODE XREF: sub_401109+1B8↑j
.text:004012DF ; sub_401109+1BD↑j
.text:004012DF mov cl, 4Dh ; 'M'
.text:004012E1 add cl, al ; cl = 0x4D + i;
.text:004012E3 jmp short loc_4012C8 ; cl 的值取决于上面那个跳转
.text:004012E5 do_while2_break: ; CODE XREF: sub_401109+1D2↑j
.text:004012E5 xor eax, eax
.text:004012E7 push 28h ; '(' ; cchMax
.text:004012E9 push offset key_buf ; lpString
.text:004012EE push 4 ; nIDDlgItem
.text:004012F0 push [ebp+hWndParent] ; hDlg
.text:004012F3 call GetDlgItemTextA
.text:004012F8 test ax, ax
.text:004012FB jz short check_err ; 密码不能为0
.text:004012FD cmp ax, 0Ah
.text:00401301 jg short check_err
.text:00401303 jl short check_err ; 密码必须为10位
.text:00401305 xor eax, eax
.text:00401307 xor ebx, ebx
.text:00401309 xor ecx, ecx
.text:0040130B xor edx, edx
.text:0040130D lea eax, key_buf
.text:00401313 do_while_3: ; CODE XREF: sub_401109+234↓j
.text:00401313 mov bl, [ecx+eax]
.text:00401316 mov dl, name_dec_buf[ecx]
.text:0040131C cmp bl, 0
.text:0040131F jz check_ok
.text:00401325 add dl, 5
.text:00401328 cmp dl, 5Ah ; 'Z'
.text:0040132B jg short max_5A ; if (name_dec_buf[ecx] + 5 > 0x5A)
.text:0040132B ; jmp loc_401341:
.text:0040132D loc_40132D: ; CODE XREF: sub_401109+23B↓j
.text:0040132D xor dl, 0Ch
.text:00401330 cmp dl, 41h ; 'A' ; if ((dl ^ 0x0C) < 'A')
.text:00401330 ; jmp loc_401346;
.text:00401333 jl short loc_401346
.text:00401335 cmp dl, 5Ah ; 'Z' ; if ((dl ^ 0x0C) > 'Z')
.text:00401335 ; jmp loc_40134C;
.text:00401338 jg short loc_40134C
.text:0040133A loc_40133A: ; CODE XREF: sub_401109+241↓j
.text:0040133A ; sub_401109+247↓j
.text:0040133A inc ecx ; index++;
.text:0040133B cmp dl, bl
.text:0040133D jz short do_while_3 ; id (dl == key_buf[index])
.text:0040133D ; do_while3 continue;
.text:0040133F jmp short check_err ; else
.text:0040133F ; check_err;
.text:00401341 max_5A: ; CODE XREF: sub_401109+222↑j
.text:00401341 sub dl, 0Dh ; dl -= 0xD;
.text:00401344 jmp short loc_40132D
.text:00401346 loc_401346: ; CODE XREF: sub_401109+22A↑j
.text:00401346 mov dl, 4Bh ; 'K'
.text:00401348 add dl, cl ; dl = 0x4B + index;
.text:0040134A jmp short loc_40133A ; index++;
.text:0040134C loc_40134C: ; CODE XREF: sub_401109+22F↑j
.text:0040134C mov dl, 4Bh ; 'K'
.text:0040134E sub dl, cl ; dl = 0x4B - index;
.text:00401350 jmp short loc_40133A ; index++;
.text:00401352 check_err: ; CODE XREF: sub_401109+1F2↑j
.text:00401352 ; sub_401109+1F8↑j ...
.text:00401352 push 0 ; uType
.text:00401354 push offset Caption ; "Dont give up..."
.text:00401359 push offset Text ; "Wrong Code!Try Again!"
.text:0040135E push 0 ; hWnd
.text:00401360 call MessageBoxA
.text:00401365 jmp short fun_end1
.text:00401367 Sorry: ; CODE XREF: sub_401109+152↑j
.text:00401367 push 0 ; uType
.text:00401369 push offset aSorry ; "Sorry..."
.text:0040136E push offset aEnterName_0 ; "Enter Name!"
.text:00401373 push 0 ; hWnd
.text:00401375 call MessageBoxA
.text:0040137A jmp short fun_end1
.text:0040137C Name_can_be_max_32: ; CODE XREF: sub_401109+15A↑j
.text:0040137C push 0 ; uType
.text:0040137E push offset aSorry ; "Sorry..."
.text:00401383 push offset aNameCanBeMax32 ; "Name can be max 32 Chars long!"
.text:00401388 push 0 ; hWnd
.text:0040138A call MessageBoxA
.text:0040138F jmp short fun_end1
.text:00401391 ame_must_be_min_5: ; CODE XREF: sub_401109+162↑j
.text:00401391 push 0 ; uType
.text:00401393 push offset aSorry ; "Sorry..."
.text:00401398 push offset aNameMustBeMin5 ; "Name must be min 5 Chars long!"
.text:0040139D push 0 ; hWnd
.text:0040139F call MessageBoxA
.text:004013A4 jmp short fun_end1
.text:004013A6 check_ok: ; CODE XREF: sub_401109+216↑j
.text:004013A6 push 0 ; uType
.text:004013A8 push offset aGoodCracker ; "Good Cracker"
.text:004013AD push offset aSerialIsCorrec ; "Serial is correct! Now write a keygen +"...
.text:004013B2 push 0 ; hWnd
.text:004013B4 call MessageBoxA
.text:004013B9 fun_end1: ; CODE XREF: sub_401109+137↑j
.text:004013B9 ; sub_401109+25C↑j ...
.text:004013B9 jmp short fun_end
0x4 C语言源码
// ConsoleApplication1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // #include <iostream> #include <stdlib.h> #include <windows.h> bool check(char* user, char* password) { int user_len = strlen(user); if (user_len < 5 || user_len > 0x20) { return false; } unsigned char name_dec[0x20] = { 0x0 }; for (int i = 0, x = 5; x > 0; x--, i++) { unsigned char tmp = (user[i] ^ 0x29) + x; if (tmp < 'A' || tmp > 'Z') { tmp = 0x52 + x; } name_dec[i] = tmp; } for (int i = 0, x = 5; x > 0; x--, i++) { unsigned char tmp = (user[i] ^ 0x27) + x + 1; if (tmp < 'A' || tmp > 'Z') { tmp = 0x4D + x; } name_dec[i + 5] = tmp; } int key_len = strlen(password); if (key_len == 0) { return false; } if (key_len != 10) { return false; } for (int i = 0; i < key_len; i++) { unsigned char k = password[i]; unsigned char t = name_dec[i] + 5; if (t > 0x5A) { t -= 0xD; } t ^= 0xC; if (t < 'A') { t = 0x4B + i; } else if (t > 'Z') { t = 0x4B - i; } if (t != k) { return false; } } return true; } bool reg(char* user, char* password) { int user_len = strlen(user); if (user_len < 5 || user_len > 0x20) { return false; } for (int i = 0, x = 5; x > 0; x--, i++) { unsigned char tmp = (user[i] ^ 0x29) + x; if (tmp < 'A' || tmp > 'Z') { tmp = 0x52 + x; } password[i] = tmp; } for (int i = 0, x = 5; x > 0; x--, i++) { unsigned char tmp = (user[i] ^ 0x27) + x + 1; if (tmp < 'A' || tmp > 'Z') { tmp = 0x4D + x; } password[i + 5] = tmp; } for (int i = 0; i < 10; i++) { unsigned char t = password[i] + 5; if (t > 0x5A) { t -= 0xD; } t ^= 0xC; if (t < 'A') { t = 0x4B + i; } else if (t > 'Z') { t = 0x4B - i; } password[i] = t; } return true; } int main() { char name[256] = { 0x0 }; char password[256] = { 0x0 }; std::cout << "in name: \n"; std::cin >> name; std::cout << "in password: \n"; std::cin >> password; reg(name, password); if (check(name, password)) { std::cout << "ok \n"; } return 0; }
发表评论