-
-
[原创]2019看雪CTF 第四题:达芬奇密码
-
发表于: 2019-6-27 00:50 8256
-
运行程序,随便输入一串字符,弹出提示框:
将程序拖入IDA,打开Strings窗口搜索 Wrong
emmmm,居然没有搜索到,这表示程序会在运行过程中,动态解密所需字符串。
动态调试,果然在程序内存中发现有Wrong字符串,计算出Wrong字符串偏移是0x1FDE
IDA打开程序,按住Ctrl+S,找出基址为0x400000,Wrong字符串在程序中偏移地址为0x400000+0x1FDE=0x401FDE
按G,输入0x401FDE,跳转到对应位置,按F5反编译成伪代码:
int __thiscall sub_401EA0(CWnd *this) { CWnd *v1; // esi int v2; // eax WCHAR String; // [esp+Ch] [ebp-310h] char v5; // [esp+Eh] [ebp-30Eh] char v6; // [esp+20Ch] [ebp-110h] char v7; // [esp+20Dh] [ebp-10Fh] DWORD v8; // [esp+30Ch] [ebp-10h] CWnd *v9; // [esp+310h] [ebp-Ch] unsigned int v10; // [esp+314h] [ebp-8h] DWORD flOldProtect; // [esp+318h] [ebp-4h] v1 = this; v9 = this; String = 0; memset(&v5, 0, 0x1FEu); v6 = 0; memset(&v7, 0, 0xFFu); CWnd::GetDlgItemTextW(v1, 0x3E8, &String, 0x14); if ( wcslen(&String) == 0x10 ) { v2 = 0; while ( !(*(&String + v2) & 0xFF00) ) { *(&v6 + v2) = *((_BYTE *)&String + 2 * v2); if ( ++v2 >= 0x10 ) { v8 = 0x40; flOldProtect = 0; VirtualProtect(sub_4010E0, 0xD17u, 0x40u, &flOldProtect); if ( GetLastError() ) return CWnd::MessageBoxW(v1, L"Wrong!", 0, 0); qmemcpy(sub_4010E0, &byte_5647B8, 0x330u); VirtualProtect(sub_4010E0, 0xD17u, flOldProtect, &v8); if ( !GetLastError() ) { v10 = 0; v10 = sub_4010E0(); if ( v10 == 1 ) return CWnd::MessageBoxW(v9, L"Congratulations! You are right!", 0, 0); } v1 = v9; return CWnd::MessageBoxW(v1, L"Wrong!", 0, 0); } } } return CWnd::MessageBoxW(v1, L"Wrong!", 0, 0); }
int __thiscall sub_401EA0(CWnd *this) { CWnd *v1; // esi int v2; // eax WCHAR String; // [esp+Ch] [ebp-310h] char v5; // [esp+Eh] [ebp-30Eh] char v6; // [esp+20Ch] [ebp-110h] char v7; // [esp+20Dh] [ebp-10Fh] DWORD v8; // [esp+30Ch] [ebp-10h] CWnd *v9; // [esp+310h] [ebp-Ch] unsigned int v10; // [esp+314h] [ebp-8h] DWORD flOldProtect; // [esp+318h] [ebp-4h] v1 = this; v9 = this; String = 0; memset(&v5, 0, 0x1FEu); v6 = 0; memset(&v7, 0, 0xFFu); CWnd::GetDlgItemTextW(v1, 0x3E8, &String, 0x14); if ( wcslen(&String) == 0x10 ) { v2 = 0; while ( !(*(&String + v2) & 0xFF00) ) { *(&v6 + v2) = *((_BYTE *)&String + 2 * v2); if ( ++v2 >= 0x10 ) { v8 = 0x40; flOldProtect = 0; VirtualProtect(sub_4010E0, 0xD17u, 0x40u, &flOldProtect); if ( GetLastError() ) return CWnd::MessageBoxW(v1, L"Wrong!", 0, 0); qmemcpy(sub_4010E0, &byte_5647B8, 0x330u); VirtualProtect(sub_4010E0, 0xD17u, flOldProtect, &v8); if ( !GetLastError() ) { v10 = 0; v10 = sub_4010E0(); if ( v10 == 1 ) return CWnd::MessageBoxW(v9, L"Congratulations! You are right!", 0, 0); } v1 = v9; return CWnd::MessageBoxW(v1, L"Wrong!", 0, 0); } } } return CWnd::MessageBoxW(v1, L"Wrong!", 0, 0); }
if ( wcslen(&String) == 0x10 ) //只能输入长度为16的字符
if ( wcslen(&String) == 0x10 ) //只能输入长度为16的字符
while ( !(*(&String + v2) & 0xFF00) ) // 字符范围是从0001到00FF,即ASCII码
while ( !(*(&String + v2) & 0xFF00) ) // 字符范围是从0001到00FF,即ASCII码
动态解密函数sub_4010E0
VirtualProtect(sub_4010E0, 0xD17u, 0x40u, &flOldProtect); if ( GetLastError() ) return CWnd::MessageBoxW(v1, L"Wrong!", 0, 0); qmemcpy(sub_4010E0, &byte_5647B8, 0x330u); VirtualProtect(sub_4010E0, 0xD17u, flOldProtect, &v8);
VirtualProtect(sub_4010E0, 0xD17u, 0x40u, &flOldProtect); if ( GetLastError() ) return CWnd::MessageBoxW(v1, L"Wrong!", 0, 0); qmemcpy(sub_4010E0, &byte_5647B8, 0x330u); VirtualProtect(sub_4010E0, 0xD17u, flOldProtect, &v8);
qmemcpy引起我的兴趣,其作用为将一段长度为0x330的字符复制到sub_4010E0里面。右击byte_5647B8,查找引用。发现sub_401D80()做了一些操作,它异或了0xAB
只要函数sub_4010E0返回值为1,我们就达到目的
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2019-6-27 15:28
被xmhwws编辑
,原因:
赞赏
看原图
赞赏
雪币:
留言: