Table of Contents
Toggle核心功能概述
WriteProcessMemory 是一个 Windows API 函数,允许一个进程向另一个进程的内存空间写入数据。这是进程间通信和内存操作的关键函数。
基本比喻:
cpp
// 就像给邻居家送包裹 你的进程.写内存(邻居家进程, 邻居家地址, 你的数据, 数据大小); // 需要邻居家的"门牌号"和"门禁权限"
📖 函数原型详解
cpp
BOOL WriteProcessMemory( HANDLE hProcess, // [目标进程] - 要写入的进程句柄 LPVOID lpBaseAddress, // [目标地址] - 要写入的内存地址 LPCVOID lpBuffer, // [数据源] - 包含数据的缓冲区 SIZE_T nSize, // [数据大小] - 要写入的字节数 SIZE_T *lpNumberOfBytesWritten // [实际写入] - 实际写入的字节数 );
🔍 参数深度解析
1. hProcess – 目标进程句柄
cpp
// 必须具有 PROCESS_VM_WRITE 和 PROCESS_VM_OPERATION 权限 HANDLE hProcess = OpenProcess( PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, // 不继承句柄 targetPID // 目标进程ID );
2. lpBaseAddress – 目标内存地址
cpp
// 必须是目标进程中有效的可写地址 // 通常通过以下方式获得: LPVOID remoteAddr = VirtualAllocEx(hProcess, NULL, size, MEM_COMMIT, PAGE_READWRITE); // 或者写入已知的固定地址
3. lpBuffer – 源数据缓冲区
cpp
// 当前进程中的数据,可以是任何类型 char data[] = "Hello from another process!"; int value = 12345; BYTE shellcode[] = { 0x90, 0x90, 0xC3 }; // NOP, NOP, RET
4. nSize – 要写入的大小
cpp
// 要写入的字节数,不能超过缓冲区大小 DWORD size = strlen(data) + 1; // 包括字符串结束符
5. lpNumberOfBytesWritten – 实际写入大小
cpp
// 输出参数,接收实际写入的字节数 SIZE_T bytesWritten;
💻 完整使用示例
示例1:基础数据写入
cpp
#include <windows.h> #include <iostream> void DemoBasicWriteProcessMemory() { std::cout << "📝 WriteProcessMemory 基础示例" << std::endl; // 1. 打开目标进程(比如记事本) DWORD targetPID = 1234; // 替换为实际PID HANDLE hProcess = OpenProcess( PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, targetPID ); if (hProcess == NULL) { std::cout << "❌ 无法打开目标进程" << std::endl; return; } // 2. 在目标进程分配内存 LPVOID remoteMemory = VirtualAllocEx( hProcess, NULL, 1024, // 1KB MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE ); if (remoteMemory == NULL) { std::cout << "❌ 无法在目标进程分配内存" << std::endl; CloseHandle(hProcess); return; } std::cout << "✅ 在目标进程分配内存: " << remoteMemory << std::endl; // 3. 准备要写入的数据 const char* message = "Hello from WriteProcessMemory!"; SIZE_T messageSize = strlen(message) + 1; // 包括null终止符 // 4. 写入数据到目标进程 SIZE_T bytesWritten; BOOL success = WriteProcessMemory( hProcess, // 目标进程 remoteMemory, // 目标地址 message, // 源数据 messageSize, // 数据大小 &bytesWritten // 实际写入字节数 ); if (success && bytesWritten == messageSize) { std::cout << "✅ 成功写入 " << bytesWritten << " 字节到目标进程" << std::endl; // 验证写入(可选 - 需要读取权限) char verifyBuffer[1024]; SIZE_T bytesRead; if (ReadProcessMemory(hProcess, remoteMemory, verifyBuffer, messageSize, &bytesRead)) { std::cout << "验证读取: " << verifyBuffer << std::endl; } } else { std::cout << "❌ 写入失败" << std::endl; if (GetLastError() == ERROR_PARTIAL_COPY) { std::cout << "错误: 部分拷贝 - 可能是地址无效" << std::endl; } } // 5. 清理资源 VirtualFreeEx(hProcess, remoteMemory, 0, MEM_RELEASE); CloseHandle(hProcess); }
示例2:Shellcode 注入(典型应用)
cpp
#include <windows.h> BOOL InjectShellcode(DWORD targetPID, BYTE* shellcode, SIZE_T shellcodeSize) { std::cout << "🎯 Shellcode 注入示例" << std::endl; // 1. 打开目标进程 HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, // 需要所有权限 FALSE, targetPID ); if (!hProcess) { std::cout << "❌ 无法打开目标进程" << std::endl; return FALSE; } // 2. 在目标进程分配可读写内存 LPVOID remoteMemory = VirtualAllocEx( hProcess, NULL, shellcodeSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE // 初始为可读写 ); if (!remoteMemory) { std::cout << "❌ 内存分配失败" << std::endl; CloseHandle(hProcess); return FALSE; } std::cout << "✅ 分配远程内存: " << remoteMemory << std::endl; // 3. 写入 Shellcode SIZE_T bytesWritten; BOOL writeSuccess = WriteProcessMemory( hProcess, remoteMemory, shellcode, shellcodeSize, &bytesWritten ); if (!writeSuccess || bytesWritten != shellcodeSize) { std::cout << "❌ Shellcode 写入失败" << std::endl; VirtualFreeEx(hProcess, remoteMemory, 0, MEM_RELEASE); CloseHandle(hProcess); return FALSE; } std::cout << "✅ Shellcode 写入成功: " << bytesWritten << " 字节" << std::endl; // 4. 修改内存权限为可执行 DWORD oldProtect; BOOL protectSuccess = VirtualProtectEx( hProcess, remoteMemory, shellcodeSize, PAGE_EXECUTE_READ, // 改为可执行 &oldProtect ); if (!protectSuccess) { std::cout << "❌ 内存权限修改失败" << std::endl; VirtualFreeEx(hProcess, remoteMemory, 0, MEM_RELEASE); CloseHandle(hProcess); return FALSE; } std::cout << "✅ 内存权限改为可执行" << std::endl; // 5. 创建远程线程执行 Shellcode HANDLE hThread = CreateRemoteThread( hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)remoteMemory, NULL, 0, NULL ); if (!hThread) { std::cout << "❌ 远程线程创建失败" << std::endl; VirtualFreeEx(hProcess, remoteMemory, 0, MEM_RELEASE); CloseHandle(hProcess); return FALSE; } std::cout << "🎉 Shellcode 注入成功!" << std::endl; // 6. 等待线程完成(可选) WaitForSingleObject(hThread, INFINITE); // 7. 清理资源 CloseHandle(hThread); VirtualFreeEx(hProcess, remoteMemory, 0, MEM_RELEASE); CloseHandle(hProcess); return TRUE; }
示例3:修改已有内存数据
cpp
#include <windows.h> #include <tlhelp32.h> BOOL ModifyProcessMemory(DWORD targetPID, LPVOID targetAddress, int newValue) { std::cout << "🔧 修改进程内存数据示例" << std::endl; // 1. 打开目标进程(只需要写入权限) HANDLE hProcess = OpenProcess( PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, targetPID ); if (!hProcess) { std::cout << "❌ 无法打开目标进程" << std::endl; return FALSE; } // 2. 检查目标地址是否可写 MEMORY_BASIC_INFORMATION mbi; if (VirtualQueryEx(hProcess, targetAddress, &mbi, sizeof(mbi))) { if (!(mbi.Protect & (PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READWRITE))) { std::cout << "❌ 目标内存不可写,当前保护: " << mbi.Protect << std::endl; // 尝试修改内存保护 DWORD oldProtect; if (VirtualProtectEx(hProcess, targetAddress, sizeof(newValue), PAGE_READWRITE, &oldProtect)) { std::cout << "✅ 临时修改内存保护为可写" << std::endl; } else { CloseHandle(hProcess); return FALSE; } } } // 3. 写入新值 SIZE_T bytesWritten; BOOL success = WriteProcessMemory( hProcess, targetAddress, &newValue, sizeof(newValue), &bytesWritten ); if (success && bytesWritten == sizeof(newValue)) { std::cout << "✅ 成功修改内存值: " << targetAddress << " -> " << newValue << std::endl; } else { std::cout << "❌ 内存修改失败" << std::endl; } CloseHandle(hProcess); return success; }
⚠️ 错误处理和常见问题
常见错误代码及处理:
cpp
BOOL SafeWriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize) { SIZE_T bytesWritten; BOOL success = WriteProcessMemory(hProcess, lpBaseAddress, lpBuffer, nSize, &bytesWritten); if (!success) { DWORD error = GetLastError(); switch (error) { case ERROR_ACCESS_DENIED: std::cout << "❌ 访问被拒绝 - 权限不足" << std::endl; break; case ERROR_INVALID_HANDLE: std::cout << "❌ 无效的进程句柄" << std::endl; break; case ERROR_PARTIAL_COPY: std::cout << "❌ 部分拷贝 - 地址范围无效" << std::endl; break; case ERROR_WRITE_FAULT: std::cout << "❌ 写入错误 - 内存不可写" << std::endl; break; default: std::cout << "❌ 未知错误: " << error << std::endl; } return FALSE; } if (bytesWritten != nSize) { std::cout << "⚠️ 部分写入: " << bytesWritten << "/" << nSize << " 字节" << std::endl; return FALSE; } return TRUE; }
权限检查函数:
cpp
BOOL CheckProcessAccess(HANDLE hProcess) { // 尝试读取进程基本信息来验证访问权限 DWORD exitCode; return GetExitCodeProcess(hProcess, &exitCode); } BOOL CanWriteToProcess(DWORD pid) { HANDLE hProcess = OpenProcess(PROCESS_VM_WRITE, FALSE, pid); if (hProcess) { CloseHandle(hProcess); return TRUE; } return FALSE; }
🔧 实际应用场景
场景1:游戏外挂(内存修改)
cpp
class GameHacker { HANDLE hGameProcess; DWORD gamePID; public: BOOL Initialize(DWORD pid) { gamePID = pid; hGameProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); return hGameProcess != NULL; } BOOL WriteInt(LPVOID address, int value) { SIZE_T bytesWritten; return WriteProcessMemory(hGameProcess, address, &value, sizeof(value), &bytesWritten); } BOOL WriteFloat(LPVOID address, float value) { SIZE_T bytesWritten; return WriteProcessMemory(hGameProcess, address, &value, sizeof(value), &bytesWritten); } BOOL WriteBytes(LPVOID address, BYTE* data, SIZE_T size) { SIZE_T bytesWritten; return WriteProcessMemory(hGameProcess, address, data, size, &bytesWritten); } };
场景2:调试器实现
cpp
class Debugger { HANDLE hDebugee; public: BOOL SetBreakpoint(LPVOID address, BYTE originalByte) { BYTE int3 = 0xCC; // INT 3 断点指令 // 备份原始字节 SIZE_T bytesWritten; BOOL success = WriteProcessMemory(hDebugee, address, &int3, 1, &bytesWritten); if (success) { // 保存原始字节以便恢复 breakpoints[address] = originalByte; } return success; } BOOL RestoreByte(LPVOID address) { auto it = breakpoints.find(address); if (it != breakpoints.end()) { SIZE_T bytesWritten; return WriteProcessMemory(hDebugee, address, &it->second, 1, &bytesWritten); } return FALSE; } };
场景3:进程修补
cpp
BOOL PatchProcessFunction(DWORD pid, LPVOID functionAddress, BYTE* patch, SIZE_T patchSize) { HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); if (!hProcess) return FALSE; // 修改内存保护为可写 DWORD oldProtect; if (!VirtualProtectEx(hProcess, functionAddress, patchSize, PAGE_EXECUTE_READWRITE, &oldProtect)) { CloseHandle(hProcess); return FALSE; } // 应用补丁 SIZE_T bytesWritten; BOOL success = WriteProcessMemory(hProcess, functionAddress, patch, patchSize, &bytesWritten); // 恢复原始保护 VirtualProtectEx(hProcess, functionAddress, patchSize, oldProtect, &oldProtect); CloseHandle(hProcess); return success && (bytesWritten == patchSize); }
🛡️ 安全注意事项
检测 WriteProcessMemory 的使用:
cpp
// 安全软件可以监控可疑的 WriteProcessMemory 调用 BOOL IsSuspiciousWriteOperation(HANDLE hProcess, LPVOID lpBaseAddress, SIZE_T nSize) { // 检查目标进程 if (IsSystemProcess(hProcess)) { return TRUE; // 向系统进程写入可疑 } // 检查目标地址 if (IsCodeSectionAddress(hProcess, lpBaseAddress)) { return TRUE; // 向代码段写入可疑 } // 检查写入大小 if (nSize > 0x10000) { // 大于64KB return TRUE; // 大块写入可疑 } return FALSE; }
防御代码注入:
cpp
class AntiInjection { public: static BOOL ProtectProcess() { // 使用 Process Protection 防止外部写入 return SetProcessMitigationPolicy(ProcessSignaturePolicy, &policy, sizeof(policy)); } static BOOL MonitorMemoryWrites() { // 定期检查进程内存是否被修改 return SetupMemoryIntegrityCheck(); } };
📊 性能优化技巧
批量写入优化:
cpp
BOOL WriteMultipleRegions(HANDLE hProcess, const std::vector<std::pair<LPVOID, std::vector<BYTE>>>& regions) { for (const auto& region : regions) { LPVOID address = region.first; const std::vector<BYTE>& data = region.second; SIZE_T bytesWritten; if (!WriteProcessMemory(hProcess, address, data.data(), data.size(), &bytesWritten)) { return FALSE; } } return TRUE; }
🎯 总结
核心要点:
-
跨进程操作:允许一个进程修改另一个进程的内存
-
权限要求:需要
PROCESS_VM_WRITE和PROCESS_VM_OPERATION权限 -
地址有效性:目标地址必须在目标进程的地址空间内且可写
-
错误处理:必须检查返回值和实际写入字节数
典型用途:
-
✅ 合法用途:调试器、性能分析工具、系统维护工具
-
⚠️ 灰色地带:游戏修改器、自动化工具
-
❌ 恶意用途:病毒、木马、恶意软件注入
使用模式:
cpp
// 标准写入流程: 1. OpenProcess() // 打开目标进程 2. VirtualAllocEx() // 分配目标内存(如需要) 3. VirtualProtectEx() // 确保内存可写(如需要) 4. WriteProcessMemory() // 执行写入 5. 验证结果和清理资源
记住:能力越大,责任越大! WriteProcessMemory 是一个强大的系统级函数,必须谨慎合法地使用。