This document specifies the requirements for a Frida-based Unreal Engine 4 (UE4) Android runtime instrumentation toolkit. The toolkit attaches to (or spawns alongside) a target Android process that has loaded libUE4.so and performs three core functions:
FConsoleManager registry, decoding each entry's type, value, flags, and help text, and capturing newly registered CVars at the point of native registration.FConfigFile instrumentation — hooking the engine's configuration read/combine/write/hierarchy methods to record configuration access and mutation events.FFileHelper, SQLite, GameplayTags, and engine-init symbols to log hot paths, dump loaded .pak-backed content to disk, and probe fixed code offsets.All captured data is exported as JSON artifacts (cvars.json, fconfig.json) and console-logged in structured, batched form. The toolkit is delivered as a single JavaScript Frida script composed of two logical parts — Part A (CVar + FConfig logging) and Part B (UE4 pak/file extractor) — sharing a package (PKG) auto-detection convention.
The toolkit runs inside a Frida agent injected into a UE4 Android process (arm64). It is driven by a static configuration block plus a small RPC surface (dump, save, unhook, unhookfconfig). Key subsystems:
libUE4.so.vtableOverride or a known-build record) and locates the live FConsoleManager instance by scanning module rw- and heap rw- ranges for a vtable pointer pattern, validating live TMap entries.ref:int, ref:float, ref:bool, int, float, bool, fstr) to marker addresses and getter functions, and resolves per-kind vtables.CModule ring buffer attached to the AddConsoleObject offset captures CVars registered after attach.FConfigFile hook set — a family of Interceptor hooks gated by individual log toggles.cvars.json and fconfig.json with candidate path fallback.The system is a headless instrumentation tool: it has no graphical UI, no server, and no datastore beyond the JSON and binary artifacts it writes to device storage.
libUE4.so as a constant, so that all hooks reference the correct module.STAGE constant to control activation level (e.g. STAGE ≥ 3 enabling native CVar and FConfig hooks), so that I can gate feature groups.dbg(cat, ...)) with per-category flags (env, stage, calibrate, instance, vtable, native, fconfig, rpc), so that I can enable only the diagnostic output I need.libUE4.so base/size/path, and a sample readable-range VA, so that I can confirm the runtime environment.<belum dimuat> when libUE4.so is not yet loaded, so that load timing is visible.t+Ns) applied to runtime log lines, so that event ordering is traceable.calibrate(mod) step that uses an explicit vtableOverride offset to skip scanning, so that I can pin a known-good offset for a specific build.ok, delta, hits, and the derived vtable pointer, so that I can verify calibration results.manualDelta, minHits, earlyExitHits, and installIfCalibrationFails, so that I can tune or force calibration and decide whether hooks proceed when calibration fails.knownBuild record with size, delta, and vtableOff, so that a recognised build can be identified and used.singletonRva option, so that a singleton can be pinned by RVA where applicable.offset tidak cocok; hook dibatalkan when calibration fails and installIfCalibrationFails is false.rw- ranges and non-file heap rw- ranges for vtable-pointer patterns, so that the FConsoleManager instance can be located without a fixed address.vptr(+0x10) and, when a known build is configured, ZTV(+0), so that multiple layout assumptions are tried.heapScanChunk), budget-limited (instanceBudgetMs), and per-range/timeout logged, so that scans terminate predictably.libRW, and a computed per-pattern budget for heap ranges), so that each candidate is given a bounded attempt.findConsoleMap routine that probes candidate struct offsets to locate the console TMap (data, num, max), so that valid maps are identified by layout inspection.isLiveEntry) that checks the name pointer, string length field, object pointer, and hash-next bounds, so that only genuine entries are enumerated.readFStringAt and readFStringArrayAt readers with bounds checks, so that string and string-array values can be safely extracted.enumerateOnAttach and a maxEnumerate cap (default 300000), so that enumeration on attach is bounded and optional.ref:int, ref:float, ref:bool, int, float, and bool with marker addresses and typed getters, and fstr with no getter, so that each entry's type and value can be resolved.r-- ranges), so that object kinds can be classified.fstr type entries to be annotated as string, nilai nggak dibaca, so that non-read string CVars are clearly marked.inspectObject to return the object's type name, return type, raw value, flags, help text, kind, and note, so that each console entry is fully described.command and all others as cvar, so that output is categorised.detectHelpOff) sampled across candidate offsets, so that help text location adapts to the build.HELP_OFF_VERIFIED) to be tracked per bucket (cvar, command), so that each kind uses a validated offset.Cheat (0x01), CreatedFromIni (0x04), ScalabilityGroup (0x80) — and lists unnamed/unknown bits, so that flag semantics are transparent.SET_BY enum (Constructor, Scalability, GameSetting, ProjectSetting, SystemSettingsIni, DeviceProfile, ConsoleVariablesIni, Commandline, Code, Console), with a "guess" distinction until the game resolves it, so that provenance is clear.TOPBYTE_CHECK status and a SET_BY_GAME resolved table, so that set-by accuracy is tracked.true/false, commands as (command), unread values as <...> — so that console output is readable.records map keyed by entry name with kind, type, value, flags, help, and source, so that state accumulates across enumeration and registration.source = 'registered' to trigger a scheduled JSON write, so that late registrations are persisted.[existing:<type>] <name> = <value> | flags=<flags> | <help>, so that enumeration is human-readable.dedupe mode that skips already-seen names, so that repeated entries are suppressed.[-] vtable belum ketemu or instance FConsoleManager tidak ditemukan when prerequisites are missing, so that failures are explicit.CModule containing a fixed-capacity ring buffer (ENTRY_CAP) to capture (name, obj) at native registration, so that newly registered CVars are recorded with minimal overhead.addObject offset (with delta), reporting the target address, so that the hook point is verifiable.[reg:<type>] ..., so that captured registrations become records.dropped counter and a one-time warning when the native buffer is full, so that lost registrations are known.maxSkipLog), so that malformed entries do not flood output.pendingCvar/pendingCmd until verification or a safety threshold), so that help text is captured once the offset is known.head, tail, emitted, skipped, pending counts, bad, and dropped.enableNativeCVarHook to toggle the native hook, so that I can disable it.autoUnhookMs option to automatically detach the native hook after a delay, so that instrumentation can be time-boxed.nativeUnhook() that clears the drain timer, performs a final drain, detaches the listener, and writes JSON, so that teardown is clean.FCONFIG.enabled switch and per-group toggles (logRead, logProcess, logGet, logSet, logCombine, logWrite, logHierarchy, logOther), so that I can enable only the config activity I care about.logRead to hook Read and record enter (this, path) and leave (ok, path), so that file reads are traced.logProcess to hook ProcessInputFileContents and record the parsed text.logCombine to hook Combine (file) and CombineFromBuffer (buffer).logGet to hook GetString, GetInt, GetFloat, GetInt64, GetBool, GetArray, and GetText, recording section/key/ok/value with type-appropriate reads (int32, float, int64, u8, string array, <FText>), so that configuration reads are decoded.logSet to hook SetString, SetInt64, SetArray, and SetText, recording section/key/value, so that configuration writes are captured.logWrite to hook Write (path, finalize, source) and WriteEx (path, finalize), so that config file writes are logged.logHierarchy to hook AddDynamicLayerToHeirarchy (layer), AddStaticLayersToHierarchy (a,b,c,d), UpdateSections (a,b,c), and UpdateSinglePropertyInSection (a,b,c), so that config hierarchy operations are traced.logOther to hook FindOrAddSection, ShouldExportQuotedString, GenerateExportedPropertyLine, AppendExportedPropertyLine, SaveSourceToBackupFile, Dump, AddMissingProperties, and ProcessPropertyAndWriteForDefaults (type, array, out, name, value), so that auxiliary config operations are captured.[FConfig:<name>] onEnter/onLeave, so that one failing hook does not break the rest.hookAmbiguousA208754 toggle to control the ambiguous hook, so that uncertain hooking can be disabled.maxValueLen, default 512) and array truncation (maxArray, default 64), so that large values do not bloat output.maxEvents, default 100000) that drops oldest events and increments a dropped counter when full, so that memory is bounded.[FConfigFile] <method> key=value ... console line, so that config activity is observable live.fconfigUnhook() that detaches all listeners, clears the pending timer, and writes the FConfig JSON, reporting the number of hooks released.cvars.json to contain meta, cvars, commands, and other arrays, sorted by name, so that the console registry can be consumed offline.meta block to include generation timestamp, library name, module size, offset delta, counts (total/cvars/commands/other), config stage, FConfig summary, flag evidence, and flag statistics (set-by source, top-byte check, set-by counts, flag counts, top-byte raw histogram, low-bits raw histogram).meta.notes to state that values are read values (not defaults), that flags.raw/setByIndex are raw, that setByGuess is a guess until resolved from the game, and that FConfig events are stored separately in fconfig.json.fconfig.json to contain meta (timestamp, library, module size, delta, count, dropped, stage) and an events array./sdcard/Android/data/<pkg>/files/…, /data/data/<pkg>/files/…), then /data/local/tmp/… and /sdcard/Download/…, so that a writable location is found.<<<CVARS_JSON … CVARS_JSON>>> / <<<FCONFIG_JSON … FCONFIG_JSON>>> delimiters when file writing fails, so that data is never lost./proc/self/cmdline, so that output paths are app-scoped.logBatch, default 200 lines) and an out() buffer flushed after 250 ms, so that I/O is efficient.rpc.exports.dump() that re-enumerates existing objects and returns the count.rpc.exports.save() that writes both cvars.json and fconfig.json (with console fallback) and returns their paths.rpc.exports.unhook() that detaches the native CVar hook and reports success or that it was inactive.rpc.exports.unhookfconfig() that detaches all FConfigFile hooks and reports success or that they were inactive.[DBG:rpc] when the rpc debug category is enabled, so that RPC activity is traceable.libUE4.so is already loaded.libUE4.so appears in SPAWN mode.call_constructors hook (when the symbol is found) to trigger start as early as possible, with a fallback message when the symbol is absent.android_dlopen_ext and dlopen hooks that detect when libUE4.so is loaded and trigger start, so that library loading is caught via multiple routes.whenLoaded(name, cb) helper (module check + dlopen hooks + 250 ms polling) for later-loaded modules./storage/emulated/0/Android/data/<pkg>/files, so that dumps land in an app-scoped directory.module, pathFilter (regex), logHot, backtrace, btDepth, rateLimit, slowMs, maxStr, statsMs, and probeOffsets.enabled, dir, pakDir, textDump, maxBinary, pakMax, pakMaxPerHandle, idleMs, sweepMs, and maxRead.tstr, cstr, and fstr, and format helpers for pointers, booleans, integers, hex, int64, offsets, and open modes (ReadOnly, ReadWrite, ReadWriteCreate), so that arguments and returns render consistently.TABLE) where each entry names a function, its argument signature, its return type, its mangled symbol, and options (hot, both, dumps, backtrace, post-processors), so that hooking is declarative.FAndroidPlatformFile (IsLocal, OpenRead, DirectoryExists, IsReadOnly, GetStatData).FPakPlatformFile::IterateDirectoryInternal, FPakFile::GetSharedReader, and FPakCompressedReaderPolicy::Serialize.FCachedReadPlatformFile::OpenRead and FCachedFileHandle::Read.FFileManagerGeneric::CreateFileReader, FindFiles[name], FindFiles[dir+ext], and FindFilesRecursiveInternal, with result counts.FFileHelper::LoadFileToString (string dump) and FFileHelper::LoadFileToArray (binary dump) hooked with character/byte counts.FGenericReadRequest::PerformRequest hooked as a hot path.FSQLiteDatabase::Open (with backtrace), FSQLiteFileFuncs::Open, and FSQLiteFileFuncs::Access (with a result post-processor).AddTagIniSearchPath, ConstructGameplayTagTree, InitializeManager, and DoneAddingNativeTags (enter/leave both).UKuroRenderQualityVolumeManager::RebuildCmdPresetCache, UEngine::InitializeObjectReferences, and UEngine::Init hooked (enter/leave both).statsMs, default 10 s) summary of incremental call counts and drops.rateLimit) using a one-second window, with dropped counts, so that hot paths do not flood output.>) and leave (<) with return value, elapsed ms when slow (slowMs), and optional backtrace (btDepth frames), so that hot vs full tracing is selectable.Thread.backtrace with module/name resolution, so that call origins are identifiable.pathFilter regex to suppress entries whose path argument does not match, so that I can scope logging.OFFSETS) probed with executable-range validation, logging register arguments, and reporting installed/total probe counts, so that unknown functions can be observed.ok/total, and list functions/symbols that were not found or failed, so that coverage gaps are explicit.FPakPlatformFile::OpenRead, with path, chunk list, position, max, and last-activity timestamp.FPakFileHandle<…>::Seek to update the tracked position.FPakFileHandle<…>::Read to capture destination buffers at the tracked offset, appending chunks and advancing position/max, so that a full file is reassembled.maxRead to skip oversized individual reads, so that memory use is bounded.sweepMs) that flushes handles idle beyond idleMs, and reuse-flush when an open handle key is reused, so that files are written when reads stop.pakMax and pakMaxPerHandle skip limits, reporting the reason.../ and slashes, converts backslashes, and clamps each segment to safe characters and a length limit, so that dumps cannot escape the output root.mkdirp to create needed dump directories, with logging on success/failure.DUMP.text to write string dumps (with textDump gating) and fall back to send() when the file write fails.DUMP.bin to write binary dumps honouring maxBinary, and fall back to send() on failure.Persona 1 — Instrumentation Engineer (Reverse-Engineering / Security Analyst) Runs the Frida script against a UE4 Android target, tunes debug and configuration flags, calibrates offsets, verifies that hooks attach, watches live console output (enumerated CVars, FConfig events, hot file/pak operations), and invokes the RPC surface to re-dump, save, or unhook. Needs precise, low-noise, budget-bounded instrumentation with clear failure signals.
Persona 2 — Artifact Analyst (Configuration & Content Analyst)
Consumes the exported artifacts offline — cvars.json, fconfig.json, dumped pak contents, and text/binary dumps — to understand engine configuration state, configuration read/write flows, and packaged content. Needs complete, well-labelled, machine-readable output with provenance metadata (source, flags, set-by, dropped counts).
System actors (not personas): the target UE4 process, libUE4.so, the Frida runtime (including CModule/Gum), and the Android dynamic linker (linker/linker64, dlopen/android_dlopen_ext).
Flow A — Attach-mode CVar & FConfig capture (Instrumentation Engineer)
libUE4.so loaded.start(already, true).vtableOverride or known build); on failure, hooks abort unless installIfCalibrationFails is set.cvars.json is written (debounced).fconfig.json.dump(), save(), unhook(), or unhookfconfig() over RPC, or rely on autoUnhookMs.Flow B — Spawn-mode early capture (Instrumentation Engineer)
libUE4.so is loaded; SPAWN mode is detected.call_constructors hook, and dlopen/android_dlopen_ext hooks watch for the module.start(mod, false/true) runs once (guarded by started).Flow C — Config read/write tracing (Artifact Analyst)
FCONFIG toggles (read/get/set/write/combine/hierarchy/other).[FConfigFile] <method> … and accumulate in fconfig.json.fconfig.json to reconstruct configuration access order and values.Flow D — Pak/content extraction (Artifact Analyst)
dump.enabled.FPakPlatformFile::OpenRead, a handle is tracked; seek/read hooks reassemble content chunk-by-chunk at tracked offsets.text/bin dumps written where configured.Flow E — Output recovery (Instrumentation Engineer)
send() is used as fallback.The toolkit has no graphical interface. Its "visual surface" is the console log and the JSON artifacts, and the following presentation defaults apply to that surface:
[DBG:cat], [ue4], [FConfig], [FConfigFile], [json], [fconfig.json], [reg:<type>], [existing:<type>], [pak dump]).[+], [-], [!], [*], [i]) rather than colour.t+Ns / padded t.xxx t<tid> prefixes so lines align in a monospace column.<<<…JSON delimiters.cvars.json and fconfig.json as the primary visual artefacts; dumped text and binary files mirror the sanitised in-game paths under app-scoped directories.The toolkit's signature concept is a dual-channel, confidence-annotated console registry:
FConsoleManager map and a native registration hook on AddConsoleObject — are merged into a single records map, so the registry is complete regardless of whether entries existed before or after attach.source, decoded flags, an explicit set-by source (with a setByGuess fallback until resolved from the game), and notes clarifying that values are read values rather than defaults. Unknown bits and unnamed flags are surfaced, not hidden.dropped, timeouts, skips), so the tool degrades observably instead of silently.TABLE of (name, signature, return, symbol, options) rows, making the instrumentation surface auditable at a glance.CONFIG, FCONFIG, DBG, STAGE, Part B CONFIG) before injection; runtime control is through the RPC surface (dump, save, unhook, unhookfconfig).onEnter/onLeave, and native registrations arrive asynchronously through a ring buffer drained on a fixed interval.cvars.json writes debounce 3000 ms, fconfig.json writes debounce 2000 ms, pak sweeps run on sweepMs, and stats summaries print on statsMs. The perceived rhythm is steady periodic summaries punctuated by bursty event lines.autoUnhookMs timer; teardown always performs a final drain and a final JSON write before detaching.Process.arch !== 'arm64', noting signatures and offsets are written for arm64).Interceptor, CModule/Gum, Memory.scanSync, NativeFunction, Thread.backtrace).0x800000; instance discovery budget 60000 ms; libRW scan budget 15000 ms; computed per-pattern heap budget of at least 20000 ms; wait-poll interval 200 ms; native drain interval 200 ms; FConfig console flush 250 ms.maxEnumerate 300000; FConfig maxEvents 100000 (drop-oldest with counter); native ring ENTRY_CAP 20000 with dropped counter; maxValueLen 512; maxArray 64; dump maxBinary, pakMax, pakMaxPerHandle, maxRead and maxStr limits.started guard); native and FConfig installers are idempotent (installed/fconfigInstalled guards); path caching avoids repeated path probing.vtableOverride, knownBuild, marker offsets, Part B OFFSETS), so new builds are supported by editing constants rather than code.The accepted delivery shape is a single injectable instrumentation script — no frontend, backend, database, or identity layers are required.
'use strict') executing in the Frida runtime.CModule (incorporating gum/guminterceptor.h) for the CVar registration ring buffer.Interceptor.attach, NativeFunction, Memory.scanSync/Memory.alloc, Process.enumerateRanges/enumerateModules, Module.findGlobalExportByName, DebugSymbol/Thread.backtrace, rpc.exports.libUE4.so (Unreal Engine 4, arm64).linker/linker64 call_constructors), dlopen/android_dlopen_ext.File (read/write/flush/close), and Java.perform + java.io.File (mkdirs) for directory creation.vtableOverride or a configured knownBuild; with neither, calibration reports ok: false and hook installation is skipped unless installIfCalibrationFails is set.FConsoleManager instance is reachable by scanning module rw- and anonymous heap rw- ranges for the vtable pointer pattern, and that its console map is discoverable by struct-offset probing with live-entry validation.setBy names are a UE4 enum assumption (setByGuess) until resolved from the game (SET_BY_GAME / TOPBYTE_CHECK).FText is recorded as the placeholder <FText>; unread/unsupported values are explicitly marked.FPakPlatformFile, FPakFileHandle, seek, and read symbols being present; missing symbols are logged and skipped.OFFSETS probes require the address to fall inside an executable range of the module, or the probe is rejected.command.TMap) of CVars and commands.data, num, max.Cheat (0x01), CreatedFromIni (0x04), ScalabilityGroup (0x80).Constructor, Scalability, GameSetting, Commandline, Console), decoded from the flags' top byte.(name, obj) at AddConsoleObject.Memory.scanSync./proc/self/cmdline, used to build output paths./storage/emulated/0/Android/data/<PKG>/files.dump, save, unhook, unhookfconfig).statsMs.No completed page designs yet.
Completed design pages will appear here when they are ready to preview.
No completed page designs yet.
Completed design pages will appear here when they are ready to preview.
No comments yet. Be the first!