【问题标题】:Read process memory of a process does not return everything读取进程的进程内存不会返回所有内容
【发布时间】:2012-05-09 12:20:55
【问题描述】:

我正在尝试扫描第 3 方应用程序的内存。我已经找到地址了;现在是0x0643FB78。问题是,因为LPMODULEENTRY32->modBaseAddr0x00400000LPMODULEENTRY32->modBaseSize 只是0x006FF000,所以我永远都爬不上去,因此我可以扫描此模块的最大地址是0x00AFF000

这是否意味着我寻找的地址确实存在于另一个进程/模块/线程/某个东西中?我非常有信心我所拥有的过程确实包含地址。那我应该如何访问内存呢?谢谢。

【问题讨论】:

  • MODULEENTRY 为您提供 code 的地址。你肯定对数据更感兴趣吗?这可以出现在任何地方,具体取决于 Windows 分配堆的位置。或者数据部分,希望如此,因为如果该地址实际上在堆中,您将几乎没有希望获得可重复的地址。使用 VirtualQueryEx() 枚举地址空间中的分配。

标签: c++ windows winapi memory readprocessmemory


【解决方案1】:

一个进程由映射了某些保护的内存页组成。这些页面被封装在模块中。每个模块都有一个底座和一个尺寸。但是,ReadProcessMemory 完全从您那里抽象出来。无论它位于哪个模块中,您都应该能够读取内存。

在这种情况下,内存不在您正在查看的模块中。如果确实需要找到它所属的位置,可以使用 CreateToolHelp32Snapshot、Module32First 和 Module32Next 遍历模块检查基数和大小。

发布一些代码,我们可以帮助您找出哪里出错了。为什么你这么确定你要找的地址就是你说的地址?由于 ASLR,地址通常使用基本模块 + 偏移量来指定。您如何获得目标进程句柄?您需要拥有一定的访问权限才能使用 ReadProcessMemory。

【讨论】:

  • 谢谢,这是我缺乏的洞察力。我接受了 Jerry 的回答,因为他有代码示例。
【解决方案2】:

至少在我看来,如果您有 LPMODULEENTRY 参与其中,那么您可能从错误的方向开始。我会用VirtualQueryEx 遍历目标进程中的内存块。这将为您提供有关该过程中每个块的MEMORY_BASIC_INFORMATION。然后,您可以使用 ReadProcessMemory 并扫描块以找到您要查找的内容。

这是我编写的一些旧代码,目的大致相同,但查找的是字符串而不是指针:

#include <iostream>
#include <vector>
#include <string>
#include <windows.h>
#include <algorithm>
#include <iterator>

template <class InIter1, class InIter2, class OutIter>
void find_all(unsigned char *base, InIter1 buf_start, InIter1 buf_end, InIter2 pat_start, InIter2 pat_end, OutIter res) {
    for (InIter1 pos = buf_start;
        buf_end!=(pos=std::search(pos, buf_end, pat_start, pat_end));
        ++pos)
    {
        *res++ = base+(pos-buf_start);
    }
}

template <class outIter>
void find_locs(HANDLE process, std::string const &pattern, outIter output) {

    unsigned char *p = NULL;
    MEMORY_BASIC_INFORMATION info;

    for ( p = NULL;
        VirtualQueryEx(process, p, &info, sizeof(info)) == sizeof(info);
        p += info.RegionSize ) 
    {
        std::vector<char> buffer;

        if (info.State == MEM_COMMIT && 
            (info.Type == MEM_MAPPED || info.Type == MEM_PRIVATE)) 
        {
            SIZE_T bytes_read;
            buffer.resize(info.RegionSize);
            ReadProcessMemory(process, p, &buffer[0], info.RegionSize, &bytes_read);
            buffer.resize(bytes_read);
            find_all(p, buffer.begin(), buffer.end(), pattern.begin(), pattern.end(), output);
        }
    }
}

int main(int argc, char **argv) {
    if (argc != 3) {
        fprintf(stderr, "Usage: %s <process ID> <pattern>", argv[0]);
        return 1;
    }

    int pid;
    sscanf(argv[1], "%i", &pid);

    std::string pattern(argv[2]);

    HANDLE process = OpenProcess( 
        PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, 
        false,
        pid);

    find_locs(process, pattern, 
        std::ostream_iterator<void *>(std::cout, "\n"));

    return 0;
}

【讨论】:

  • 太好了,这肯定会让我走上正确的道路。谢谢。
  • @Jerry Coffin - +1 以获得最佳答案。我想进一步问两件事:1)一旦我将页面内容读入char向量std::vector&lt;char&gt; buffer - 我应该如何“处理”它?我的意思是,它是否包含 ASCII 字符或 UTF-8/UTF-16 编码字符?如果内存中包含 ASCII 字符,我如何将它们转换为 Unicode(我想应该是 UTF-16)? 2) std::vector&lt;char&gt;::iterator pos 到底是做什么用的?非常感谢您的帮助!
  • @GuyAvraham:数据是从目标进程逐字复制的,因此它是目标进程使用的任何格式。 pos 是一些早期版本代码的遗留物——它根本没有被使用。
猜你喜欢
  • 1970-01-01
  • 2023-03-12
  • 1970-01-01
  • 2015-12-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多