我希望能够搜索进程分配的内存(例如,打开记事本并键入“ HelloWorld”,然后运行搜索以查找字符串“ HelloWorld”)。对于32位应用程序,这不是问题,但是对于64位应用程序,大量已分配的虚拟内存需要花费数小时来搜索。
显然,绝大多数应用程序没有利用分配的全部虚拟内存。我可以使用VirtualQueryEX识别分配给每个进程的内存中的区域,并使用ReadProcessMemory进行读取,但是对于64位应用程序,这仍然需要花费数小时才能完成。
有人知道任何资源或方法可以用来缩小搜索的内存量吗?
答案 0 :(得分:1)
仅扫描适当的内存很重要。如果您只是从0x0扫描到0xFFFFFFFFF,则在大多数过程中至少需要5秒钟。您可以通过使用VirtualQueryEx检查内存页面设置来跳过内存的错误区域。这将检索一个MEMORY_BASIC_INFORMATION,它将定义该内存区域的状态。
如果MemoryBasicInformation.state不是MEM_COMMIT,则它是错误的内存 如果MBI.Protect是PAGE_NOACCESS,则您还想跳过此内存。 如果VirtualQuery失败,则跳到下一个区域。
通过这种方式,由于您只扫描良好的内存,因此在平均过程中只需要0-2秒即可扫描内存。
char* ScanEx(char* pattern, char* mask, char* begin, intptr_t size, HANDLE hProc)
{
char* match{ nullptr };
SIZE_T bytesRead;
DWORD oldprotect;
char* buffer{ nullptr };
MEMORY_BASIC_INFORMATION mbi;
mbi.RegionSize = 0x1000;//
VirtualQueryEx(hProc, (LPCVOID)begin, &mbi, sizeof(mbi));
for (char* curr = begin; curr < begin + size; curr += mbi.RegionSize)
{
if (!VirtualQueryEx(hProc, curr, &mbi, sizeof(mbi))) continue;
if (mbi.State != MEM_COMMIT || mbi.Protect == PAGE_NOACCESS) continue;
delete[] buffer;
buffer = new char[mbi.RegionSize];
if (VirtualProtectEx(hProc, mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &oldprotect))
{
ReadProcessMemory(hProc, mbi.BaseAddress, buffer, mbi.RegionSize, &bytesRead);
VirtualProtectEx(hProc, mbi.BaseAddress, mbi.RegionSize, oldprotect, &oldprotect);
char* internalAddr = ScanBasic(pattern, mask, buffer, (intptr_t)bytesRead);
if (internalAddr != nullptr)
{
//calculate from internal to external
match = curr + (internalAddr - buffer);
break;
}
}
}
delete[] buffer;
return match;
}
ScanBasic只是一个标准比较功能,可以将您的模式与缓冲区进行比较。
第二,如果您知道地址是相对于模块的,则仅扫描该模块的地址范围,即可通过ToolHelp32Snapshot获取模块的大小。如果您知道它是堆上的动态内存,则仅扫描堆。您还可以使用ToolHelp32Snapshot和TH32CS_SNAPHEAPLIST获得所有堆。
您也可以为此函数创建包装器,以扫描进程的整个地址空间,看起来像这样
char* Pattern::Ex::ScanProc(char* pattern, char* mask, ProcEx& proc)
{
unsigned long long int kernelMemory = IsWow64Proc(proc.handle) ? 0x80000000 : 0x800000000000;
return Scan(pattern, mask, 0x0, (intptr_t)kernelMemory, proc.handle);
}