Table of Contents
Finding offsets opcode access signature
As soon as we have generated a SDK with Dumper-7, we have to open the Basic.hpp file generated in order to get the offsets.
They look like this :
/*
* Disclaimer:
* - The 'GNames' is only a fallback and null by default, FName::AppendString is used
* - THe 'GWorld' offset is not used by the SDK, it's just there for "decoration", use the provided 'UWorld::GetWorld()' function instead
*/
namespace Offsets
{
constexpr int32 GObjects = 0x092F8D70;
constexpr int32 AppendString = 0x01273B00;
constexpr int32 GNames = 0x092155C0;
constexpr int32 GWorld = 0x090C7008;
constexpr int32 ProcessEvent = 0x0149DC80;
constexpr int32 ProcessEventIdx = 0x0000004F;
}
These offsets will vary with game' updates and thus can't be used as static in our code because SDK functions call will make the game to crash sooner or later.
So the workaround here is to search for opcode that access them (load the address pointed by the offset).
Typical opcode address loading by offset looks like these :
lea rax,["HellIsUs-Win64-Shipping.exe"+92155C0]
mov rax, ["HellIsUs-Win64-Shipping.exe"+92155C0]
mov eax, ["HellIsUs-Win64-Shipping.exe"+92155C0]
We will need a Cheat Engine lua script in order to find an opcode accessing the offset.
local MODNAME = "HellIsUs-Win64-Shipping.exe" has to be modified with the game executable name
local OFFSET_HEX has to be modified with the Unreal Engine offset we look for found in Basic.hpp
As soon as the script has pointed an address with the opcode accessing the offset, we can generate a unique AOB signature.
For code to be used see below :
-- Lua script for Cheat Engine
-- Scanne plusieurs patterns RIP-relative et ajoute "GNames_ptr" si le match correspond
local MODNAME = "HellIsUs-Win64-Shipping.exe"
local OFFSET_HEX = 0x92155C0
local SIG_SCAN_FLAGS = "+X-C-W" -- sections exécutables uniquement
local SIGNATURES = {
{pattern="48 8D 05 ?? ?? ?? ??", dispOffset=3, instrLen=7}, -- lea rax,[rip+disp32]
{pattern="48 8B 05 ?? ?? ?? ??", dispOffset=3, instrLen=7}, -- mov rax,[rip+disp32]
{pattern="8B 05 ?? ?? ?? ??", dispOffset=2, instrLen=6}, -- mov eax,[rip+disp32]
}
-- Helper: lit un int32 little-endian safe
local function safeReadInt32(addr)
local ok, b = pcall(readBytes, addr, 4, true)
if not ok or not b or #b < 4 then return nil end
local val = b[1] | (b[2] << 8) | (b[3] << 16) | (b[4] << 24)
if val >= 0x80000000 then val = val - 0x100000000 end
return val
end
-- Helper: trouve module
local function findModule(name)
local mods = enumModules()
if not mods then return nil end
for i, m in ipairs(mods) do
if m.Name == name then
return {base = m.Address, size = m.Size}
end
end
return nil
end
-- Récup module
local mod = findModule(MODNAME)
if not mod then
print("Module non trouvé : " .. MODNAME)
return
end
local moduleBase = mod.base
local targetAddr = moduleBase + OFFSET_HEX
print(string.format("Module trouvé: %s base=0x%X size=0x%X", MODNAME, moduleBase, mod.size))
print(string.format("Recherche offset cible = 0x%X", targetAddr))
local found = false
for _, sig in ipairs(SIGNATURES) do
local matches = AOBScan(sig.pattern, SIG_SCAN_FLAGS)
if matches then
for i=0, matches.Count-1 do
local addr = tonumber(matches[i],16)
if addr then
local disp32 = safeReadInt32(addr + sig.dispOffset)
if disp32 then
local resolved = (addr + sig.instrLen) + disp32
if resolved == targetAddr then
found = true
print(string.format("Match trouvé à 0x%X -> résolu = 0x%X", addr, resolved))
-- Ajoute à la table
local al = getAddressList()
local mr = al.createMemoryRecord()
mr.Description = "Offset pointer"
mr.Address = string.format("%X", resolved)
mr.Type = vtQword
mr.Active = true
-- Enregistre symbole pour Auto Assembler
pcall(function() registerSymbol("Offset pointer", resolved, true) end)
break
end
end
end
end
matches.destroy()
if found then break end
end
end
if not found then
print("Aucun match valide trouvé pour Offset pointer.")
else
print("Adresse ajoutée sous le nom 'Offset pointer'.")
end
Modifiying SDK
The SDK doesn't allow to modify the offsets natively. So we got to modify the code a bit in order to achieve it.
Open the Basic.hpp and modify at the very beginning the Offsets namespace to look like this.
namespace Offsets
{
inline int32 GObjects = 0x092F8D70;
inline int32 AppendString = 0x01273B00;
inline int32 GNames = 0x092155C0;
inline int32 GWorld = 0x090C7008;
inline int32 ProcessEvent = 0x0149DC80;
inline int32 ProcessEventIdx = 0x0000004F;
}