#pragma once class MemoryAddress { public: enum class Direction : int { UP = 0, DOWN, }; std::uintptr_t GetPtr() { return ptr; } MemoryAddress() = default; MemoryAddress(std::uintptr_t ptr) : ptr(ptr) {} MemoryAddress(void* ptr) : ptr(std::uintptr_t(ptr)) {} operator std::uintptr_t() const { return ptr; } operator void*() { return reinterpret_cast(ptr); } operator bool() { return ptr != NULL; } bool operator!= (const MemoryAddress& addr) const { return ptr != addr.ptr; } bool operator== (const MemoryAddress& addr) const { return ptr == addr.ptr; } bool operator== (const std::uintptr_t& addr) const { return ptr == addr; } template T CCast() { return (T)ptr; } template T RCast() { return reinterpret_cast(ptr); } MemoryAddress Offset(std::ptrdiff_t offset) { return MemoryAddress(ptr + offset); } MemoryAddress OffsetSelf(std::ptrdiff_t offset) { ptr += offset; return *this; } MemoryAddress Deref(int deref = 1) { std::uintptr_t reference = ptr; while (deref--) { if (reference) reference = *reinterpret_cast(reference); } return MemoryAddress(reference); } MemoryAddress DerefSelf(int deref = 1) { while (deref--) { if (ptr) ptr = *reinterpret_cast(ptr); } return *this; } bool CheckOpCode(char opcode) { return *reinterpret_cast(ptr) == opcode; } template T GetVirtualFunctionIndex() { return *reinterpret_cast(ptr) / 4; } void Patch(std::vector opcodes) { DWORD oldProt = NULL; SIZE_T dwSize = opcodes.size(); VirtualProtect((void*)ptr, dwSize, PAGE_EXECUTE_READWRITE, &oldProt); for (int i = 0; i < opcodes.size(); i++) { *(byte*)(ptr + i) = opcodes[i]; } dwSize = opcodes.size(); VirtualProtect((void*)ptr, dwSize, oldProt, &oldProt); } MemoryAddress FindPattern(const char* pattern, Direction searchDirect, int opCodesToScan = 100) { static auto PatternToBytes = [](const char* pattern) { char* PatternStart = const_cast(pattern); // Cast const away and get start of pattern. char* PatternEnd = PatternStart + std::strlen(pattern); // Get end of pattern. std::vector Bytes = std::vector{ }; // Initialize byte vector. for (char* CurrentByte = PatternStart; CurrentByte < PatternEnd; ++CurrentByte) { if (*CurrentByte == '?') // Is current char(byte) a wildcard? { ++CurrentByte; // Skip 1 character. if (*CurrentByte == '?') // Is it a double wildcard pattern? ++CurrentByte; // If so skip the next space that will come up so we can reach the next byte. Bytes.push_back(-1); // Push the byte back as invalid. } else { // https://stackoverflow.com/a/43860875/12541255 // Here we convert our string to a unsigned long integer. We pass our string then we use 16 as the base because we want it as hexadecimal. // Afterwards we push the byte into our bytes vector. Bytes.push_back(std::strtoul(CurrentByte, &CurrentByte, 16)); } } return Bytes; }; std::uint8_t* ScanBytes = reinterpret_cast(ptr); // Get the base of the module. const std::vector PatternBytes = PatternToBytes(pattern); // Convert our pattern to a byte array. const std::pair BytesInfo = std::make_pair(PatternBytes.size(), PatternBytes.data()); // Get the size and data of our bytes. for (auto i = 01; i < opCodesToScan + BytesInfo.first; ++i) { bool FoundAddress = true; int memOffset = searchDirect == Direction::UP ? -i : i; for (DWORD j = 0ul; j < BytesInfo.first; ++j) { // If either the current byte equals to the byte in our pattern or our current byte in the pattern is a wildcard // our if clause will be false. if (ScanBytes[memOffset + j] != BytesInfo.second[j] && BytesInfo.second[j] != -1) { FoundAddress = false; break; } } if (FoundAddress) { return MemoryAddress(&ScanBytes[memOffset]); } } return MemoryAddress(); } private: std::uintptr_t ptr = 0; }; class Module { public: Module() = default; Module(std::string moduleName) : moduleName(moduleName) { const MODULEINFO mInfo = GetModuleInfo(moduleName.c_str()); // Get module info. sizeOfModule = (DWORD64)mInfo.SizeOfImage; // Grab the module size. moduleBase = (std::uintptr_t)mInfo.lpBaseOfDll; // Grab module base. } MemoryAddress PatternSearch(const char* signature) { static auto PatternToBytes = [](const char* pattern) { char* PatternStart = const_cast(pattern); // Cast const away and get start of pattern. char* PatternEnd = PatternStart + std::strlen(pattern); // Get end of pattern. std::vector Bytes = std::vector{ }; // Initialize byte vector. for (char* CurrentByte = PatternStart; CurrentByte < PatternEnd; ++CurrentByte) { if (*CurrentByte == '?') // Is current char(byte) a wildcard? { ++CurrentByte; // Skip 1 character. if (*CurrentByte == '?') // Is it a double wildcard pattern? ++CurrentByte; // If so skip the next space that will come up so we can reach the next byte. Bytes.push_back(-1); // Push the byte back as invalid. } else { // https://stackoverflow.com/a/43860875/12541255 // Here we convert our string to a unsigned long integer. We pass our string then we use 16 as the base because we want it as hexadecimal. // Afterwards we push the byte into our bytes vector. Bytes.push_back(std::strtoul(CurrentByte, &CurrentByte, 16)); } } return Bytes; }; std::uint8_t* ScanBytes = reinterpret_cast(moduleBase); // Get the base of the module. const std::vector PatternBytes = PatternToBytes(signature); // Convert our pattern to a byte array. const std::pair BytesInfo = std::make_pair(PatternBytes.size(), PatternBytes.data()); // Get the size and data of our bytes. for (DWORD i = 0ul; i < sizeOfModule - BytesInfo.first; ++i) { bool FoundAddress = true; for (DWORD j = 0ul; j < BytesInfo.first; ++j) { // If either the current byte equals to the byte in our pattern or our current byte in the pattern is a wildcard // our if clause will be false. if (ScanBytes[i + j] != BytesInfo.second[j] && BytesInfo.second[j] != -1) { FoundAddress = false; break; } } if (FoundAddress) { return MemoryAddress(&ScanBytes[i]); } } return MemoryAddress(); } std::uintptr_t GetModuleBase() { return moduleBase; } private: std::string moduleName = std::string(); std::uintptr_t moduleBase = 0; DWORD64 sizeOfModule = 0; };