VirtualQueryEx 无法读取内存,因此无法取消引用指针 (LPCVOID/uint8_t*) [英] VirtualQueryEx unable to read memory, so can't dereference pointer (LPCVOID/uint8_t*)

查看:28
本文介绍了VirtualQueryEx 无法读取内存,因此无法取消引用指针 (LPCVOID/uint8_t*)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个函数来读取应用程序的内存

I have a function to read the memory of an application

template<class T>
std::unordered_map<uint8_t, T> find_byte(T find) {
    std::cout << "Searching for value\n";

    std::unordered_map<uint8_t, T> mapping;

    // Turn the T bytes to a vector to use nice C++ functions
    std::vector<uint8_t> byte_check;
    if constexpr (std::is_same_v<T, std::string>) {
        byte_check = std::vector<uint8_t>(find.begin(), find.end());
    }
    else {
        uint8_t* data = static_cast<uint8_t*>(static_cast<void*>(&find));
        byte_check    = std::vector<uint8_t>(data, data + sizeof(find));
    }

    MEMORY_BASIC_INFORMATION info;
    for (uint8_t* addr = nullptr; VirtualQueryEx(m_proc, addr, &info, sizeof(info)) == sizeof(info); addr += info.RegionSize) {
        if (info.State == MEM_COMMIT && (info.Type == MEM_MAPPED || info.Type == MEM_PRIVATE)) {
            size_t read{};
            std::vector<uint8_t> mem_chunk;
            mem_chunk.resize(info.RegionSize);
            if (ReadProcessMemory(m_proc, addr, mem_chunk.data(), mem_chunk.size(), &read)) {
                mem_chunk.resize(read);
                for (auto pos = mem_chunk.begin();
                     mem_chunk.end() != (pos = std::search(pos, mem_chunk.end(), byte_check.begin(), byte_check.end()));
                     pos++) {
                    uint8_t* int_addr_ptr  = (addr + (pos - mem_chunk.begin()));
                    mapping[*int_addr_ptr] = find;
                }
            }
        }
    }
    return mapping;
}

它编译得很好,但是,它在尝试取消引用 int_addr_ptr 指针时崩溃.在调试器逐步调试后,我注意到从 VirtualQueryEx 返回的 addr 无法读取.

It compiles just fine, however, it crashes it tries to dereference the int_addr_ptr pointer. After stepping through with a debugger, I noticed that the addr returned from VirtualQueryEx was unable to be read.

我认为问题在于我如何取消引用,但我不知道如何解决.我累了:

I assume the issue lies in how I dereference, but I don't know how to fix it. I have tired:

auto lpcvoid       = (addr + (pos - mem_chunk.begin()));
auto int_addr_ptr = reinterpret_cast<const uint8_t*>(lpcvoid);

来自这里,但没有产生任何结果.

from here, but it yielded no results.

我想注意,如果我返回一个 的映射,它工作正常,但想避免指针

I want to note that if I return a map of <uint8_t, T> it works fine, but wanted to avoid the pointers

推荐答案

当你查询一个内存区域时,你应该从它的 BaseAddress 开始扫描它的内容,而不是从 address 您实际查询的.VirtualQueryEx() 可能需要四舍五入地址.info.RegionSize 是相对于 info.BaseAddress 的,所以在调用 ReadProcessMemory() 时,mem_chunk.size()如果 addr > 将有太多字节无法读取info.BaseAddress,您需要从读取的大小中减去该偏移量.

When you query a memory region, you should start scanning through its content from its BaseAddress, not from the address that you actually queried. VirtualQueryEx() may have to round down the address. info.RegionSize is relative to info.BaseAddress, so when calling ReadProcessMemory(), mem_chunk.size() will be too many bytes to read if addr > info.BaseAddress, you would need to subtract that offset from the size being read.

std::search() 循环中,pos 应该增加正在搜索的 find 的大小,而不是按 1 个字节.而 addr 又应该是 info.BaseAddress.

In the std::search() loop, pos should be incremented by the size of find that is being searched for, not by 1 byte. And addr should again be info.BaseAddress.

但更重要的是,为什么 int_addr_ptr 被取消引用?它的值表示另一个进程中的内存地址,而不是你自己的进程.因此,您不能简单地取消引用它来读取值,这样做会尝试从您的进程 中读取该值.如果要读取存储在该地址的值,则必须改用 ReadProcessMemory().但是,mapping 究竟应该关闭什么?为什么要取消引用 int_addr_ptr 来读取 mapping 键的字节?难道您不应该键入找到每个 find 副本的实际地址吗?在 mapping 中存储 find 的副本有什么意义?

But more importantly, why is int_addr_ptr being dereferenced at all? Its value represents a memory address in another process, not in your own process. So, you can't simply dereference it to read a value, doing so will try to read the value from your process. If you want to read the value stored at that address, you will have to use ReadProcessMemory() instead. But, what is mapping supposed to be keying off of exactly? Why are you dereferencing int_addr_ptr to read a byte for a mapping key? Shouldn't you be keying the actual addresses where each copy of find is found? And what is the point of storing copies of find in the mapping?

一个更简单的 vector 会更有意义,因为调用者已经知道它正在搜索的 find 值,所以不需要重复它输出.

A simpler vector<void*> would make more sense, since the caller already knows the find value it is searching for, so no need to repeat it in the output.

作为额外的优化,我建议完全摆脱 byte_check 向量,因为它是不必要的内存分配.您使用它只是为了让迭代器与 std::search() 一起使用.原始指针也是有效的迭代器.

As an added optimization, I would suggest getting rid of the byte_check vector altogether, as it is an unnecessary memory allocation. You are using it only to have iterators for use with std::search(). Raw pointers are also valid iterators.

话虽如此,请尝试更像这样的事情:

With that said, try something more like this:

template<class T>
std::vector<void*> find_value(const T &find) {
    std::cout << "Searching for value\n";

    std::vector<void*> found;
    std::vector<uint8_t> mem_chunk;

    const uint8_t *find_begin, *find_end;
    size_t find_size;

    if constexpr (std::is_same_v<T, std::string>) {
        find_begin = reinterpret_cast<const uint8_t*>(find.c_str());
        find_size = find.size();
    }
    else {
        find_begin = reinterpret_cast<const uint8_t*>(&find);
        find_size = sizeof(find);
    }

    find_end = find_begin + find_size;

    uint8_t *addr = reinterpret_cast<uint8_t*>(0), *base;
    MEMORY_BASIC_INFORMATION info;

    while (VirtualQueryEx(m_proc, addr, &info, sizeof(info))) {
        base = static_cast<uint8_t*>(info.BaseAddress);

        if (info.State == MEM_COMMIT && (info.Type == MEM_MAPPED || info.Type == MEM_PRIVATE)) {
            mem_chunk.reserve(info.RegionSize);

            size_t read;
            if (ReadProcessMemory(m_proc, info.BaseAddress, mem_chunk.data(), info.RegionSize, &read)) {
                auto start = mem_chunk.data(),
                     end = start + read,
                     pos = start;

                if (addr > base) {
                    pos += (addr - base);
                }

                while ((pos = std::search(pos, end, find_begin, find_end)) != end) {
                    found.push_back(base + (pos - start));
                    pos += find_size;
                }
            }
        }

        addr = base + info.RegionSize;
    }

    return found;
}

这篇关于VirtualQueryEx 无法读取内存,因此无法取消引用指针 (LPCVOID/uint8_t*)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆