一天學(xué)硬件,一天學(xué)軟件。哈~正所謂【軟硬兼施】啊。今天輪到學(xué)軟件了,由于之前對DLL木馬有一些研究,大部分木馬都是通過遠程線程注入的方式實現(xiàn)無進程執(zhí)行。早就想學(xué) 這種技術(shù)了,無奈當時自身的編程技術(shù)還不到那個境界,現(xiàn)在試試。。。
花了一下午的時間, 查詢相關(guān)資料,看視頻教程,大概給弄懂怎么回事了。就是將木馬的實現(xiàn)功能全部寫在一個DLL中(DLL 也是可執(zhí)行文件,但是不可以直接執(zhí)行,需要EXE調(diào)用),然后找個目標進程(一般是IE進程,突破防火墻~),將自身路徑寫入到該進程空間內(nèi),然后在該進程中尋找LoadLibraryA()這個加載DLL 的函數(shù)地址,通過遠程線程函數(shù)使該進程執(zhí)行LoadLibraryA()這個加載函數(shù),加載DLL。 直白點,就是先將DLL的路徑寫入到目標進程空間內(nèi),然后在目標進程空間內(nèi)尋找 LoadLibraryA()這個函數(shù)的地址,再利用LoadLibraryA()這個函數(shù)調(diào)用木馬的DLL。相當于執(zhí)行了木馬...然后木馬就可以隨意的xxoxoxox你的電腦了~
遠程線程注入的細分過程 共可分5 步:
1、通過進程PID 打開目標進程獲得目標進程句柄。(為了能操作該進程就要獲得它的句柄)
利用到的API: HANDLE OpenProcess( DWORD dwDesiredAccess,BOOL bInheritHandle, DWORD dwProcessId);
功能:OpenProcess 函數(shù)用來打開一個已存在的進程對象,并返回進程的句柄。
函數(shù)原型:
HANDLE OpenProcess( DWORD dwDesiredAccess, //權(quán)限
BOOL bInheritHandle, // 是否繼承句柄
DWORD dwProcessId // 目標進程的PID標識符
);
返回值: 如成功,返回值為指定進程的句柄。 如失敗,返回值為空,可調(diào)用GetLastError獲得錯誤代碼。
2、根據(jù)上面提供的目標進程句柄在其申請一塊內(nèi)存空間。(用于存放DLL的完整路徑)
利用到的API:LPVOID VirtualAllocEx(HANDLE hProcess,LPVOID lpAddress,SIZE_T dwSize,DWORD flAllocationType, DWORD flProtect )
功能:VirtualAllocEx 函數(shù)的作用是在指定進程的虛擬空間保留或提交內(nèi)存區(qū)域,除非指定MEM_RESET參數(shù),否則將該內(nèi)存區(qū)域置0。
函數(shù)原形:
LPVOID VirtualAllocEx(
HANDLE hProcess, // 進程句柄
LPVOID lpAddress, // 獲取內(nèi)存空間的區(qū)域
SIZE_T dwSize, // 要獲取空間的大小
DWORD flAllocationType, // 內(nèi)存分配的類型
DWORD flProtect // 內(nèi)存頁保護
);
返回值:執(zhí)行成功就返回分配內(nèi)存的首地址,不成功就是NULL。
3、將DLL的路徑寫入到目標進程內(nèi)申請的內(nèi)存空間。(因為進程間是有邊界的,不能互相訪問彼此的內(nèi)存空間)
利用到的API:BOOL WriteProcessMemory( HANDLE hProcess, LPVOID lpBaseAddress, LPVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesWritten );
功能: 此函數(shù)能寫入某一進程的內(nèi)存區(qū)域(直接寫入會出Access Violation錯誤,故需此函數(shù))。
函數(shù)原形:
BOOL WriteProcessMemory(
HANDLE hProcess, // 進程句柄
LPVOID lpBaseAddress, // 內(nèi)存空間分配的首地址
LPVOID lpBuffer, // 寫入的內(nèi)容
DWORD nSize, // 寫入的內(nèi)容大小
LPDWORD lpNumberOfBytesWritten // 不知道干嘛用 ...
);
返回值:非零值代表成功。
4、在目標進程中尋找LoadLibraryA()這個函數(shù)的函數(shù)地址。(找到函數(shù)地址才能調(diào)用它)
利用到的API: FARPROC GetProcAddress( HMODULE hModule, LPCSTR lpProcName );
HMODULE GetModuleHandle ( LPCTSTR lpModuleName );
功能:GetProcAddress函數(shù)檢索指定的動態(tài)鏈接庫(DLL)中的輸出庫函數(shù)地址。
函數(shù)原型:
FARPROC GetProcAddress(
HMODULE hModule, // DLL模塊句柄
LPCSTR lpProcName // 函數(shù)名
);
返回值:
如果函數(shù)調(diào)用成功,返回值是DLL中的輸出函數(shù)地址。
如果函數(shù)調(diào)用失敗,返回值是NULL。得到進一步的錯誤信息,調(diào)用函數(shù)GetLastError。
說明:GetModuleHandle 獲取一個應(yīng)用程序或動態(tài)鏈接庫的模塊句柄
參數(shù):lpModuleName 模塊名稱 如果參數(shù)是NULL 則獲取自身句柄
返回值:如執(zhí)行成功成功,則返回模塊句柄。零表示失敗。通過GetLastError獲得錯誤信息
5、創(chuàng)建遠程線程,根據(jù)上面找到LoadLibraryA()的函數(shù)地址,調(diào)用該函數(shù),LoadLibraryA()函數(shù)的參數(shù)就是目標進程中的DLL路徑 (這時就是執(zhí)行我們的DLL 了) 利用到的API:HANDLE WINAPI CreateRemoteThread( __in HANDLE hProcess, __in LPSECURITY_ATTRIBUTES lpThreadAttributes, __in SIZE_T dwStackSize, __in LPTHREAD_START_ROUTINE lpStartAddress, __in LPVOID lpParameter, __in DWORD dwCreationFlags, __out LPDWORD lpThreadId );
功能:創(chuàng)建一個在其它進程地址空間中運行的線程(也稱:創(chuàng)建遠程線程).
函數(shù)原型:
HANDLE WINAPI CreateRemoteThread(
1 __in HANDLE hProcess, // 目標進程句柄
__in LPSECURITY_ATTRIBUTES lpThreadAttributes, // 線程安全屬性
__in SIZE_T dwStackSize, // 線程棧初始大小
__in LPTHREAD_START_ROUTINE lpStartAddress, // 線程函數(shù)
__in LPVOID lpParameter, // 線程參數(shù)
__in DWORD dwCreationFlags, // 創(chuàng)建的標志 (立即執(zhí)行、掛起等)
__out LPDWORD lpThreadId // 線程句柄
);
返回值: 如果調(diào)用成功,返回新線程句柄.
如果失敗,返回NULL.
具體實現(xiàn)代碼:(EXE)
======================================================================================================
#include <windows.h>
#include <stdio.h>
BOOL InjectDll(char *DllPath, DWORD dwProcessID)
{
if ( (DllPath == NULL) && (dwProcessID < 0))
return FALSE;
// 1、打開目標進程獲得目標進程句柄 // 權(quán)限 ,句柄繼續(xù)承,加成PID
HANDLE hRemoteProcess = OpenProcess(PROCESS_ALL_ACCESS,0,dwProcessID);
if (hRemoteProcess == NULL)
return FALSE;
// 2、通過目標進程句柄在其申請一塊內(nèi)存空間 // 進程句柄,獲取內(nèi)存地址區(qū)域,分配的內(nèi)存大小,內(nèi)存分配的類型,內(nèi)存頁保護
LPVOID RemoteProcessSize = VirtualAllocEx(hRemoteProcess,NULL,strlen(DllPath)+1,MEM_COMMIT|MEM_RESERVE,PAGE_READWRITE);
if (RemoteProcessSize == NULL)
return FALSE;
// 3、將DLL的路徑寫入到目標進程內(nèi)申請的內(nèi)存空間
// 進程句柄,要寫入的內(nèi)存首地址,寫入的內(nèi)容,內(nèi)容的大小,未知
BOOL bRet = WriteProcessMemory(hRemoteProcess,RemoteProcessSize,DllPath,strlen(DllPath)+1,0);
if(!bRet)
return FALSE;
// 4、將函數(shù)LoadLibraryA的入口地址作為我們的遠程線程的入口地址
// 當遠程線程啟動時,就會調(diào)用LoadLibraryA 裝載我們的DLL // 模塊句柄 /*獲取模塊句柄(模塊名)*/ ,函數(shù)名
PTHREAD_START_ROUTINE ScanLoad = (PTHREAD_START_ROUTINE) GetProcAddress(GetModuleHandle("Kernel32.DLL"),"LoadLibraryA");
if (ScanLoad == NULL)
return FALSE;
/* 哈前天才剛從小凡那挖過來的知識點 沒想到現(xiàn)在就用上了。再次感謝我家滴小凡!o(∩_∩)o 哈哈 PTHREAD_START_ROUTINE 這個其實是函數(shù)型指針,原型typedef DWORD (WINAPI *PTHREAD_START_ROUTINE)(LPVOID lpThreadParameter); 用來指向LoadLibraryA 函數(shù) */
// 5、創(chuàng)建遠程線程執(zhí)行DLL 這里其實就是用LoadLibraryA 加載我們的DLL
HANDLE hRemoteThread = NULL;
// 目標進程句柄,線程安全屬性,線程初始大小,線程函數(shù)(目標中的LoadLibraryA),函數(shù)參數(shù)(就是目標進程中的DLL路徑),標志,線程句柄
hRemoteThread = CreateRemoteThread(hRemoteProcess,NULL,0,ScanLoad,RemoteProcessSize,0,0);
if(hRemoteThread == NULL)
return FALSE;
return TRUE;
}
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
if (InjectDll("D:\\ssdddd.dll",1552)) // 傳遞DLL 完整路徑和需要注入的目標進程的PID
MessageBox(0,"注入成功!","",MB_SYSTEMMODAL);
else
MessageBox(0,"注入失敗!","",MB_SYSTEMMODAL);
}
========================================================================================================
這個是被調(diào)用的DLL:
========================================================================================================
#include "windows.h"
BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD fdwReason, PVOID fImpLoad) // 這是個回調(diào)函數(shù) 也是DLL 入口點
{
switch(fdwReason)
{
case DLL_PROCESS_ATTACH: // 進程被調(diào)用
MessageBox(NULL,"嘎嘎~DLL自身被調(diào)用~","進程被調(diào)用 ",MB_SYSTEMMODAL);
break;
case DLL_THREAD_ATTACH: // 線程被調(diào)用
MessageBox(NULL,"嘎嘎~目標程序啟動了一個線程~","線程被調(diào)用 ",MB_SYSTEMMODAL);
break;
case DLL_PROCESS_DETACH: // 進程退出
MessageBox(NULL,"嘎嘎~目標進程退出~","進程退出",MB_SYSTEMMODAL);
break;
case DLL_THREAD_DETACH: // 線程退出
MessageBox(NULL,"嘎嘎~目標線程退出~","線程退出",MB_SYSTEMMODAL);
break;
}
return(TRUE);
}
========================================================================================================
遠程線程注入還有其他的方式,好像是將要實現(xiàn)的功能函數(shù)直接寫入到目標進程內(nèi),在明白進程內(nèi)執(zhí)行該函數(shù)...不過原理應(yīng)該都是一樣滴,遠程線程注入還有其他的用處,例如外掛啊、破解補丁啊、等等...
嗯,這就是今天理解到的東西,剛接觸,可能有些地方理解錯了,請大家不要見笑哈,歡迎批評指正~ 有興趣的童鞋可以加我 共同探討
等學(xué)會了遠程線程注入,準備開始研究研究HOOK了,HOOK 更好玩~ 興奮吖~~
|