Code:
#include <iostream>
#include <vector>
#include <windows.h>
#include <string>
#include <sstream>
#include <iomanip>
#include <TlHelp32.h> // For process and module enumeration
struct SignaturePattern {
std::string Name;
std::string IdaPattern;
// Converts the IDA-style pattern into a byte pattern and mask
std::pair<std::vector<BYTE>, std::string> ConvertIdaPattern() const {
std::vector<BYTE> pattern;
std::string mask;
std::istringstream stream(IdaPattern);
std::string part;
while (stream >> part) {
if (part == "?") {
pattern.push_back(0); // Wildcard byte
mask += "?";
}
else {
pattern.push_back(static_cast<BYTE>(std::stoi(part, nullptr, 16))); // Convert hex string to byte
mask += "x";
}
}
return { pattern, mask };
}
};
struct SignatureConfig {
std::string WindowTitle; // Title of the window (not process name)
std::vector<SignaturePattern> Patterns;
};
// Function to read memory of a process
BOOL ReadProcessMemorySafe(HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T* lpNumberOfBytesRead) {
return ReadProcessMemory(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead);
}
// Function to scan memory for the given pattern
std::pair<LPVOID, int> FindPattern(const std::vector<BYTE>& buffer, const std::vector<BYTE>& pattern, const std::string& mask, LPVOID baseAddress) {
for (size_t i = 0; i < buffer.size() - pattern.size(); ++i) {
bool found = true;
for (size_t j = 0; j < pattern.size(); ++j) {
if (mask[j] != '?' && pattern[j] != buffer[i + j]) {
found = false;
break;
}
}
if (found) {
// Here we need to get an integer value from the byte buffer
int offset = *reinterpret_cast<const int*>(&buffer[i + 3]); // Using const_cast for safely casting away constness
return { reinterpret_cast<LPVOID>(reinterpret_cast<ULONG_PTR>(baseAddress) + i), offset };
}
}
return { nullptr, 0 };
}
// Function to scan process memory for a pattern
std::pair<LPVOID, int> ScanProcessMemory(HANDLE hProcess, LPVOID baseAddress, DWORD moduleSize, const std::vector<BYTE>& pattern, const std::string& mask) {
std::vector<BYTE> buffer(moduleSize);
SIZE_T bytesRead = 0;
// Read memory into buffer
if (!ReadProcessMemorySafe(hProcess, baseAddress, buffer.data(), moduleSize, &bytesRead)) {
std::cerr << "Failed to read process memory" << std::endl;
return { nullptr, 0 };
}
return FindPattern(buffer, pattern, mask, baseAddress);
}
int main() {
// Configuration for memory signatures
SignatureConfig config = {
"World of Warcraft", // Window title (not process name)
{
{ "ObjectManager", "4C 8B 3D ? ? ? ? 45 33 F6" },
{ "PlayerGUID", "48 8D 0D ? ? ? ? E8 ? ? ? ? 48 83 BC 24 ? ? ? ? ? 7C ? 48 8B 4C 24" },
{ "PlayerTargetGUID", "0F 10 05 ? ? ? ? C7 05" },
{ "MouseOverGUID", "0F 11 05 ? ? ? ? 0F 10 07" },
{ "ZoneText", "4C 8B 0D ? ? ? ? 8B C0" },
{ "Camera", "48 8B 0D ? ? ? ? B3" },
{ "FrameBase", "4C 8B 35 ? ? ? ? BF" }
}
};
// Find the window by title
HWND hwnd = FindWindowA(NULL, config.WindowTitle.c_str());
if (hwnd == NULL) {
std::cout << "Window with title '" << config.WindowTitle << "' not found." << std::endl;
return 1;
}
DWORD pid;
GetWindowThreadProcessId(hwnd, &pid);
HANDLE hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, pid);
if (hProcess == NULL) {
std::cerr << "Failed to open process." << std::endl;
return 1;
}
// Module snapshot and loading
MODULEENTRY32 modEntry = { 0 };
modEntry.dwSize = sizeof(MODULEENTRY32);
// Create snapshot of modules and find the first module (usually the main module)
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid);
if (hSnapshot == INVALID_HANDLE_VALUE) {
std::cerr << "Failed to create snapshot of modules." << std::endl;
CloseHandle(hProcess);
return 1;
}
if (Module32First(hSnapshot, &modEntry) == FALSE) {
std::cerr << "Failed to get module information." << std::endl;
CloseHandle(hSnapshot);
CloseHandle(hProcess);
return 1;
}
// Scan for each pattern in the configuration
for (const auto& sigPattern : config.Patterns) {
auto patternData = sigPattern.ConvertIdaPattern();
std::vector<BYTE> pattern = patternData.first;
std::string mask = patternData.second;
auto result = ScanProcessMemory(hProcess, modEntry.modBaseAddr, modEntry.modBaseSize, pattern, mask);
if (result.first != nullptr) {
// Calculate and output the final address
ULONG_PTR finalAddress = reinterpret_cast<ULONG_PTR>(result.first) + result.second + 7 - reinterpret_cast<ULONG_PTR>(modEntry.modBaseAddr);
std::cout << sigPattern.Name << ": 0x" << std::uppercase << std::hex << finalAddress << std::endl;
}
else {
std::cout << sigPattern.Name << ": Not found" << std::endl;
}
}
// Clean up
CloseHandle(hSnapshot);
CloseHandle(hProcess);
return 0;
}