[攻防世界 - reverse - 新手区] csaw2013reversing2

先用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里可以看到,这个加密函数是在倒数第二句话的,简单分析就可以知道他是加密函数

(懒得重新上图了)

posted @ 2021-09-30 15:32  iPlayForSG  阅读(216)  评论(2)    收藏  举报