#include <vector>
#include <Windows.h>
#include <iostream>
#include <sstream>
#include <string>
//字符串转换成整数表
std::vector<int> BuildSkipTable(const std::vector<int>& pattern) {
const int wildcard = -1;
//最大支持字符数
const int tableSize = 256;
std::vector<int> table(tableSize, pattern.size());
for (int i = 0; i < pattern.size() - 1; i++) {
if (pattern[i] != wildcard) {
table[pattern[i]] = pattern.size() - 1 - i;
}
}
return table;
}
//解析字符串特征码
std::vector<int> ParsePattern(const std::string& pattern) {
std::vector<int> parsedPattern;
std::stringstream ss(pattern);
std::string byte;
while (std::getline(ss, byte, ' ')) {
//过滤通配符 目前支持 "?" "??" "*"
if (byte == "?" || byte == "*" || byte == "??") {
parsedPattern.push_back(-1);
}
else {
parsedPattern.push_back(std::stoi(byte, 0, 16));
}
}
return parsedPattern;
}
std::vector<SIZE_T> BMH_AOBScanWithWildcard(HANDLE process, const std::vector<int>& pattern) {
std::vector<SIZE_T> results;
MEMORY_BASIC_INFORMATION mbi = { 0 };
SIZE_T size = 0;
std::vector<int> skipTable = BuildSkipTable(pattern);
while (VirtualQueryEx(process, (LPCVOID)size, &mbi, sizeof(mbi))) {
//内存页属性要求要有可执行属性,否则会被被过滤掉 可以根据需求调整
if (mbi.State == MEM_COMMIT && (mbi.Protect >= PAGE_EXECUTE && mbi.Protect <= PAGE_EXECUTE_WRITECOPY)) {
BYTE* buffer = new BYTE[mbi.RegionSize];
SIZE_T bytesRead;
if (ReadProcessMemory(process, mbi.BaseAddress, buffer, mbi.RegionSize, &bytesRead)) {
BYTE* begin = buffer;
BYTE* end = buffer + bytesRead;
int m = pattern.size();
for (BYTE* i = begin; i <= end - m;) {
int j = m - 1;
while (j >= 0 && (pattern[j] == -1 || pattern[j] == i[j])) {
--j;
}
if (j < 0) {
results.push_back((SIZE_T)((BYTE*)mbi.BaseAddress + (i - begin)));
i += m;
}
else {
i += skipTable[i[m - 1]];
}
}
}
delete[] buffer;
}
size += mbi.RegionSize;
}
return results;
}
#include <tchar.h>
#include <tlhelp32.h>
#pragma comment(lib, "kernel32.lib")
//通过进程名字获取PID
DWORD GetProcessIdByName(const TCHAR* processName){
DWORD processId = 0;
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot != INVALID_HANDLE_VALUE) {
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hSnapshot, &pe32)) {
do {
if (_tcscmp(pe32.szExeFile, processName) == 0) {
processId = pe32.th32ProcessID;
break;
}
} while (Process32Next(hSnapshot, &pe32));
}
CloseHandle(hSnapshot);
}
return processId;
}
示例代码:
int main() {
// 目标进程的名字,获取PID
SIZE_T processId = GetProcessIdByName(L"WS-Win64-Shipping.exe");
//特征码
std::string pattern = "48 83 C1 10 E8 9D EC 42 FF 48 8D 57 20 48 8D 4B 20 E8 90 EC 42 FF 48 8D 57 30";
HANDLE process = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, processId);
if (process != NULL) {
std::vector<int> parsedPattern = ParsePattern(pattern);
std::vector<SIZE_T> results = BMH_AOBScanWithWildcard(process, parsedPattern);
for (SIZE_T address : results) {
std::cout << "Found pattern at: " << std::hex << address << std::endl;
}
CloseHandle(process);
}
else {
std::cerr << "Failed to open process: " << GetLastError() << std::endl;
}
return 0;
}
代码使用注意事项:
1.目前代码只会查询带可执行属性的内存页,可以根据自己的需求进行修改。
2.目前代码只支持 “?” "??" "*",类型的通配符,可以根据自己需求添加。(通配符需要使用英文字符)
3.特征码每个字节需要用 空格分隔。
4.最大支持256个字符,可以根据实际需求更改。