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í)行我們需要的事情。