Win32编程之远程注入(十八)
一、VirtualAllocEx函数
VirtualAllocEx
用于在另一个进程的虚拟地址空间中分配内存。这个函数通常与其他进程间内存操作函数一起使用,允许一个进程分配内存并将其映射到另一个进程的地址空间中。
函数原型:
1 2 3 4 5 6 7 | 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
函数一起使用,用于在另一个进程中分配内存并在不再需要时释放它。
函数原型:
1 2 3 4 5 6 | 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
等函数一起使用,允许一个进程向另一个进程写入数据,这在一些应用程序和系统工具中非常有用。
函数原型:
1 2 3 4 5 6 7 | 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
等函数一起使用,允许一个进程从另一个进程读取数据。
函数原型:
1 2 3 4 5 6 7 | 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
一起使用,允许一个进程在另一个进程中执行代码。
函数原型:
1 2 3 4 5 6 7 8 9 | 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
用于打开一个已存在进程的句柄,以便后续进行与该进程相关的操作,如读取或写入其内存、查看其线程、以及执行其他与进程有关的任务。
函数原型:
1 2 3 4 5 | 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.进程注入的示例源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | #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测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | // 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)并运行,然后再运行远程注入的代码
其效果如下:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?