远程注入【注入分类】
?
注入分類
?
?
所謂注入就是將代碼放進某個進程的地址空間并使它成為該進程的一部分;為了對某個進程進行操作,如獲取某進程的數(shù)據(jù),或者修改進程的私有數(shù)據(jù)結構等;則需將自己的代碼放在目標進程的地址空間中運行,這時就需使用注入技術了;
?
代碼編寫為DLL格式,并注入到其它進程中稱為DLL注入。另一種是利用API相關函數(shù)直接把代碼寫入要注入的進程。
進程是一個正在運行的程序,它擁有自己的地址空間,擁有自己的代碼、數(shù)據(jù)和其他系統(tǒng)資源。一個進程包含了一個或者多個運行在此進程內(nèi)的線程。
從定義上看出進程一定要有線程,線程是進程內(nèi)存中的獨立實體。
?
1. 利用注冊表注入(myDLL)
?
?
?
在Windows NT/2000/XP/2003中,有一個注冊表鍵值:
HKEY_LOCAL_MACHINE\Software\Microsoft\WindowsHKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs。
當某個進程加載User32.dll時,這里面列出的所有的DLL都將User32.dll利用LoadLibrary函數(shù)加載到該進程空間中。我們可以把自己的代碼放在一個DLL中,并加入該鍵值,這樣就可以注入到所有使用User32.dll的進程中了。當DLL以LoadLibrary的方式加載時,DllMain會被以DLL_PROCESS_ATTACH為原因調(diào)用,實際上我們也只需要關心DLL_PROCESS_ATTACH。
?
2. 利用Windows Hooks注入(mydll)
Windows系統(tǒng)給我們提供了一些掛鉤函數(shù)(Hook),使得被掛鉤的進程可以在自己處理接收到的消息之前,先執(zhí)行我們的消息處理函數(shù),而這個消息處理函數(shù)一般會放在DLL中,來讓目標進程加載,這實際上已經(jīng)達到了注入代碼的效果。一般情況下,我們把掛鉤函數(shù)和消息處理函數(shù)都放在dll中。如果是全局鉤子,那么你的DLL將會在進程調(diào)用時載入到任意一個調(diào)用的進程的地址空間中,這樣是相當浪費資源的。因此只對某一個指定的線程安裝線程鉤子。
?
3. 利用遠程線程注入(myDLL)(自寫裝載器注入 myDLL)
1、取得遠程進程的進程PID;//使用GetWindowThreadProcessId;
2、打開進程PID,并設定相應操作權限;//OpenProcess;
3、在遠程進程空間中分配一段內(nèi)存用來存放要注入的myDLL完整路徑;//VirtualAllocEx;
4、將要注入的myDLL的路徑寫到剛才分配的遠程進程空間;//WriteProcessMemory;
為什么要把我們要注入的myDLL的文件名寫到遠程進程的地址空間進行操作,《WINDOWS核心編程》中是這樣描述的:“(要注入的DLL文件名)字符串是在調(diào)用進程的地址空間中。該字符串的地址已經(jīng)被賦予新創(chuàng)建的遠程線程,該線程將它傳遞給LoadLibraryA。但是,當LoadLibraryA取消對內(nèi)存地址的引用時,DLL路徑名字符串將不再存在,遠程進程的線程就可能引發(fā)訪問違規(guī)”;
5、從Kernel32.dll中取得LoadLibray的地址;?// GetProcAddress(GetModuleHandle("Kernel32.dll"),"LoadLibraryW");?
為什么不直接對LoadLibrary進行調(diào)用,《WINDOWS核心編程》中是這樣描述的:“如果在對CreateRemoteThread的調(diào)用中使用一個對LoadLibrayA的直接引用,這將在你的模塊的輸入節(jié)中轉換成LoadLibrayA的形實替換程序的地址。將形實替換程序的地址作為遠程線程的起始地址來傳遞,會導致遠程線程開始執(zhí)行一些令人莫名其妙的東西。其結果很可能造成訪問違規(guī)。”
6、調(diào)用CreateRemoteThread函數(shù)以從Kernel32.dll中取得的LoadLibraryA函數(shù)的地址為線程函數(shù)的地址,以我們要注入的DLL文件名為參數(shù),創(chuàng)建遠程線程;
7、等待遠程線程結束(WaitForSingleObject),即等待LoadLibrary返回。
8、取回遠程線程的結束碼(GetExitCodeThtread),即LoadLibrary的返回值
9、釋放分配的內(nèi)存(VirtualFreeEx)。
10、關閉打開的句柄。(CloseHandle)
4. 利用特洛伊DLL進行注入:
這種方法的原理就是由自己寫一個與原有進程調(diào)用的DLL具有相同接口函數(shù)的DLL,再用我們的DLL替換原有的DLL。在替換的過程中,由我們自己編寫感興趣的函數(shù)替換原有函數(shù),而對其它不感興趣的函數(shù),則以函數(shù)轉發(fā)的形式調(diào)用原有DLL中的函數(shù)。這里面有個前提,就是你在編寫DLL時你必須知道原有DLL中的函數(shù)都有哪些,以免導至其它進程調(diào)用DLL時找不到相應的API函數(shù),特別是在替換系統(tǒng)DLL文件時更要小心。
5. 利用遠程線程直接注入:(無DLL)
?
在第三中方法中,我們啟動遠程線程時,線程函數(shù)是我們從Kernel32.dll中取得的LoadLibrary函數(shù)的地址為線程函數(shù)的地址,其實我們可以直接將線程函數(shù)體和函數(shù)參數(shù)寫入目標進程的地址空間,然后創(chuàng)建遠程線程。
使用這個方法時,需要注意以下幾個問題:
(▲) 遠程線程函數(shù)體不得使用kernel32.dll,user32.dll以外的函數(shù)。因為這個兩個模塊在各個進程的相對地址是一樣的,如果一定要使用其它函數(shù),則必須將函數(shù)體寫入目標進程空間。
(▲) 不能使用任何字符串常量,因為字符串常量是存放在PE文件里.data這個段里面的,函數(shù)里保存的只是相對地址。
(▲) 去掉編譯器的/GZ編譯選項,這個選項是用來Enable Stack Frame Run-Time Error Checking。當這個選項打開時,編譯器會在每個函數(shù)中加入一些代碼,用來檢驗ESP在函數(shù)體中是否被改變,但是這些檢驗函數(shù)的地址在不同PE文件中有可能是不一樣的。
(▲) 不得使用增量鏈接(incremental linking)。增量鏈接是編譯器為了減少鏈接時間做的處理,把函數(shù)體用一個JMP指令代替,這樣就可以隨意改變函數(shù)的內(nèi)容,而不用修改CALL指令。
(▲) 不要在函數(shù)體內(nèi)使用超過4kb的局部變量。局部變量是存放在棧中的,例如下面這個函數(shù)
?void Dummy(void) {
BYTE var[256];
var[0] = 0;
var[1] = 1;
var[255] = 255;
?}
?在分配局部變量空間時是這樣的
?:00401000?? push ebp
?:00401001?? mov? ebp, esp
?:00401003?? sub? esp, 00000100?????????? ; change ESP as storage for
????????????????????????????????????????? ; local variables is needed
?:00401006?? mov? byte ptr [esp], 00???? ; var[0] = 0;
?:0040100A?? mov? byte ptr [esp+01], 01?? ; var[1] = 1;
?:0040100F?? mov? byte ptr [esp+FF], FF?? ; var[255] = 255;
?:00401017?? mov? esp, ebp?????????????? ; restore stack pointer
?:00401019?? pop? ebp
?:0040101A?? ret
?但是當局部變量的大小超過4kb時,棧指針并不直接改版,而是調(diào)用另一個函數(shù)來分配內(nèi)存,這個函數(shù)有可能在不同進程中的地址不一樣。
(▲) 函數(shù)體內(nèi)switch語句中的case不要超過3個,否則編譯器會在PE文件中使用跳轉表,而這個跳轉表有可能在目標進程中并不存在。
?
?
?
轉載于:https://www.cnblogs.com/okwary/articles/1358480.html
總結
以上是生活随笔為你收集整理的远程注入【注入分类】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 通用的权限管理系统发布
- 下一篇: 数字模拟信号 单双信道传输