WoW64 架構閱讀心得

參考文獻

心得


  1. 傳統上 x86 所有系統模組實作都是 ntdll.dll 的函數封裝,最後都會回到 ntdll.dll 的 ZW 函數以 kikifastcall 發送出去就切 Kernel Mode 中斷了。
  2. 不過當 WoW64 架構下,需要把 32 位元程式跑在 64 位元架構的 Process 裡,那麼 32 位元的函數資料丟 64 位元在查 SSDT(其實我不是很清楚 64 位元還有沒有 SSDT)就會因為數字存放的基本資料結構 size 不同導致函數呼叫整個爛掉,因此無法直接把 32 位元程式就直接丟在 64 Process 跑(即使 Thread 可以,但架構上 r0 進去會爛掉)
  3. 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 位元的
  4. ntdll.dll 模組放在 4G 以下,不然這個 TIB 欄位保存不了XD)
  5. 4. 很多設計很爛的 AntiVirus(AV)甚至是早期版本的微軟防漏洞架構 EMET
  6. 的函數監測攔截都是放在 userland、然後 r0 的 hook 強制在每隻 Process 創建時把監測用的 dll 注入到 Process 內做檢測:WoW64 Process 就注入 32 位元的監測 dll 到記憶體裡、64 位元 Process 就把 64 位元監測 dll 注入到記憶體。
  7. 5. 所以 WoW64 架構怎麼被濫用?我故意設計一個 x86 PE 跑在 WoW64 架構下,但是 AV 所有監測都放在 userland 的 4G 底下,因此 32 位元 Process 跑在 WoW64 下只要故意去抓自己的 fs:[0xc0] 呼叫 X86SwitchTo64BitMode, 所有函數請求從 64 位元 ntdll.dll 送出,就可以躲過所有 32bit userland hook
  8. 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 跟辨識哪個是你要的
  9. 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 之類好用的封裝模組給你用

留言

這個網誌中的熱門文章

[C#] Lambda花式應用噁爛寫法(跨UI委派秒幹、多線程處理...etc)

[Windows] 逆向工程 C++ 中入口函數參數 main(argc, argv) 與如何正確的進行參數劫持

重建天堂之門:從 32 位元地獄一路打回天堂聖地(上)深度逆向工程 WOW64 設計