gravatar

Win32 EXE/DLL Injection & An Winamp Example

Windows EXE 執行檔的格式有很多 sections,常見的有 code, data, rdata, res 等等外,還有 EXPORT/IMPORT tables。通常 EXE 比較少有 EXPORT table,因為 EXE 主要是用其他人的 APIs, functions;相反的 DLL 會有 EXPORT table,提供該 DLL 內部的 function name or number 給其他程式使用。

因此在執行一個程式時,windows 載入執行檔後,需要去 resolve 該執行檔需要的 DLL function entry points。因此載入該 DLL file 後,會去查 function address 填回/修改執行檔在記憶體中的 IMPORT table。因為每台電腦的 DLL 版本或是執行時載入的 function address 可能會不一樣,所以需要執行前作這一步動作。然後 EXE 執行時就可以靠著某地方的 pointer 作 jump/call 就可以呼叫想要用的 APIs/functions。

因此,有個很好的機會來作 Injection,也就是只要寫個 DLL,export 同樣 function name。程式就很有可能載入到你自己的 DLL,然後在自己的 DLL 只要呼叫原本的 function,基本上程式運作並不會受到影響。

在以前寫過一個用於 winamp 的 DLL,主要是來擷取聲音資料。winamp 是用一堆 plugins 構成,像是 in_xxx.dll 和 out_xxx.dll 等等。試想,不管怎樣,player 要播放音樂,總得透過 Windows 的 API 來寫入 wave 的資料,因此經由 Injection,可以嘗試把 streaming 或是不能下載或轉換的聲音檔轉出來,而且並不是透過 soundcard Wave in/out 之間的介面,因此 DA/AD 失真就不存在。

所以,這個範例的主要對象是傳統的 wave 開頭的 API 為目標。winamp 可以選擇 waveOut 介面來作為聲音輸出,使用的是 out_wave.dll,而 system waveOut API 則是 winmm.dll。因此在這個範例,我寫了一個 DLL 會 export 與 winmm.dll 相同的 function names;並且會呼叫 winmm.dll 中的相對應 APIs。為了確保 winamp 所載入的是我的 DLL 而非 winmm.dll,於是利用 hex editor 把 out_wave.dll 中的 IMPORT table 的 winmm.dll 改為 winmf.dll,並且把我寫的 dll 檔名也取為 winmf.dll,擺入 winamp 目錄下,如此一來它便會載入我的 winmf.dll 而非 winmm.dll。然後執行時,例如播放 streaming,當 winamp 透過 out_wave.dll 來將 wave 資料送給 soundcard,於是就會經過我的 DLL,透過 "側錄" 方式,把 wave 內容存下來,並且呼叫原本的 winmm.dll 執行正常的功能。

在這個範例裡面,可以看到如何寫一個簡單的 DLL,如何把 function name export 出去成為想要的 Export name(因為不可能在程式寫成與目標 DLL 同樣的 function name,否則等於重複定義,也會變成遞迴)。以及怎樣使用 blade/lame3 mp3 encoder。不過程式使用上會有些限制,例如沒有寫太多 configuration,所以設定便是寫死不夠 flexibility。而且 runtime 可能有些 timing 問題,因為不是 threaded,而 MP3 encode 通常時間要比較久,且又是在 winamp 送出 wave 資料給系統時候即時處理聲音輸出,因此可能會有 timing、thread 方面的問題。不過可以當作一個參考範例,或是不要直接 on-the-fly 壓縮,都應該是可以用的範例。原始碼下載處

Tags: , EXE, winamp