日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

挂接CreateProcessW实现对进程创建的完全控制

發(fā)布時間:2025/3/15 编程问答 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 挂接CreateProcessW实现对进程创建的完全控制 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
掛接CreateProcessW實現(xiàn)對進(jìn)程創(chuàng)建的完全控制

文章作者:System32

這份文檔演示了如何實現(xiàn)全局HOOK
【前言】
【概述】
【copy-on-write】
【三種可行的辦法】
<查詢CreateProcessW的基址及屬性>
<枚舉系統(tǒng)中所有進(jìn)程>
<修改CreateProcessW頁屬性>
<在進(jìn)程中分配一塊可用空間>
<將代碼寫入遠(yuǎn)程進(jìn)程空間>
<編譯器的魔術(shù)>
<解決麻煩的定位問題>
【完整演示代碼】
【資源】
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
【前言】
寫這篇文檔的時候由于我足夠菜,碰到了不少問題,多謝bkbll,a1rsupply和SobeIt的指點,還有TCH的辛勤勞動,才有這篇文檔的誕生,本文中可能存在一些錯誤,這些錯誤都是由于我的失誤造成的,如果您有什么意見和看法,歡迎來
http://www.itaq.org指出,或者E-mail:zf35@citiz.net
【概述】
在服務(wù)器上實現(xiàn)對進(jìn)程創(chuàng)建的控制有很大的意義,通過監(jiān)控進(jìn)程的創(chuàng)建,我們可以讓被允許運行的進(jìn)程正確創(chuàng)建,而未被允許的程序則會創(chuàng)建失敗,這樣就可以防止未知木馬,病毒和蠕蟲對服務(wù)器的威脅。要實現(xiàn)上述目的,必須hook windows創(chuàng)建進(jìn)程相關(guān)的API,根據(jù)《inside the windows NT》和《Native API Reference》中記載,加上softIce的實際跟蹤,windows創(chuàng)建進(jìn)程的API調(diào)用流程如下:

代碼
CreateProcessA-> CreateProcessW-> CreateProcessInternalW->…->最終調(diào)用ZwCreateProcess


本文檔中我們選用CreateProcessW來實現(xiàn)我們的目的,當(dāng)然你也可以使用其它幾個API。本文檔的演示代碼稍做改動可應(yīng)用于任意Ring3函數(shù)。
對于hook一個API而言,可使用的辦法有很多,本文選用改寫函數(shù)入口點的辦法來實現(xiàn)掛接CreateProcessW,更多的詳細(xì)資料請參閱SobeIt寫的《windows下hook API的幾種辦法》。

【copy-on-write】
最初試驗時,我使用softice的 a CreateProcessW改寫函數(shù)入口點的代碼,F5切換回windows之后發(fā)現(xiàn)一切如愿以償,但是當(dāng)我編寫程序修改CreateProcessW入口點代碼時,發(fā)現(xiàn)所做的改動僅對本進(jìn)程有效,而對于系統(tǒng)的其他進(jìn)程沒有產(chǎn)生任何影響。用softice跟蹤后發(fā)現(xiàn)本進(jìn)程中CreateProcessW的虛擬地址被映射到了一個新的,與其它進(jìn)程不同的物理地址上,如果你讀過Webcrazy的《copy-on-write機(jī)制》一文,就不難看出這是copy-on-write機(jī)制產(chǎn)生的影響。對于系統(tǒng)的dll,每個dll都被映射在不同進(jìn)程的相同的虛擬地址上,而這些虛擬地址又指向相同的物理地址,通過這種機(jī)制,系統(tǒng)實現(xiàn)最低的資源消耗.當(dāng)某個進(jìn)程試圖改寫物理內(nèi)存中的數(shù)據(jù)時,為了不對其它進(jìn)程產(chǎn)生影響,系統(tǒng)自動新分配一塊物理內(nèi)存,把原物理內(nèi)存中的數(shù)據(jù)復(fù)制過去,改寫,然后把改寫內(nèi)存的那個進(jìn)程的虛擬地址重新映射到新的物理內(nèi)存上去,而其它進(jìn)程則還是映射在原來的物理內(nèi)存上,這就是“寫時復(fù)制技術(shù)”(copy-on-write),那么系統(tǒng)是如何判斷何時應(yīng)該使用copy-on-write呢?這是以虛擬地址的PTE來決定的,當(dāng)PTE中copy-on-write標(biāo)志被置位時,任何對該虛擬地址的寫操作都將導(dǎo)致一個copy-on-write.


【三種可行的辦法】
為了實現(xiàn)全局hook,我們不能被copy-on-write機(jī)制所限制住,目前我想到了三種辦法來達(dá)到我們的目的。
1. 通過驅(qū)動來修改頁表項(PTE)的屬性,使CreateProcessW對應(yīng)的虛擬地址失去copy-on-write的屬性,這樣在本身進(jìn)程中對CreateProcessW入口點代碼的修改會對系統(tǒng)中所有進(jìn)程生效,從而實現(xiàn)全局hook。

2. 通過windows本身提供的一個對象//phymem來對物理內(nèi)存進(jìn)行直接讀寫,先定位本身進(jìn)程的Eprocess(KTEB)(PS:如何在Ring3下定位任意進(jìn)程的Eprocess請參考我之前寫的《獲取進(jìn)程的Eprocess》一文),獲得Eprocess之后,可以得到進(jìn)程的頁目錄,然后利用//phymem讀取存放頁目錄的物理內(nèi)存的內(nèi)容,再模擬操作系統(tǒng)進(jìn)行虛擬地址->物理內(nèi)存地址的轉(zhuǎn)換,最終得到CreateProcessW所對應(yīng)的物理地址,利用//phymem我們避開copy-on-write機(jī)制,直接改寫CreateProcessW。

3. 通過最常規(guī)的手段來達(dá)到目的,先枚舉系統(tǒng)中所有進(jìn)程,然后通過VirtualQueryEx,VirtualAllocEx,VirtualProtectEx等函數(shù)修改每個進(jìn)程的頁面屬性,分配新的空間等。最后將我們的代碼用WriteProcessMemory寫到各進(jìn)程的空間中,利用改寫CreateProcessW入口為Jmp *******來跳到我們的代碼中,改變函數(shù)的執(zhí)行流程。

以上三個辦法中,方法1只是一個構(gòu)想,還沒成為現(xiàn)實,有空的話我回去試試看的,當(dāng)然頁歡迎各位高手去實現(xiàn),然后mail一份代碼給我:P方法2我寫了一份完整的代碼來實現(xiàn)它,但是在本文檔中不進(jìn)行討論,否則文檔會變的很長,我將在另一份文檔中專門說明這種辦法的具體實現(xiàn)。方法3使本文討論的重點,下面就方法3進(jìn)行詳細(xì)說明。
<查詢CreateProcessW的基址及屬性>
這里我們使用VirtualQueryEx這個函數(shù),其原型如下:
SIZE_T
VirtualQueryEx
(
HANDLE hProcess,
LPCVOID lpAddress,
PMEMORY_BASIC_INFORMATION lpBuffer,
SIZE_T dwLength
);
參數(shù)說明:
HANDLE hProcess 想要查詢內(nèi)存信息的進(jìn)程句柄
LPCVOID lpAddress 指向想要查詢內(nèi)存區(qū)域的指針
PMEMORY_BASIC_INFORMATION lpBuffer 指向MEMORY_BASIC_INFORMATION結(jié)構(gòu)的指針
SIZE_T dwLength lpBuffer的大小

調(diào)用這個函數(shù)之后,相關(guān)的信息存放在lpBuffer指向的結(jié)構(gòu)中


<修改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
);
參數(shù)說明:
HANDLE hProcess 進(jìn)程句柄
LPVOID lpAddress 指向想要修改的內(nèi)存區(qū)域的指針
SIZE_T dwSize 修改的內(nèi)存區(qū)域的大小
DWORD flNewProtect 新的頁屬性
PDWORD lpflOldProtect 指向保存老的頁屬性的內(nèi)存的指針

從后面的代碼中我們可以看到,為了改寫函數(shù)入口點代碼,我們必須賦予它PAGE_EXECUTE_READWRITE屬性。


<在進(jìn)程中分配可用空間>
光修改函數(shù)入口點代碼是不夠的。我們必須自己編寫一段code來接管CreateProcessW的工作,由于進(jìn)程空間是相互隔離的,為了達(dá)到全局hook的目標(biāo),我們必須向每個進(jìn)程索要一塊空間來存放我們的代碼,這就要用到VirtualAllocEx這個函數(shù)了,VirtualAllocEx原型如下:
LPVOID
VirtualAllocEx
(
HANDLE hProcess,
LPVOID lpAddress,
SIZE_T dwSize,
DWORD flAllocationType,
DWORD flProtect
);
參數(shù)說明:
HANDLE hProcess 進(jìn)程句柄
LPVOID lpAddress 指向分配內(nèi)存區(qū)域的指針
SIZE_T dwSize 分配的區(qū)域的大小
DWORD flAllocationType 內(nèi)存類型
DWORD flProtect 新內(nèi)存的屬性

<將代碼寫入遠(yuǎn)程進(jìn)程空間>
我們使用WriteProcessMemory這個函數(shù)來向遠(yuǎn)程進(jìn)程寫入我們的代碼和數(shù)據(jù),其原型如下:
BOOL
WriteProcessMemory(
HANDLE hProcess,
LPVOID lpBaseAddress,
LPCVOID lpBuffer,
SIZE_T nSize,
SIZE_T* lpNumberOfBytesWritten
);
參數(shù)說明:
HANDLE hProcess 進(jìn)程句柄
LPVOID lpBaseAddress 指向?qū)懭氲刂返闹羔?br />LPCVOID lpBuffer 指向?qū)懭霐?shù)據(jù)的指針
SIZE_T nSize lpBuffer的大小
SIZE_T* lpNumberOfBytesWritten 實際寫入的字節(jié)數(shù)


<編譯器的魔術(shù)>
我在使用WriteProcessMemory把我自己寫的一個函數(shù)JmpToAddress的內(nèi)容寫入遠(yuǎn)程進(jìn)程空間時,發(fā)現(xiàn)無論我的JmpToAddress的內(nèi)容是什么,寫入空間的都是E9****這幾個字節(jié),這令我非常困惑,從機(jī)器碼來看,這是一條相對跳轉(zhuǎn)指令。那么它又是從何而來呢,為了搞清楚這個問題,我用VC調(diào)試了一下,在watch窗口中輸入JmpToAddress,顯示出JmpToAddress的虛擬地址0x00410XXX,然后打開memory窗口,查看這段內(nèi)存中存放的內(nèi)容,發(fā)現(xiàn)確實是JmpToAddress的代碼,這就奇怪了,那神秘的E9****是從何而來呢,于是我請教了a1rsupply,他告訴我VC的調(diào)試版本會生成跳轉(zhuǎn)表,這下真相大白,原來是編譯器玩的魔術(shù)。

為了向遠(yuǎn)程進(jìn)程正確寫入代碼,我們必須自己計算真正的函數(shù)地址,下面我寫了一段代碼來計算真正的函數(shù)地址:
__asm
{
pushad
lea eax,JmpToAddress
mov ecx,JmpToAddress
shr ecx,8
add eax,ecx
add eax,5
mov JmpAfterCalc,eax
popad
}

<解決麻煩的定位問題>
在編寫代碼的過程中,我遇到的另一個較大的問題就是如何定位地址。我編寫的JmpToAddress()函數(shù)如下:
void __declspec(naked) JmpToAddress(void)
{
__asm jmp [HookedAddr]
}
在本地進(jìn)程中這句代碼沒什么問題,但是當(dāng)它被寫入遠(yuǎn)端進(jìn)程后便會產(chǎn)生種種問題,我們來看看它的匯編代碼,如下
jmp [00401Cxxx]
我們注意到本進(jìn)程中這個虛擬地址里存放的是HookedAddr的地址,但是在遠(yuǎn)程進(jìn)程中,這個地址指向的是別的什么東西,jmp過去會產(chǎn)生不可預(yù)料的結(jié)果,為了實現(xiàn)正確的行為,我們先用WriteProcessMemory向遠(yuǎn)程進(jìn)程寫入HookedAddr的內(nèi)容,然后用一個相對地址引用它
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寫入的數(shù)據(jù)。

完整演示代碼
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;
}

總結(jié)

以上是生活随笔為你收集整理的挂接CreateProcessW实现对进程创建的完全控制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。