9X 環(huán)境中Windows提供了想光的API函數(shù)用于隱藏系統(tǒng)進程。但是到了 2000 以上系統(tǒng),已經(jīng)無法真正的做到對于進程的隱藏,除非編寫底層驅(qū)動。但是我們可以通過一些變通的辦法來達到隱藏進程的目的,其中一個就是遠程注入。簡單的說就是先編寫一個?API的DLL,然后將這個DLL庫注入到一個系統(tǒng)進程中,作為它的一個線程去執(zhí)行。
要實現(xiàn)DLL注入,首先需要打開目標進程。
hRemoteProcess?
=? OpenProcess ( PROCESS_CREATE_THREAD? |? //允許遠程創(chuàng)建線程
   ?PROCESS_VM_OPERATION  |? //允許遠程VM操作
   ?PROCESS_VM_WRITE ,   //允許遠程VM寫
   ?FALSE ,? dwRemoteProcessId? )
由于我們后面需要寫入遠程進程的內(nèi)存地址空間并建立遠程線程,所以需要申請足夠的權限(PROCESS_CREATE_THREAD、VM_OPERATION、VM_WRITE)。
如果進程打不開,以后的操作就別想了。進程打開后,就可以建立遠線程了,不過別急,先想想這個遠線程的線程函數(shù)是什么?我們的目的是注入一個DLL。而且我們知道用LoadLibrary可以加載一個DLL到本進程的地址空間。于是,自然會想到如果可以在目標進程中調(diào)用LoadLibrary,不就可以把?DLL加載到目標進程的地址空間了嗎?對!就是這樣。遠線程就在這兒用了一次,建立的遠線程的線程函數(shù)就是LoadLibrary,而參數(shù)就是要注入的?DLL的文件名。
( 這里需要自己想一想,注意到了嗎,線程函數(shù)ThreadProc和LoadLibrary函數(shù)非常相似,返回值,參數(shù)個數(shù)都一樣 )? 還有一個問題,LoadLibrary這個函數(shù)的地址在哪兒?也許你會說,這個簡單,GetProcAddress就可以得出。于是代碼就出來了。
char? * pszLibFileRemote = "my.dll" ;
PTHREAD_START_ROUTINE?pfnStartAddr? =?( PTHREAD_START_ROUTINE ) GetProcAddress ( GetModuleHandle ( "Kernel32" ),? "LoadLibraryA" );
CreateRemoteThread (? hRemoteProcess ,? NULL ,? 0 ,? pfnStartAddr ,? pszLibFileRemote ,? 0 ,? NULL );
????
但是不對!不要忘了,這是遠線程,不是在你的進程里,而pszLibFileRemote指向的是你的進程里的數(shù)據(jù),到了目標進程,這個指針都不知道指向哪兒去了,同樣pfnStartAddr這個地址上的代碼到了目標進程里也不知道是什么了,不知道是不是你想要的LoadLibraryA了。但是,問題總是可以解決的,Windows有些很強大的API函數(shù),他們可以在目標進程里分配內(nèi)存,可以將你的進程中的數(shù)據(jù)拷貝到目標進程中。因此?pszLibFileRemote的問題可以解決了。
char? * pszLibFileName = "my.dll" ; //注意,這個一定要是全路徑文件名,除非它在系統(tǒng)目錄里;原因大家自己想想。
//計算DLL路徑名需要的內(nèi)存空間
int? cb? =?( 1? +? lstrlenA ( pszLibFileName ))?*? sizeof ( char );
//使用VirtualAllocEx函數(shù)在遠程進程的內(nèi)存地址空間分配DLL文件名緩沖區(qū)
pszLibFileRemote? =?( char? *)? VirtualAllocEx (? hRemoteProcess ,? NULL ,? cb ,? MEM_COMMIT ,? PAGE_READWRITE );
//使用WriteProcessMemory函數(shù)將DLL的路徑名復制到遠程進程的內(nèi)存空間
iReturnCode? =? WriteProcessMemory ( hRemoteProcess ,? pszLibFileRemote ,?( PVOID )? pszLibFileName ,? cb ,? NULL );
????
OK,現(xiàn)在目標進程也認識pszLibFileRemote了,但是pfnStartAddr好像不好辦,我怎么可能知道LoadLibraryA在目標進程中的地址呢?其實Windows為我們解決了這個問題,LoadLibraryA這個函數(shù)是在Kernel32 . dll這個核心DLL里的,而這個?DLL很特殊,不管對于哪個進程,Windows總是把它加載到相同的地址上去。因此你的進程中LoadLibraryA的地址和目標進程中?LoadLibraryA的地址是相同的 ( 其實,這個DLL里的所有函數(shù)都是如此 ) 。至此,DLL注入結(jié)束了。
?
但是目前還有一個問題,上面的方法是無法將DLL注入到系統(tǒng)進程中去的,原因是進程級別不夠。那么我們就要提升注入程序的進程級別。使用下面的函數(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? );
}
?
?
?
最后我們來做一個簡單的例子:
首先編寫注入程序的代碼
//?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" ; //注意,這個一定要是全路徑文件名,除非它在系統(tǒng)目錄里
?
hRemoteProcess? =? OpenProcess ( PROCESS_CREATE_THREAD
????????
| PROCESS_VM_OPERATION
????????
| PROCESS_VM_WRITE ,
????????
FALSE , 0x3E0 ); //0x3E0是進程的id,測試時是explorer的進程id,可以用spy++去查找。
?//計算DLL路徑名需要的內(nèi)存空間
?
int? cb? =?( 1? +? lstrlenA ( pszLibFileName ))?*? sizeof ( char );
?
//使用VirtualAllocEx函數(shù)在遠程進程的內(nèi)存地址空間分配DLL文件名緩沖區(qū)
?
pszLibFileRemote? =?( char? *)? VirtualAllocEx ( hRemoteProcess ,? NULL ,? cb ,
????????????
MEM_COMMIT ,? PAGE_READWRITE );
?
//使用WriteProcessMemory函數(shù)將DLL的路徑名復制到遠程進程的內(nèi)存空間
?
iReturnCode? =? WriteProcessMemory ( hRemoteProcess ,
????
pszLibFileRemote ,?( PVOID )? pszLibFileName ,? cb ,? NULL );
?
//計算LoadLibraryW的入口地址
?
PTHREAD_START_ROUTINE?pfnStartAddr? =?( PTHREAD_START_ROUTINE )
??????????
GetProcAddress ( GetModuleHandle ( TEXT ( "Kernel32" )),
??????????
"LoadLibraryA" );
?
//啟動遠程線程LoadLibraryW,通過遠程線程調(diào)用用戶的DLL文件
?
hRemoteThread? =? CreateRemoteThread (? hRemoteProcess ,? NULL ,? 0 ,
??????????
pfnStartAddr ,? pszLibFileRemote ,? 0 ,? NULL );

?
return? 0 ;
}
?
//提升權限
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盤根目錄下面運行注入程序。我們可以發(fā)現(xiàn)彈出了一個標示了被注入進程id的對話框。
如上,只要我們再dll中編寫我們需要的代碼,就可以隱秘的在電腦里執(zhí)行我們需要的事情。