-
-
[原创]2019看雪CTF 第四题:达芬奇密码
-
发表于: 2019-6-27 00:50 8361
-
运行程序,随便输入一串字符,弹出提示框:

将程序拖入IDA,打开Strings窗口搜索 Wrong
emmmm,居然没有搜索到,这表示程序会在运行过程中,动态解密所需字符串。
动态调试,果然在程序内存中发现有Wrong字符串,计算出Wrong字符串偏移是0x1FDE
IDA打开程序,按住Ctrl+S,找出基址为0x400000,Wrong字符串在程序中偏移地址为0x400000+0x1FDE=0x401FDE
按G,输入0x401FDE,跳转到对应位置,按F5反编译成伪代码:
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 38 39 40 41 42 43 44 45 46 47 48 49 | 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); } |
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 38 39 40 41 42 43 44 45 46 47 48 49 | 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); } |
1 | if ( wcslen(&String) == 0x10 ) //只能输入长度为16的字符 |
1 | if ( wcslen(&String) == 0x10 ) //只能输入长度为16的字符 |
1 | while ( !(*(&String + v2) & 0xFF00) ) // 字符范围是从0001到00FF,即ASCII码 |
1 | while ( !(*(&String + v2) & 0xFF00) ) // 字符范围是从0001到00FF,即ASCII码 |
动态解密函数sub_4010E0
1 2 3 4 | 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); |
1 2 3 4 | 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,我们就达到目的

[招生]科锐逆向工程师培训(2025年3月11日实地,远程教学同时开班, 第52期)!
最后于 2019-6-27 15:28
被xmhwws编辑
,原因:
赞赏
赞赏
雪币:
留言: