當前位置:
首頁 > 最新 > RCTF 2018 Magic題目詳解

RCTF 2018 Magic題目詳解

背景&摘要

此題來自 RCTF 2018 的一道逆向題目 magic. 賽後分析許久, 看了幾個 writeup, 但是始終不得要領, 大神們寥寥數語, 扔下一堆代碼, 就搞定問題. 也理解這寥寥數語, 畢竟比賽的時候時間緊張, 做出題目後就開始下一道了, 而賽後, 大多也會因為一些亂七八糟的事情不再去整理題解. 最終在網上留下的就是一份草稿版題解, 對於新手, 實在是難. 此文從六月一號開始寫, 中間各種事情, 一直拖著, 直到六月八號才寫完.

本著分享知識, 就分享讓大家能看的懂的原則, 在這裡寫一份題解. 希望對於新手有所幫助,還望大佬輕拍.

本文涉及到的知識點有

IDA 遠程調試設置

使用 IDA Keypatch 插件對程序打補丁

了解並能夠識別 rc4 加密演算法

setjmp/longjmp

簡單虛擬機指令的分析方法

根據 IDA 偽代碼分析程序時的細節問題

我並非逐一羅列這些知識點, 而是從拿到程序, 一步步往下走, 遇到什麼說什麼, 直到最後找到 flag 為止.


一個 IDA Pro 和 Windows 足矣.

但是因為我用的是 mac 筆記本, 安裝的 IDA Pro 7.0, 虛擬機是 VirtualBox 中安裝的 Windows 10, 有些路徑需要根據你自己的環境進行配置.

附件下載

初步分析

解壓 magic_9761645341b9b91421388b9631cb6877.zip 後, 我們將會得到一個 magic.exe. 是騾子是馬拉出來溜溜, 運行一下程序, 提示如下:

用 file 簡要看一下信息(workshop 是我的工作目錄)

因為是 Windows 64 位程序, 我們設置一下 IDA 的編譯器選項, 依次 Options/Compiler, 確保設置如下, 如果你不設置的話, IDA 用 Linux x64 的約定來分析函數, 分析出來的函數參數都是錯誤的, 我在這上面踩了很大一個坑.

因此讓我們用 ida64 打開該程序, 打開字元串窗口(shift+F12), 搜索上面的」flag only appears …」 字元串, 得到如下一條結果.

通過交叉引用, 可以定位到該字元串位於 0x4025B4. 然後我們動態調試一下,如何動態調試呢? 我這裡是在 Mac 中運行 IDA, 然後 VirtualBox 中的 Windows 虛擬機, 首先在 Windows 虛擬機中運行 IDA 提供的 win64_remote64.exe, 獲取虛擬機的 ip 地址 (我的為 192.168.56.102), 然後 win64_remote64 就會監聽 23946 埠等待連接. 在 IDA 中 按下 F9, 選擇調試器, 如下

然後依次 Debugger/Process Options 打開如下界面, 並設置正確的路徑, 設置的路徑都是遠程主機上的路徑. 如下所示

由於0x4025B4 位於 main 函數中, 我們可以在 main 函數開頭(0x402563)和 0x4025B4 處設置斷點, 然後就可以按下 F9 運行程序了. 我們發現, 在 main 函數開頭處斷下來時, 程序已經輸出了 「flag only appears at a specific time …」 這一句話, 說明在 main 函數執行之前有其他操作, 並且操作應該是解密字元串並列印. 那我們怎麼找到底是哪裡列印呢? 藉助 trace 功能.

我們用交叉引用可以知道 sub_4011B0() 調用了 main. 所以我們在 0x4011B0 處下斷點, 保持 main 處的斷點, 然後依次選擇 Debugger/Tracing/Function Tracing. F9 運行程序後, 程序中斷在 main 函數處, 我們 Debugger/Tracing/Trace Window 打開 Trace 窗口, 內容如下

於是我們就知道, 在 0x402218 + 0x2B 處調用了列印函數, 往上看, 我們可以知道是 sub_402357 調用了 0x402218 函數. 我們可以以這個為線索, 看看代碼.

sub_402218() 如下所示

對一個字元串先解密, 列印, 然後再加密. 這裡列印的就是 「flag only appears …」. 然後去看一下 sub_402357() 函數. 這個函數如下.

如果 dword_4099D0[0] 為 false, 則調用 sub_402218(), 說明失敗. 因此dword_4099D0[0] 應為 true. dword_4099D0[0] 的值應該是在其上的 sub_402268() 中設置的. 我們來查看這個函數. 我把這個函數重命名為 check_time. 進入該函數看一下, 將一些變數, 函數的名字, 類型等重命名一下, 得到如下

上述代碼裡面, istimeok 變數 ida 將其識別為 int64 類型的, 然後傳入 check_secret 函數時為 (int64)&check_secret, (int64)&check_secret+4, 從這一點我們可以看出這個變數可能是一個長度為 2 的 DWORD 類型數組. 於是將其重定義為 DWORD istimeok[2] 即可. check_secret 的參數個數也不對, 默認的 IDA 給出了四個參數, 最後一個參數沒用到, 查看彙編代碼,發現 check_secret 的參數實際上為 3 個(rcx, rdx, r8), 所以將其參數類型重定義為 _DWORD__fastcall check_secret(BYTEsecret, DWORDa2, DWORDa3). 經過這樣稍微整理之後, 代碼看起來清晰了許多.

邏輯大概是這樣的: 程序運行時, 先計算運行的時間, 看時間戳是否位於 (0x5AFFE78F,0x5B028A8F]. 如果時間戳範圍正確, 則根據時間戳生成一個種子, 把 secret 數組和 rand() 隨機數進行運算並保存. 然後傳入 check_secret 進行檢查. check_secret 函數計算完成後, 會對 istimeok 進行設置, 如果計算結果 istimeok[1] 的值為 1792 說明正確, dword_4099D0[0] 應該會被賦予一個非零值(因為在 else 分支中 dword_4099D0[0] 被賦予了一個 0 值).

注意一下 srand 函數, 傳入一個一定的初始值, rand() 函數生成的隨機數將是一個固定的序列. 但是要注意的是, 這個固定序列在不同平台下, 生成的偽隨機序列是不一致的, 在 Windows 平台下, 該函數在同一初始種子的情況下, 生成相同的隨機序列. 這就要求我們爆破時間戳的時候, 程序應該在 Windows 下跑.

如果我們得到了正確的時間戳, 那麼 check_secret 執行後, istimeok[1] 的值應該是 1792. 所以暴力破解前, 需要弄清楚 check_secret 的功能. 這是本題目的第一個障礙.

第一階段: 尋找正確的時間戳

進入 check_secret, 其代碼如下

這樣子看, 讓人看的很迷茫, v4 是幹什麼的, 以及 vars0 是幹什麼的, 感覺變數都是直接空降, 一臉懵逼. 這個時候就是該看彙編代碼的時候了.

1 處使用 memset 對 Dst 進行置零操作, 注意 Dst 的偏移是 -0C10h, emudst 的偏移地址是 0. 2 處獲取到 secret[i], 3 處計算了一個偏移值, 每次循環向前移動 12 位元組, 所以是 12 * idx, idx 表示當前索引值. 4 處是重點, 由於 emudst 偏移為 0, 減去 0C10 後, 正好指向 Dst, 然後前移 idx, 相當於 Dst[i]. 所以我們明白, 實際上, emudst 和 Dst 是同一個東西. 而且我們看到循環中每次前移 12 位元組, 分為三次賦值, 所以 Dst 的類型 為 DWORD, 大小為 0xc00/ 4 = 768. 在反編譯窗口中對 Dst 類型重定義為 DWORD Dst[768], 發現反編譯代碼變成如下所示

讓人不知所措的 v6, v7 已經消失不見了, 代碼邏輯也清晰可見. 對於 v4 我們可以視而不見, 我們只需要知道 memst 是對 Dst 置零, 然後循環中, 從 Dst 開始, 每次處理三個元素, 然後交給 sub_4026D0 處理, 當所有循環完成後, 檢查 Dst 的最後兩個元素.

於是, 現在的問題變成分析 sub_4026D0 的邏輯. 如下

這個代碼其實沒什麼可說的, 一大堆操作邏輯, 其中的 get_dst_block 用於獲取當前循環 的三個元素, 即對於循環 idx, 返回 Dst + idx * 3. 我們爆破的時候, 直接使用這些代碼 , 做一些微調即可使用. 複製代碼的時候記得加上啟用 IDA 的強制類型轉換, 移除不必要的函數調用約定, 比如 fastcall, 修正一些 C 編譯器無法識別的寫法, 如 0i64. 參考代碼如下


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 FreeBuf 的精彩文章:

思科設備存在硬編碼密碼,安全更新第四次刪除後門賬戶
技術討論 | Windows 10進程鏤空技術(木馬免殺)

TAG:FreeBuf |