Win32编程之远程注入(十八)
一、VirtualAllocEx函数
VirtualAllocEx
用于在另一个进程的虚拟地址空间中分配内存。这个函数通常与其他进程间内存操作函数一起使用,允许一个进程分配内存并将其映射到另一个进程的地址空间中。
函数原型:
LPVOID VirtualAllocEx( HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect );
参数:
- hProcess(HANDLE):
描述:目标进程的句柄,用于指定在哪个进程中分配内存。
注意事项:你需要有足够的权限来打开目标进程。
- lpAddress(LPVOID,可选):
描述:可选参数,用于指定分配内存的首选地址。如果为 NULL,则系统会选择一个合适的地址。
- dwSize(SIZE_T):
描述:要分配的内存大小,以字节为单位。
- flAllocationType(DWORD):
描述:内存分配类型,可以是以下值之一:
MEM_COMMIT:分配内存并提交它,使其可用。
MEM_RESERVE:仅保留内存地址空间,但不分配物理内存。
MEM_RESET:重置已经提交的内存区域。
- flProtect(DWORD):
描述:内存保护标志,用于指定内存的访问权限,可以是以下值之一:
PAGE_EXECUTE_READ:可执行代码。
PAGE_EXECUTE_READWRITE:可读写的可执行代码。
PAGE_READWRITE:可读写。
等等,还有其他选项,用于控制内存的保护级别。
返回值:
- 如果函数成功分配内存,它将返回一个指向分配内存区域的指针(LPVOID),通常是分配内存的起始地址。
- 如果函数失败,它将返回 NULL。你可以使用 GetLastError 函数来获取详细的错误信息。
二、VirtualFreeEx函数
VirtualFreeEx
用于释放在另一个进程的虚拟地址空间中分配的内存。这个函数通常与 VirtualAllocEx
函数一起使用,用于在另一个进程中分配内存并在不再需要时释放它。
函数原型:
BOOL VirtualFreeEx( HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType );
参数介绍:
hProcess
:目标进程的句柄,用于指定在哪个进程中释放内存。lpAddress
:要释放的内存区域的起始地址。dwSize
:要释放的内存大小,以字节为单位。通常,这应该与之前使用VirtualAllocEx
分配的内存大小相匹配。dwFreeType
:内存释放类型,可以是以下值之一:- MEM_DECOMMIT:释放内存并标记为未提交。这个选项允许稍后重新提交。
- MEM_RELEASE:释放内存,并从进程的地址空间中删除。这个选项将释放内存并返回系统。
三、WriteProcessMemory函数
WriteProcessMemory
用于在另一个进程的虚拟地址空间中写入数据。这个函数通常与 VirtualAllocEx
、ReadProcessMemory
和 CreateRemoteThread
等函数一起使用,允许一个进程向另一个进程写入数据,这在一些应用程序和系统工具中非常有用。
函数原型:
BOOL WriteProcessMemory( HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesWritten );
参数介绍:
hProcess
:目标进程的句柄,用于指定在哪个进程中写入数据。lpBaseAddress
:目标进程中的起始地址,指定要写入数据的位置。lpBuffer
:包含要写入目标进程的数据的缓冲区。nSize
:要写入的数据大小,以字节为单位。lpNumberOfBytesWritten
:一个指向SIZE_T
类型的变量指针,用于接收成功写入的字节数。这是一个可选参数,可以为 NULL。
四、ReadProcessMemory函数
ReadProcessMemory
是 Windows 操作系统提供的函数,用于从另一个进程的虚拟地址空间中读取数据。这个函数通常与 WriteProcessMemory
、VirtualAllocEx
和 CreateRemoteThread
等函数一起使用,允许一个进程从另一个进程读取数据。
函数原型:
BOOL ReadProcessMemory( HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesRead );
参数介绍:
hProcess
:目标进程的句柄,用于指定从哪个进程中读取数据。lpBaseAddress
:目标进程中的起始地址,指定要读取数据的位置。lpBuffer
:用于接收从目标进程读取的数据的缓冲区。nSize
:要读取的数据大小,以字节为单位。lpNumberOfBytesRead
:一个指向SIZE_T
类型的变量指针,用于接收成功读取的字节数。这是一个可选参数,可以为 NULL。
五、CreateRemoteThread函数
CreateRemoteThread
用于在另一个进程的上下文中创建一个新的线程。这个函数通常与其他进程间通信函数如 VirtualAllocEx
、WriteProcessMemory
、ReadProcessMemory
一起使用,允许一个进程在另一个进程中执行代码。
函数原型:
HANDLE CreateRemoteThread( HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId );
参数介绍:
hProcess
:目标进程的句柄,用于指定在哪个进程中创建线程。lpThreadAttributes
:一个指向SECURITY_ATTRIBUTES
结构的指针,用于指定新线程的安全属性,通常可以设置为 NULL。dwStackSize
:新线程的堆栈大小,通常可以设置为 0。lpStartAddress
:新线程的起始地址,即要在目标进程中执行的函数指针。lpParameter
:传递给新线程的参数,通常可以设置为 NULL。dwCreationFlags
:线程创建标志,通常可以设置为 0。lpThreadId
:一个指向DWORD
类型的变量指针,用于接收新线程的标识。这是一个可选参数,可以为 NULL。
六、OpenProcess函数
OpenProcess
用于打开一个已存在进程的句柄,以便后续进行与该进程相关的操作,如读取或写入其内存、查看其线程、以及执行其他与进程有关的任务。
函数原型:
HANDLE OpenProcess( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId );
参数介绍:
-
dwDesiredAccess
:指定要打开的进程的访问权限。这是一个标志位,可以指定多个权限选项,如下所示的一些常见选项:- PROCESS_ALL_ACCESS:具有对进程的完全访问权限,包括读取、写入、执行、终止等。
- PROCESS_VM_READ:允许读取进程的虚拟内存。
- PROCESS_VM_WRITE:允许写入进程的虚拟内存。
- PROCESS_QUERY_INFORMATION:允许获取进程信息。
-
bInheritHandle
:一个布尔值,指定句柄是否可以被子进程继承。通常可以设置为 FALSE。 -
dwProcessId
:目标进程的进程标识符(PID),用于指定要打开的进程。
七、远程注入
1.进程注入的示例源码
#include <Windows.h> #include <TlHelp32.h> #include <stdio.h> DWORD getMainThreadIdFormName(const WCHAR* szName) { DWORD idProcess = 0; //进程ID PROCESSENTRY32 pe; //进程信息 pe.dwSize = sizeof(PROCESSENTRY32); HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); //获取系统进程列表快照 if (Process32First(hSnapshot, &pe)) { //返回系统中第一个进程的信息 do { if (_wcsicmp(pe.szExeFile, szName) == 0) { idProcess = pe.th32ProcessID; break; } } while (Process32Next(hSnapshot, &pe)); //下一个进程 } CloseHandle(hSnapshot); //删除快照 return idProcess; } int main() { DWORD idProcess = getMainThreadIdFormName(TEXT("WinInjection.exe")); if (idProcess == 0) { return 0; } printf("Process id:%d\n", idProcess); HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, idProcess); if (hProcess == NULL) { printf("OpenProcess failed...\n"); return 0; } char dllName[] = "mydll.dll"; DWORD dllSize = strlen(dllName) + 1; DWORD dwWritten = 0; LPVOID lpBuf = VirtualAllocEx(hProcess, NULL, strlen(dllName) + 1, MEM_COMMIT, PAGE_READWRITE); if (lpBuf == NULL) { CloseHandle(hProcess); printf("VirtualAllocEx failed...\n"); return 0; } if (WriteProcessMemory(hProcess, lpBuf, (LPCVOID)dllName, dllSize, &dwWritten)) { if (dwWritten != dllSize) { VirtualFreeEx(hProcess, lpBuf, dllSize, MEM_DECOMMIT); CloseHandle(hProcess); } } else { printf("WriteProcessMemory failed..\n"); CloseHandle(hProcess); return 0; } DWORD dwID; LPVOID pFunc = LoadLibraryA; HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pFunc, lpBuf, 0, &dwID); if (hThread == NULL) { printf("CreateRemoteThread failed\n"); VirtualFreeEx(hProcess, lpBuf, dllSize, MEM_DECOMMIT); CloseHandle(hProcess); return 0; } WaitForSingleObject(hThread, INFINITE); VirtualFreeEx(hProcess, lpBuf, dllSize, MEM_DECOMMIT); CloseHandle(hThread); CloseHandle(hProcess); return 1; }
2.dll测试代码
// dllmain.cpp : 定义 DLL 应用程序的入口点。 #include "pch.h" BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: ::MessageBox(NULL, L"dll attach", L"dll", MB_OK); break; case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: break; case DLL_PROCESS_DETACH: ::MessageBox(NULL, L"dll detach", L"dll", MB_OK); break; } return TRUE; }
3.创建一个Win32的桌面应用程序(WinInjection.exe)并运行,然后再运行远程注入的代码
其效果如下: