0

I have been working on a couple of way to read memeoy of another process in Windows. Now I been wanting to speed things up, as for the program I am trying to read takes me about 1.5 minutes to find all instances of a certain stream of memory. In this I thought that threading the search from different part of memory would work. In short python/pseudo code:

start = max_memory/max_threads;

for i in max_threads:
    search_memory(from=start*i, to=start*(i+1));

Now I normally been using the HANDLE, VirtualQueryEx and ReadProcessMemory combination. Can be found here, in a former question I asked.

I also attempted to go though a process different modules, as MODULEINFO has a SizeOfImage. However, this implementation does not find every occurrence of the memory stream I am looking for.

template<class T>
std::vector<const uint8_t*> scan_memory(const T& find) {
    HMODULE base[1024];
    DWORD cbNeeded;

    std::vector<const uint8_t*> found;
    if (EnumProcessModules(m_proc, base, sizeof(base), &cbNeeded)) {
        for (int i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) {
            MODULEINFO minfo{};
            GetModuleInformation(m_proc, base[i], &minfo, sizeof(minfo));
            auto ret = scan_memory(base[i], minfo.SizeOfImage, find);
            found.insert(found.end(), ret.begin(), ret.end());
            }
        }
    }
    return found;
}
// Scan Memory
template<class T>
std::vector<const uint8_t*> scan_memory(void* address_low, std::size_t nbytes, const T& find) {
    std::vector<const uint8_t*> addresses_found;

    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 {
        const uint8_t* data = static_cast<const uint8_t*>(static_cast<const void*>(&find));
        byte_check          = std::vector<uint8_t>(data, data + sizeof(find));
    }

    // all readable pages: adjust this as required
    const DWORD pmask = PAGE_READONLY | PAGE_READWRITE;

    MEMORY_BASIC_INFORMATION info{};

    uint8_t* address      = static_cast<uint8_t*>(address_low);
    uint8_t* address_high = address + nbytes;

    std::vector<uint8_t> mem_chunk;

    size_t read;
    while (address < address_high && VirtualQueryEx(m_proc, address, std::addressof(info), sizeof(info))) {
        mem_chunk.reserve(info.RegionSize);
        if (ReadProcessMemory(m_proc, info.BaseAddress, mem_chunk.data(), info.RegionSize, &read)) {
            auto start = mem_chunk.data(), end = start + read, pos = start;

            if (address > info.BaseAddress) {
                pos += (address - info.BaseAddress);
            }

            while ((pos = std::search(pos, end, byte_check.begin(), byte_check.end())) != end) {
                addresses_found.push_back(static_cast<const uint8_t*>(info.BaseAddress) + (pos - start));
                pos += byte_check.size();
            }
        }
        address += read;
    }

    return addresses_found;
}

Implementation based of this

So the question is primarily, how do I get the highest/max address space of a Process with using winapi?

I would also love some suggestions on how to thread the search. I have successfully threaded the ReadProcessMemory However the speed gain was only about 30 seconds, implementation found here.

Tomas Berger
  • 173
  • 1
  • 3
  • 15
  • 1
    "*I would also love some suggestions on how to thread the search*" - I probably wouldn't thread it at all. I would move the search code into a DLL that is injected into the target process so that the search is performed inside the process itself, and then use IPC to send the search results back to the main app when finished. – Remy Lebeau Apr 26 '21 at 18:21
  • @RemyLebeau Thanks again Remy for being an absolute chad for my WinAPI questions. I was considering that as other questions I stalked suggested this, but I have never tried to do a DLL injection before. Got any suggestions of where to start? – Tomas Berger Apr 26 '21 at 18:28
  • 1
    There are plenty of questions on SO (and other forums) related to DLL injection. There are many different ways to inject a DLL into a process - `CreateRemoteThread()`, `QueueUserAPC()`, `SetWindowsHookEx()`, just to name a few. – Remy Lebeau Apr 26 '21 at 18:50

0 Answers0