22.4 injecting DLLs with remote threads
22.4.1 Overview
(1) Remote thread injection refers to the technique by which a process creates a thread in another process, and then loads the DLL that we write and executes the DLL code. The basic idea is to create a remote thread through CreateRemoteThread and use the LoadLibrary function as the thread function to start the thread and pass the DLL file name as a parameter to the thread function. The approximate procedure is as follows: CreateRemoteThread () →loadlibrary () →dllmain ().
(2) Core function: CreateRemoteThread
Parameters |
Description |
HANDLE hprocess |
The process handle to create the remote thread. In addition to this parameter, CreateRemoteThread is exactly the same as the CreateThread function parameter! |
Psecurity_attributes PSA |
Used to define the security properties of the new thread, which is set to NULL with the default value |
DWORD dwstacksize |
Initialize the thread stack size, NULL is the default size |
Pthread_start_routine pfnstartaddr |
The address of the thread function, where the address of the LoadLibrary function is passed in, but it must be in the address space of the remote process because it is called by the remote thread. How to obtain this function address in the remote process, refer to the following. |
PVOID Pvparam |
Thread function parameters, which are usually DLL file names, but this name must be stored in the remote process's address space, which is a tricky issue. |
DWORD fdwcreate |
function indicates the running state of the thread after the thread was created |
Pdword Pdwthreadid |
Returns the thread ID, does not care can be set to NULL does not return |
Note: The key to use this function is to solve the three parameter problem: ① obtains the process handle of the remote thread, and ensures that the appropriate permissions (such as debug permissions), ② gets the start address of the thread function of the remote process, not the local address; ③ successfully passed the DLL path string to the remote threads. |
(3) Other functions
① allocating/freeing memory in remote processes: Virtualallocex/virtualfreeex
② to read and write to the remote process address space: readprocessmemory/writeprocessmemory
22.4.2 get the remote address of the LoadLibrary function
(1) LoadLibrary to be used as a remote thread function, two conditions must be met:
① the function conforms to the prototype of the thread function. (see MSDN, they have the same calling convention, and all have a parameter and a return value.) For different types, it can be obtained by a strong-turn type, so the condition is satisfied)
② the function exists in the remote thread address space. This can also be guaranteed, Because the LoadLibrary function is in Kernel32.dll, the local process and Kernel32.dll in the remote process are mapped to the same memory address in the address space for the Windows system, so as long as the local process is fetched through GetProcAddress Loadlibrar The address of Y, which is also the same address in the remote process, can be passed directly to CreateRemoteThread.
(2) LoadLibrary is defined as a macro, not a function. There are two versions of LoadLibraryA and Loadlibraryw.
(3) Why the pfnstartaddr parameter of the CreateRemoteThread cannot be written directly to LoadLibrary W (or a), but the address of the Loadlibary function to be obtained using GetProcAddress .
①loadlibrary W (or a) is an export function in Kernel32.dll, but when the function is referenced directly in our DLL, it is recorded in the DLL's import table. We all know that the real address of the import function is determined when the DLL is loaded, the loader takes the import function name from the import table and, after being loaded into the process address space, calculates the actual address of the function and fills in the corresponding location of the import table (IAT). This function does not know the correct address at compile time, so it is compiled into code such as call DWORD Ptr[xxxxxxxx], although the value in brackets is a definite value, but not the real address of the import function (like Call XXXXXXXX), but the address of a subroutine. , the program is called a conversion function (Thunk). "By the way, this is why the __declspec (dllimport) prefix is added when declaring an import function, because the compiler cannot differentiate whether the application is called on a generic function call or an import function. When this prefix is added, the compiler will assume that this function comes from the import function and will produce the command for call DWORD Ptr[xxxxxxxx] instead of call XXXXXXXX. 】
② when the program calls the import function, the compiler processes the transform function to call the conversion functions, then the conversion function obtains the actual address of the import function from the IAT table, and then calls the corresponding address. So if the pfnstartaddr parameter of CreateRemoteThread is written as Loadlibraryw (or a), the address will be compiled into the address of the conversion function, not the real address of the LoadLibrary.
22.4.3 storing the path string of a DLL in a remote address space
(1) if the DLL path is passed directly to CreateRemoteThread (), such as "C:\\mydll.dll", then it is actually passing a local pointer value to the remote thread, which is meaningless in the address space of the remote process .
(2) You can use the VirtualAllocEx () function to allocate a space in the remote process before using WriteProcessMemory to copy the DLL path string to the address space of the remote process. Finally, a pointer to the remote memory is passed to the createremotethead corresponding parameter.
24.4.4 summarizing the steps to inject a DLL using a remote thread
① uses the VirtualAllocEx function to allocate a chunk of memory in the address space of the remote process.
② using the WriteProcessMemory function to reflect the DLL's path name to the 1th step of the allocated memory
③ uses the GetProcAddress function to get the real address of the LoadLibrary W (or a) function at Kernel32.dll.
④ creates a thread in the remote process with the CreateRemoteThread function, lets the new thread invoke the correct LoadLibrary function, and passes in the parameter the memory address of the 1th step assignment. At this point, the DLL has been injected into the remote process's address space, the DLL's DllMain function will receive DLL_PROCESS_ATTACH notification and the county can execute the code we want to execute. When DllMain returns, the remote thread is returned from the thread function (loadlibraryw/a) call to the thread-start function rtluserthreadstart (the implementation of the function can refer to chapter 6th), and the last call to ExitThread causes the remote thread to terminate.
⑤ at this point in the remote process the memory allocated in the 1th step is still in, the DLL is also in the remote process's address space. Just call VirtualFreeEx here to free the memory of the remote process.
⑥ but the release of the DLL, to get the address of freelibrary through GetProcAddress, and then through CreateRemoteThread in the remote process to create a thread, let the thread call FreeLibrary, The Pvparam parameter is passed to the handle in the remote DLL.
"Injectlibrary Sample Program"
22nd DLL injection and API blocking (2)