C ++ - ReadProcessMemory 到缓冲区,WriteProcessMemory(在同一缓冲区上具有新值)将缓冲区恢复为旧值

Posted

技术标签:

【中文标题】C ++ - ReadProcessMemory 到缓冲区,WriteProcessMemory(在同一缓冲区上具有新值)将缓冲区恢复为旧值【英文标题】:C++ - ReadProcessMemory to buffer, WriteProcessMemory (with new value on same buffer) reverts buffer to old value 【发布时间】:2018-04-05 17:17:15 【问题描述】:

我不知道为什么会这样,我很好奇。 我已经成功地写入/读取,而不是使用 WriteProcessMemory 上的缓冲区,但我想知道为什么会发生这种情况。

这就是它的工作原理。你扔测试

target.cpp(将变量地址输出到读/写的进程)

#include <iostream>
#include <string>

using namespace std;

int main()
int test = 5;
string pero = "hola";
cout << sizeof(test);
cout<<"Address of test is :" <<&test <<endl; //Address to put on Principal.cpp
cin.get(); //Wait that other process writes then I manually continue.
cout << "Value of test is: " << test<<endl; //Outputs 5, should output 20.
cin.get();
return 0;

Principal.cpp(读取和写入地址)。从 main 开始。

#include <windows.h>
#include <tlhelp32.h>
#include <iostream> // For STL i/o
#include <ctime>    // For std::chrono
#include <thread>   // For std::this_thread
using namespace std;
DWORD FindProcessId(const char *name)

    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnapshot == INVALID_HANDLE_VALUE)
        return 0;
    PROCESSENTRY32 ProcEntry;
    ProcEntry.dwSize = sizeof(PROCESSENTRY32);
    if (Process32First(hSnapshot, &ProcEntry))
    
        
            if (stricmp(ProcEntry.szExeFile, name) == 0)
                return ProcEntry.th32ProcessID;
            while (Process32Next(hSnapshot, &ProcEntry))
                if (stricmp(ProcEntry.szExeFile, name) == 0)
                
                    return ProcEntry.th32ProcessID;
                
        
    

 // IMPORTANT PART STARTS HERE.
int main()

    int buffer;
    DWORD Address = 0x28ff28; //Address of int test.
    DWORD ProcessId = FindProcessId("test.exe");

    if (ProcessId == 0)
        cout << "Doesn't exist.";
    else
        cout << "Process Id is : " << ProcessId << endl;
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, ProcessId);
    if (hProcess == INVALID_HANDLE_VALUE)
    
        cout << "Error in HANDLE";
    
    if (ReadProcessMemory(hProcess, (LPCVOID)Address, (LPVOID)&buffer, sizeof(buffer), 0) == 0)
    
        DWORD error = GetLastError();
        cout << "Error is " << error << endl;
    

    cout << "Buffer is: " << buffer << endl; //Outputs 5

    buffer = 20; // Want to write 20 and then read variable on test.exe.
    if (WriteProcessMemory(hProcess, (LPVOID)Address, (LPCVOID)&buffer, sizeof(buffer), 0) == 0)
    
        DWORD error = GetLastError();
        cout << "Error is " << error << endl;
    
    cout << "Buffer is: " << buffer << endl; //Outputs 5, should output 20.
    CloseHandle(hProcess);
    return 0;

这里发生了什么。

ReadMemory 到缓冲区 缓冲区 = 5 使缓冲区 = 20 将缓冲区写入内存。 缓冲区 = 5;

如果有人能向我解释这一点,我将不胜感激!

【问题讨论】:

如果没有找到目标进程,FindProcessId的返回值是不确定的。如果搜索循环退出但未找到匹配项,则需要 return 0 语句。它还泄漏了CreateToolhelp32Snapshot 返回的句柄。而main 的错误处理也不是很好。 "buffer = 5; " - 您是否声称在调用WriteProcessMemorybuffer 内部的principal.cpp 已恢复为5?或者target.cpp 内部的test 永远不会更新到20? 您的编译器发出了警告。不要忽视它。 你好@RemyLebeau,principal.cpp 中的缓冲区恢复到 5。 @HeTheMan 鉴于您显示的代码,这根本不可能 【参考方案1】:

一些事情。

 DWORD Address = 0x28ff28;

你是怎么得到这个的,你是从上面的程序告诉你的地址输入的吗?

如果是从上面的地址获取地址,需要找到程序的入口点,并在那个数字上加上0x28ff28

编辑:如果你使用内存查看器,你可以看到程序吐出的地址并没有指向那个 int,我说的偏移量也没有。您需要找出它相对于程序启动路径的存储位置。我的假设是错误的,您可以使用上面程序吐出的数字。

window 的设计方式是出于安全原因,它会在不同的地址随机启动程序,而您看到的地址是程序启动位置的偏移量。

您应该能够从 nModule.modBaseAddr 中找到基地址,但如果您在 64- 中运行程序,则可能需要将其转换为 uint64_t位。

我希望这会有所帮助。

编辑: 你也可以这样做而不是遍历快照

hWnd_ = FindWindow(nullptr, processName.c_str());
GetWindowThreadProcessId(hWnd_, &pid_);

还要确保您以管理员身份运行。

【讨论】:

&amp;test 将始终返回test绝对地址。您不需要添加任何偏移量。 ASLR 没有效果。此外,FindWindow 不采用进程名称。它需要一个窗口名称和窗口类名称。

以上是关于C ++ - ReadProcessMemory 到缓冲区,WriteProcessMemory(在同一缓冲区上具有新值)将缓冲区恢复为旧值的主要内容,如果未能解决你的问题,请参考以下文章

A log about Reading the memroy of Other Process in C++/WIN API--ReadProcessMemory()

ReadProcessMemory 整个过程

如何使用 ReadProcessMemory 获取托盘按钮文本

确定外部进程的主线程 ID(ReadProcessMemory - 错误 299)

使用 ReadProcessMemory 获取字符串值的访问冲突

ReadProcessMemory WriteProcessMemory iOS