diff --git a/libs/ASILoader/ASILoader.vcxproj b/libs/ASILoader/ASILoader.vcxproj
new file mode 100644
index 0000000..b72b107
--- /dev/null
+++ b/libs/ASILoader/ASILoader.vcxproj
@@ -0,0 +1,266 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release_internal
+ Win32
+
+
+ Release_internal
+ x64
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 17.0
+ Win32Proj
+ {0db8f2e7-eec8-4c7a-a1bf-c7d51af69d28}
+ ASILoader
+ 10.0
+
+
+
+ DynamicLibrary
+ true
+ v143
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+ DynamicLibrary
+ true
+ v143
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;ASILOADER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ NotUsing
+
+
+ MultiThreaded
+
+ stdcpp17
+
+
+ Windows
+ true
+ false
+
+ version.def
+ version.lib
+ false
+ false
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;ASILOADER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ NotUsing
+
+
+ MultiThreaded
+
+ stdcpp17
+
+
+ Windows
+ true
+ false
+
+ version.def
+ version.lib
+ false
+ false
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;ASILOADER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ NotUsing
+
+
+ MultiThreaded
+
+
+ stdcpp17
+
+
+ Windows
+ true
+ false
+
+
+ version.def
+ version.lib
+ false
+ false
+
+
+
+
+ Level3
+ true
+ _DEBUG;ASILOADER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ NotUsing
+
+
+ MultiThreaded
+
+ stdcpp17
+
+
+ Windows
+ true
+ false
+
+ version.def
+ version.lib
+ false
+ false
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;ASILOADER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ NotUsing
+
+
+ MultiThreaded
+
+ stdcpp17
+
+
+ Windows
+ true
+ false
+
+ version.def
+ version.lib
+ false
+ false
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;ASILOADER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ NotUsing
+
+
+ MultiThreaded
+
+
+ stdcpp17
+
+
+ Windows
+ true
+ false
+
+
+ version.def
+ version.lib
+ false
+ false
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libs/ASILoader/version.cpp b/libs/ASILoader/version.cpp
new file mode 100644
index 0000000..258f3d2
--- /dev/null
+++ b/libs/ASILoader/version.cpp
@@ -0,0 +1,147 @@
+#include
+#include
+namespace fs = std::filesystem;
+
+static HMODULE real_version = nullptr;
+
+void LoadRealVersionDLL()
+{
+ if (!real_version)
+ {
+ real_version = LoadLibraryW(L"C:\\Windows\\System32\\version.dll");
+ }
+}
+
+extern "C" BOOL WINAPI GetFileVersionInfoA(LPCSTR file, DWORD handle, DWORD len, LPVOID data)
+{
+ LoadRealVersionDLL();
+ using Fn = BOOL(WINAPI*)(LPCSTR, DWORD, DWORD, LPVOID);
+ static Fn real = (Fn)GetProcAddress(real_version, "GetFileVersionInfoA");
+ return real(file, handle, len, data);
+}
+
+extern "C" BOOL WINAPI GetFileVersionInfoW(LPCWSTR file, DWORD handle, DWORD len, LPVOID data)
+{
+ LoadRealVersionDLL();
+ using Fn = BOOL(WINAPI*)(LPCWSTR, DWORD, DWORD, LPVOID);
+ static Fn real = (Fn)GetProcAddress(real_version, "GetFileVersionInfoW");
+ return real(file, handle, len, data);
+}
+
+extern "C" BOOL WINAPI GetFileVersionInfoExA(DWORD dwFlags, LPCSTR lpstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData)
+{
+ LoadRealVersionDLL();
+ using Fn = BOOL(WINAPI*)(DWORD, LPCSTR, DWORD, DWORD, LPVOID);
+ static Fn real = (Fn)GetProcAddress(real_version, "GetFileVersionInfoExA");
+ return real(dwFlags, lpstrFilename, dwHandle, dwLen, lpData);
+}
+
+extern "C" BOOL WINAPI GetFileVersionInfoExW(DWORD dwFlags, LPCWSTR lpwstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData)
+{
+ LoadRealVersionDLL();
+ using Fn = BOOL(WINAPI*)(DWORD, LPCWSTR, DWORD, DWORD, LPVOID);
+ static Fn real = (Fn)GetProcAddress(real_version, "GetFileVersionInfoExW");
+ return real(dwFlags, lpwstrFilename, dwHandle, dwLen, lpData);
+}
+
+extern "C" DWORD WINAPI GetFileVersionInfoSizeA(LPCSTR lptstrFilename, LPDWORD lpdwHandle)
+{
+ LoadRealVersionDLL();
+ using Fn = DWORD(WINAPI*)(LPCSTR, LPDWORD);
+ static Fn real = (Fn)GetProcAddress(real_version, "GetFileVersionInfoSizeA");
+ return real(lptstrFilename, lpdwHandle);
+}
+
+extern "C" DWORD WINAPI GetFileVersionInfoSizeW(LPCWSTR lptstrFilename, LPDWORD lpdwHandle)
+{
+ LoadRealVersionDLL();
+ using Fn = DWORD(WINAPI*)(LPCWSTR, LPDWORD);
+ static Fn real = (Fn)GetProcAddress(real_version, "GetFileVersionInfoSizeW");
+ return real(lptstrFilename, lpdwHandle);
+}
+
+extern "C" DWORD WINAPI GetFileVersionInfoSizeExA(DWORD dwFlags, LPCSTR lpwstrFilename, LPDWORD lpdwHandle)
+{
+ LoadRealVersionDLL();
+ using Fn = DWORD(WINAPI*)(DWORD, LPCSTR, LPDWORD);
+ static Fn real = (Fn)GetProcAddress(real_version, "GetFileVersionInfoSizeExA");
+ return real(dwFlags, lpwstrFilename, lpdwHandle);
+}
+
+extern "C" DWORD WINAPI GetFileVersionInfoSizeExW(DWORD dwFlags, LPCWSTR lpwstrFilename, LPDWORD lpdwHandle)
+{
+ LoadRealVersionDLL();
+ using Fn = DWORD(WINAPI*)(DWORD, LPCWSTR, LPDWORD);
+ static Fn real = (Fn)GetProcAddress(real_version, "GetFileVersionInfoSizeExW");
+ return real(dwFlags, lpwstrFilename, lpdwHandle);
+}
+
+extern "C" DWORD WINAPI VerFindFileA(DWORD uFlags, LPCSTR szFileName, LPCSTR szWinDir, LPCSTR szAppDir, LPSTR szCurDir, UINT* pcchCurDir, LPSTR szDestDir, UINT* pcchDestDir)
+{
+ LoadRealVersionDLL();
+ using Fn = DWORD(WINAPI*)(DWORD, LPCSTR, LPCSTR, LPCSTR, LPSTR, UINT*, LPSTR, UINT*);
+ static Fn real = (Fn)GetProcAddress(real_version, "VerFindFileA");
+ return real(uFlags, szFileName, szWinDir, szAppDir, szCurDir, pcchCurDir, szDestDir, pcchDestDir);
+}
+
+extern "C" DWORD WINAPI VerFindFileW(DWORD uFlags, LPCWSTR szFileName, LPCWSTR szWinDir, LPCWSTR szAppDir, LPWSTR szCurDir, UINT* pcchCurDir, LPWSTR szDestDir, UINT* pcchDestDir)
+{
+ LoadRealVersionDLL();
+ using Fn = DWORD(WINAPI*)(DWORD, LPCWSTR, LPCWSTR, LPCWSTR, LPWSTR, UINT*, LPWSTR, UINT*);
+ static Fn real = (Fn)GetProcAddress(real_version, "VerFindFileW");
+ return real(uFlags, szFileName, szWinDir, szAppDir, szCurDir, pcchCurDir, szDestDir, pcchDestDir);
+}
+
+extern "C" DWORD WINAPI VerLanguageNameA(DWORD wLang, LPSTR szLang, DWORD cchLang)
+{
+ LoadRealVersionDLL();
+ using Fn = BOOL(WINAPI*)(DWORD, LPSTR, DWORD);
+ static Fn real = (Fn)GetProcAddress(real_version, "VerLanguageNameA");
+ return real(wLang, szLang, cchLang);
+}
+
+extern "C" DWORD WINAPI VerLanguageNameW(DWORD wLang, LPWSTR szLang, DWORD cchLang)
+{
+ LoadRealVersionDLL();
+ using Fn = BOOL(WINAPI*)(DWORD, LPWSTR, DWORD);
+ static Fn real = (Fn)GetProcAddress(real_version, "VerLanguageNameW");
+ return real(wLang, szLang, cchLang);
+}
+
+extern "C" BOOL WINAPI VerQueryValueA(LPCVOID pBlock, LPCSTR lpSubBlock, LPVOID* lplpBuffer, PUINT puLen)
+{
+ LoadRealVersionDLL();
+ using Fn = BOOL(WINAPI*)(LPCVOID, LPCSTR, LPVOID*, PUINT);
+ static Fn real = (Fn)GetProcAddress(real_version, "VerQueryValueA");
+ return real(pBlock, lpSubBlock, lplpBuffer, puLen);
+}
+
+extern "C" BOOL WINAPI VerQueryValueW(LPCVOID pBlock, LPCWSTR lpSubBlock, LPVOID* lplpBuffer, PUINT puLen)
+{
+ LoadRealVersionDLL();
+ using Fn = BOOL(WINAPI*)(LPCVOID, LPCWSTR, LPVOID*, PUINT);
+ static Fn real = (Fn)GetProcAddress(real_version, "VerQueryValueW");
+ return real(pBlock, lpSubBlock, lplpBuffer, puLen);
+}
+
+// Charge les ASI dans le répertoire courant
+void LoadAllASI()
+{
+ auto path = fs::current_path();
+ for (const auto& entry : fs::directory_iterator(path))
+ {
+ if (entry.path().extension() == ".asi")
+ {
+ LoadLibraryW(entry.path().c_str());
+ }
+ }
+}
+
+BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID)
+{
+ if (reason == DLL_PROCESS_ATTACH)
+ {
+ LoadAllASI();
+ }
+ return TRUE;
+}
diff --git a/libs/ASILoader/version.def b/libs/ASILoader/version.def
new file mode 100644
index 0000000..15597f0
--- /dev/null
+++ b/libs/ASILoader/version.def
@@ -0,0 +1,16 @@
+LIBRARY version
+EXPORTS
+ GetFileVersionInfoA
+ GetFileVersionInfoW
+ GetFileVersionInfoExA
+ GetFileVersionInfoExW
+ GetFileVersionInfoSizeA
+ GetFileVersionInfoSizeW
+ GetFileVersionInfoSizeExA
+ GetFileVersionInfoSizeExW
+ VerFindFileA
+ VerFindFileW
+ VerLanguageNameA
+ VerLanguageNameW
+ VerQueryValueA
+ VerQueryValueW
diff --git a/libs/Maths/Maths.cpp b/libs/Maths/Maths.cpp
new file mode 100644
index 0000000..84870a4
--- /dev/null
+++ b/libs/Maths/Maths.cpp
@@ -0,0 +1,27 @@
+// Maths.cpp : Définit les fonctions de la bibliothèque statique.
+//
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+#include "Maths.hpp"
+#include
+
+double Maths::DegreesToRadians(double degrees) {
+ return degrees * M_PI / 180.0;
+}
+
+// Convertit des radians en degrés
+double Maths::RadiansToDegrees(double radians) {
+ return radians * 180.0 / M_PI;
+}
+
+double Maths::CompensateHorizontalFOV(double baseHorizontalFOVDeg, double baseAspectRatio, double targetAspectRatio) {
+ double baseFOVRad = DegreesToRadians(baseHorizontalFOVDeg);
+ // Step 1 : FOV vertical from horizontal FOV
+ double verticalFOVRad = 2.0 * std::atan(std::tan(baseFOVRad / 2.0) / baseAspectRatio);
+ // Step 2 : New horizontal FOV for target aspect ratio
+ double newFOVRad = 2.0 * std::atan(std::tan(verticalFOVRad / 2.0) * targetAspectRatio);
+
+ return RadiansToDegrees(newFOVRad);
+}
\ No newline at end of file
diff --git a/libs/Maths/Maths.hpp b/libs/Maths/Maths.hpp
new file mode 100644
index 0000000..f7d9892
--- /dev/null
+++ b/libs/Maths/Maths.hpp
@@ -0,0 +1,14 @@
+#pragma once
+
+#include
+
+class Maths
+{
+ public:
+ // Compute new horizontal FOV based on native and target aspect ratio
+ static double CompensateHorizontalFOV(const double baseHorizontalFOVDeg, const double baseAspectRatio, const double targetAspectRatio);
+
+ private:
+ static double DegreesToRadians(double degrees);
+ static double RadiansToDegrees(double radians);
+};
diff --git a/libs/Maths/Maths.vcxproj b/libs/Maths/Maths.vcxproj
new file mode 100644
index 0000000..b92ea5e
--- /dev/null
+++ b/libs/Maths/Maths.vcxproj
@@ -0,0 +1,246 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release_internal
+ Win32
+
+
+ Release_internal
+ x64
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 17.0
+ Win32Proj
+ {9a3c36e4-b32b-43db-ac7b-8ab45dc3097e}
+ Maths
+ 10.0
+
+
+
+ StaticLibrary
+ true
+ v143
+ Unicode
+
+
+ StaticLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+ StaticLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+ StaticLibrary
+ true
+ v143
+ Unicode
+
+
+ StaticLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+ StaticLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(SolutionDir)bin\$(Configuration)\
+
+
+ $(SolutionDir)bin\$(Configuration)\
+
+
+ $(SolutionDir)bin\$(Configuration)\
+
+
+ $(SolutionDir)bin\$(Configuration)\
+
+
+ $(SolutionDir)bin\$(Configuration)\
+
+
+ $(SolutionDir)bin\$(Configuration)\
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ NotUsing
+
+
+
+ /utf-8 %(AdditionalOptions)
+
+
+
+
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ NotUsing
+
+
+
+ /utf-8 %(AdditionalOptions)
+
+
+
+
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ NotUsing
+
+
+
+
+ /utf-8 %(AdditionalOptions)
+
+
+
+
+ true
+
+
+
+
+ Level3
+ true
+ _DEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ NotUsing
+
+
+
+ /utf-8 %(AdditionalOptions)
+
+
+
+
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ NotUsing
+
+
+
+ /utf-8 %(AdditionalOptions)
+
+
+
+
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ NotUsing
+
+
+
+
+ /utf-8 %(AdditionalOptions)
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libs/Memory/Memory.cpp b/libs/Memory/Memory.cpp
new file mode 100644
index 0000000..60291c4
--- /dev/null
+++ b/libs/Memory/Memory.cpp
@@ -0,0 +1,341 @@
+// MemoryScanner.cpp : Définit les fonctions de la bibliothèque statique.
+//
+
+#include "Memory.hpp"
+#include "UEngine.hpp"
+#include
+#include
+#include
+#include
+#include
+#include
+
+// Rich verbose for internal release only
+#ifdef MY_VERBOSE_LOGS
+#define LOG_SIGNATURE_FOUND(name, addr) \
+ logger->info( \
+ "{} signature found at address: 0x{:X}.", \
+ name, addr \
+ )
+#else
+#define LOG_SIGNATURE_FOUND(name, addr) \
+ logger->info("{} signature found", name)
+#endif
+
+static std::shared_ptr _log;
+std::unordered_map Memory::patches;
+
+uint8_t* Memory::GetOffsetFromOpcode(uint8_t* opcode, int extraOffset) {
+ if (!opcode) return nullptr;
+
+ int32_t disp = 0;
+ std::memcpy(&disp, opcode, sizeof(int32_t));
+
+ if (disp < 0)
+ return nullptr; // optionnel : gérer ou pas les offsets négatifs
+
+ // Retourne l'adresse "offsetée" (base + disp)
+ return opcode + 4 + disp + extraOffset; // +4 car disp32 fait 4 octets
+}
+
+uint8_t* Memory::GetAddressFromOpcode(uint8_t* opcode, uint32_t dispOffset, uint32_t instructionLen) {
+ int32_t disp = 0;
+ std::memcpy(&disp, opcode + dispOffset, sizeof(disp)); // lit le disp32 de manière safe
+ return opcode + instructionLen + disp; // gère automatiquement disp négatif
+}
+
+const char* Memory::Float32ToHexBytes(float value) {
+ static char bytes[4]; // buffer persistant (évite les problèmes de scope)
+ std::memcpy(bytes, &value, sizeof(float));
+ return bytes; // pointeur vers les 4 octets bruts
+}
+
+std::vector Memory::ReadBytes(const void* addr, std::size_t size) {
+ std::vector buffer(size);
+ std::memcpy(buffer.data(), addr, size);
+ return buffer;
+}
+
+void Memory::PatchBytes(void* address, const char* bytes, size_t len) {
+ auto it = patches.find(address);
+ if (it == patches.end()) {
+ // If a patch doesn't exist, create a new one.
+ PatchInfo info;
+ info.address = address;
+ info.originalBytes.resize(len);
+ memcpy(info.originalBytes.data(), address, len);
+ // Store the patch info.
+ patches[address] = info;
+ }
+
+ // Patch the bytes.
+ DWORD oldProtect;
+ VirtualProtect(address, len, PAGE_EXECUTE_READWRITE, &oldProtect);
+ memcpy(address, bytes, len);
+ VirtualProtect(address, len, oldProtect, &oldProtect);
+}
+
+void Memory::RestoreBytes(void *address) {
+ auto it = patches.find(address);
+ if (it != patches.end()) {
+ // Restore the original bytes.
+ const auto& info = it->second;
+ DWORD oldProtect;
+ VirtualProtect(info.address, info.originalBytes.size(), PAGE_EXECUTE_READWRITE, &oldProtect);
+ memcpy(info.address, info.originalBytes.data(), info.originalBytes.size());
+ VirtualProtect(info.address, info.originalBytes.size(), oldProtect, &oldProtect);
+
+ // Remove the patch info.
+ patches.erase(it);
+ }
+}
+
+MODULEINFO Memory::WaitForModule(const std::string& module_name, int timeoutMs, int intervalMs)
+{
+ const HANDLE hProc = GetCurrentProcess();
+ MODULEINFO modInfo{};
+
+ for (int waited = 0; waited < timeoutMs; waited += intervalMs) {
+ HMODULE hMods[1024];
+ DWORD cbNeeded;
+
+ if (EnumProcessModules(hProc, hMods, sizeof(hMods), &cbNeeded)) {
+ for (unsigned int i = 0; i < (cbNeeded / sizeof(HMODULE)); ++i) {
+ char modName[MAX_PATH];
+ if (GetModuleBaseNameA(hProc, hMods[i], modName, sizeof(modName))) {
+ if (_stricmp(modName, module_name.c_str()) == 0) {
+ if (GetModuleInformation(hProc, hMods[i], &modInfo, sizeof(modInfo)))
+ return modInfo;
+ }
+ }
+ }
+ }
+
+ Sleep(intervalMs);
+ }
+
+ if (_log) _log->warn("Timeout: module '{}' not found in process after {} ms.", module_name, timeoutMs);
+ return MODULEINFO{};
+}
+
+std::string Memory::ByteToHexEscaped(const BYTE byte) {
+ std::ostringstream oss;
+ oss << "\\x" << std::uppercase << std::hex << std::setw(2)
+ << std::setfill('0') << static_cast(byte);
+ return oss.str();
+}
+
+uint8_t* Memory::AOBScan(
+ const std::string& module_name,
+ const std::string& signature,
+ DWORD protect_flags = PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_READWRITE | PAGE_EXECUTE_WRITECOPY,
+ std::shared_ptr log) {
+
+ bool found = false;
+
+ _log = log;
+ HANDLE hProc = GetCurrentProcess();
+ MODULEINFO modInfo{};
+ HMODULE targetModule = nullptr;
+ // Get module when name is specidifed
+ if (!(module_name.empty() || module_name == "*")) {
+ if (_log) _log->info("Module name: {}", module_name);
+ MODULEINFO modinfo = WaitForModule(module_name);
+ if (modinfo.lpBaseOfDll == nullptr) {
+ if (_log) _log->warn("Skipping AOB scan because module '{}' is unavailable.", module_name);
+ return nullptr;
+ }
+ }
+ // Fallback to determine module loaded
+ if (!found || module_name.empty() || module_name == "*") {
+ char exeBuf[MAX_PATH] = { 0 };
+ DWORD exeLen = GetModuleFileNameA(nullptr, exeBuf, MAX_PATH);
+ std::string exeName = (exeLen > 0) ? std::string(exeBuf, exeBuf + exeLen) : std::string();
+ size_t pos = exeName.find_last_of("\\/");
+
+ if (pos != std::string::npos) exeName = exeName.substr(pos + 1);
+ if (_log && !exeName.empty()) _log->info("Module name: {}", exeName);
+
+ targetModule = GetModuleHandleA(nullptr);
+ if (!targetModule || !GetModuleInformation(hProc, targetModule, &modInfo, sizeof(modInfo))) {
+ if (_log) _log->error("Failed to find main module.");
+ return nullptr;
+ }
+ }
+ // Convert AOB string into vector bytes
+ std::vector pattern_bytes;
+ std::istringstream stream(signature);
+ std::string byte_str;
+ while (stream >> byte_str) {
+ if (byte_str == "??" || byte_str == "?")
+ pattern_bytes.push_back(-1);
+ else
+ pattern_bytes.push_back(static_cast(std::strtol(byte_str.c_str(), nullptr, 16)));
+ }
+
+ if (pattern_bytes.empty()) {
+ if (_log) _log->warn("Empty AOB pattern passed.");
+ return nullptr;
+ }
+ // Logging scanning area
+ uint8_t* base = reinterpret_cast(modInfo.lpBaseOfDll);
+ size_t size = modInfo.SizeOfImage;
+ if (_log) _log->info("Scanning memory region: 0x{:X} - 0x{:X}",
+ reinterpret_cast(base), reinterpret_cast(base + size));
+
+ // Memory scan
+ MEMORY_BASIC_INFORMATION mbi{};
+ for (uint8_t* current = base; current < base + size;) {
+ if (!VirtualQuery(current, &mbi, sizeof(mbi)))
+ break;
+
+ bool isCommitted = (mbi.State & MEM_COMMIT) != 0;
+ bool hasAccess = (mbi.Protect & protect_flags) != 0;
+ bool isNoAccess = (mbi.Protect & PAGE_NOACCESS) != 0;
+ bool isGuard = (mbi.Protect & PAGE_GUARD) != 0;
+
+ if (isCommitted && hasAccess && !isNoAccess && !isGuard) {
+ uint8_t* regionBase = reinterpret_cast(mbi.BaseAddress);
+ size_t regionSize = mbi.RegionSize;
+
+ for (size_t i = 0; i <= regionSize - pattern_bytes.size(); ++i) {
+ bool match = true;
+ for (size_t j = 0; j < pattern_bytes.size(); ++j) {
+ if (pattern_bytes[j] != -1 && regionBase[i + j] != static_cast(pattern_bytes[j])) {
+ match = false;
+ break;
+ }
+ }
+
+ if (match) {
+ uint8_t* result = regionBase + i;
+ return result;
+ }
+ }
+ }
+
+ current = reinterpret_cast(mbi.BaseAddress) + mbi.RegionSize;
+ }
+ return nullptr;
+}
+
+void Memory::AOBScanBatch(const std::vector& entries, std::shared_ptr logger) {
+ for (auto scanEntry = entries.begin(); scanEntry != entries.end(); ++scanEntry) {
+ if (*scanEntry->address) continue;
+
+ std::string decryptedSignature = scanEntry->getSignature();
+ uint8_t* result = nullptr;
+ if (scanEntry == entries.begin()) // Only log module and area scanned once
+ result = Memory::AOBScan(scanEntry->moduleName, decryptedSignature, scanEntry->protection, logger);
+ else result = Memory::AOBScan(scanEntry->moduleName, decryptedSignature, scanEntry->protection);
+
+ if (!result) {
+ logger->warn(
+ "{} signature not found. Maybe your game has been updated and is no more compatible with this plugin.",
+ scanEntry->featureName);
+ continue;
+ }
+ // Write final signature address
+ uintptr_t finalAddress = reinterpret_cast(result) + scanEntry->offset;
+ *scanEntry->address = reinterpret_cast(finalAddress);
+
+ LOG_SIGNATURE_FOUND(scanEntry->featureName, finalAddress);
+ }
+}
+
+void Memory::OffsetScanBatch(const std::vector& entries, uint8_t* baseModule,
+ std::shared_ptr logger, const std::string& moduleName) {
+ for (const auto& scanEntry : entries) {
+ if (!scanEntry.outAddress) continue;
+
+ // Scan Unreal Engine Objects and functions
+ *scanEntry.outAddress = Memory::AOBScan(moduleName, scanEntry.getSignature(), scanEntry.protection);
+ if (!*scanEntry.outAddress) {
+ logger->warn("{} signature not found. Maybe your game has been updated and is no more compatible with this plugin.", scanEntry.name);
+ continue;
+ }
+
+ UT::uint32 calculatedOffset = 0;
+ // Calculate offset according type
+ switch (scanEntry.calcType) {
+ case OffsetCalcType::GetOffsetFromOpcode: {
+ calculatedOffset = static_cast(Memory::GetOffsetFromOpcode(*scanEntry.outAddress + scanEntry.opcodeOffset) - baseModule);
+ break;
+ }
+ case OffsetCalcType::UE_CalculateOffset: {
+ auto opt = UE::CalculateOffset(moduleName, *scanEntry.outAddress);
+ if (!opt) continue;
+ calculatedOffset = *opt;
+ break;
+ }
+ }
+ // Write final Unreal Engine offset
+ if (scanEntry.outOffset) *scanEntry.outOffset = calculatedOffset;
+
+ logger->info("{} offset is: 0x{:X}", scanEntry.name, calculatedOffset);
+ }
+}
+
+PVOID Memory::SetupOrClearHardwareBreakPointForAllThreads(uintptr_t targetAddress, PVOID vehHandle, bool enable, PVECTORED_EXCEPTION_HANDLER pVEH, int hwIndex)
+{
+ DWORD pid = GetCurrentProcessId();
+ HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
+ if (snapshot == INVALID_HANDLE_VALUE) return nullptr;
+
+ THREADENTRY32 te;
+ te.dwSize = sizeof(te);
+
+ // Add VectoredExceptionHandler
+ if (enable && !vehHandle && pVEH)
+ vehHandle = AddVectoredExceptionHandler(1, pVEH);
+
+ if (Thread32First(snapshot, &te)) {
+ do {
+ if (te.th32OwnerProcessID != pid) continue;
+
+ HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, te.th32ThreadID);
+ if (!hThread) continue;
+
+ CONTEXT ctx = {};
+ ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
+
+ if (GetThreadContext(hThread, &ctx)) {
+ if (enable) {
+ switch (hwIndex) {
+ case 0: ctx.Dr0 = targetAddress; break; // Set Hardware breakpoint #1
+ case 1: ctx.Dr1 = targetAddress; break; // Set Hardware breakpoint #2
+ case 2: ctx.Dr2 = targetAddress; break; // Set Hardware breakpoint #3
+ case 3: ctx.Dr3 = targetAddress; break; // Set Hardware breakpoint #4
+ default: break;
+ }
+ ctx.Dr7 |= (1ULL << (hwIndex * 2)); // activate hardware breakpoint
+ }
+ else {
+ switch (hwIndex) {
+ case 0: ctx.Dr0 = 0; break; // Unset Hardware breakpoint #1
+ case 1: ctx.Dr1 = 0; break; // Unset Hardware breakpoint #2
+ case 2: ctx.Dr2 = 0; break; // Unset Hardware breakpoint #3
+ case 3: ctx.Dr3 = 0; break; // Unset Hardware breakpoint #4
+ default: break;
+ }
+ ctx.Dr7 &= ~(1ULL << (hwIndex * 2)); // deactivate hardware breakpoint
+ }
+
+ SetThreadContext(hThread, &ctx);
+ }
+
+ CloseHandle(hThread);
+
+ } while (Thread32Next(snapshot, &te));
+ }
+
+ CloseHandle(snapshot);
+
+ // Remove VectoredExceptionHandler
+ if (!enable && vehHandle) {
+ RemoveVectoredExceptionHandler(vehHandle);
+ vehHandle = nullptr;
+ }
+
+ return vehHandle;
+}
\ No newline at end of file
diff --git a/libs/Memory/Memory.hpp b/libs/Memory/Memory.hpp
new file mode 100644
index 0000000..801aab7
--- /dev/null
+++ b/libs/Memory/Memory.hpp
@@ -0,0 +1,184 @@
+#pragma once
+#include
+#include
+#include
+#include
+
+#define AUTO_ASSEMBLE_TRAMPOLINE(ADDRESS, TRAMPOLINE_LENGTH, INSTRUCTIONS) \
+do { \
+auto allocMemory = Memory::AllocateNearbyMemory(ADDRESS, sizeof INSTRUCTIONS + 14); \
+Memory::CreateTrampoline(ADDRESS, allocMemory, TRAMPOLINE_LENGTH); \
+Memory::WriteInstructions(allocMemory, INSTRUCTIONS, sizeof INSTRUCTIONS, ADDRESS + TRAMPOLINE_LENGTH); \
+} while (false)
+
+namespace UT { // Typedef used by Unreal Engine
+ typedef int8_t int8;
+ typedef int16_t int16;
+ typedef int32_t int32;
+ typedef int64_t int64;
+
+ typedef uint8_t uint8;
+ typedef uint16_t uint16;
+ typedef uint32_t uint32;
+ typedef uint64_t uint64;
+}
+
+struct AOBScanEntry {
+ uint8_t** address;
+ std::function getSignature;
+ const char* featureName;
+ std::string moduleName = ""; // "" = main exe
+ DWORD protection = PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE |
+ PAGE_READWRITE | PAGE_EXECUTE_WRITECOPY;
+ intptr_t offset = 0;
+};
+
+namespace AOBScan {
+ // Helper template to create entry with ObfuscatedString
+ template
+ static AOBScanEntry Make(uint8_t** addr, ObfStr& obf, const char* name, std::string module = "", DWORD prot = PAGE_EXECUTE_READ) {
+ return AOBScanEntry{ addr, [&, obf]() { return obf.decrypt(); }, name, module, prot, 0 };
+ }
+}
+
+enum class OffsetCalcType
+{
+ None,
+ GetOffsetFromOpcode,
+ UE_CalculateOffset
+};
+
+struct OffsetScanEntry
+{
+ uint8_t** outAddress; // Address where the pointer will be stored
+ std::function getSignature; // decrypted AOB
+ std::string name; // Name for the log (GWorlds ...)
+ OffsetCalcType calcType; // Method to calculate offset
+ UT::int32* outOffset = nullptr; // Offset pointer to update
+ size_t opcodeOffset = 0; // Relative offset for GetOffsetFromOpcode method
+ DWORD protection = PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE |
+ PAGE_READWRITE | PAGE_EXECUTE_WRITECOPY;
+};
+
+namespace OffsetScan {
+ // Helper template to create an entry
+ template
+ static OffsetScanEntry Make(uint8_t** addr, ObfStr& obf, const char* featureName,
+ OffsetCalcType type, UT::int32* outOffsetPtr,
+ size_t opOffset = 0, DWORD prot = PAGE_EXECUTE_READ) {
+ return OffsetScanEntry{
+ addr,
+ [&obf]() { return obf.decrypt(); }, // signature lambda
+ featureName, type,
+ outOffsetPtr,
+ opOffset, prot
+ };
+ }
+}
+
+class Memory
+{
+ public:
+
+ /**
+ * Get offset from opcode.
+ *
+ * @param opcode : The address where the offset begins.
+ */
+ static uint8_t* GetOffsetFromOpcode(uint8_t* opcode, int extraOffset = 0);
+
+ /**
+ * Get Address from opcode.
+ *
+ * @param opcode : The opcode pointer targeted.
+ * @param dispOffset : The offset to target disp (4 bytes) in opcode.
+ * @param instructionLen : The total opcode length in bytes.
+ */
+ static uint8_t* GetAddressFromOpcode(uint8_t* opcode, uint32_t dispOffset, uint32_t instructionLen);
+
+ /**
+ * Converts flkoat 32 bits into a char*.
+ *
+ * @param value : The value to encode.
+ */
+ static const char* Float32ToHexBytes(float value);
+
+ /**
+ * Read x bytes in memory.
+ *
+ * @param address : The address to read.
+ * @param size : The size in bytes to read
+ * @std::vector : The bytes read.
+ */
+ static std::vector ReadBytes(const void* addr, std::size_t size);
+
+ /**
+ * Patch x bytes in memory.
+ *
+ * @param address : The address to patch.
+ * @param bytes : The bytes to patch
+ * @param len : The number of bytes to be patched
+ */
+ static void PatchBytes(void* address, const char* bytes, size_t len);
+
+ /**
+ * Restore x bytes in memory.
+ *
+ * @param address : The address to patch.
+ */
+ static void RestoreBytes(void* address);
+
+ /**
+ * Achieve an AOB scan in memory.
+ *
+ * @param module_name : The executable to scan.
+ * @param signature : The signature to search for (eg : 7F ?? F3 0F ?? ?? ?? F2)
+ * @param protect_flags : Page protection (PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_READWRITE | PAGE_EXECUTE_WRITECOPY)
+ * @param log : If any log is to be used
+ * @return uint_8* : Pointer to address where AOB is found.
+ */
+ static uint8_t* AOBScan(const std::string& module_name, const std::string& signature, DWORD protect_flags, std::shared_ptr log = nullptr);
+
+ /**
+ * Achieve an AOB scan in memory by batch.
+ *
+ * @param const std::vector& entries : AOB signatures of AOBScanEntry type.
+ * @param logger : If any log is to be used
+ */
+ static void AOBScanBatch(const std::vector& entries, std::shared_ptr logger);
+
+ /**
+ * Achieve an unreal offsets scan by batch.
+ *
+ * @param const std::vector& entries : AOB signatures of OffsetScanEntry type.
+ * @param baseModule : The starting address of module scanned.
+ * @param logger : If any log is to be used
+ * @param moduleName : The module targeted (.exe, .dll ...)
+ */
+ static void OffsetScanBatch(const std::vector& entries, uint8_t* baseModule,
+ std::shared_ptr logger, const std::string& moduleName = "");
+
+ static std::string ByteToHexEscaped(const BYTE byte);
+
+ /**
+ * Set or clear VEH hardware breakpoint.
+ *
+ * @param targetAddress : The memory target to set a VEH breakpoint.
+ * @param vehHandle : The VEH handle (nullptr when to set breakpoint or a handle when to unset
+ * @param enable : Set or unset the VEH debugger
+ * @param pVEH : The function where to detour (set to nullptr to unset)
+ * @param hwIndex : The hawdware breakpoint to set (0 - 4)
+ * @return hwIndex : The VEH breakpoint handle
+ */
+ static PVOID SetupOrClearHardwareBreakPointForAllThreads(uintptr_t targetAddress, PVOID vehHandle, bool enable, PVECTORED_EXCEPTION_HANDLER pVEH = nullptr, int hwIndex = 0);
+ private:
+ static MODULEINFO WaitForModule(const std::string& module_name, int timeoutMs = 15000, int intervalMs = 500);
+ struct PatchInfo {
+ void* address;
+ std::vector originalBytes;
+ bool hasTrampoline = false;
+ void* trampolineDestination = nullptr;
+ };
+
+ static std::unordered_map patches;
+};
diff --git a/libs/Memory/Memory.vcxproj b/libs/Memory/Memory.vcxproj
new file mode 100644
index 0000000..bbe9882
--- /dev/null
+++ b/libs/Memory/Memory.vcxproj
@@ -0,0 +1,262 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release_internal
+ Win32
+
+
+ Release_internal
+ x64
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 17.0
+ Win32Proj
+ {f9b5bbc6-67d4-4290-986f-08c6bac41ba3}
+ Memory
+ 10.0
+ Memory
+
+
+
+ StaticLibrary
+ true
+ v143
+ Unicode
+
+
+ StaticLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+ StaticLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+ StaticLibrary
+ true
+ v143
+ Unicode
+
+
+ StaticLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+ StaticLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(SolutionDir)bin\$(Configuration)\
+
+
+ $(SolutionDir)bin\$(Configuration)\
+
+
+ $(SolutionDir)bin\$(Configuration)\
+
+
+ $(SolutionDir)bin\$(Configuration)\
+
+
+ $(SolutionDir)bin\$(Configuration)\
+
+
+ $(SolutionDir)bin\$(Configuration)\
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ NotUsing
+
+
+ $(SolutionDir)external;$(SolutionDir)UEngine;%(AdditionalIncludeDirectories)
+
+ /utf-8 %(AdditionalOptions)
+ stdcpp20
+
+
+
+
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ NotUsing
+
+
+ $(SolutionDir)external;$(SolutionDir)UEngine;%(AdditionalIncludeDirectories)
+
+ /utf-8 %(AdditionalOptions)
+ stdcpp20
+
+
+
+
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ NotUsing
+
+
+ $(SolutionDir)external;$(SolutionDir)UEngine;%(AdditionalIncludeDirectories)
+
+
+ /utf-8 %(AdditionalOptions)
+ stdcpp20
+
+
+
+
+ true
+
+
+
+
+ Level3
+ true
+ _DEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ NotUsing
+
+
+ $(SolutionDir)external;$(SolutionDir)UEngine;%(AdditionalIncludeDirectories)
+
+ /utf-8 %(AdditionalOptions)
+ stdcpp20
+
+
+
+
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ NotUsing
+
+
+ $(SolutionDir)external;$(SolutionDir)UEngine;%(AdditionalIncludeDirectories)
+
+ /utf-8 %(AdditionalOptions)
+ stdcpp20
+
+
+
+
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ NotUsing
+
+
+ $(SolutionDir)external;$(SolutionDir)UEngine;%(AdditionalIncludeDirectories)
+
+
+ /utf-8 %(AdditionalOptions)
+ stdcpp20
+
+
+
+
+ true
+
+
+
+
+
+
+
+ MY_VERBOSE_LOGS
+ MY_VERBOSE_LOGS
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libs/Obfuscate/Obfuscate.vcxproj b/libs/Obfuscate/Obfuscate.vcxproj
new file mode 100644
index 0000000..9cdaf10
--- /dev/null
+++ b/libs/Obfuscate/Obfuscate.vcxproj
@@ -0,0 +1,226 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release_internal
+ Win32
+
+
+ Release_internal
+ x64
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 17.0
+ Win32Proj
+ {7e0aec88-78b4-43ea-bbef-216e00df1424}
+ Obfuscate
+ 10.0
+
+
+
+ StaticLibrary
+ true
+ v143
+ Unicode
+
+
+ StaticLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+ StaticLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+ StaticLibrary
+ true
+ v143
+ Unicode
+
+
+ StaticLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+ StaticLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ NotUsing
+
+
+ stdcpp20
+
+
+
+
+
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ NotUsing
+
+
+ stdcpp20
+
+
+
+
+
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ NotUsing
+
+
+ stdcpp20
+
+
+
+
+
+
+ true
+
+
+
+
+ Level3
+ true
+ _DEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ NotUsing
+
+
+ stdcpp20
+
+
+
+
+
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ NotUsing
+
+
+ stdcpp20
+
+
+
+
+
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ NotUsing
+
+
+ stdcpp20
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libs/Obfuscate/ObfuscateString.h b/libs/Obfuscate/ObfuscateString.h
new file mode 100644
index 0000000..9b420bc
--- /dev/null
+++ b/libs/Obfuscate/ObfuscateString.h
@@ -0,0 +1,39 @@
+#pragma once
+#include
+#include
+
+template
+class ObfuscatedString {
+private:
+ std::array data;
+
+public:
+
+ constexpr ObfuscatedString(const std::array& obfuscatedData)
+ : data(obfuscatedData) {}
+
+ /**
+ * @brief Decrypt a string with a static key
+ */
+ std::string decrypt() const {
+ std::string result;
+ result.resize(N - 1); // remove '\0'
+
+ for (size_t i = 0; i < N - 1; ++i)
+ result[i] = data[i] ^ KEY;
+
+ return result;
+ }
+};
+
+// Helper constexpr to encrypt at building
+//template
+template
+constexpr auto make_obfuscated(const char(&str)[N])
+{
+ std::array enc{};
+ for (size_t i = 0; i < N; ++i)
+ enc[i] = str[i] ^ KEY;
+
+ return ObfuscatedString(enc);
+}
diff --git a/libs/Obfuscate/framework.h b/libs/Obfuscate/framework.h
new file mode 100644
index 0000000..afd886f
--- /dev/null
+++ b/libs/Obfuscate/framework.h
@@ -0,0 +1,3 @@
+#pragma once
+
+#define WIN32_LEAN_AND_MEAN // Exclure les en-têtes Windows rarement utilisés
diff --git a/libs/UEngine/UEMath.hpp b/libs/UEngine/UEMath.hpp
new file mode 100644
index 0000000..0b13f12
--- /dev/null
+++ b/libs/UEngine/UEMath.hpp
@@ -0,0 +1,40 @@
+#pragma once
+#include
+
+
+
+namespace UEMath
+{
+ struct Vector
+ {
+ float X;
+ float Y;
+ float Z;
+ };
+
+ struct Rotator
+ {
+ float Pitch; // X
+ float Yaw; // Y
+ float Roll; // Z
+ };
+
+ /**
+ * @brief Converts a rotator (Pitch, Yaw) to a forward direction vector.
+ * Computes a normalized forward vector from the given FRotator,
+ * using Pitch and Yaw angles (in degrees).
+ * @param rotator Input rotation (degrees).
+ * @return Forward direction vector.
+ */
+ static inline Vector RotatorToForwardVector(const Rotator& rotator)
+ {
+ constexpr float DEG_TO_RAD = 3.14159265358979323846f / 180.0f;
+
+ const float cp = cosf(rotator.Pitch * DEG_TO_RAD);
+ const float sp = sinf(rotator.Pitch * DEG_TO_RAD);
+ const float cy = cosf(rotator.Yaw * DEG_TO_RAD);
+ const float sy = sinf(rotator.Yaw * DEG_TO_RAD);
+
+ return Vector(cp * cy, cp * sy, sp);
+ }
+}
\ No newline at end of file
diff --git a/libs/UEngine/UEngine.cpp b/libs/UEngine/UEngine.cpp
new file mode 100644
index 0000000..42a5328
--- /dev/null
+++ b/libs/UEngine/UEngine.cpp
@@ -0,0 +1,28 @@
+// UEngine.cpp : Defines all Unreal Engine static tools functions
+//
+#include
+#include
+#include
+#include
+#include
+#include "UEngine.hpp"
+
+std::optional UE::CalculateOffset(const std::string& exeName, uint8_t* AOBResult)
+{
+ // Récupère la base du module via GetModuleHandleA
+ HMODULE hModule = GetModuleHandleA(exeName.c_str());
+ if (!AOBResult)
+ return std::nullopt;
+
+ if (!hModule)
+ hModule = GetModuleHandleA(nullptr);
+
+ uintptr_t baseModule = reinterpret_cast(hModule);
+ uintptr_t AOBAbsoluteAdress = reinterpret_cast(AOBResult);
+
+ if (AOBAbsoluteAdress < baseModule)
+ return std::nullopt;
+
+ uintptr_t relativeOffset = AOBAbsoluteAdress - baseModule;
+ return static_cast(relativeOffset);
+}
\ No newline at end of file
diff --git a/libs/UEngine/UEngine.hpp b/libs/UEngine/UEngine.hpp
new file mode 100644
index 0000000..26192ff
--- /dev/null
+++ b/libs/UEngine/UEngine.hpp
@@ -0,0 +1,12 @@
+class UE
+{
+public:
+ /**
+ * Get offset calculated from an AOB scan result and an executable base address
+ *
+ * @param exeName : A string of the executable name
+ * @param AOBResult : A valid (uint8_t) pointer to the result of an AOB scan
+ * @return std::optional The offset calculated
+ */
+ static std::optional CalculateOffset(const std::string& exeName, uint8_t* AOBResult);
+};
diff --git a/libs/UEngine/UEngine.vcxproj b/libs/UEngine/UEngine.vcxproj
new file mode 100644
index 0000000..3bf6313
--- /dev/null
+++ b/libs/UEngine/UEngine.vcxproj
@@ -0,0 +1,236 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release_internal
+ Win32
+
+
+ Release_internal
+ x64
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+
+
+
+
+
+
+
+ 17.0
+ Win32Proj
+ {e6ea0264-0c8f-4050-88f0-02cd4f6ef457}
+ UEngine
+ 10.0
+ UEngine
+
+
+
+ StaticLibrary
+ true
+ v143
+ Unicode
+
+
+ StaticLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+ StaticLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+ StaticLibrary
+ true
+ v143
+ Unicode
+
+
+ StaticLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+ StaticLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(SolutionDir)bin\$(Configuration)\
+
+
+ $(SolutionDir)bin\$(Configuration)\
+
+
+ $(SolutionDir)bin\$(Configuration)\
+
+
+ $(SolutionDir)bin\$(Configuration)\
+
+
+ $(SolutionDir)bin\$(Configuration)\
+
+
+ $(SolutionDir)bin\$(Configuration)\
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+ stdcpp20
+
+
+
+
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+ stdcpp20
+
+
+
+
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+ stdcpp20
+
+
+
+
+ true
+
+
+
+
+ Level3
+ true
+ _DEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+ stdcpp20
+
+
+
+
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ NotUsing
+
+
+ stdcpp20
+
+
+
+
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ NotUsing
+
+
+ stdcpp20
+
+
+
+
+ true
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libs/UEngine/UEvars.hpp b/libs/UEngine/UEvars.hpp
new file mode 100644
index 0000000..c549808
--- /dev/null
+++ b/libs/UEngine/UEvars.hpp
@@ -0,0 +1,6 @@
+
+// Common Unreal Engine variables used
+static uint8_t* GWorldaddress = nullptr;
+inline uint8_t* GObjectsaddress = nullptr;
+inline uint8_t* AppendStringaddress = nullptr;
+inline uint8_t* ProcessEventaddress = nullptr;
\ No newline at end of file