写/读受内存保护的进程的内存

Posted

技术标签:

【中文标题】写/读受内存保护的进程的内存【英文标题】:Write/Read a memory-protected process's memory 【发布时间】:2014-09-29 21:06:28 【问题描述】:

我会尽力解释我的问题。 我正在尝试访问受内存保护的进程内存 (Minesweeper)。 我会先放我的代码,然后我会解释我想要归档的东西是什么。 (如果您阅读了所有内容并知道另一种方法,请发布)。 首先是 getProcessHandle,该函数返回一个名为 procName 的进程的打开句柄。 它运行良好,我可以列出所有进程。

HANDLE getProcessHandle(const wchar_t *procName)
HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 procEnt;
procEnt.dwSize = sizeof(PROCESSENTRY32);
Process32First(snap, &procEnt);
printf("--Listando procesos...\n");
do
    printf("Process name: %S \n", procEnt.szExeFile);
    if (!wcscmp(procName, procEnt.szExeFile))
        printf("Encontrado %S.\n\n", procName);
        return OpenProcess(PROCESS_ALL_ACCESS, FALSE, procEnt.th32ProcessID);
    
 while (Process32Next(snap, &procEnt));
printf("No se ha encontrado el proceso.");
CloseHandle(snap);
return NULL;

第二,getModule 函数。它的工作应该是查找并枚举作为 HANDLE 传递的进程中的所有模块。

HMODULE getHModule(HANDLE procHandle, const wchar_t *procName)
HMODULE moduleHandle[1024];
DWORD bytesNeeded;
unsigned int i = 0;
if (EnumProcessModulesEx(procHandle, moduleHandle, sizeof(moduleHandle), &bytesNeeded, LIST_MODULES_ALL))
    printf("--Modulos del proceso:\n");
    for (i = 0; i < (bytesNeeded / sizeof(HMODULE)); i++)
        TCHAR pathModule[1024];
        GetModuleBaseName(procHandle, moduleHandle[i], pathModule, sizeof(pathModule) / sizeof(TCHAR));
        if (!wcscmp(procName, pathModule))
            printf("Encontrado modulo %S.", procName);
            return moduleHandle[i];
        
        printf("Module %d: %S \n", i + 1, pathModule);
    
    printf("No se ha encontrado el modulo.");
    return NULL;

else 
    printf("Error en EnumProcessModulesEx n: %ls", GetLastError());

return NULL;

问题来了。当我尝试枚举进程中的所有模块时,如果该进程是正常进程,我的意思是,一个不受内存保护的进程,它可以完美运行。 问题在于进程何时受内存保护。 在这一点上,我决定搜索,我发现了特权令牌。据说如果我激活了 SE_DEBUG_NAME 令牌,我的进程可能会超过保护,所以,我做了那个功能:

int privileges()
HANDLE token;
TOKEN_PRIVILEGES tp;
DWORD siz = sizeof(TOKEN_PRIVILEGES);

if (OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &token) != 0)
    LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);
    tp.PrivilegeCount = 1;
    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    if (AdjustTokenPrivileges(token, 0, &tp, siz, NULL ,NULL) != 0)
        cout << "--Conseguido acceso debug.\n";
        return TRUE;
    
    else 
        cout << "fail adjust\n";
        return FALSE;
    

else 
    cout << "fail if: " << GetLastError() << endl;
    cin.get();
    return FALSE;

以及“主要”功能:

int _tmain(int argc, _TCHAR* argv[])

privileges();
wchar_t *processName = _T("calc.exe");
HANDLE hProc = getProcessHandle(processName);
  if (hProc)
      HMODULE hMod = getHModule(hProc, processName);
      cout << hMod;
  
cin.get();
return 0;

我现在遇到的问题是,当我执行这个函数时,privileges(),它返回了 ERROR_NO_TOKEN 代码。 这里有人说我将OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &amp;token) 更改为OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &amp;token),这不会导致问题,也不会导致结果,通过该修复,我遇到的问题与未执行privileges() 相同。 感谢您阅读所有文字,如果有其他方法可以做到这一点,请告诉我,我正在努力学习。

【问题讨论】:

尝试 OpenThreadToken 并回退到 OpenProcessToken 是正确的。一旦你以这种方式更新了代码,你说特权()仍然失败,但你没有说如何。我假设此时它没有收到 ERROR_NO_TOKEN。它在做什么? “受内存保护的进程”是什么意思?当您尝试访问这样的进程时,究竟是什么不起作用? 也许问题在于您的代码在 64 位操作系统上的 32 位进程中运行?根据文档,32位进程无法枚举64位进程的模块。 我在 Cheat Engine 中打开了该进程,它说它的内存已完全受保护,我不知道这是什么意思,但我知道当我尝试访问 HMODULE 时,它会抛出一个例外,就像我没有使用特权()一样; 也许...我有一个 64 位操作。系统。但它适用于其他进程。 【参考方案1】:

documentation for EnumProcessModulesEx 说:

此函数主要用于 64 位应用程序。如果该函数由在 WOW64 下运行的 32 位应用程序调用,则 dwFilterFlag 选项将被忽略,并且该函数提供与 EnumProcessModules 函数相同的结果。

转到documentation for EnumProcessModules,我们发现:

如果这个函数是从运行在 WOW64 上的 32 位应用程序调用的,它只能枚举 32 位进程的模块。

所以要在 64 位进程上工作,您的代码本身必须是 64 位的。

文档继续:

如果进程是 64 位进程,则此函数失败,最后一个错误代码为 ERROR_PARTIAL_COPY (299)。

这似乎是不正确的,因为您收到的是访问冲突异常。

【讨论】:

是的,这很奇怪,但现在它可以完美运行,即使没有权限功能。谢谢老哥 @Norwelian:是的,正如预期的那样。您只需要调试权限即可访问其他用户的进程,而不是您自己的。 (更准确地说,如果目标进程的权限没有为您提供所需的访问权限,则您需要调试权限。)

以上是关于写/读受内存保护的进程的内存的主要内容,如果未能解决你的问题,请参考以下文章

用信号量保护共享内存段不起作用

强制读写进程的内存

Linux中关于swap虚拟内存和page的区别

由 urlmon.dll 引起的“试图读取或写入受保护的内存”

示尝试读取或写入受保护的内存 这通常指示其它内存已损坏

操作系统之内存管理