天天看点

攻防世界REVERSE新手题解答getitcsaw2013reversing2

getit

程序分析

使用IDA打开程序,F5键利用HexRay工具生成可读代码如下:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char v3; // al
  __int64 j; // [rsp+0h] [rbp-40h]
  int i; // [rsp+4h] [rbp-3Ch]
  FILE *stream; // [rsp+8h] [rbp-38h]
  char filename[8]; // [rsp+10h] [rbp-30h]
  unsigned __int64 v9; // [rsp+28h] [rbp-18h]

  v9 = __readfsqword(0x28u);
  LODWORD(j) = 0;
  while ( (signed int)j < strlen(s) )
  {
    if ( j & 1 )
      v3 = 1;
    else
      v3 = -1;
    *(&t + (signed int)j + 10) = s[(signed int)j] + v3;
    LODWORD(j) = j + 1;
  }
  strcpy(filename, "/tmp/flag.txt");
  stream = fopen(filename, "w");
  fprintf(stream, "%s\n", u, j);
  for ( i = 0; i < strlen(&t); ++i )
  {
    fseek(stream, p[i], 0);
    fputc(*(&t + p[i]), stream);
    fseek(stream, 0LL, 0);
    fprintf(stream, "%s\n", u);
  }
  fclose(stream);
  remove(filename);
  return 0;
}
           

从上面代码可以看出,该程序将flag储存在了

/tmp/flag.txt

的位置,然后作者很贱的又remove了这个文件,所以程序执行之后看不见。

那么,理论上只要在remove的位置加断点,然后在文件被删除之前打开就行。但实际上作者特别贱,不仅挖了remove这个坑,还通过fprintf(stream, “%s\n”, u);这条语句将flag.txt文件中的信息用覆盖了,所以即便拿到flag.txt文件也是没有用的,里面是“************”。但是无所谓,这时只要查看变量

t

处的内存就能找到flag明文。

csaw2013reversing2

程序分析

使用IDA打开程序,F5键利用HexRay工具生成可读代码如下:

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, lpMem);
    ExitProcess(0xFFFFFFFF);
  }
  MessageBoxA(0, lpMem + 1, "Flag", 2u);
  HeapFree(hHeap, 0, lpMem);
  HeapDestroy(hHeap);
  ExitProcess(0);
}
           

阅读代码可知,IsDebuggerPresent()用于判断调试器是否打开,也就是说只有当调试器开启的时候才会进到if语句里面。而if里面的sub_401000函数是解密函数,所以必须要执行这个函数才能得到正确的flag。但是,解密之后程序会ExitProcess退出,因此没法执行MessageBoxA让我们看到flag的结果。

这里有两种思路,一种是通过调试,在ExitProcess处加断点,然后从内存中找到lpMem对应的flag数据。另一种是修改跳转语句,使得sub_401000执行完之后直接跳到MessageBoxA执行。

方法1

攻防世界REVERSE新手题解答getitcsaw2013reversing2

如上图所示设置断点,开始调试后由于__debugbreak();的存在,调试程序会先断在__debugbreak处,这时点继续运行,然后选择“否”就能断到ExitProcess的位置。

这时鼠标移到lpMem上方,可以看到lpMem的值是

0x26505B8

。在Hex-View窗口中按“g”键,输入上面的地址值,就能看到flag。

攻防世界REVERSE新手题解答getitcsaw2013reversing2
攻防世界REVERSE新手题解答getitcsaw2013reversing2

方法2

如下图所示是程序的跳转关系,只需如红箭头所示将jmp指令的跳转位置修改为loc_9E10B9即可,很简单。

攻防世界REVERSE新手题解答getitcsaw2013reversing2

jmp short loc_9E10EF

上右键选择“keypatch->patch”,如下图所示进行修改。修改后窗口会继续跳转到下一条指令,这时关闭这个窗口就行了。

攻防世界REVERSE新手题解答getitcsaw2013reversing2

然后点击“Edit->Patch Program->Apply…”将修改应用到exe文件。

这时开调试模式运行程序就可以看到弹窗变为正确的flag了。

如果想要直接运行exe得到正常的结果,还需进行以下两处修改:

  1. IsDebuggerPresent下方的jz改为jnz,相当于逆转条件判断后的跳转;
  2. __debugbreak处会触发中断,会导致正常执行时程序奔溃,将对应的汇编指令int 3改为NOP即可,NOP为空指令,不做任何操作。
攻防世界REVERSE新手题解答getitcsaw2013reversing2