9X 環(huán)境中Windows提供了想光的API函數(shù)用于隱藏系統(tǒng)進(jìn)程。但是到了 2000 以上系統(tǒng),已經(jīng)無(wú)法真正的做到對(duì)于進(jìn)程的隱藏,除非編寫底層驅(qū)動(dòng)。但是我們可以通過(guò)一些變通的辦法來(lái)達(dá)到隱藏進(jìn)程的目的,其中一個(gè)就是遠(yuǎn)程注入。簡(jiǎn)單的說(shuō)就是先編寫一個(gè)?API的DLL,然后將這個(gè)DLL庫(kù)注入到一個(gè)系統(tǒng)進(jìn)程中,作為它的一個(gè)線程去執(zhí)行。
要實(shí)現(xiàn)DLL注入,首先需要打開目標(biāo)進(jìn)程。
hRemoteProcess?
=? OpenProcess ( PROCESS_CREATE_THREAD? |? //允許遠(yuǎn)程創(chuàng)建線程
   ?PROCESS_VM_OPERATION  |? //允許遠(yuǎn)程VM操作
   ?PROCESS_VM_WRITE ,   //允許遠(yuǎn)程VM寫
   ?FALSE ,? dwRemoteProcessId? )
由于我們后面需要寫入遠(yuǎn)程進(jìn)程的內(nèi)存地址空間并建立遠(yuǎn)程線程,所以需要申請(qǐng)足夠的權(quán)限(PROCESS_CREATE_THREAD、VM_OPERATION、VM_WRITE)。
如果進(jìn)程打不開,以后的操作就別想了。進(jìn)程打開后,就可以建立遠(yuǎn)線程了,不過(guò)別急,先想想這個(gè)遠(yuǎn)線程的線程函數(shù)是什么?我們的目的是注入一個(gè)DLL。而且我們知道用LoadLibrary可以加載一個(gè)DLL到本進(jìn)程的地址空間。于是,自然會(huì)想到如果可以在目標(biāo)進(jìn)程中調(diào)用LoadLibrary,不就可以把?DLL加載到目標(biāo)進(jìn)程的地址空間了嗎?對(duì)!就是這樣。遠(yuǎn)線程就在這兒用了一次,建立的遠(yuǎn)線程的線程函數(shù)就是LoadLibrary,而參數(shù)就是要注入的?DLL的文件名。
( 這里需要自己想一想,注意到了嗎,線程函數(shù)ThreadProc和LoadLibrary函數(shù)非常相似,返回值,參數(shù)個(gè)數(shù)都一樣 )? 還有一個(gè)問(wèn)題,LoadLibrary這個(gè)函數(shù)的地址在哪兒?也許你會(huì)說(shuō),這個(gè)簡(jiǎn)單,GetProcAddress就可以得出。于是代碼就出來(lái)了。
char? * pszLibFileRemote = "my.dll" ;
PTHREAD_START_ROUTINE?pfnStartAddr? =?( PTHREAD_START_ROUTINE ) GetProcAddress ( GetModuleHandle ( "Kernel32" ),? "LoadLibraryA" );
CreateRemoteThread (? hRemoteProcess ,? NULL ,? 0 ,? pfnStartAddr ,? pszLibFileRemote ,? 0 ,? NULL );
????
但是不對(duì)!不要忘了,這是遠(yuǎn)線程,不是在你的進(jìn)程里,而pszLibFileRemote指向的是你的進(jìn)程里的數(shù)據(jù),到了目標(biāo)進(jìn)程,這個(gè)指針都不知道指向哪兒去了,同樣pfnStartAddr這個(gè)地址上的代碼到了目標(biāo)進(jìn)程里也不知道是什么了,不知道是不是你想要的LoadLibraryA了。但是,問(wèn)題總是可以解決的,Windows有些很強(qiáng)大的API函數(shù),他們可以在目標(biāo)進(jìn)程里分配內(nèi)存,可以將你的進(jìn)程中的數(shù)據(jù)拷貝到目標(biāo)進(jìn)程中。因此?pszLibFileRemote的問(wèn)題可以解決了。
char? * pszLibFileName = "my.dll" ; //注意,這個(gè)一定要是全路徑文件名,除非它在系統(tǒng)目錄里;原因大家自己想想。
//計(jì)算DLL路徑名需要的內(nèi)存空間
int? cb? =?( 1? +? lstrlenA ( pszLibFileName ))?*? sizeof ( char );
//使用VirtualAllocEx函數(shù)在遠(yuǎn)程進(jìn)程的內(nèi)存地址空間分配DLL文件名緩沖區(qū)
pszLibFileRemote? =?( char? *)? VirtualAllocEx (? hRemoteProcess ,? NULL ,? cb ,? MEM_COMMIT ,? PAGE_READWRITE );
//使用WriteProcessMemory函數(shù)將DLL的路徑名復(fù)制到遠(yuǎn)程進(jìn)程的內(nèi)存空間
iReturnCode? =? WriteProcessMemory ( hRemoteProcess ,? pszLibFileRemote ,?( PVOID )? pszLibFileName ,? cb ,? NULL );
????
OK,現(xiàn)在目標(biāo)進(jìn)程也認(rèn)識(shí)pszLibFileRemote了,但是pfnStartAddr好像不好辦,我怎么可能知道LoadLibraryA在目標(biāo)進(jìn)程中的地址呢?其實(shí)Windows為我們解決了這個(gè)問(wèn)題,LoadLibraryA這個(gè)函數(shù)是在Kernel32 . dll這個(gè)核心DLL里的,而這個(gè)?DLL很特殊,不管對(duì)于哪個(gè)進(jìn)程,Windows總是把它加載到相同的地址上去。因此你的進(jìn)程中LoadLibraryA的地址和目標(biāo)進(jìn)程中?LoadLibraryA的地址是相同的 ( 其實(shí),這個(gè)DLL里的所有函數(shù)都是如此 ) 。至此,DLL注入結(jié)束了。
?
但是目前還有一個(gè)問(wèn)題,上面的方法是無(wú)法將DLL注入到系統(tǒng)進(jìn)程中去的,原因是進(jìn)程級(jí)別不夠。那么我們就要提升注入程序的進(jìn)程級(jí)別。使用下面的函數(shù):
void? EnableDebugPriv (? void? )
{
?
HANDLE?hToken ;
?
LUID?sedebugnameValue ;
?
TOKEN_PRIVILEGES?tkp ;
?
if? (?!? OpenProcessToken (? GetCurrentProcess (),
??
TOKEN_ADJUST_PRIVILEGES? |? TOKEN_QUERY ,?& hToken? )?)
??
return ;
?
if? (?!? LookupPrivilegeValue (? NULL ,? SE_DEBUG_NAME ,?& sedebugnameValue? )?){
??
CloseHandle (? hToken? );
??
return ;
?}
?
tkp . PrivilegeCount? =? 1 ;
?
tkp . Privileges [ 0 ]. Luid? =? sedebugnameValue ;
?
tkp . Privileges [ 0 ]. Attributes? =? SE_PRIVILEGE_ENABLED ;
?
if? (?!? AdjustTokenPrivileges (? hToken ,? FALSE ,?& tkp ,? sizeof? tkp ,? NULL ,? NULL? )?)
??
CloseHandle (? hToken? );
}
?
?
?
最后我們來(lái)做一個(gè)簡(jiǎn)單的例子:
首先編寫注入程序的代碼
//?DLLAdd.cpp?:?Defines?the?entry?point?for?the?application.
//
#include? "stdafx.h"
#include? "winnt.h"
void? EnableDebugPriv ();
int? APIENTRY?WinMain ( HINSTANCE?hInstance ,
?????????????????????
HINSTANCE?hPrevInstance ,
?????????????????????
LPSTR?????lpCmdLine ,
?????????????????????
int??????? nCmdShow )
{
?
EnableDebugPriv ();
??
//?TODO:?Place?code?here.
?
HANDLE?hRemoteProcess ;
?
HANDLE?hRemoteThread ;
?
//PWSTR?pszLibFileRemote;
?//LPCWSTR?pszLibFileName;
?
BOOL?iReturnCode ;
?
char? * pszLibFileRemote = "RemoteDLL.dll" ;
?
char? * pszLibFileName = "C:\\RemoteDLL.dll" ; //注意,這個(gè)一定要是全路徑文件名,除非它在系統(tǒng)目錄里
?
hRemoteProcess? =? OpenProcess ( PROCESS_CREATE_THREAD
????????
| PROCESS_VM_OPERATION
????????
| PROCESS_VM_WRITE ,
????????
FALSE , 0x3E0 ); //0x3E0是進(jìn)程的id,測(cè)試時(shí)是explorer的進(jìn)程id,可以用spy++去查找。
?//計(jì)算DLL路徑名需要的內(nèi)存空間
?
int? cb? =?( 1? +? lstrlenA ( pszLibFileName ))?*? sizeof ( char );
?
//使用VirtualAllocEx函數(shù)在遠(yuǎn)程進(jìn)程的內(nèi)存地址空間分配DLL文件名緩沖區(qū)
?
pszLibFileRemote? =?( char? *)? VirtualAllocEx ( hRemoteProcess ,? NULL ,? cb ,
????????????
MEM_COMMIT ,? PAGE_READWRITE );
?
//使用WriteProcessMemory函數(shù)將DLL的路徑名復(fù)制到遠(yuǎn)程進(jìn)程的內(nèi)存空間
?
iReturnCode? =? WriteProcessMemory ( hRemoteProcess ,
????
pszLibFileRemote ,?( PVOID )? pszLibFileName ,? cb ,? NULL );
?
//計(jì)算LoadLibraryW的入口地址
?
PTHREAD_START_ROUTINE?pfnStartAddr? =?( PTHREAD_START_ROUTINE )
??????????
GetProcAddress ( GetModuleHandle ( TEXT ( "Kernel32" )),
??????????
"LoadLibraryA" );
?
//啟動(dòng)遠(yuǎn)程線程LoadLibraryW,通過(guò)遠(yuǎn)程線程調(diào)用用戶的DLL文件
?
hRemoteThread? =? CreateRemoteThread (? hRemoteProcess ,? NULL ,? 0 ,
??????????
pfnStartAddr ,? pszLibFileRemote ,? 0 ,? NULL );

?
return? 0 ;
}
?
//提升權(quán)限
void? EnableDebugPriv (? void? )
{
?
HANDLE?hToken ;
?
LUID?sedebugnameValue ;
?
TOKEN_PRIVILEGES?tkp ;
?
if? (?!? OpenProcessToken (? GetCurrentProcess (),
??
TOKEN_ADJUST_PRIVILEGES? |? TOKEN_QUERY ,?& hToken? )?)
??
return ;
?
if? (?!? LookupPrivilegeValue (? NULL ,? SE_DEBUG_NAME ,?& sedebugnameValue? )?){
??
CloseHandle (? hToken? );
??
return ;
?}
?
tkp . PrivilegeCount? =? 1 ;
?
tkp . Privileges [ 0 ]. Luid? =? sedebugnameValue ;
?
tkp . Privileges [ 0 ]. Attributes? =? SE_PRIVILEGE_ENABLED ;
?
if? (?!? AdjustTokenPrivileges (? hToken ,? FALSE ,?& tkp ,? sizeof? tkp ,? NULL ,? NULL? )?)
??
CloseHandle (? hToken? );
}
?
?

然后編寫需要注入的DLL的代碼

#include? "stdafx.h"
#include? "winnt.h"
#include? < stdlib . h >
BOOL?APIENTRY?DllMain (? HANDLE?hModule ,
???????????????????????
DWORD??ul_reason_for_call ,
???????????????????????
LPVOID?lpReserved
??????
)
{
?
char? szProcessId [ 64 ];
?
int? i = 1 ;
?
switch ( ul_reason_for_call )
?{
?
case? DLL_PROCESS_ATTACH :
??{
???
_itoa ( GetCurrentProcessId (), szProcessId , 10 );
???
MessageBox ( NULL , szProcessId , "RemoteDLL" , MB_OK );
??}
?
default :
??
return? TRUE ;
?}
}
?
將編譯好的dll放到C盤根目錄下面運(yùn)行注入程序。我們可以發(fā)現(xiàn)彈出了一個(gè)標(biāo)示了被注入進(jìn)程id的對(duì)話框。
如上,只要我們?cè)賒ll中編寫我們需要的代碼,就可以隱秘的在電腦里執(zhí)行我們需要的事情。