如何识别进程正在使用的已分配虚拟内存的哪些部分

问题描述 投票:0回答:1

我希望能够搜索进程分配的内存(例如,打开记事本并键入“ HelloWorld”,然后运行搜索以查找字符串“ HelloWorld”)。对于32位应用程序,这不是问题,但是对于64位应用程序,大量已分配的虚拟内存需要花费数小时来搜索。

显然,大多数应用程序没有利用分配的全部虚拟内存。我可以使用VirtualQueryEX识别分配给每个进程的内存中的区域,并使用ReadProcessMemory进行读取,但是对于64位应用程序,这仍然需要花费数小时才能完成。

没有人知道任何资源或方法可用于帮助缩小要搜索的内存量吗?

windows 64-bit virtual-memory readprocessmemory
1个回答
0
投票

仅扫描适当的内存很重要。如果您只是从0x0扫描到0xFFFFFFFFF,则在大多数过程中至少需要5秒钟。您可以通过使用VirtualQueryEx检查内存页面设置来跳过内存的错误区域。这将检索一个MEMORY_BASIC_INFORMATION,它将定义该内存区域的状态。

如果MemoryBasicInformation.state不是MEM_COMMIT,则它是错误的内存如果MBI.Protect是PAGE_NOACCESS,则您还想跳过此内存。如果VirtualQuery失败,则跳到下一个区域。

以这种方式,由于您只扫描良好的内存,因此在平均过程中只需要花费0-2秒即可扫描内存。

char* ScanEx(char* pattern, char* mask, char* begin, intptr_t size, HANDLE hProc)
{
    char* match{ nullptr };
    SIZE_T bytesRead;
    DWORD oldprotect;
    char* buffer{ nullptr };
    MEMORY_BASIC_INFORMATION mbi;
    mbi.RegionSize = 0x1000;//

    VirtualQueryEx(hProc, (LPCVOID)begin, &mbi, sizeof(mbi));

    for (char* curr = begin; curr < begin + size; curr += mbi.RegionSize)
    {
        if (!VirtualQueryEx(hProc, curr, &mbi, sizeof(mbi))) continue;
        if (mbi.State != MEM_COMMIT || mbi.Protect == PAGE_NOACCESS) continue;

        delete[] buffer;
        buffer = new char[mbi.RegionSize];

        if (VirtualProtectEx(hProc, mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &oldprotect))
        {
            ReadProcessMemory(hProc, mbi.BaseAddress, buffer, mbi.RegionSize, &bytesRead);
            VirtualProtectEx(hProc, mbi.BaseAddress, mbi.RegionSize, oldprotect, &oldprotect);

            char* internalAddr = ScanBasic(pattern, mask, buffer, (intptr_t)bytesRead);

            if (internalAddr != nullptr)
            {
                //calculate from internal to external
                match = curr + (internalAddr - buffer);
                break;
            }
        }
    }
    delete[] buffer;
    return match;
}

ScanBasic只是一个标准比较功能,它将您的模式与缓冲区进行比较。

其次,如果您知道该地址是相对于模块的,则仅扫描该模块的地址范围,即可通过ToolHelp32Snapshot获取模块的大小。如果您知道它是堆上的动态内存,则仅扫描堆。您还可以使用ToolHelp32Snapshot和TH32CS_SNAPHEAPLIST获得所有堆。

您也可以为此函数创建包装器,以扫描进程的整个地址空间,看起来像这样

char* Pattern::Ex::ScanProc(char* pattern, char* mask, ProcEx& proc)
{
    unsigned long long int kernelMemory = IsWow64Proc(proc.handle) ? 0x80000000 : 0x800000000000;

    return Scan(pattern, mask, 0x0, (intptr_t)kernelMemory, proc.handle);
}
© www.soinside.com 2019 - 2024. All rights reserved.