0x0 环境
——————–
环境:
系统:Windows 10
工具:IDA 7.X
——————–
0x1 跑起来
这个cm跑起来能看到两个按钮,并且两个按钮错误提示都是相同字符串“Sorry, please try again.”。


不过第二个按钮如果你不输入任何东西会弹出“Please enter your serial number.”

0x2 IDA分析
把程序用丢进IDA字符串查找看样子是可以搜索到弹框的字符串列表。

先通过对“Sorry, please try again.”查看引用出能发现两个地方,sub_401178和sub_4015E4两处。

通过对字符串“Please enter your serial number.”进行交叉引用发现只有一处sub_4015E4使用。

通过分析字符串引用处能够知道sub_401178是负责第一个检查按钮的实现函数。sub_4015E4是检查第二个按钮的实现函数。
第一个按钮
第一个按钮是在sub_401178函数中有引用“Please enter your serial number.”那么跳转到那里去用IDA图形分析模式看看那附近是什么样子。

图片可以看到1处为错误的弹框信息,旁边2也有个MessageBox弹框内容为“Congratulations, you got the hard coded serial”看起来像是验证成功的关键字。在3处为函数GetWindowText专门用于获取窗口字符串的,4处有个字符串“HardCoded”看起来像是正确的关键Key的样子。

测试结果蒙对了。
第二个按钮分析
上面分析可以知道sub_4015E4是检查第二个按钮的实现函数。还是通过字符串引用过去看看。

看起来函数并不大,但是我的显示器窗口太小。好想要一台32寸的144HZ的2K高清显示器用来学逆向啊。
0x3 分析第二个按钮解码逻辑
.text:004015E4 sub_4015E4 proc near ; CODE XREF: sub_401178+28A↑p .text:004015E4 .text:004015E4 arg_0 = dword ptr 8 .text:004015E4 hWnd = dword ptr 0Ch .text:004015E4 .text:004015E4 push ebp .text:004015E5 mov ebp, esp .text:004015E7 push 20h ; ' ' ; nMaxCount .text:004015E9 push offset g_key_buf ; lpString .text:004015EE push [ebp+hWnd] ; hWnd .text:004015F1 call GetWindowTextA .text:004015F6 test eax, eax .text:004015F8 jz in_key_null .text:004015FE mov g_key_length, eax .text:00401603 push 0Bh ; nMaxCount .text:00401605 push offset g_name_buf ; lpString .text:0040160A push [ebp+arg_0] ; hWnd .text:0040160D call GetWindowTextA .text:00401612 test eax, eax .text:00401614 jz short in_name_null .text:00401616 mov g_name_length, eax .text:0040161B xor ecx, ecx .text:0040161D xor ebx, ebx .text:0040161F xor edx, edx .text:00401621 lea esi, g_name_buf .text:00401627 lea edi, g_name_dec_buf .text:0040162D mov ecx, 0Ah .text:00401632 do_while: ; CODE XREF: sub_4015E4+6C↓j .text:00401632 movsx eax, byte ptr [esi+ebx] .text:00401636 cdq .text:00401637 idiv ecx .text:00401639 xor edx, ebx .text:0040163B add edx, 2 ; edx = (g_name_buf[i] % 10) ^ i + 2; .text:0040163E cmp dl, 0Ah .text:00401641 jl short loc_401646 ; if ((BYTE)edx > 0x10) .text:00401641 ; edx -= 0x10; .text:00401643 sub dl, 0Ah .text:00401646 .text:00401646 loc_401646: ; CODE XREF: sub_4015E4+5D↑j .text:00401646 mov [edi+ebx], dl ; g_name_dec_buf[i] = edx; .text:00401649 inc ebx ; index++; .text:0040164A cmp ebx, g_name_length .text:00401650 jnz short do_while ; .text:00401650 ; ; .text:00401652 xor ecx, ecx .text:00401654 xor ebx, ebx .text:00401656 xor edx, edx .text:00401658 lea esi, g_key_buf .text:0040165E lea edi, g_key_dec_buf .text:00401664 mov ecx, 0Ah .text:00401669 do_while_2: ; CODE XREF: sub_4015E4+96↓j .text:00401669 movsx eax, byte ptr [esi+ebx] .text:0040166D cdq .text:0040166E idiv ecx .text:00401670 mov [edi+ebx], dl ; g_key_dec_buf[index] = g_name_buf[i] % 10; .text:00401673 inc ebx ; index++; .text:00401674 cmp ebx, g_key_length .text:0040167A jnz short do_while_2 .text:0040167C jmp short continue .text:0040167E in_name_null: ; CODE XREF: sub_4015E4+30↑j .text:0040167E push 0 ; uType .text:00401680 push offset Caption ; "Splish, Splash" .text:00401685 push offset aPleaseEnterYou ; "Please enter your name." .text:0040168A push 0 ; hWnd .text:0040168C call MessageBoxA .text:00401691 jmp short fun_end .text:00401693 in_key_null: ; CODE XREF: sub_4015E4+14↑j .text:00401693 push 0 ; uType .text:00401695 push offset Caption ; "Splish, Splash" .text:0040169A push offset aPleaseEnterYou_0 ; "Please enter your serial number." .text:0040169F push 0 ; hWnd .text:004016A1 call MessageBoxA .text:004016A6 jmp short fun_end .text:004016A8 continue: ; CODE XREF: sub_4015E4+98↑j .text:004016A8 lea esi, g_key_dec_buf .text:004016AE lea edi, g_name_dec_buf .text:004016B4 xor ebx, ebx .text:004016B6 do_while_3: ; CODE XREF: sub_4015E4+E7↓j .text:004016B6 cmp ebx, g_name_length .text:004016BC jz short check_ok .text:004016BE movsx eax, byte ptr [edi+ebx] .text:004016C2 movsx ecx, byte ptr [esi+ebx] .text:004016C6 cmp eax, ecx .text:004016C8 jnz short check_err ; if (g_key_dec_buf[i] != g_name_dec_buf[i]) .text:004016C8 ; jmp check_err; .text:004016CA inc ebx .text:004016CB jmp short do_while_3 .text:004016CD check_ok: ; CODE XREF: sub_4015E4+D8↑j .text:004016CD push 0 ; uType .text:004016CF push offset Caption ; "Splish, Splash" .text:004016D4 push offset aGoodJobNowKeyg ; "Good job, now keygen it." .text:004016D9 push 0 ; hWnd .text:004016DB call MessageBoxA .text:004016E0 jmp short fun_end .text:004016E2 check_err: ; CODE XREF: sub_4015E4+E4↑j .text:004016E2 push 0 ; uType .text:004016E4 push offset Caption ; "Splish, Splash" .text:004016E9 push offset aSorryPleaseTry ; "Sorry, please try again." .text:004016EE push 0 ; hWnd .text:004016F0 call MessageBoxA .text:004016F5 fun_end: ; CODE XREF: sub_4015E4+AD↑j .text:004016F5 ; sub_4015E4+C2↑j ... .text:004016F5 leave .text:004016F6 retn 8 .text:004016F6 sub_4015E4 endp
算法比较简单,就是对输入的账户每一位进行摸10的结果在对当前字符所在的位置偏移进行异或结果在+2。并且这个结果不能超过10超过10就得减10得出来的数字。KEY的话只要上面NAME的计算结果搞搞只要能摸10还原就可以了。
0x4 C语言源码
// ConsoleApplication1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // #include <iostream> #include <stdlib.h> #include <windows.h> bool check(char* user, char* password) { int user_length = strlen(user); int key_length = strlen(password); char user_dec_buf[30] = { 0x0 }; char key_dec_buf[30] = { 0x0 }; for (int i = 0; i < user_length; i++) { char t = ((user[i] % 10) ^ i) + 2; if (t > 10) t -= 10; user_dec_buf[i] = t; } for (int i = 0; i < key_length; i++) { key_dec_buf[i] = password[i] % 10; } for (int i = 0; i < user_length; i++) { if (key_dec_buf[i] != user_dec_buf[i]) { return false; } } return true; } bool reg(char* user, char* password) { int user_length = strlen(user); int key_length = strlen(password); char user_dec_buf[30] = { 0x0 }; char key_dec_buf[30] = { 0x0 }; for (int i = 0; i < user_length; i++) { char t = ((user[i] % 10) ^ i) + 2; if (t > 10) t -= 10; user_dec_buf[i] = t; } for (int i = 0; i < user_length; i++) { password[i] = user_dec_buf[i] + 0x41 + 5; } return true; } int main() { char name[] = "CTFHUB"; char password[256] = { 0x0 }; reg(name, password); if (check(name, password)) { std::cout << "ok \n"; } return 0; }
发表评论