C++ ReadProcessMemory 收到 998 / 3E6 错误

C++ ReadProcessMemory receiving 998 / 3E6 Error

所以我正在尝试使用 ReadProcessMemory() 从 运行ning exe 中读取内存,如您在下面提供的代码中所见。 我经常 运行 遇到的唯一问题是我收到似乎是 NOACCESS 的错误 3E6 / 998,但我找不到解决此问题的解决方案。 是的,我尝试 运行 管理员模式下的 exe 但没有成功...

#include <Windows.h>
#include <iostream>
#include <string>
#include <tlhelp32.h>
#include <Psapi.h>
#include <tchar.h>

using namespace std;

int id = NULL;
HANDLE hProcess = NULL;
int getPID(const string name);
bool setHandle(int id, HANDLE &out);
DWORD64 GetModule(const string name);

int main()
{
    bool success = false;
    id = getPID("sample.exe");
    string name = "SAMPLE";
    cout << "Process Name: " << name << endl;
    cout << "Process ID: " << id << endl;

    success = setHandle(id, hProcess);
    if (success)
    {
        cout << "Handle set..." << endl;
    }
    else if (!success) 
    {
        cout << "You need to have SOMETHING opened..." << endl;
        cout << "ERROR CODE: " << GetLastError() << endl;
        system("pause");
        return 1;
    }
    success = false;

    DWORD64 baseAddress = GetModule("sample.exe");
    DWORD64 ammo = 0x24ED13273A8;
    DWORD64 addr = baseAddress + ammo;

    cout << "Base Address: " << hex << uppercase << "0x" << baseAddress << endl;
    cout << "Ammo Address: " << hex << uppercase << "0x" << ammo << endl;
    cout << "Complete Address: " << hex << uppercase << "0x" << addr << endl;

    int buffer = 0;

    success = ReadProcessMemory(hProcess, (LPCVOID)addr, (LPVOID)&buffer, sizeof(&buffer), NULL);

    if (success) 
    {
        cout << "ReadProccess succeeded..." << endl;
        system("pause");
        return 0;
    }
    else if (!success) 
    {
        cout << "ERROR CODE: " << GetLastError() << endl;
        system("pause");
        return 1;
    }

    system("pause");
    return 0;

}

bool setHandle(int id, HANDLE &out)
{
    out = OpenProcess(PROCESS_ALL_ACCESS, FALSE, id);
    if (!out) return false;

    return true;
}

int getPID(const string name)
{
    PROCESSENTRY32 entry;
    entry.dwSize = sizeof(PROCESSENTRY32);
    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);

    if (!Process32First(snapshot, &entry)) return NULL;

    do
    {
        if (strcmp(entry.szExeFile, name.c_str()) == 0)
        {
            CloseHandle(snapshot);
            return entry.th32ProcessID;
        }
    } while (Process32Next(snapshot, &entry));

    CloseHandle(snapshot);
    return NULL;
}

DWORD64 GetModule(const string name)
{
    HMODULE hMods[1024];
    DWORD cbNeeded;

    if (EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded))
    {
        for (int i = 0; i < (cbNeeded / sizeof(HMODULE)); i++)
        {
            TCHAR szModName[MAX_PATH];
            if (GetModuleFileNameEx(hProcess, hMods[i], szModName, sizeof(szModName) / sizeof(TCHAR)))
            {
                string modName = szModName;
                if (modName.find(name) != string::npos)
                {
                    return (DWORD64)hMods[i];
                }
            }
        }
    }
    return NULL;
}

我对 C++ 有点陌生...很抱歉? :)

您的代码中实际上有两个基本错误,不幸的是,对于您、我和文明世界的其他人来说,这两个错误都会生成相同的错误代码。是否曾经如此。还有一个逻辑错误,但你很幸运能够逃脱它(差不多)。我在下面发布的代码中评论了修复。

您的代码中还有许多 'good practise' 缺点,具体而言:

  • NULL 不应用于表示 整数
  • 应检查所有 错误情况并(明智地!)报告
  • 您在两个不同的地方使用相同的字符串文字(因此如果您更改它,您将需要在两个地方都更改它,而且您可能会忘记)。所以不要那样做。
  • using namespace std; 被广泛反对(因为它造成了如此多的命名空间污染)
  • 为什么 idhProcess 是全局变量?这完全没有必要。
  • 你应该给你的函数起一个更具描述性的名字,setHandle 是我特别想要的那个。我完全摆脱了那个。
  • std::string作为只读函数参数传递时,通常最好将其作为const ref传递,这样就不需要复制了。
  • 仅当您真正想要刷新缓冲区时才使用 std::endl。效率低下。
  • 之后清理(在这种情况下,关闭所有打开的句柄)。我知道这只是一个一次性程序,但养成一个好习惯。

好的,下面是一些有效的代码(我发布了自己的代码,因为我清理了以上所有内容)。实质性变化是:

  • 要读取另一个进程的内存,您需要为您的用户令牌授予 SE_DEBUG_NAME 权限。这反过来意味着您需要 运行 您的程序作为管理员(又名提升)。
  • 你不能(显然)从目标进程中的无意义地址读取所以我只是悄悄地修复了它。

就像我说的,这两个生成相同的错误代码。嗯!

好的,给你。享受:

#include <Windows.h>
#include <iostream>
#include <string>
#include <tlhelp32.h>
#include <Psapi.h>
#include <tchar.h>

int getPID(const std::string& name);
DWORD64 GetModule(HANDLE hProcess, const std::string& name);

// Stolen from: https://docs.microsoft.com/en-gb/windows/desktop/SecAuthZ/enabling-and-disabling-privileges-in-c--
BOOL SetPrivilege(
    HANDLE hToken,          // access token handle
    LPCTSTR lpszPrivilege,  // name of privilege to enable/disable
    BOOL bEnablePrivilege   // to enable or disable privilege
    ) 
{
    TOKEN_PRIVILEGES tp;
    LUID luid;

    if ( !LookupPrivilegeValue( 
            NULL,            // lookup privilege on local system
            lpszPrivilege,   // privilege to lookup 
            &luid ) )        // receives LUID of privilege
    {
        printf("LookupPrivilegeValue error: %u\n", GetLastError() ); 
        return FALSE; 
    }

    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = luid;
    if (bEnablePrivilege)
        tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    else
        tp.Privileges[0].Attributes = 0;

    // Enable the privilege or disable all privileges.

    if ( !AdjustTokenPrivileges(
           hToken, 
           FALSE, 
           &tp, 
           sizeof(TOKEN_PRIVILEGES), 
           (PTOKEN_PRIVILEGES) NULL, 
           (PDWORD) NULL) )
    { 
          printf("AdjustTokenPrivileges error: %u\n", GetLastError() ); 
          return FALSE; 
    } 

    if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)

    {
          printf("The token does not have the specified privilege. \n");
          return FALSE;
    } 

    return TRUE;
}


constexpr const char* theProcess = "notepad.exe";

int main()
{
    HANDLE hToken;
    BOOL ok = OpenProcessToken (GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken);
    if (!ok)
    {
         std::cout << "OpenProcessToken failed, error " << GetLastError() << "\n";
         return 255;
    }

    ok = SetPrivilege (hToken, SE_DEBUG_NAME, TRUE);
    if (!ok)
    {
        CloseHandle (hToken);
        return 1;
    }

    int pid = getPID (theProcess);

    HANDLE hProcess = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid);
    if (hProcess == NULL)
    {
         std::cout << "OpenProcess failed, error " << GetLastError() << "\n";
         CloseHandle (hToken);
         return 1;
    }

    DWORD64 baseAddress = GetModule(hProcess, theProcess);
    std::cout << "Base Address: " << std::hex << std::uppercase << "0x" << baseAddress << "\n";
    int buffer = 0;  // Note: sizeof (buffer) below, not sizeof (&buffer)
    ok = ReadProcessMemory(hProcess, (LPCVOID)baseAddress, (LPVOID)&buffer, sizeof(buffer), NULL);

    CloseHandle (hProcess);
    CloseHandle (hToken);

    if (ok) 
    {
        std::cout << "ReadProcessMemory succeeded, buffer = " << buffer << "\n";
        system("pause");
        return 0;
    }

    std::cout << "ReadProcessMemory failed, error " << GetLastError() << "\n";
    system("pause");
    return 1;
}

int getPID(const std::string& name)
{
    PROCESSENTRY32 entry;
    entry.dwSize = sizeof(PROCESSENTRY32);
    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);

    if (!Process32First(snapshot, &entry)) return NULL;

    do
    {
        if (strcmp(entry.szExeFile, name.c_str()) == 0)
        {
            CloseHandle(snapshot);
            return entry.th32ProcessID;
        }
    } while (Process32Next(snapshot, &entry));

    CloseHandle(snapshot);
    return NULL;
}

DWORD64 GetModule(HANDLE hProcess, const std::string& name)
{
    HMODULE hMods[1024];
    DWORD cbNeeded;

    if (EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded))
    {
        for (int i = 0; i < (cbNeeded / sizeof(HMODULE)); i++)
        {
            TCHAR szModName[MAX_PATH];
            if (GetModuleFileNameEx(hProcess, hMods[i], szModName, sizeof(szModName) / sizeof(TCHAR)))
            {
                std::string modName = szModName;
                if (modName.find(name) != std::string::npos)
                {
                    return (DWORD64)hMods[i];
                }
            }
        }
    }
    return NULL;
}

输出(当 运行 作为管理员时):

Base Address: 0x7FF6D8470000
ReadProcessMemory succeeded, buffer = 905A4D

输出(当运行作为普通用户时):

The token does not have the specified privilege.

您还可以在 GitHub 获取一些代码。