Ring3下注入DLL的另類方法,能過殺軟和遊戲NP(原始碼)
2009-08-16 13:41:30 www.hackbase.com 來源:YPN電腦技術支援工作室
Ring3下注入DLL的另類方法,能過殺軟和遊戲NP(原始碼) 注入DLL是做全域性鉤子或者攔截類軟體都有可能用到的技術,如果做外掛的話我們也有可能需要注入一個DLL到遊戲程序中去幹點什麼“壞事”。 但我們知道現在 ...
Ring3下注入DLL的另類方法,能過殺軟和遊戲NP(原始碼) 注入DLL是做全域性鉤子或者攔截類軟體都有可能用到的技術,如果做外掛的話我們也有可能需要注入一個DLL到遊戲程序中去幹點什麼“壞事”。 但我們知道現在要注入DLL是越來越難了。場景1:製作火星文輸入法外掛,原理是利用API HOOK攔截並修改輸入法相關函式,需要注入一個DLL到所有程序中,但是後來發現,在開啟了瑞星的帳號保險箱後,使用者將不能在QQ中輸入火星文。原因是瑞星保護了QQ程序,禁止對其注入DLL,解決方法是提示使用者關閉帳號保險箱 -_-|
確實是很降低使用者體驗的一個不是辦法的辦法。場景2:製作某遊戲外掛,需要注入一個DLL到遊戲程序中去直接呼叫遊戲函式完成某一功能。結果發現該遊戲有NP保護,OpenProcess打不開,建立遠端執行緒也不行,試用其它方法也一一失敗。遇到上面的情況,高手們自然是轉到Ring0下面去,使用驅動之類的辦法來對付啦,不過吾等菜鳥可就是酒井沒法子了 -_-|
不過也別太灰心,凡事總會有辦法的。我想我們需要一種持久的、穩定的、不容易被安全軟體遮蔽的DLL注入方法,後來發現,輸入法程式就是能完成這一任務的理想人選。輸入法程式程式到底是什麼?它沒有自己的程序,並且在系統還沒有登入時就已被載入(在歡迎介面你也可以調出輸入法),它可以在遊戲中開啟,也可以在控制檯程式中開啟,還可以在瑞星保護下的QQ中開啟,在殺軟中也可以開啟,這不就是我們要找的特性嗎。那麼,輸入法到底是什麼呢?根據Windows的規定,輸入法其實就是一個DLL,不過它是一個特殊的DLL,它必須具有標準輸入法程式所規定的那些介面,輸入法是由輸入法管理器(imm32.dll)控制的,輸入法管理器又是由user32.dll控制的。輸入法在系統目錄是以IME為副檔名的檔案,當在應用程式中啟用某個輸入法時,輸入法管理器就會在那個應用程式的程序中載入對應的IME檔案,注意,載入IME檔案跟載入普通的DLL並沒有本質區別,所以,可以認為,輸入法其實就是注入到應用程式中的一個DLL檔案,並且,這種“注入”是不會被殺軟和遊戲NP攔截的(至少目前是)。現在,我們已經有了一個注入DLL的另類方法,那就是利用輸入法。具體流程是這樣,首先製作一個標準輸入法檔案,但是這個輸入法並不完成文字輸入工作,它的唯一任務就是用來注入DLL,所以稱為“服務輸入法”,然後,製作一個控制程式,來控制服務輸入法,當然最後還需要一個用於注入的目標DLL,這樣一共就有3個檔案。開始工作後,控制程式首先將服務輸入法安裝到系統中,然後傳遞幾個引數給服務輸入法,引數中包括了需要注入的DLL檔案的名稱和路徑,然後,控制程式將服務輸入法設定為系統的預設輸入法,這樣新的程式一開啟,服務輸入法就會注入那個程式。當然,在服務輸入法安裝之前開啟的程式不會被注入,這時需要向系統中的所有視窗POST一條WM_INPUTLANGCHANGEREQUEST訊息,該訊息可以在指定視窗中後臺啟用服務輸入法,這樣,系統中所有擁有視窗的程序就都被我們的服務輸入法注入了。服務輸入法注入程式之後,就會根據控制程式傳遞過來的引數載入目標DLL,這樣目標DLL也就隨著服務輸入法一同注入到目標程式中了。注意服務輸入法是控制程式用WM_INPUTLANGCHANGEREQUEST訊息在所有視窗中自動啟用的,如果某個視窗自動啟用失敗,你就需要在那個視窗中手工切換到服務輸入法,這樣才能注入進去了。至於注入以後,你就可以在視窗中切換到別的輸入法,這並不會影響已經注入進去的DLL。我將這一套功能製作成一個完整的示例,你可以在以下地址下載:
Public Declare Function IMESetPubString Lib "imedllhost09.ime" (ByVal RunDLLStr As String, ByVal UnloadDll As Long, ByVal loadNextIme As Long, ByVal DllData1 As Long, ByVal DllData2 As Long, ByVal DllData3 As Long) As Long
Public Declare Function IMEClearPubString Lib "imedllhost09.ime" () As Long
其中IMESetPubString用於向輸入法傳遞要注入的DLL等引數。RunDLLStr,要注入的DLL命令和完整路徑。UnloadDll,當輸入法退出時,是否同時解除安裝目標DLL 0-是,1-否。loadNextIme,當切換至該服務輸入法時,是否直接切換到下一個輸入法(這樣服務輸入法就好像被跳過了,可最小限度影響使用者的輸入法順序) 0-否,1-是。DllData1,DllData2,DllData3是傳遞給目標DLL的回撥函式(函式名稱必須為RunDllHostCallBack)的引數,你可以在目標DLL中匯出一個函式,名稱為RunDllHostCallBack,這樣當輸入法注入時會呼叫目標DLL的該回調函式並向其傳遞這3個引數。函式原型為(VC):
DWORD RunDllHostCallBack(DWORD calldata1, DWORD calldata2,DWORD calldata3);
IMEClearPubString函式用於清除輸入法的配置,清除後,輸入法將停止在新的程式中注入目標DLL,但已注入的DLL不會解除安裝。
好了,利用輸入法來注入DLL基本上就是這樣了,詳細的用法大家可以看壓縮包中的第8個資料夾,其中服務輸入法是VC寫的,控制程式是VB的,程式碼都是有註釋的。測試發現該方法能過目前所有殺軟,也能注入冰刃。當然缺點還是有的,就是目標程式如果不接受輸入法那就沒辦法了,但是現在一般的遊戲都不會禁止玩家在裡面打字吧,而且殺軟也不能禁止使用者輸入漢字吧,哈哈,所以通用性應該還是蠻好的。
最後,我再介紹另一個注入DLL的方法,估計也很少被用到。是利用一個未公開函式RegisterUserApiHook,可以在網上搜索關鍵詞“RegisterUserApiHook”,查到有人在Windows 2003下測試成功,但是我在Windows XP測試卻失敗。後來終於找到了失效的原因。RegisterUserApiHook函式可以在系統中註冊一個全域性鉤子,你需要在鉤子中指定一個DLL和一個回撥函式,然後,所有載入了user32.dll的程式就都會在啟動時載入你指定的這個DLL。用這個函式來注入DLL也是很不錯的。但是測試發現它的注入能力似乎趕不上上面提到的利用輸入法來注入的辦法,可以注入一般的程式和某些安全程式,但是對冰刃無效。而且它有一個限制,就是系統中只能同時存在一個這樣的鉤子。實際上這個鉤子平時是被系統中的Themes服務佔用了,Themes服務正是利用這個鉤子HOOK了繪製視窗的相關API,所以才讓所有程式視窗變成XP主題樣式的。所以我們要用這個鉤子的話,必須先關閉Themes服務,這樣在XP下也可以用了,但是這樣系統就變成Windows
2000的樣式了 -_-|
RegisterUserApiHook函式的VB宣告如下:
Public Declare Function RegisterUserApiHookXP Lib "user32" Alias "RegisterUserApiHook" (ByVal hInstance As Long, ByVal fnUserApis As Long) As Long
Public Declare Function RegisterUserApiHook2003 Lib "user32" Alias "RegisterUserApiHook" (pRegInfo As HookAPIRegInfo2003) As Long
可以看到,在XP和2003下這個函式的引數是不一樣的。關於此函式的示例程式碼,請參見壓縮包中的第5個資料夾。
最後的最後,再介紹一個未公開函式InitializeLpkHooks,這個函式在網上能找到的資料更少,只有一個宣告而已。但是它名稱中最後那個“Hooks”誤導了我,我以為又是一個可以用來注入DLL的不錯函式,用OD反出來一看,原來只是個區域性HOOK而已。雖然沒太大用,還是一併寫上吧,也許誰用得著呢。InitializeLpkHooks顧名思義就是HOOK LPK的,Windows有個lpk.dll,就是支援多語言包的那麼個功能。測試發現好多程式在TextOut之前似乎是要呼叫lpk.dll裡面的相關函式的,可能是支援多語言的程式就需要用這個來判斷到底要顯示那種語言吧。而InitializeLpkHooks,就是用來HOOK
lpk.dll裡面的4個函式的,這4個函式是LpkTabbedTextOut,LpkPSMTextOut,LpkDrawTextEx,LpkEditControl。我們先開啟VB,在窗體中加入以下程式碼吧:
Private Sub Form_Load()
DLLhwnd = LoadLibrary("lpk.dll") '載入DLL
DLLFunDre = GetProcAddress(DLLhwnd, "LpkDrawTextEx") '獲取回撥函式地址
LpkHooksInfo.lpHookProc_LpkTabbedTextOut = 0
LpkHooksInfo.lpHookProc_LpkPSMTextOut = 0
LpkHooksInfo.lpHookProc_LpkDrawTextEx = GetLocalProcAdress(AddressOf HookProc1) '設定要HOOK的LPK函式
LpkHooksInfo.lpHookProc_LpkEditControl = 0
InitializeLpkHooks LpkHooksInfo
End Sub
Private Sub Form_Unload(Cancel As Integer)
LpkHooksInfo.lpHookProc_LpkTabbedTextOut = 0
LpkHooksInfo.lpHookProc_LpkPSMTextOut = 0
LpkHooksInfo.lpHookProc_LpkDrawTextEx = DLLFunDre
LpkHooksInfo.lpHookProc_LpkEditControl = 0
InitializeLpkHooks LpkHooksInfo
FreeLibrary DLLhwnd
End Sub
然後新建一個模組,在模組中加入以下程式碼:
Public Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long
Public Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As Long
Public Declare Function FreeLibrary Lib "kernel32" (ByVal hLibModule As Long) As Long
' ----------------未公開函式--------------------------------------
Public Declare Sub InitializeLpkHooks Lib "user32" (lpProcType As Any)
Type LpkHooksSetting
lpHookProc_LpkTabbedTextOut As Long
lpHookProc_LpkPSMTextOut As Long
lpHookProc_LpkDrawTextEx As Long
lpHookProc_LpkEditControl As Long
End Type
' -------------------------------
Public DLLhwnd As Long, DLLFunDre As Long
Public LpkHooksInfo As LpkHooksSetting
Public Function GetLocalProcAdress(ByVal lpProc As Long) As Long
GetLocalProcAdress = lpProc
End Function
Function HookProc1(ByVal a1 As Long, ByVal a2 As Long, ByVal a3 As Long, ByVal a4 As Long, ByVal a5 As Long, ByVal a6 As Long, ByVal a7 As Long, ByVal a8 As Long, ByVal a9 As Long, ByVal a10 As Long) As Long
HookProc1 = 0
End Function
執行一下看看,是不是窗體中標題欄和按鈕上的文字都沒有了,因為我們把函式LpkDrawTextEx替換成自己的函式HookProc1了。這個函式有10個引數,其中幾個好像是字串指標,似乎可以用來截獲窗體要顯示的文字,然後改成另一種語言的文字,我猜想,也許就是這個用途吧。哈哈,純屬猜測。以上就是函式InitializeLpkHooks的用法了。
以上就是全部。
本文所有示例程式碼的下載地址是:
黑基論壇邀請碼:48540f805bJda1S1