程式設計對於一個有著資訊工程基礎的人,可能不會太困難,但是有些技巧在學習程式設計卻永遠學習不了,這方面的知識需要透過額外學習系統相關的資訊,才會了解,原來可以這麼做,因此這篇的主題是關於如何調用外部程序(Process)的函式(Function),這種技術通常會使用在惡意程式或遊戲外掛上面,惡意程式是為了隱藏自己而附著在外部程序之下;遊戲外掛是為了要蒐集遊戲的資訊以及調用遊戲中的函式,所以我們來探討一下要如何做到這種技術。
要調用外部程序的函式之前,我們需要擁有外部程序的記憶體空間,不過一般遊戲程式或惡意程式是在ring3層(應用層),因此存取記憶體的權限並不能像ring0(核心層)那麼大,所以我們需要透過Code injection或DLL injection技術來同步外部程序的記憶體。
Code injection:通常惡意程式比較會使用此技巧,因為可以毫不留下痕跡的附著在外部程序之下,但是所有用到的API都需要重載它們的位址,也不能使用全域變數,因此局限性非常高。
DLL injection:遊戲外掛最常使用到此種技巧,因為它的撰寫方式較為容易,只要撰寫一個DLL的程式,隨後再利用注入程式將它注入到外部程序之中。
在了解Code injection和DLL injection的優劣,我們也會挑一種做法來達到我們要的目的,我們就挑選DLL injection這種比較簡單的做法來實踐調用外部程序的函式。
這邊先說明一下,我們等下要調用的函式是64位元的外部程序,因此會比32位元複雜一點,在32位元調用組合語言只需要使用asm語法,然而在64位元並沒有此語法,所以需要透過別的方法來完成此技巧。
工具
1. Visual Studio 2015
2. x64dbg
3. Cheat Engine
程式碼
https://drive.google.com/file/d/1eJmbx9UBieYX_KgcsrWRzf2vMob90GbE/view?usp=sharing
解壓縮密碼:1111
一、編輯範例程式
我們接下來要撰寫要被調用函式的範例程式,File->New->Project,Win32 Console Application->next,然後將Empty project打勾。
在專案名稱按右鍵->properties->Linker->Advanced->Target Machine->改成MachineX64。
在上方的編譯選項改成x64,這樣程式在編譯後就是64位元的程式。
範例程式執行後,什麼都不運行,只會無窮迴圈,我們後續會透過DLL來調用PintString函式。
二、編輯DLL程式碼
首先點選File->New->Project,Wim32 Project->next,選擇DLL專案,然後將Empty project打勾。
我們接下來要調用的函式是64位元的程序,因此我們也要使用x64來編譯程式碼,跟範例程式相同的設定,這邊就省略了。
接下來在專案名稱按右鍵->Configuration Properties->General->Configuration Type,選擇Dynamic Library(.dll)。
一樣在專案名稱按右鍵->Build Dependencies->Build Customizations…。
接著將masm的選項打勾,這樣就能在此專案調用組合語言的函式。
DLL程式碼的部分需要注意的是,調用組合語言要透過extern來宣告,它的傳入值是0x13F1216F0(要調用的函式位址),我們在後續會解釋為什麼是0x13F1216F0。
三、編輯組合語言程式碼
組合語言的部分就相當簡單,不過可能會有很多人有一些疑問吧,為什麼是call rcx,因為在64位元的Calling convention的第一個傳遞參數是rcx,所以直接call rcx就能完成調用函式。
四、尋找調用函式位址
首先執行CallFunctionSample.exe,再運行x64dbg->Attach。
我們找到PrintString的函式位址,它是位於13F1216F0,所以在DLL程式裡面調用的位址就是它。
直接調用13F1216F0,其實是比較偷懶的做法,在64位元程序會有ASLR (Address space layout randomization),所以程序重啟後,就會變成其它的位址,通常我們會獲取此程序的模組啟始位址,從記憶體上我們知道它的模組啟始位址是13F110000,所以要調用的位址是callfunctionsample.exe + 0x116F0,這樣就能保證每次都能成功調用此函式。
五、DLL Injection
我們接下來不會撰寫DLL injection的程式,因為Cheat Engine工具能幫我們完成這項任務。
首先在Cheat Engine Attach CallFunctionSample.exe。
然後選擇位於中間的欄位Memory View->Tools->Inject DLL,選擇剛才撰寫好的DLL(CallFunction.dll)。
最後在輸出結果就會顯示此函式調用的字串。