天天看點

攻防世界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