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.