先用exeinfo查一下,发现是32位程序
运行程序,发现抛出了乱码窗口
ida打开,反编译主函数
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
int v3; // ecx
CHAR *lpMem; // [esp+8h] [ebp-Ch]
HANDLE hHeap; // [esp+10h] [ebp-4h]
hHeap = HeapCreate(0x40000u, 0, 0);
lpMem = (CHAR *)HeapAlloc(hHeap, 8u, MaxCount + 1);
memcpy_s(lpMem, MaxCount, &unk_409B10, MaxCount);
if ( sub_40102A() || IsDebuggerPresent() )
{
__debugbreak();
sub_401000(v3 + 4, (int)lpMem);
ExitProcess(0xFFFFFFFF);
}
MessageBoxA(0, lpMem + 1, "Flag", 2u);
HeapFree(hHeap, 0, lpMem);
HeapDestroy(hHeap);
ExitProcess(0);
}
阅读函数,发现在if中对lpMen进行了操作,查看函数sub_401000()
unsigned int __fastcall sub_401000(int a1, int a2)
{
int v2; // esi
unsigned int v3; // eax
unsigned int v4; // ecx
unsigned int result; // eax
v2 = dword_409B38;
v3 = a2 + 1 + strlen((const char *)(a2 + 1)) + 1;
v4 = 0;
result = ((v3 - (a2 + 2)) >> 2) + 1;
if ( result )
{
do
*(_DWORD *)(a2 + 4 * v4++) ^= v2;
while ( v4 < result );
}
return result;
}
疑似加密操作,联想到lpMem = (CHAR *)HeapAlloc(hHeap, 8u, MaxCount + 1);
为lpMem申请空间,猜测lpMem存储flag
下文有MessageBoxA(),联系到打开程序时抛出的乱码窗口,猜测sub_40102A() || IsDebuggerPresent()
为否,未能进入if
Ollydbg打开程序,找到IsDebuggerPresent()所在的位置
在此设置断点,单步调试,发现跳过了第一个MessageBoxA
猜测IsDebuggerPresent()指令是反调试函数,观察其中的指令,发现该高亮行跳过了第一个MessageBox函数,将其修改为nop跳过
但继续调试时发现在int3
处程序强行停止,尝试将刚才的语句改为跳转到mov edx,dword ptr ss:[ebp-0xC]
处,并将call
后的跳转语句nop掉,运行得到
发现窗口中输出了空语句。
联想到伪代码中MessageBoxA(0, lpMem + 1, "Flag", 2u);
,lpMem + 1说明该变量的第0位极有可能是空位符,则尝试把刚才call
后的跳转语句重新定向至第二个MessageBox处
得到flag:
flag{reversing_is_not_that_hard!}
upd on 2021/11/12
"尝试将刚才的语句改为跳转到mov edx,dword ptr ss:[ebp-0xC]
处,并将call
后的跳转语句nop掉"
这里当时做题实际上歪打正着了,call调用的函数实际上是对lpMen的加密函数,执行此函数后才能让输出不是乱码,当时做题的时候没考虑到这一点。
在IDA里可以看到,这个加密函数是在倒数第二句话的,简单分析就可以知道他是加密函数
(懒得重新上图了)