void CheatEngine::addAddressesWithValue(const value_t& value, value_size_t size) { assert(size > 0); MEMORY_BASIC_INFORMATION info; for (address_t address = nullptr; VirtualQueryEx(m_process, address, &info, sizeof(info)) == sizeof(info); address = static_cast<unsigned char*>(info.BaseAddress) + info.RegionSize) { if (can_modify_page(info)) { chunk_t chunk(info.RegionSize); DWORD bytesRead; ReadProcessMemory(m_process, address, chunk.data(), info.RegionSize, &bytesRead); chunk.resize(bytesRead); offsets_t matches; for (chunk_t::size_type i = 0; i <= chunk.size() - size; ++i) { if (std::equal(chunk.cbegin() + i, chunk.cbegin() + i + size, value.cbegin())) { matches.push_back(i); } } if (!matches.empty()) { MemoryBlock block; block.matches = matches; block.baseAddress = info.BaseAddress; block.size = bytesRead; m_blocks.push_back(block); } } } }
void CheatEngine::keepAddressesWithValue(const value_t& value, value_size_t size) { assert(!m_blocks.empty()); for (auto blockIt = begin(m_blocks); blockIt != end(m_blocks);) { MEMORY_BASIC_INFORMATION info; const auto len = VirtualQueryEx(m_process, blockIt->baseAddress, &info, sizeof(info)); assert(len == sizeof(info)); if (can_modify_page(info)) { chunk_t chunk(blockIt->size); DWORD bytesRead; ReadProcessMemory(m_process, blockIt->baseAddress, chunk.data(), blockIt->size, &bytesRead); chunk.resize(bytesRead); blockIt->size = bytesRead; // from the offsets that matched before within that page, only keep the ones that still match offsets_t stillMatches; for (auto offsetIt = blockIt->matches.cbegin(); offsetIt != blockIt->matches.cend(); ++offsetIt) { assert(*offsetIt + size <= chunk.size()); if (std::equal(chunk.cbegin() + *offsetIt, chunk.cbegin() + *offsetIt + size, value.cbegin())) { stillMatches.push_back(*offsetIt); } } blockIt->matches = stillMatches; // memory page no longer has matching addresses: drop it if (blockIt->matches.empty()) { blockIt = m_blocks.erase(blockIt); } else { ++blockIt; } } else { ++blockIt; } } }