挂接CreateProcessW实现对进程创建的完全控制
生活随笔
收集整理的這篇文章主要介紹了
挂接CreateProcessW实现对进程创建的完全控制
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
掛接CreateProcessW實現對進程創建的完全控制
文章作者:System32
這份文檔演示了如何實現全局HOOK
【前言】
【概述】
【copy-on-write】
【三種可行的辦法】
<查詢CreateProcessW的基址及屬性>
<枚舉系統中所有進程>
<修改CreateProcessW頁屬性>
<在進程中分配一塊可用空間>
<將代碼寫入遠程進程空間>
<編譯器的魔術>
<解決麻煩的定位問題>
【完整演示代碼】
【資源】
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
【前言】
寫這篇文檔的時候由于我足夠菜,碰到了不少問題,多謝bkbll,a1rsupply和SobeIt的指點,還有TCH的辛勤勞動,才有這篇文檔的誕生,本文中可能存在一些錯誤,這些錯誤都是由于我的失誤造成的,如果您有什么意見和看法,歡迎來http://www.itaq.org指出,或者E-mail:zf35@citiz.net
【概述】
在服務器上實現對進程創建的控制有很大的意義,通過監控進程的創建,我們可以讓被允許運行的進程正確創建,而未被允許的程序則會創建失敗,這樣就可以防止未知木馬,病毒和蠕蟲對服務器的威脅。要實現上述目的,必須hook windows創建進程相關的API,根據《inside the windows NT》和《Native API Reference》中記載,加上softIce的實際跟蹤,windows創建進程的API調用流程如下:
代碼
CreateProcessA-> CreateProcessW-> CreateProcessInternalW->…->最終調用ZwCreateProcess
本文檔中我們選用CreateProcessW來實現我們的目的,當然你也可以使用其它幾個API。本文檔的演示代碼稍做改動可應用于任意Ring3函數。
對于hook一個API而言,可使用的辦法有很多,本文選用改寫函數入口點的辦法來實現掛接CreateProcessW,更多的詳細資料請參閱SobeIt寫的《windows下hook API的幾種辦法》。
【copy-on-write】
最初試驗時,我使用softice的 a CreateProcessW改寫函數入口點的代碼,F5切換回windows之后發現一切如愿以償,但是當我編寫程序修改CreateProcessW入口點代碼時,發現所做的改動僅對本進程有效,而對于系統的其他進程沒有產生任何影響。用softice跟蹤后發現本進程中CreateProcessW的虛擬地址被映射到了一個新的,與其它進程不同的物理地址上,如果你讀過Webcrazy的《copy-on-write機制》一文,就不難看出這是copy-on-write機制產生的影響。對于系統的dll,每個dll都被映射在不同進程的相同的虛擬地址上,而這些虛擬地址又指向相同的物理地址,通過這種機制,系統實現最低的資源消耗.當某個進程試圖改寫物理內存中的數據時,為了不對其它進程產生影響,系統自動新分配一塊物理內存,把原物理內存中的數據復制過去,改寫,然后把改寫內存的那個進程的虛擬地址重新映射到新的物理內存上去,而其它進程則還是映射在原來的物理內存上,這就是“寫時復制技術”(copy-on-write),那么系統是如何判斷何時應該使用copy-on-write呢?這是以虛擬地址的PTE來決定的,當PTE中copy-on-write標志被置位時,任何對該虛擬地址的寫操作都將導致一個copy-on-write.
【三種可行的辦法】
為了實現全局hook,我們不能被copy-on-write機制所限制住,目前我想到了三種辦法來達到我們的目的。
1. 通過驅動來修改頁表項(PTE)的屬性,使CreateProcessW對應的虛擬地址失去copy-on-write的屬性,這樣在本身進程中對CreateProcessW入口點代碼的修改會對系統中所有進程生效,從而實現全局hook。
2. 通過windows本身提供的一個對象//phymem來對物理內存進行直接讀寫,先定位本身進程的Eprocess(KTEB)(PS:如何在Ring3下定位任意進程的Eprocess請參考我之前寫的《獲取進程的Eprocess》一文),獲得Eprocess之后,可以得到進程的頁目錄,然后利用//phymem讀取存放頁目錄的物理內存的內容,再模擬操作系統進行虛擬地址->物理內存地址的轉換,最終得到CreateProcessW所對應的物理地址,利用//phymem我們避開copy-on-write機制,直接改寫CreateProcessW。
3. 通過最常規的手段來達到目的,先枚舉系統中所有進程,然后通過VirtualQueryEx,VirtualAllocEx,VirtualProtectEx等函數修改每個進程的頁面屬性,分配新的空間等。最后將我們的代碼用WriteProcessMemory寫到各進程的空間中,利用改寫CreateProcessW入口為Jmp *******來跳到我們的代碼中,改變函數的執行流程。
以上三個辦法中,方法1只是一個構想,還沒成為現實,有空的話我回去試試看的,當然頁歡迎各位高手去實現,然后mail一份代碼給我:P方法2我寫了一份完整的代碼來實現它,但是在本文檔中不進行討論,否則文檔會變的很長,我將在另一份文檔中專門說明這種辦法的具體實現。方法3使本文討論的重點,下面就方法3進行詳細說明。
<查詢CreateProcessW的基址及屬性>
這里我們使用VirtualQueryEx這個函數,其原型如下:
SIZE_T
VirtualQueryEx
(
HANDLE hProcess,
LPCVOID lpAddress,
PMEMORY_BASIC_INFORMATION lpBuffer,
SIZE_T dwLength
);
參數說明:
HANDLE hProcess 想要查詢內存信息的進程句柄
LPCVOID lpAddress 指向想要查詢內存區域的指針
PMEMORY_BASIC_INFORMATION lpBuffer 指向MEMORY_BASIC_INFORMATION結構的指針
SIZE_T dwLength lpBuffer的大小
調用這個函數之后,相關的信息存放在lpBuffer指向的結構中
<修改CreateProcessW的頁屬性>
對于一個頁來說,有如下幾種屬性:
PAGE_EXECUTE
PAGE_EXECUTE_READ
PAGE_EXECUTE_READWRITE
PAGE_EXECUTE_WRITECOPY
PAGE_NOACCESS
PAGE_READONLY
PAGE_READWRITE
PAGE_WRITECOPY
我們通過VirtualProtectEx來修改頁的屬性:
BOOL
VirtualProtectEx
(
HANDLE hProcess,
LPVOID lpAddress,
SIZE_T dwSize,
DWORD flNewProtect,
PDWORD lpflOldProtect
);
參數說明:
HANDLE hProcess 進程句柄
LPVOID lpAddress 指向想要修改的內存區域的指針
SIZE_T dwSize 修改的內存區域的大小
DWORD flNewProtect 新的頁屬性
PDWORD lpflOldProtect 指向保存老的頁屬性的內存的指針
從后面的代碼中我們可以看到,為了改寫函數入口點代碼,我們必須賦予它PAGE_EXECUTE_READWRITE屬性。
<在進程中分配可用空間>
光修改函數入口點代碼是不夠的。我們必須自己編寫一段code來接管CreateProcessW的工作,由于進程空間是相互隔離的,為了達到全局hook的目標,我們必須向每個進程索要一塊空間來存放我們的代碼,這就要用到VirtualAllocEx這個函數了,VirtualAllocEx原型如下:
LPVOID
VirtualAllocEx
(
HANDLE hProcess,
LPVOID lpAddress,
SIZE_T dwSize,
DWORD flAllocationType,
DWORD flProtect
);
參數說明:
HANDLE hProcess 進程句柄
LPVOID lpAddress 指向分配內存區域的指針
SIZE_T dwSize 分配的區域的大小
DWORD flAllocationType 內存類型
DWORD flProtect 新內存的屬性
<將代碼寫入遠程進程空間>
我們使用WriteProcessMemory這個函數來向遠程進程寫入我們的代碼和數據,其原型如下:
BOOL
WriteProcessMemory(
HANDLE hProcess,
LPVOID lpBaseAddress,
LPCVOID lpBuffer,
SIZE_T nSize,
SIZE_T* lpNumberOfBytesWritten
);
參數說明:
HANDLE hProcess 進程句柄
LPVOID lpBaseAddress 指向寫入地址的指針
LPCVOID lpBuffer 指向寫入數據的指針
SIZE_T nSize lpBuffer的大小
SIZE_T* lpNumberOfBytesWritten 實際寫入的字節數
<編譯器的魔術>
我在使用WriteProcessMemory把我自己寫的一個函數JmpToAddress的內容寫入遠程進程空間時,發現無論我的JmpToAddress的內容是什么,寫入空間的都是E9****這幾個字節,這令我非常困惑,從機器碼來看,這是一條相對跳轉指令。那么它又是從何而來呢,為了搞清楚這個問題,我用VC調試了一下,在watch窗口中輸入JmpToAddress,顯示出JmpToAddress的虛擬地址0x00410XXX,然后打開memory窗口,查看這段內存中存放的內容,發現確實是JmpToAddress的代碼,這就奇怪了,那神秘的E9****是從何而來呢,于是我請教了a1rsupply,他告訴我VC的調試版本會生成跳轉表,這下真相大白,原來是編譯器玩的魔術。
為了向遠程進程正確寫入代碼,我們必須自己計算真正的函數地址,下面我寫了一段代碼來計算真正的函數地址:
__asm
{
pushad
lea eax,JmpToAddress
mov ecx,JmpToAddress
shr ecx,8
add eax,ecx
add eax,5
mov JmpAfterCalc,eax
popad
}
<解決麻煩的定位問題>
在編寫代碼的過程中,我遇到的另一個較大的問題就是如何定位地址。我編寫的JmpToAddress()函數如下:
void __declspec(naked) JmpToAddress(void)
{
__asm jmp [HookedAddr]
}
在本地進程中這句代碼沒什么問題,但是當它被寫入遠端進程后便會產生種種問題,我們來看看它的匯編代碼,如下
jmp [00401Cxxx]
我們注意到本進程中這個虛擬地址里存放的是HookedAddr的地址,但是在遠程進程中,這個地址指向的是別的什么東西,jmp過去會產生不可預料的結果,為了實現正確的行為,我們先用WriteProcessMemory向遠程進程寫入HookedAddr的內容,然后用一個相對地址引用它
void __declspec(naked) JmpAddress(void)
{
__asm call flag
flag:
__asm pop eax
__asm add eax,0x0e
__asm mov ebx,[eax]
__asm jmp ebx
}
pop eax后,eax里面存放的就是本條指令的虛擬的地址,加上一個固定值后,[eax]就是我們通過WriteProcessMemory寫入的數據。
完整演示代碼
CODE: /******************************************************************
*Author: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? *
* [I.T.S]SystEm32 ? ? ? ? ? ? ? ? ? ? ? *
*Module Name ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? *
* Hook_Api_1.cpp ? ? ? ? ? ? ? ? ? ? ? ? *
*Abstract: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? *
* This Code Show the Method of Hooking Win32 API ? *
*Environment: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? *
* User Mode - Win32 ? ? ? ? ? ? ? ? ? ? ? *
*Revision History: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? *
* 2004-9-20 ? ? ? ? ? ? ? ? ? ? ? ? ? *
*express My thanks to: ? ? ? ? ? ? ? ? ? ? ? ? ? ? *
* Bkbll,A1rsupp1y,SoBeIt and TCH ? ? ? ? ? ? *
*Our HomePage: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? *
* [url]http://www.itaq.org[/url] ? ? ? ? ? ? ? ? ? *
******************************************************************/
#include <windows.h>
#include <stdio.h>
#include "psapi.h"
#pragma comment(lib,"psapi.lib")
#define NTAPIADDR FARPROC
#define K_MODULE "kernel32.dll"
#define HOOK_API "CreateProcessW"
HMODULE hKernel32 = GetModuleHandle(K_MODULE);
NTAPIADDR pCreateProcessW = GetProcAddress(hKernel32,HOOK_API);
LPVOID HookedAddr = NULL;
void __declspec(naked) RealExecute(void)
{
/*You can add your own Hooked CreateProcessW function here*/
__asm ret 0x28
}
void __declspec(naked) JmpToAddress(void)
{
__asm call flag
flag:
__asm pop eax
__asm add eax,0x0e
__asm ? mov ebx,[eax]
__asm jmp ebx
}
BOOL WINAPI GetDebugPrivilege(void);
BOOL WINAPI InsertHook(DWORD ProcessID);
void main(void)
{
DWORD ProcessList[80],ProcessNUM;
EnumProcesses(ProcessList,sizeof(ProcessList),&ProcessNUM);
ProcessNUM/=sizeof(DWORD);
printf("Current process num is %d/n/r",ProcessNUM);
//printf("%08x/n/r",(LPVOID)RealExecute);
GetDebugPrivilege();
//step over the 0 process
for(DWORD Count=1;Count<ProcessNUM;Count++)
{
InsertHook(ProcessList[Count]);
}
Sleep(2000);
return;
}
BOOL WINAPI GetDebugPrivilege(void)
{
HANDLE ? hToken,hProcess;
TOKEN_PRIVILEGES tp;
char *pSEDEBUG = "SeDebugPrivilege";
hProcess = GetCurrentProcess();
OpenProcessToken(hProcess,TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hToken);
LookupPrivilegeValue(NULL,pSEDEBUG,&tp.Privileges[0].Luid);
tp.PrivilegeCount ? = 1;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(hToken,FALSE,&tp,NULL,NULL,NULL);
return 0;
}
BOOL WINAPI InsertHook(DWORD ProcessID)
{
MEMORY_BASIC_INFORMATION MBI;
HANDLE ? ? hProcess;
LPVOID ? ? RealAfterCalc,JmpAfterCalc;
int cb=sizeof(TCHAR)*4*1024;
//only for test
//if(1860 != ProcessID) goto end;
printf("PID is %d/n/r",ProcessID);
hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,ProcessID);
if(NULL == hProcess)
{
printf("failed!/n/r");
goto end;
}
//calculate the real address of RealExecute
__asm
{
pushad
lea eax,RealExecute
mov ecx,RealExecute
shr ecx,8
add eax,ecx
add eax,5
mov RealAfterCalc,eax
popad
}
//calculate the real address of JmpToAddress
__asm
{
pushad
lea eax,JmpToAddress
mov ecx,JmpToAddress
shr ecx,8
add eax,ecx
add eax,5
mov JmpAfterCalc,eax
popad
}
//Alloc some memory in the process
HookedAddr = VirtualAllocEx(hProcess,NULL,cb,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
if(0 == WriteProcessMemory(hProcess,HookedAddr,RealAfterCalc,5,NULL))
printf("WriteProcessMemory failed!/n/r");
VirtualQueryEx(hProcess,(LPVOID*)pCreateProcessW,&MBI,sizeof(MBI));
VirtualProtectEx(hProcess,MBI.BaseAddress,MBI.RegionSize,PAGE_EXECUTE_READWRITE,&MBI.Protect);
printf("HookedAddr is 0x%08x/n/r",HookedAddr);
WriteProcessMemory(hProcess,pCreateProcessW,JmpAfterCalc,0x0e,NULL);
WriteProcessMemory(hProcess,(char*)pCreateProcessW+0x13,&HookedAddr,4,NULL);
end:
return 0;
}
文章作者:System32
這份文檔演示了如何實現全局HOOK
【前言】
【概述】
【copy-on-write】
【三種可行的辦法】
<查詢CreateProcessW的基址及屬性>
<枚舉系統中所有進程>
<修改CreateProcessW頁屬性>
<在進程中分配一塊可用空間>
<將代碼寫入遠程進程空間>
<編譯器的魔術>
<解決麻煩的定位問題>
【完整演示代碼】
【資源】
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
【前言】
寫這篇文檔的時候由于我足夠菜,碰到了不少問題,多謝bkbll,a1rsupply和SobeIt的指點,還有TCH的辛勤勞動,才有這篇文檔的誕生,本文中可能存在一些錯誤,這些錯誤都是由于我的失誤造成的,如果您有什么意見和看法,歡迎來http://www.itaq.org指出,或者E-mail:zf35@citiz.net
【概述】
在服務器上實現對進程創建的控制有很大的意義,通過監控進程的創建,我們可以讓被允許運行的進程正確創建,而未被允許的程序則會創建失敗,這樣就可以防止未知木馬,病毒和蠕蟲對服務器的威脅。要實現上述目的,必須hook windows創建進程相關的API,根據《inside the windows NT》和《Native API Reference》中記載,加上softIce的實際跟蹤,windows創建進程的API調用流程如下:
代碼
CreateProcessA-> CreateProcessW-> CreateProcessInternalW->…->最終調用ZwCreateProcess
本文檔中我們選用CreateProcessW來實現我們的目的,當然你也可以使用其它幾個API。本文檔的演示代碼稍做改動可應用于任意Ring3函數。
對于hook一個API而言,可使用的辦法有很多,本文選用改寫函數入口點的辦法來實現掛接CreateProcessW,更多的詳細資料請參閱SobeIt寫的《windows下hook API的幾種辦法》。
【copy-on-write】
最初試驗時,我使用softice的 a CreateProcessW改寫函數入口點的代碼,F5切換回windows之后發現一切如愿以償,但是當我編寫程序修改CreateProcessW入口點代碼時,發現所做的改動僅對本進程有效,而對于系統的其他進程沒有產生任何影響。用softice跟蹤后發現本進程中CreateProcessW的虛擬地址被映射到了一個新的,與其它進程不同的物理地址上,如果你讀過Webcrazy的《copy-on-write機制》一文,就不難看出這是copy-on-write機制產生的影響。對于系統的dll,每個dll都被映射在不同進程的相同的虛擬地址上,而這些虛擬地址又指向相同的物理地址,通過這種機制,系統實現最低的資源消耗.當某個進程試圖改寫物理內存中的數據時,為了不對其它進程產生影響,系統自動新分配一塊物理內存,把原物理內存中的數據復制過去,改寫,然后把改寫內存的那個進程的虛擬地址重新映射到新的物理內存上去,而其它進程則還是映射在原來的物理內存上,這就是“寫時復制技術”(copy-on-write),那么系統是如何判斷何時應該使用copy-on-write呢?這是以虛擬地址的PTE來決定的,當PTE中copy-on-write標志被置位時,任何對該虛擬地址的寫操作都將導致一個copy-on-write.
【三種可行的辦法】
為了實現全局hook,我們不能被copy-on-write機制所限制住,目前我想到了三種辦法來達到我們的目的。
1. 通過驅動來修改頁表項(PTE)的屬性,使CreateProcessW對應的虛擬地址失去copy-on-write的屬性,這樣在本身進程中對CreateProcessW入口點代碼的修改會對系統中所有進程生效,從而實現全局hook。
2. 通過windows本身提供的一個對象//phymem來對物理內存進行直接讀寫,先定位本身進程的Eprocess(KTEB)(PS:如何在Ring3下定位任意進程的Eprocess請參考我之前寫的《獲取進程的Eprocess》一文),獲得Eprocess之后,可以得到進程的頁目錄,然后利用//phymem讀取存放頁目錄的物理內存的內容,再模擬操作系統進行虛擬地址->物理內存地址的轉換,最終得到CreateProcessW所對應的物理地址,利用//phymem我們避開copy-on-write機制,直接改寫CreateProcessW。
3. 通過最常規的手段來達到目的,先枚舉系統中所有進程,然后通過VirtualQueryEx,VirtualAllocEx,VirtualProtectEx等函數修改每個進程的頁面屬性,分配新的空間等。最后將我們的代碼用WriteProcessMemory寫到各進程的空間中,利用改寫CreateProcessW入口為Jmp *******來跳到我們的代碼中,改變函數的執行流程。
以上三個辦法中,方法1只是一個構想,還沒成為現實,有空的話我回去試試看的,當然頁歡迎各位高手去實現,然后mail一份代碼給我:P方法2我寫了一份完整的代碼來實現它,但是在本文檔中不進行討論,否則文檔會變的很長,我將在另一份文檔中專門說明這種辦法的具體實現。方法3使本文討論的重點,下面就方法3進行詳細說明。
<查詢CreateProcessW的基址及屬性>
這里我們使用VirtualQueryEx這個函數,其原型如下:
SIZE_T
VirtualQueryEx
(
HANDLE hProcess,
LPCVOID lpAddress,
PMEMORY_BASIC_INFORMATION lpBuffer,
SIZE_T dwLength
);
參數說明:
HANDLE hProcess 想要查詢內存信息的進程句柄
LPCVOID lpAddress 指向想要查詢內存區域的指針
PMEMORY_BASIC_INFORMATION lpBuffer 指向MEMORY_BASIC_INFORMATION結構的指針
SIZE_T dwLength lpBuffer的大小
調用這個函數之后,相關的信息存放在lpBuffer指向的結構中
<修改CreateProcessW的頁屬性>
對于一個頁來說,有如下幾種屬性:
PAGE_EXECUTE
PAGE_EXECUTE_READ
PAGE_EXECUTE_READWRITE
PAGE_EXECUTE_WRITECOPY
PAGE_NOACCESS
PAGE_READONLY
PAGE_READWRITE
PAGE_WRITECOPY
我們通過VirtualProtectEx來修改頁的屬性:
BOOL
VirtualProtectEx
(
HANDLE hProcess,
LPVOID lpAddress,
SIZE_T dwSize,
DWORD flNewProtect,
PDWORD lpflOldProtect
);
參數說明:
HANDLE hProcess 進程句柄
LPVOID lpAddress 指向想要修改的內存區域的指針
SIZE_T dwSize 修改的內存區域的大小
DWORD flNewProtect 新的頁屬性
PDWORD lpflOldProtect 指向保存老的頁屬性的內存的指針
從后面的代碼中我們可以看到,為了改寫函數入口點代碼,我們必須賦予它PAGE_EXECUTE_READWRITE屬性。
<在進程中分配可用空間>
光修改函數入口點代碼是不夠的。我們必須自己編寫一段code來接管CreateProcessW的工作,由于進程空間是相互隔離的,為了達到全局hook的目標,我們必須向每個進程索要一塊空間來存放我們的代碼,這就要用到VirtualAllocEx這個函數了,VirtualAllocEx原型如下:
LPVOID
VirtualAllocEx
(
HANDLE hProcess,
LPVOID lpAddress,
SIZE_T dwSize,
DWORD flAllocationType,
DWORD flProtect
);
參數說明:
HANDLE hProcess 進程句柄
LPVOID lpAddress 指向分配內存區域的指針
SIZE_T dwSize 分配的區域的大小
DWORD flAllocationType 內存類型
DWORD flProtect 新內存的屬性
<將代碼寫入遠程進程空間>
我們使用WriteProcessMemory這個函數來向遠程進程寫入我們的代碼和數據,其原型如下:
BOOL
WriteProcessMemory(
HANDLE hProcess,
LPVOID lpBaseAddress,
LPCVOID lpBuffer,
SIZE_T nSize,
SIZE_T* lpNumberOfBytesWritten
);
參數說明:
HANDLE hProcess 進程句柄
LPVOID lpBaseAddress 指向寫入地址的指針
LPCVOID lpBuffer 指向寫入數據的指針
SIZE_T nSize lpBuffer的大小
SIZE_T* lpNumberOfBytesWritten 實際寫入的字節數
<編譯器的魔術>
我在使用WriteProcessMemory把我自己寫的一個函數JmpToAddress的內容寫入遠程進程空間時,發現無論我的JmpToAddress的內容是什么,寫入空間的都是E9****這幾個字節,這令我非常困惑,從機器碼來看,這是一條相對跳轉指令。那么它又是從何而來呢,為了搞清楚這個問題,我用VC調試了一下,在watch窗口中輸入JmpToAddress,顯示出JmpToAddress的虛擬地址0x00410XXX,然后打開memory窗口,查看這段內存中存放的內容,發現確實是JmpToAddress的代碼,這就奇怪了,那神秘的E9****是從何而來呢,于是我請教了a1rsupply,他告訴我VC的調試版本會生成跳轉表,這下真相大白,原來是編譯器玩的魔術。
為了向遠程進程正確寫入代碼,我們必須自己計算真正的函數地址,下面我寫了一段代碼來計算真正的函數地址:
__asm
{
pushad
lea eax,JmpToAddress
mov ecx,JmpToAddress
shr ecx,8
add eax,ecx
add eax,5
mov JmpAfterCalc,eax
popad
}
<解決麻煩的定位問題>
在編寫代碼的過程中,我遇到的另一個較大的問題就是如何定位地址。我編寫的JmpToAddress()函數如下:
void __declspec(naked) JmpToAddress(void)
{
__asm jmp [HookedAddr]
}
在本地進程中這句代碼沒什么問題,但是當它被寫入遠端進程后便會產生種種問題,我們來看看它的匯編代碼,如下
jmp [00401Cxxx]
我們注意到本進程中這個虛擬地址里存放的是HookedAddr的地址,但是在遠程進程中,這個地址指向的是別的什么東西,jmp過去會產生不可預料的結果,為了實現正確的行為,我們先用WriteProcessMemory向遠程進程寫入HookedAddr的內容,然后用一個相對地址引用它
void __declspec(naked) JmpAddress(void)
{
__asm call flag
flag:
__asm pop eax
__asm add eax,0x0e
__asm mov ebx,[eax]
__asm jmp ebx
}
pop eax后,eax里面存放的就是本條指令的虛擬的地址,加上一個固定值后,[eax]就是我們通過WriteProcessMemory寫入的數據。
完整演示代碼
CODE: /******************************************************************
*Author: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? *
* [I.T.S]SystEm32 ? ? ? ? ? ? ? ? ? ? ? *
*Module Name ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? *
* Hook_Api_1.cpp ? ? ? ? ? ? ? ? ? ? ? ? *
*Abstract: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? *
* This Code Show the Method of Hooking Win32 API ? *
*Environment: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? *
* User Mode - Win32 ? ? ? ? ? ? ? ? ? ? ? *
*Revision History: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? *
* 2004-9-20 ? ? ? ? ? ? ? ? ? ? ? ? ? *
*express My thanks to: ? ? ? ? ? ? ? ? ? ? ? ? ? ? *
* Bkbll,A1rsupp1y,SoBeIt and TCH ? ? ? ? ? ? *
*Our HomePage: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? *
* [url]http://www.itaq.org[/url] ? ? ? ? ? ? ? ? ? *
******************************************************************/
#include <windows.h>
#include <stdio.h>
#include "psapi.h"
#pragma comment(lib,"psapi.lib")
#define NTAPIADDR FARPROC
#define K_MODULE "kernel32.dll"
#define HOOK_API "CreateProcessW"
HMODULE hKernel32 = GetModuleHandle(K_MODULE);
NTAPIADDR pCreateProcessW = GetProcAddress(hKernel32,HOOK_API);
LPVOID HookedAddr = NULL;
void __declspec(naked) RealExecute(void)
{
/*You can add your own Hooked CreateProcessW function here*/
__asm ret 0x28
}
void __declspec(naked) JmpToAddress(void)
{
__asm call flag
flag:
__asm pop eax
__asm add eax,0x0e
__asm ? mov ebx,[eax]
__asm jmp ebx
}
BOOL WINAPI GetDebugPrivilege(void);
BOOL WINAPI InsertHook(DWORD ProcessID);
void main(void)
{
DWORD ProcessList[80],ProcessNUM;
EnumProcesses(ProcessList,sizeof(ProcessList),&ProcessNUM);
ProcessNUM/=sizeof(DWORD);
printf("Current process num is %d/n/r",ProcessNUM);
//printf("%08x/n/r",(LPVOID)RealExecute);
GetDebugPrivilege();
//step over the 0 process
for(DWORD Count=1;Count<ProcessNUM;Count++)
{
InsertHook(ProcessList[Count]);
}
Sleep(2000);
return;
}
BOOL WINAPI GetDebugPrivilege(void)
{
HANDLE ? hToken,hProcess;
TOKEN_PRIVILEGES tp;
char *pSEDEBUG = "SeDebugPrivilege";
hProcess = GetCurrentProcess();
OpenProcessToken(hProcess,TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hToken);
LookupPrivilegeValue(NULL,pSEDEBUG,&tp.Privileges[0].Luid);
tp.PrivilegeCount ? = 1;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(hToken,FALSE,&tp,NULL,NULL,NULL);
return 0;
}
BOOL WINAPI InsertHook(DWORD ProcessID)
{
MEMORY_BASIC_INFORMATION MBI;
HANDLE ? ? hProcess;
LPVOID ? ? RealAfterCalc,JmpAfterCalc;
int cb=sizeof(TCHAR)*4*1024;
//only for test
//if(1860 != ProcessID) goto end;
printf("PID is %d/n/r",ProcessID);
hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,ProcessID);
if(NULL == hProcess)
{
printf("failed!/n/r");
goto end;
}
//calculate the real address of RealExecute
__asm
{
pushad
lea eax,RealExecute
mov ecx,RealExecute
shr ecx,8
add eax,ecx
add eax,5
mov RealAfterCalc,eax
popad
}
//calculate the real address of JmpToAddress
__asm
{
pushad
lea eax,JmpToAddress
mov ecx,JmpToAddress
shr ecx,8
add eax,ecx
add eax,5
mov JmpAfterCalc,eax
popad
}
//Alloc some memory in the process
HookedAddr = VirtualAllocEx(hProcess,NULL,cb,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
if(0 == WriteProcessMemory(hProcess,HookedAddr,RealAfterCalc,5,NULL))
printf("WriteProcessMemory failed!/n/r");
VirtualQueryEx(hProcess,(LPVOID*)pCreateProcessW,&MBI,sizeof(MBI));
VirtualProtectEx(hProcess,MBI.BaseAddress,MBI.RegionSize,PAGE_EXECUTE_READWRITE,&MBI.Protect);
printf("HookedAddr is 0x%08x/n/r",HookedAddr);
WriteProcessMemory(hProcess,pCreateProcessW,JmpAfterCalc,0x0e,NULL);
WriteProcessMemory(hProcess,(char*)pCreateProcessW+0x13,&HookedAddr,4,NULL);
end:
return 0;
}
總結
以上是生活随笔為你收集整理的挂接CreateProcessW实现对进程创建的完全控制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: USB驱动开发任务
- 下一篇: vue手机端回退_vue移动端弹框组件,