diff --git a/source/cpp/memory/ci_compat.h b/source/cpp/memory/ci_compat.h new file mode 100644 index 0000000..b9f73ad --- /dev/null +++ b/source/cpp/memory/ci_compat.h @@ -0,0 +1,42 @@ +#pragma once + +// CI compatibility header +// This file provides compatibility definitions for continuous integration builds +// where certain platform-specific features may not be available + +// Define CI_BUILD when building in CI environment +// #define CI_BUILD + +// Disable certain features in CI builds +#ifdef CI_BUILD + #define DISABLE_MEMORY_SCANNING + #define DISABLE_HOOKS + #define DISABLE_JIT +#endif + +// Platform detection +#if defined(__APPLE__) + #include + #if TARGET_OS_IPHONE + #define PLATFORM_IOS + #elif TARGET_OS_MAC + #define PLATFORM_MACOS + #endif +#elif defined(_WIN32) || defined(_WIN64) + #define PLATFORM_WINDOWS +#elif defined(__ANDROID__) + #define PLATFORM_ANDROID +#elif defined(__linux__) + #define PLATFORM_LINUX +#endif + +// Memory protection utilities for CI compatibility +#ifdef CI_BUILD + #define MEMORY_PROTECT(addr, size, prot) (void)0 + #define MEMORY_UNPROTECT(addr, size) (void)0 +#else + // Real implementations will be provided elsewhere + // These are just forward declarations + void* MEMORY_PROTECT(void* addr, size_t size, int prot); + bool MEMORY_UNPROTECT(void* addr, size_t size); +#endif diff --git a/source/cpp/memory/mem.cpp b/source/cpp/memory/mem.cpp new file mode 100644 index 0000000..bcf81f5 --- /dev/null +++ b/source/cpp/memory/mem.cpp @@ -0,0 +1,476 @@ +#include "mem.hpp" +#include +#include + +#ifdef __APPLE__ +#include +#include +#include +#include +#endif + +namespace Memory { + // Initialize memory subsystem + bool Initialize() { + std::cout << "Memory subsystem initializing..." << std::endl; + + // Initialize memory cache + MemoryCache::GetInstance(); + + return true; + } + + // Shutdown memory subsystem + void Shutdown() { + std::cout << "Memory subsystem shutting down..." << std::endl; + + // Clear any active patches or hooks + // This would be implemented in a real system + } + + // Memory utilities implementation + std::string MemoryUtils::ReadString(uintptr_t address, size_t maxLength) { + if (address == 0) { + return ""; + } + + std::string result; + char buffer[256]; + size_t bytesRead = 0; + + while (bytesRead < maxLength) { + size_t chunkSize = std::min(sizeof(buffer), maxLength - bytesRead); + if (!ReadMemory(address + bytesRead, buffer, chunkSize)) { + break; + } + + for (size_t i = 0; i < chunkSize; i++) { + if (buffer[i] == '\0') { + return result; + } + result.push_back(buffer[i]); + } + + bytesRead += chunkSize; + } + + return result; + } + + bool MemoryUtils::WriteString(uintptr_t address, const std::string& str) { + if (address == 0) { + return false; + } + + return WriteMemory(address, str.c_str(), str.length() + 1); // +1 for null terminator + } + + bool MemoryUtils::Protect(uintptr_t address, size_t size, Protection protection) { + if (address == 0 || size == 0) { + return false; + } + +#ifdef __APPLE__ + vm_prot_t prot = VM_PROT_NONE; + + if ((static_cast(protection) & static_cast(Protection::Read)) != 0) { + prot |= VM_PROT_READ; + } + if ((static_cast(protection) & static_cast(Protection::Write)) != 0) { + prot |= VM_PROT_WRITE; + } + if ((static_cast(protection) & static_cast(Protection::Execute)) != 0) { + prot |= VM_PROT_EXECUTE; + } + + vm_address_t addr = static_cast(address); + return vm_protect(mach_task_self(), addr, size, FALSE, prot) == KERN_SUCCESS; +#else + // Placeholder for other platforms + return false; +#endif + } + + std::vector MemoryUtils::GetMemoryRegions() { + std::vector regions; + +#ifdef __APPLE__ + mach_port_t task = mach_task_self(); + vm_address_t address = 0; + vm_size_t size = 0; + uint32_t depth = 1; + + while (true) { + vm_region_submap_info_data_64_t info; + mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64; + + if (vm_region_recurse_64(task, &address, &size, &depth, + (vm_region_info_t)&info, &count) != KERN_SUCCESS) { + break; + } + + Protection prot = Protection::None; + if (info.protection & VM_PROT_READ) prot = static_cast(static_cast(prot) | static_cast(Protection::Read)); + if (info.protection & VM_PROT_WRITE) prot = static_cast(static_cast(prot) | static_cast(Protection::Write)); + if (info.protection & VM_PROT_EXECUTE) prot = static_cast(static_cast(prot) | static_cast(Protection::Execute)); + + regions.emplace_back(address, size, prot); + + address += size; + } +#endif + + return regions; + } + + MemoryRegion MemoryUtils::FindMemoryRegion(uintptr_t address) { + auto regions = GetMemoryRegions(); + + for (const auto& region : regions) { + if (address >= region.baseAddress && address < region.baseAddress + region.size) { + return region; + } + } + + return MemoryRegion(); + } + + bool MemoryUtils::ReadMemory(uintptr_t address, void* buffer, size_t size) { + if (address == 0 || buffer == nullptr || size == 0) { + return false; + } + +#ifdef __APPLE__ + vm_size_t bytesRead = 0; + kern_return_t result = vm_read_overwrite(mach_task_self(), + static_cast(address), + size, + reinterpret_cast(buffer), + &bytesRead); + + return result == KERN_SUCCESS && bytesRead == size; +#else + // Fallback for other platforms or when vm_read is not available + try { + std::memcpy(buffer, reinterpret_cast(address), size); + return true; + } catch (...) { + return false; + } +#endif + } + + bool MemoryUtils::WriteMemory(uintptr_t address, const void* buffer, size_t size) { + if (address == 0 || buffer == nullptr || size == 0) { + return false; + } + +#ifdef __APPLE__ + // First, ensure the memory is writable + MemoryRegion region = FindMemoryRegion(address); + bool wasProtected = false; + Protection originalProtection = region.protection; + + if ((static_cast(region.protection) & static_cast(Protection::Write)) == 0) { + wasProtected = true; + Protect(region.baseAddress, region.size, Protection::ReadWriteExecute); + } + + // Write the memory + kern_return_t result = vm_write(mach_task_self(), + static_cast(address), + reinterpret_cast(buffer), + static_cast(size)); + + // Restore original protection if needed + if (wasProtected) { + Protect(region.baseAddress, region.size, originalProtection); + } + + return result == KERN_SUCCESS; +#else + // Fallback for other platforms + try { + std::memcpy(reinterpret_cast(address), buffer, size); + return true; + } catch (...) { + return false; + } +#endif + } + + // Memory cache implementation + MemoryCache& MemoryCache::GetInstance() { + static MemoryCache instance; + return instance; + } + + MemoryCache::MemoryCache() { + // Initialize cache + } + + MemoryCache::~MemoryCache() { + // Clean up cache + Invalidate(); + } + + bool MemoryCache::CacheRegion(uintptr_t address, size_t size) { + if (address == 0 || size == 0) { + return false; + } + + std::vector data(size); + if (!MemoryUtils::ReadMemory(address, data.data(), size)) { + return false; + } + + std::lock_guard lock(m_cacheMutex); + m_cachedRegions[address] = std::move(data); + + return true; + } + + bool MemoryCache::ReadFromCache(uintptr_t address, void* buffer, size_t size) { + std::lock_guard lock(m_cacheMutex); + + // Find a cached region that contains the requested address + for (const auto& pair : m_cachedRegions) { + uintptr_t regionStart = pair.first; + const auto& regionData = pair.second; + + if (address >= regionStart && address + size <= regionStart + regionData.size()) { + size_t offset = address - regionStart; + std::memcpy(buffer, regionData.data() + offset, size); + return true; + } + } + + // Not found in cache, read directly from memory + return MemoryUtils::ReadMemory(address, buffer, size); + } + + void MemoryCache::Invalidate() { + std::lock_guard lock(m_cacheMutex); + m_cachedRegions.clear(); + } + + // Memory patch implementation + MemoryPatch::MemoryPatch(uintptr_t address, const std::vector& bytes) + : m_address(address), m_patchBytes(bytes), m_applied(false) { + // Read original bytes + m_originalBytes.resize(bytes.size()); + MemoryUtils::ReadMemory(address, m_originalBytes.data(), m_originalBytes.size()); + + // Get original protection + MemoryRegion region = MemoryUtils::FindMemoryRegion(address); + m_originalProtection = region.protection; + } + + MemoryPatch::~MemoryPatch() { + // Restore original bytes if still applied + if (m_applied) { + Restore(); + } + } + + bool MemoryPatch::Apply() { + if (m_applied) { + return true; // Already applied + } + + // Make memory writable + MemoryUtils::Protect(m_address, m_patchBytes.size(), Protection::ReadWriteExecute); + + // Apply patch + bool result = MemoryUtils::WriteMemory(m_address, m_patchBytes.data(), m_patchBytes.size()); + + // Restore original protection + MemoryUtils::Protect(m_address, m_patchBytes.size(), m_originalProtection); + + if (result) { + m_applied = true; + } + + return result; + } + + bool MemoryPatch::Restore() { + if (!m_applied) { + return true; // Not applied + } + + // Make memory writable + MemoryUtils::Protect(m_address, m_originalBytes.size(), Protection::ReadWriteExecute); + + // Restore original bytes + bool result = MemoryUtils::WriteMemory(m_address, m_originalBytes.data(), m_originalBytes.size()); + + // Restore original protection + MemoryUtils::Protect(m_address, m_originalBytes.size(), m_originalProtection); + + if (result) { + m_applied = false; + } + + return result; + } + + bool MemoryPatch::IsApplied() const { + return m_applied; + } + + // PatternScanner implementation + uintptr_t PatternScanner::GetBaseAddress() { +#ifdef __APPLE__ + return 0; // On iOS, this would be the base address of the main executable +#else + return 0; +#endif + } + + uintptr_t PatternScanner::GetModuleBaseAddress(const std::string& moduleName) { +#ifdef __APPLE__ + // This would be implemented to find a specific module/framework + return 0; +#else + return 0; +#endif + } + + size_t PatternScanner::GetModuleSize(const std::string& moduleName) { + // This would be implemented to get the size of a module + return 0; + } + + ScanResult PatternScanner::ScanForPattern(const char* pattern, const char* mask, void* startAddress, void* endAddress) { + // Basic pattern scanning implementation + if (!pattern || !mask || !startAddress || !endAddress || startAddress >= endAddress) { + return ScanResult(); + } + + size_t patternLength = strlen(mask); + if (patternLength == 0) { + return ScanResult(); + } + + uintptr_t start = reinterpret_cast(startAddress); + uintptr_t end = reinterpret_cast(endAddress); + + // Read memory in chunks for efficiency + const size_t chunkSize = 4096; + std::vector buffer(chunkSize); + + for (uintptr_t addr = start; addr < end; addr += chunkSize) { + size_t bytesToRead = std::min(chunkSize, end - addr); + + if (!MemoryUtils::ReadMemory(addr, buffer.data(), bytesToRead)) { + continue; + } + + // Search for pattern in this chunk + for (size_t i = 0; i <= bytesToRead - patternLength; i++) { + bool found = true; + + for (size_t j = 0; j < patternLength; j++) { + if (mask[j] == 'x' && buffer[i + j] != static_cast(pattern[j])) { + found = false; + break; + } + } + + if (found) { + return ScanResult(addr + i, patternLength); + } + } + } + + return ScanResult(); + } + + ScanResult PatternScanner::ScanForSignature(const std::string& signature, void* startAddress, void* endAddress) { + auto [pattern, mask] = Signature::Parse(signature); + + if (pattern.empty() || mask.empty()) { + return ScanResult(); + } + + if (!startAddress) { + startAddress = reinterpret_cast(GetBaseAddress()); + } + + if (!endAddress) { + // Use a reasonable default end address + endAddress = reinterpret_cast(GetBaseAddress() + 0x10000000); // 256 MB + } + + return ScanForPattern(reinterpret_cast(pattern.data()), mask.c_str(), startAddress, endAddress); + } + + ScanResult PatternScanner::ScanForString(const std::string& str, void* startAddress, void* endAddress) { + if (str.empty()) { + return ScanResult(); + } + + if (!startAddress) { + startAddress = reinterpret_cast(GetBaseAddress()); + } + + if (!endAddress) { + // Use a reasonable default end address + endAddress = reinterpret_cast(GetBaseAddress() + 0x10000000); // 256 MB + } + + return ScanForPattern(str.c_str(), std::string(str.length(), 'x').c_str(), startAddress, endAddress); + } + + std::vector PatternScanner::FindAllPatterns(const char* pattern, const char* mask, void* startAddress, void* endAddress) { + std::vector results; + + if (!pattern || !mask || !startAddress || !endAddress || startAddress >= endAddress) { + return results; + } + + size_t patternLength = strlen(mask); + if (patternLength == 0) { + return results; + } + + uintptr_t start = reinterpret_cast(startAddress); + uintptr_t end = reinterpret_cast(endAddress); + + // Read memory in chunks for efficiency + const size_t chunkSize = 4096; + std::vector buffer(chunkSize); + + for (uintptr_t addr = start; addr < end; addr += chunkSize) { + size_t bytesToRead = std::min(chunkSize, end - addr); + + if (!MemoryUtils::ReadMemory(addr, buffer.data(), bytesToRead)) { + continue; + } + + // Search for pattern in this chunk + for (size_t i = 0; i <= bytesToRead - patternLength; i++) { + bool found = true; + + for (size_t j = 0; j < patternLength; j++) { + if (mask[j] == 'x' && buffer[i + j] != static_cast(pattern[j])) { + found = false; + break; + } + } + + if (found) { + results.emplace_back(addr + i, patternLength); + } + } + } + + return results; + } + + uintptr_t PatternScanner::GetAddressByPattern(const char* pattern) { + ScanResult result = ScanForSignature(pattern); + return result.address; + } +} diff --git a/source/cpp/memory/mem.hpp b/source/cpp/memory/mem.hpp new file mode 100644 index 0000000..4a8f4d4 --- /dev/null +++ b/source/cpp/memory/mem.hpp @@ -0,0 +1,175 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include "ci_compat.h" +#include "signature.hpp" + +namespace Memory { + // Memory protection flags + enum class Protection { + None = 0, + Read = 1, + Write = 2, + Execute = 4, + ReadWrite = Read | Write, + ReadExecute = Read | Execute, + ReadWriteExecute = Read | Write | Execute + }; + + // Memory region information + struct MemoryRegion { + uintptr_t baseAddress; + size_t size; + Protection protection; + std::string name; + + MemoryRegion() : baseAddress(0), size(0), protection(Protection::None) {} + MemoryRegion(uintptr_t base, size_t s, Protection prot, const std::string& n = "") + : baseAddress(base), size(s), protection(prot), name(n) {} + }; + + // Memory scanning model + class MemoryScanModel { + public: + // Scan for a specific pattern in memory + static ScanResult ScanForPattern(const std::string& pattern, const MemoryRegion& region); + + // Scan for a specific string in memory + static ScanResult ScanForString(const std::string& str, const MemoryRegion& region); + + // Scan for multiple patterns and return all matches + static std::vector ScanForMultiplePatterns(const std::vector& patterns, const MemoryRegion& region); + + // Predict memory locations based on previous scans + static std::map PredictMemoryLocations(const std::string& version); + }; + + // Memory utilities + class MemoryUtils { + public: + // Read memory + template + static T Read(uintptr_t address) { + T value = T(); + ReadMemory(address, &value, sizeof(T)); + return value; + } + + // Write memory + template + static bool Write(uintptr_t address, const T& value) { + return WriteMemory(address, &value, sizeof(T)); + } + + // Read string from memory + static std::string ReadString(uintptr_t address, size_t maxLength = 256); + + // Write string to memory + static bool WriteString(uintptr_t address, const std::string& str); + + // Change memory protection + static bool Protect(uintptr_t address, size_t size, Protection protection); + + // Get memory regions + static std::vector GetMemoryRegions(); + + // Find memory region containing address + static MemoryRegion FindMemoryRegion(uintptr_t address); + + private: + // Low-level memory operations + static bool ReadMemory(uintptr_t address, void* buffer, size_t size); + static bool WriteMemory(uintptr_t address, const void* buffer, size_t size); + }; + + // Memory patching utilities + class MemoryPatch { + public: + MemoryPatch(uintptr_t address, const std::vector& bytes); + ~MemoryPatch(); + + // Apply the patch + bool Apply(); + + // Restore original bytes + bool Restore(); + + // Check if patch is applied + bool IsApplied() const; + + private: + uintptr_t m_address; + std::vector m_originalBytes; + std::vector m_patchBytes; + bool m_applied; + Protection m_originalProtection; + }; + + // Memory hook utilities + class MemoryHook { + public: + using HookCallback = std::function; + + MemoryHook(uintptr_t address, const HookCallback& callback); + ~MemoryHook(); + + // Install the hook + bool Install(); + + // Remove the hook + bool Remove(); + + // Check if hook is installed + bool IsInstalled() const; + + private: + uintptr_t m_address; + HookCallback m_callback; + bool m_installed; + std::vector m_originalBytes; + }; + + // Memory cache for optimizing repeated memory operations + class MemoryCache { + public: + // Get instance (singleton) + static MemoryCache& GetInstance(); + + // Cache a memory region + bool CacheRegion(uintptr_t address, size_t size); + + // Read from cache + template + T Read(uintptr_t address) { + T value = T(); + ReadFromCache(address, &value, sizeof(T)); + return value; + } + + // Invalidate cache + void Invalidate(); + + private: + MemoryCache(); + ~MemoryCache(); + + // Read from cache implementation + bool ReadFromCache(uintptr_t address, void* buffer, size_t size); + + // Cache data + std::map> m_cachedRegions; + std::mutex m_cacheMutex; + }; + + // Initialize memory subsystem + bool Initialize(); + + // Shutdown memory subsystem + void Shutdown(); +} diff --git a/source/cpp/memory/signature.hpp b/source/cpp/memory/signature.hpp new file mode 100644 index 0000000..acbda47 --- /dev/null +++ b/source/cpp/memory/signature.hpp @@ -0,0 +1,111 @@ +#pragma once + +#include +#include +#include +#include "ci_compat.h" + +namespace Memory { + // Signature scanning utilities + class Signature { + public: + // Parse a signature string into byte pattern and mask + // Format: "48 8B 05 ?? ?? ?? ??" where ?? represents wildcard bytes + static std::pair, std::string> Parse(const std::string& signatureString) { + std::vector pattern; + std::string mask; + + for (size_t i = 0; i < signatureString.length(); i++) { + // Skip spaces + if (signatureString[i] == ' ') { + continue; + } + + // Handle wildcards + if (signatureString[i] == '?') { + pattern.push_back(0); + mask.push_back('?'); + + // Skip second ? if present (for "??") + if (i + 1 < signatureString.length() && signatureString[i + 1] == '?') { + i++; + } + } else { + // Parse hex byte + if (i + 1 >= signatureString.length()) { + // Incomplete hex byte + break; + } + + char hex[3] = { signatureString[i], signatureString[i + 1], 0 }; + pattern.push_back(static_cast(strtol(hex, nullptr, 16))); + mask.push_back('x'); + + // Skip second character of the hex byte + i++; + } + } + + return { pattern, mask }; + } + + // Convert a byte array to a signature string + static std::string ToString(const std::vector& bytes) { + std::string result; + + for (size_t i = 0; i < bytes.size(); i++) { + char hex[3]; + snprintf(hex, sizeof(hex), "%02X", bytes[i]); + result += hex; + + if (i < bytes.size() - 1) { + result += " "; + } + } + + return result; + } + }; + + // Pattern scanning result + struct ScanResult { + uintptr_t address; + size_t size; + + ScanResult() : address(0), size(0) {} + ScanResult(uintptr_t addr, size_t s) : address(addr), size(s) {} + + operator bool() const { return address != 0; } + + template + T* As() const { return reinterpret_cast(address); } + }; + + // Forward declaration of PatternScanner + class PatternScanner { + public: + // Scan for a pattern in memory + static ScanResult ScanForPattern(const char* pattern, const char* mask, void* startAddress, void* endAddress); + + // Scan for a signature string + static ScanResult ScanForSignature(const std::string& signature, void* startAddress = nullptr, void* endAddress = nullptr); + + // Scan for a string in memory + static ScanResult ScanForString(const std::string& str, void* startAddress = nullptr, void* endAddress = nullptr); + + // Find all occurrences of a pattern + static std::vector FindAllPatterns(const char* pattern, const char* mask, void* startAddress = nullptr, void* endAddress = nullptr); + + // Get base address of the process + static uintptr_t GetBaseAddress(); + + // Get base address of a module + static uintptr_t GetModuleBaseAddress(const std::string& moduleName); + + // Get size of a module + static size_t GetModuleSize(const std::string& moduleName); + + // Get address by pattern + static uintptr_t GetAddressByPattern(const char* pattern); + }; +}