WriteProcessMemory

核心功能概述

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;
}

🎯 总结

核心要点:

  1. 跨进程操作:允许一个进程修改另一个进程的内存

  2. 权限要求:需要 PROCESS_VM_WRITE 和 PROCESS_VM_OPERATION 权限

  3. 地址有效性:目标地址必须在目标进程的地址空间内且可写

  4. 错误处理:必须检查返回值和实际写入字节数

典型用途:

  • ✅ 合法用途:调试器、性能分析工具、系统维护工具

  • ⚠️ 灰色地带:游戏修改器、自动化工具

  • ❌ 恶意用途:病毒、木马、恶意软件注入

使用模式:

cpp
// 标准写入流程:
1. OpenProcess()           // 打开目标进程
2. VirtualAllocEx()        // 分配目标内存(如需要)
3. VirtualProtectEx()      // 确保内存可写(如需要)  
4. WriteProcessMemory()    // 执行写入
5. 验证结果和清理资源

记住:能力越大,责任越大! WriteProcessMemory 是一个强大的系统级函数,必须谨慎合法地使用。

 

此条目发表在安全分析分类目录。将固定链接加入收藏夹。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注