WoW64 架構閱讀心得
參考文獻
心得
- 傳統上 x86 所有系統模組實作都是 ntdll.dll 的函數封裝,最後都會回到 ntdll.dll 的 ZW 函數以 kikifastcall 發送出去就切 Kernel Mode 中斷了。
- 不過當 WoW64 架構下,需要把 32 位元程式跑在 64 位元架構的 Process 裡,那麼 32 位元的函數資料丟 64 位元在查 SSDT(其實我不是很清楚 64 位元還有沒有 SSDT)就會因為數字存放的基本資料結構 size 不同導致函數呼叫整個爛掉,因此無法直接把 32 位元程式就直接丟在 64 Process 跑(即使 Thread 可以,但架構上 r0 進去會爛掉)
- 3. 所以在 Win7 架構下會在 TIB 的 fs:[0xc0] 用 uint32_t 欄位(WOW32Reserved)保存了一個 WoW32CPU.dll(32bit) 的函數地址 -- X86SwitchTo64BitMode,也就是 32 位元程式 kikifastcall 原本應該送什麼中斷請求出去,這邊改為用 call dword ptr fs:[0xc0] 就可以直接呼叫到 X86SwitchTo64BitMode API,這個 API 內部實作再幫你把 32 位元的中斷請求參數轉換為 64 位元送給 r0,然後再返還。(這也清楚解釋了為什麼 Win7 64bit 需要把 64 位元的
- ntdll.dll 模組放在 4G 以下,不然這個 TIB 欄位保存不了XD)
- 4. 很多設計很爛的 AntiVirus(AV)甚至是早期版本的微軟防漏洞架構 EMET
- 的函數監測攔截都是放在 userland、然後 r0 的 hook 強制在每隻 Process 創建時把監測用的 dll 注入到 Process 內做檢測:WoW64 Process 就注入 32 位元的監測 dll 到記憶體裡、64 位元 Process 就把 64 位元監測 dll 注入到記憶體。
- 5. 所以 WoW64 架構怎麼被濫用?我故意設計一個 x86 PE 跑在 WoW64 架構下,但是 AV 所有監測都放在 userland 的 4G 底下,因此 32 位元 Process 跑在 WoW64 下只要故意去抓自己的 fs:[0xc0] 呼叫 X86SwitchTo64BitMode, 所有函數請求從 64 位元 ntdll.dll 送出,就可以躲過所有 32bit userland hook
- 6. 有鑒於這種混合 64/32 程式碼在 PE32 搞爛 WoW64 架構繞過 userland AV 的手法,微軟爸爸做法在 Win8+ 系統後把 64bit ntdll.dll 擺到 4G 之上,不過 X86SwitchTo64BitMode 仍然必須呼叫,那怎麼辦?那就讓 32bit ntdll.dll 內增加一個 Wow64SystemServiceCall,kikifastcall 呼叫了先跳到 ntdll32!Wow64SystemServiceCall,而這個 API 內部實作先檢查 TIB32 檢查當前執行程式是否真的是 32 位元程式,如果是才進一步把 32 位元請求發送至 ntdll64.dll 的 X86SwitchTo64BitMode(採用二段跳+偏移定址方式跳過去XD)並且 fs:[0xc0] 也沒有 API 惹,要就直接 call Wow64SystemServiceCall)並且這種濫用手法要拿來 bypass 常見的 sandbox 變得相當困難,因為 ntdll64 開始順序會亂飄,你沒辦法在「沒辦法取得記憶體實際內容」情形下穩定地抓取函數 API 跟辨識哪個是你要的
- 7. 這種混合 32/64 Payload 作法,試圖將 64 Payload 在 WoW64 內運行時,因為這支 Process 是開給 32 位元的程式,所以 PE Loader 只會給當前 Process 加載 ntdll32、ntdll64、還有其他該 32 位元程式所需要的其他 32 函數模組(Kernel32、user32、etc)因此 64 Payload 只能直接呼叫 ntdll64.dll 的 API,沒有 KernelBase 64bit 或者 Kernel32 64mode 之類好用的封裝模組給你用
留言
張貼留言