C++ code colored by C++2HTML
每個進程都有它自己的私有地址空間。當使用指針來引用內存時,指針的值將引用你自己進程的地址空間中的一個內存地址,有些情況下,必須打破進程的界限,訪問另一個進程的地址空間,這些情況包括:

? 當你想要為另一個進程創建的窗口建立子類時。

? 當你需要調試幫助時(例如,當你需要確定另一個進程正在使用哪個DLL時)。

? 當你想要掛接其他進程時

將DLL 插入到另一個進程的地址空間中。一旦DLL進入另一個進程的地址空間,就可以對另一個進程為所欲為。Dll必須進入進程的空間否則就會出現地址訪問的越界違規。這就是問什么不能直接用函數 SetWindowLongPtr(hwnd,GWLP_WNDPROC,Mysubclassproc);插入的方法有多種:

1:注冊表插入

windows98不可以用!是在windows初始化的時候加載的!DLL只會映射到使用User 32.dll的進程中。所有基于GUI的應用程序均使用User32.dll,不過大多數基于CUI的應用程序并不使用它。很容易實現但很不安全,系統易崩潰!

2:用windows掛鉤插入DLL

Microsoft Spy++就是安裝了掛鉤(wm_getmessage)查看系統各個窗口處理的消息!用下面的函數安裝

HHOOK HhOOK = SetWindowsHookEx(WH_GETMESSAGE,GetMsgProc,hinstDll,0);

第一個參數WH_GETMESSAGE用于指定安裝掛鉤的類型,GetMsgProc用于指明窗口準備處理一個消息時系統應該調用的函數的地址。 HinstDll指明包含GetMsgProc函數的DLL,DLL的hinstDll的值用于標識DLL被映射到的進程的地址空間中的虛擬內存地址;最后一個參數0用于指明要掛接的線程,對于一個線程來說,它可以調用SetWindowsHookEx函數,傳遞系統中的另一個線程的ID。通過為這個參數傳遞0,就告訴系統說,我們想要掛接系統中的所有GUI線程。現在讓我們來看一看將會發生什么情況:

1) 進程B中的一個線程準備將一條消息發送到一個窗口。

2) 系統查看該線程上是否已經安裝了WH_GETMESSAGE掛鉤。

3) 系統查看包含GetMsgProc函數的DLL是否被映射到進程B的地址空間中。

4) 如果該DLL尚未被映射,系統將強制該DLL映射到進程B的地址空間,并且將進程B中的DLL映像的自動跟蹤計數遞增1

這個方法允許你在另一個進程的地址空間中不再需要DLL時刪除該DLL的映像,方法是調用函數 BOOL UnhookWindowsHookEx(HHOOK hhook);

3: 使用遠程線程來插入D L L

這個DLL插入法要求目標進程中的線程調用LoadLibrary函數來加載必要的DLL。但我們無法控制其它線程,因此要求我們可以在目標進程中創建一個新進程以便控制它。CreateRemoteThread函數可以做到這一點:

HANDLE CreateRemoteThread(
HANDLE hProcess, //指明擁有新創建線程的進程句柄

PSECURITY_ATTRIBUTES psa,

PTHREAD_START_ROUTINE pfnStartAddr, //線程函數的地址空間

PVOID pvParam,

DWORD fdwCreate,

PDWORD pdwThreadId);

使用實例:

HANDLE hThread=CreateRemoteThread(hProcessRemote,NULL,0,

LoadLibraryA,”C:\\mylib.dll”,0,NULL);

CreateRemoteThread的前提條件是Kernel32.dll已經被同事映射到了本地和遠程進程的地址空間中,恰好每個程序都要用到Kernel32.dll。

PTHREAD_START_ROUTIME pfnThreadRtn = (PTHREAD_START_ROUTIME)

GetProcAddress(GetModuleHandle(TEXT(“Kernel32”),LoadLibraryA);

HANDLE hThread = CreateRemoteThread(hProcessRemote,NULL,0,

pfnThreadRtn,”c:\\mylib.dll”,0,NULL);

《WINDOWS核心編程》中的例子

BOOL WINAPI InjectLibW(DWORD dwProcessId, PCWSTR pszLibFile)

{

BOOL fOk = FALSE; // Assume that the function fails

HANDLE hProcess = NULL, hThread = NULL;

PWSTR pszLibFileRemote = NULL;

__try {

// Get a handle for the target process.

hProcess = OpenProcess(

PROCESS_QUERY_INFORMATION | // Required by Alpha

PROCESS_Create_THREAD | // For CreateRemoteThread

PROCESS_VM_OPERATION | // For VirtualAllocEx/VirtualFreeEx

PROCESS_VM_WRITE, // For WriteProcessMemory

FALSE, dwProcessId);

if (hProcess == NULL) __leave;

// Calculate the number of bytes needed for the DLL's pathname

int cch = 1 + lstrlenW(pszLibFile);

int cb = cch * sizeof(WCHAR);

// Allocate space in the remote process for the pathname

pszLibFileRemote = (PWSTR)

VirtualAllocEx(hProcess, NULL, cb, MEM_COMMIT, PAGE_READWRITE);

if (pszLibFileRemote == NULL) __leave;

// Copy the DLL's pathname to the remote process's address space

if (!WriteProcessMemory(hProcess, pszLibFileRemote,

(PVOID) pszLibFile, cb, NULL)) __leave;

// Get the real address of LoadLibraryW in Kernel32.dll

PTHREAD_START_ROUTINE pfnThreadRtn = (PTHREAD_START_ROUTINE)

GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW");

if (pfnThreadRtn == NULL) __leave;

// Create a remote thread that calls LoadLibraryW(DLLPathname)

hThread = CreateRemoteThread(hProcess, NULL, 0,

pfnThreadRtn, pszLibFileRemote, 0, NULL);

if (hThread == NULL) __leave;

// Wait for the remote thread to terminate

WaitForSingleObject(hThread, INFINITE);

fOk = TRUE; // Everything executed successfully

}

__finally { // Now, we can clean everthing up

// Free the remote memory that contained the DLL's pathname

if (pszLibFileRemote != NULL)

VirtualFreeEx(hProcess, pszLibFileRemote, 0, MEM_RELEASE);

if (hThread != NULL)

CloseHandle(hThread);

if (hProcess != NULL)

CloseHandle(hProcess);

}