swift-halo

byDimas Muhammad

Halo

No preview

Comments (0)

No comments yet. Be the first!

System Requirements

Page 1 of 15

System Requirements Document

1. Introduction

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:

  1. Console variable (CVar) and console command discovery — enumerating the live FConsoleManager registry, decoding each entry's type, value, flags, and help text, and capturing newly registered CVars at the point of native registration.
  2. FConfigFile instrumentation — hooking the engine's configuration read/combine/write/hierarchy methods to record configuration access and mutation events.
  3. Pak and file-I/O extraction — hooking platform file, pak reader, cached reader, file-manager, 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.

Page 2 of 15

2. System Overview

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:

  • Environment & module discovery — reports Frida/process/module facts and locates libUE4.so.
  • Calibration & instance discovery — resolves the runtime offset delta (via explicit 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.
  • Type model — maps CVar kinds (ref:int, ref:float, ref:bool, int, float, bool, fstr) to marker addresses and getter functions, and resolves per-kind vtables.
  • Enumeration & inspection — walks the console map, inspects each object (type, value, flags, help), and records it.
  • Native registration hook — a 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.
  • Artifact writers — batched JSON writers for cvars.json and fconfig.json with candidate path fallback.
  • Pak/file extractor (Part B) — a symbol-driven hook table, fixed-offset probes, and a pak-handle reassembly/dump engine writing to disk under the app's external files directory.

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.

3. Functional Requirements (User Stories)

3.1 Environment, Module & Stage Control

  • As an instrumentation engineer, I want the script to target the library named libUE4.so as a constant, so that all hooks reference the correct module.
  • As an instrumentation engineer, I want a STAGE constant to control activation level (e.g. STAGE ≥ 3 enabling native CVar and FConfig hooks), so that I can gate feature groups.
  • As an instrumentation engineer, I want a category-scoped debug logging facility (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.
  • As an instrumentation engineer, I want an environment dump that reports Frida version, process architecture, pointer size, platform, page size, the libUE4.so base/size/path, and a sample readable-range VA, so that I can confirm the runtime environment.
  • As an instrumentation engineer, I want the environment dump to report <belum dimuat> when libUE4.so is not yet loaded, so that load timing is visible.
  • As an instrumentation engineer, I want a monotonic timestamp helper (t+Ns) applied to runtime log lines, so that event ordering is traceable.
Page 3 of 15

3.2 Offset Calibration & Runtime Configuration

  • As an instrumentation engineer, I want a 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.
  • As an instrumentation engineer, I want calibration to report ok, delta, hits, and the derived vtable pointer, so that I can verify calibration results.
  • As an instrumentation engineer, I want configuration knobs manualDelta, minHits, earlyExitHits, and installIfCalibrationFails, so that I can tune or force calibration and decide whether hooks proceed when calibration fails.
  • As an instrumentation engineer, I want a knownBuild record with size, delta, and vtableOff, so that a recognised build can be identified and used.
  • As an instrumentation engineer, I want a singletonRva option, so that a singleton can be pinned by RVA where applicable.
  • As an instrumentation engineer, I want the process to abort hook installation and log offset tidak cocok; hook dibatalkan when calibration fails and installIfCalibrationFails is false.

3.3 Instance & Console Map Discovery

  • As an instrumentation engineer, I want heap scanning to search module rw- ranges and non-file heap rw- ranges for vtable-pointer patterns, so that the FConsoleManager instance can be located without a fixed address.
  • As an instrumentation engineer, I want candidate patterns to include vptr(+0x10) and, when a known build is configured, ZTV(+0), so that multiple layout assumptions are tried.
  • As an instrumentation engineer, I want heap scans to be chunked (heapScanChunk), budget-limited (instanceBudgetMs), and per-range/timeout logged, so that scans terminate predictably.
  • As an instrumentation engineer, I want per-target scan budgets (e.g. 15000 ms for libRW, and a computed per-pattern budget for heap ranges), so that each candidate is given a bounded attempt.
  • As an instrumentation engineer, I want the discovered instance cached and revalidated against the current vtable pointer before reuse, so that stale instances are discarded.
  • As an instrumentation engineer, I want a findConsoleMap routine that probes candidate struct offsets to locate the console TMap (data, num, max), so that valid maps are identified by layout inspection.
  • As an instrumentation engineer, I want live-entry validation (isLiveEntry) that checks the name pointer, string length field, object pointer, and hash-next bounds, so that only genuine entries are enumerated.
  • As an instrumentation engineer, I want readFStringAt and readFStringArrayAt readers with bounds checks, so that string and string-array values can be safely extracted.
  • As an instrumentation engineer, I want an option enumerateOnAttach and a maxEnumerate cap (default 300000), so that enumeration on attach is bounded and optional.

3.4 CVar Type Model & Vtable Discovery

  • As an instrumentation engineer, I want a CVar type table covering 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.
  • As an instrumentation engineer, I want to locate per-type vtables by scanning ranges for each type marker (narrow range first, then all non-executable r-- ranges), so that object kinds can be classified.
  • As an instrumentation engineer, I want vtable detection to extend a candidate table start by walking backwards across executable-range pointers, so that the true vtable base is found.
  • As an instrumentation engineer, I want getter failures to be logged without aborting the scan, so that partial type coverage is tolerated.
  • As an instrumentation engineer, I want fstr type entries to be annotated as string, nilai nggak dibaca, so that non-read string CVars are clearly marked.
Page 4 of 15

3.5 Object Inspection, Flags & Value Formatting

  • As an instrumentation engineer, I want 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.
  • As an instrumentation engineer, I want command objects to be bucketed as command and all others as cvar, so that output is categorised.
  • As an instrumentation engineer, I want a HelpText offset auto-detection routine (detectHelpOff) sampled across candidate offsets, so that help text location adapts to the build.
  • As an instrumentation engineer, I want help offset verification (HELP_OFF_VERIFIED) to be tracked per bucket (cvar, command), so that each kind uses a validated offset.
  • As an instrumentation engineer, I want flag decoding that names known bits — Cheat (0x01), CreatedFromIni (0x04), ScalabilityGroup (0x80) — and lists unnamed/unknown bits, so that flag semantics are transparent.
  • As an instrumentation engineer, I want the flags' set-by source decoded from the top byte against the 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.
  • As an instrumentation engineer, I want a TOPBYTE_CHECK status and a SET_BY_GAME resolved table, so that set-by accuracy is tracked.
  • As an instrumentation engineer, I want value formatting per type — floats to 4 decimals, booleans as true/false, commands as (command), unread values as <...> — so that console output is readable.
  • As an instrumentation engineer, I want a JSON value formatter that emits null for unread values and precision-limited numbers/floats, so that artifacts stay machine-readable.
  • As an instrumentation engineer, I want a records map keyed by entry name with kind, type, value, flags, help, and source, so that state accumulates across enumeration and registration.
  • As an instrumentation engineer, I want records captured with source = 'registered' to trigger a scheduled JSON write, so that late registrations are persisted.
  • As an instrumentation engineer, I want flag statistics (set-by counts, flag-name counts, unnamed/unknown-bit counts) and raw-byte histograms (top byte, low bits) computed for the artifact.

3.6 CVar Enumeration Output

  • As an instrumentation engineer, I want enumerated entries logged as [existing:<type>] <name> = <value> | flags=<flags> | <help>, so that enumeration is human-readable.
  • As an instrumentation engineer, I want an optional dedupe mode that skips already-seen names, so that repeated entries are suppressed.
  • As an instrumentation engineer, I want an enumeration summary reporting the processed count and completion timestamp, so that run progress is visible.
  • As an instrumentation engineer, I want enumeration to log [-] vtable belum ketemu or instance FConsoleManager tidak ditemukan when prerequisites are missing, so that failures are explicit.
Page 5 of 15

3.7 Native CVar Registration Hook

  • As an instrumentation engineer, I want a 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.
  • As an instrumentation engineer, I want the native hook attached at the addObject offset (with delta), reporting the target address, so that the hook point is verifiable.
  • As an instrumentation engineer, I want a periodic drain loop (200 ms) that consumes ring-buffer entries and emits them as [reg:<type>] ..., so that captured registrations become records.
  • As an instrumentation engineer, I want a dropped counter and a one-time warning when the native buffer is full, so that lost registrations are known.
  • As an instrumentation engineer, I want invalid native names skipped with bounded skip logging (maxSkipLog), so that malformed entries do not flood output.
  • As an instrumentation engineer, I want deferred handling of entries whose help offset is not yet verified (batching pendingCvar/pendingCmd until verification or a safety threshold), so that help text is captured once the offset is known.
  • As an instrumentation engineer, I want a drain status debug line reporting head, tail, emitted, skipped, pending counts, bad, and dropped.
  • As an instrumentation engineer, I want enableNativeCVarHook to toggle the native hook, so that I can disable it.
  • As an instrumentation engineer, I want an autoUnhookMs option to automatically detach the native hook after a delay, so that instrumentation can be time-boxed.
  • As an instrumentation engineer, I want a nativeUnhook() that clears the drain timer, performs a final drain, detaches the listener, and writes JSON, so that teardown is clean.
Page 6 of 15

3.8 FConfigFile Hooks

  • As an instrumentation engineer, I want a master 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.
  • As an instrumentation engineer, I want logRead to hook Read and record enter (this, path) and leave (ok, path), so that file reads are traced.
  • As an instrumentation engineer, I want logProcess to hook ProcessInputFileContents and record the parsed text.
  • As an instrumentation engineer, I want logCombine to hook Combine (file) and CombineFromBuffer (buffer).
  • As an instrumentation engineer, I want 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.
  • As an instrumentation engineer, I want logSet to hook SetString, SetInt64, SetArray, and SetText, recording section/key/value, so that configuration writes are captured.
  • As an instrumentation engineer, I want logWrite to hook Write (path, finalize, source) and WriteEx (path, finalize), so that config file writes are logged.
  • As an instrumentation engineer, I want 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.
  • As an instrumentation engineer, I want logOther to hook FindOrAddSection, ShouldExportQuotedString, GenerateExportedPropertyLine, AppendExportedPropertyLine, SaveSourceToBackupFile, Dump, AddMissingProperties, and ProcessPropertyAndWriteForDefaults (type, array, out, name, value), so that auxiliary config operations are captured.
  • As an instrumentation engineer, I want per-hook attach success/failure reporting and an active-hook count, so that hook coverage is visible.
  • As an instrumentation engineer, I want any hook handler error to be caught and logged as [FConfig:<name>] onEnter/onLeave, so that one failing hook does not break the rest.
  • As an instrumentation engineer, I want a hookAmbiguousA208754 toggle to control the ambiguous hook, so that uncertain hooking can be disabled.
  • As an instrumentation engineer, I want value truncation (maxValueLen, default 512) and array truncation (maxArray, default 64), so that large values do not bloat output.
  • As an instrumentation engineer, I want a bounded event buffer (maxEvents, default 100000) that drops oldest events and increments a dropped counter when full, so that memory is bounded.
  • As an instrumentation engineer, I want each event to carry a relative timestamp and be emitted as a one-line [FConfigFile] <method> key=value ... console line, so that config activity is observable live.
  • As an instrumentation engineer, I want a fconfigUnhook() that detaches all listeners, clears the pending timer, and writes the FConfig JSON, reporting the number of hooks released.
Page 7 of 15

3.9 Artifact Export

  • As an artifact analyst, I want cvars.json to contain meta, cvars, commands, and other arrays, sorted by name, so that the console registry can be consumed offline.
  • As an artifact analyst, I want the 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).
  • As an artifact analyst, I want 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.
  • As an artifact analyst, I want fconfig.json to contain meta (timestamp, library, module size, delta, count, dropped, stage) and an events array.
  • As an instrumentation engineer, I want JSON writes scheduled with debounce (3000 ms for cvars, 2000 ms for FConfig), so that frequent updates are coalesced.
  • As an instrumentation engineer, I want writer routines to try a cached path first, then package-specific candidate paths (/sdcard/Android/data/<pkg>/files/…, /data/data/<pkg>/files/…), then /data/local/tmp/… and /sdcard/Download/…, so that a writable location is found.
  • As an instrumentation engineer, I want the successful path cached for reuse and the write to report record/event count and file size, so that output location and volume are visible.
  • As an instrumentation engineer, I want a console fallback that prints the JSON between <<<CVARS_JSON … CVARS_JSON>>> / <<<FCONFIG_JSON … FCONFIG_JSON>>> delimiters when file writing fails, so that data is never lost.
  • As an instrumentation engineer, I want the package name resolved from /proc/self/cmdline, so that output paths are app-scoped.
  • As an instrumentation engineer, I want console output batched (logBatch, default 200 lines) and an out() buffer flushed after 250 ms, so that I/O is efficient.

3.10 RPC Export Surface

  • As an instrumentation engineer, I want an rpc.exports.dump() that re-enumerates existing objects and returns the count.
  • As an instrumentation engineer, I want an rpc.exports.save() that writes both cvars.json and fconfig.json (with console fallback) and returns their paths.
  • As an instrumentation engineer, I want an rpc.exports.unhook() that detaches the native CVar hook and reports success or that it was inactive.
  • As an instrumentation engineer, I want an rpc.exports.unhookfconfig() that detaches all FConfigFile hooks and reports success or that they were inactive.
  • As an instrumentation engineer, I want RPC calls to log [DBG:rpc] when the rpc debug category is enabled, so that RPC activity is traceable.

3.11 Process Integration (Attach / Spawn)

  • As an instrumentation engineer, I want automatic detection of ATTACH vs SPAWN mode based on whether libUE4.so is already loaded.
  • As an instrumentation engineer, I want a 200 ms polling fallback that starts instrumentation once libUE4.so appears in SPAWN mode.
  • As an instrumentation engineer, I want a linker call_constructors hook (when the symbol is found) to trigger start as early as possible, with a fallback message when the symbol is absent.
  • As an instrumentation engineer, I want 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.
  • As an instrumentation engineer, I want the start path to run the environment dump, calibration, optional enumeration, native CVar hook, and FConfig hooks in order, guarded so it runs only once.
  • As an instrumentation engineer, I want a whenLoaded(name, cb) helper (module check + dlopen hooks + 250 ms polling) for later-loaded modules.
Page 8 of 15

3.12 Pak & File-I/O Instrumentation (Part B)

  • As an instrumentation engineer, I want Part B to auto-detect the package name and derive an output root under /storage/emulated/0/Android/data/<pkg>/files, so that dumps land in an app-scoped directory.
  • As an instrumentation engineer, I want Part B configuration knobs: module, pathFilter (regex), logHot, backtrace, btDepth, rateLimit, slowMs, maxStr, statsMs, and probeOffsets.
  • As an instrumentation engineer, I want Part B dump options: enabled, dir, pakDir, textDump, maxBinary, pakMax, pakMaxPerHandle, idleMs, sweepMs, and maxRead.
  • As an instrumentation engineer, I want string readers 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.
  • As an instrumentation engineer, I want a symbol-driven hook table (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.
  • As an instrumentation engineer, I want platforms hooked: FAndroidPlatformFile (IsLocal, OpenRead, DirectoryExists, IsReadOnly, GetStatData).
  • As an instrumentation engineer, I want pak layer functions hooked: FPakPlatformFile::IterateDirectoryInternal, FPakFile::GetSharedReader, and FPakCompressedReaderPolicy::Serialize.
  • As an instrumentation engineer, I want cached-reader functions hooked: FCachedReadPlatformFile::OpenRead and FCachedFileHandle::Read.
  • As an instrumentation engineer, I want file-manager functions hooked: FFileManagerGeneric::CreateFileReader, FindFiles[name], FindFiles[dir+ext], and FindFilesRecursiveInternal, with result counts.
  • As an instrumentation engineer, I want FFileHelper::LoadFileToString (string dump) and FFileHelper::LoadFileToArray (binary dump) hooked with character/byte counts.
  • As an instrumentation engineer, I want FGenericReadRequest::PerformRequest hooked as a hot path.
  • As an instrumentation engineer, I want SQLite functions hooked: FSQLiteDatabase::Open (with backtrace), FSQLiteFileFuncs::Open, and FSQLiteFileFuncs::Access (with a result post-processor).
  • As an instrumentation engineer, I want GameplayTags functions hooked: AddTagIniSearchPath, ConstructGameplayTagTree, InitializeManager, and DoneAddingNativeTags (enter/leave both).
  • As an instrumentation engineer, I want UKuroRenderQualityVolumeManager::RebuildCmdPresetCache, UEngine::InitializeObjectReferences, and UEngine::Init hooked (enter/leave both).
  • As an instrumentation engineer, I want a per-symbol call/emission/drop statistics table and a periodic (statsMs, default 10 s) summary of incremental call counts and drops.
  • As an instrumentation engineer, I want per-symbol rate limiting (rateLimit) using a one-second window, with dropped counts, so that hot paths do not flood output.
  • As an instrumentation engineer, I want argument-type validation that rejects unknown signature kinds or return types at hook-build time, so that table errors surface early.
  • As an instrumentation engineer, I want hot-path hooks to log entry arguments, and non-hot hooks to log enter (>) and leave (<) with return value, elapsed ms when slow (slowMs), and optional backtrace (btDepth frames), so that hot vs full tracing is selectable.
  • As an instrumentation engineer, I want optional backtrace capture using Thread.backtrace with module/name resolution, so that call origins are identifiable.
  • As an instrumentation engineer, I want a pathFilter regex to suppress entries whose path argument does not match, so that I can scope logging.
  • As an instrumentation engineer, I want fixed code offsets (OFFSETS) probed with executable-range validation, logging register arguments, and reporting installed/total probe counts, so that unknown functions can be observed.
  • As an instrumentation engineer, I want hook installation to report ok/total, and list functions/symbols that were not found or failed, so that coverage gaps are explicit.
Page 9 of 15

3.13 Pak Handle Reassembly & Dumping

  • As an artifact analyst, I want pak handles tracked by returned pointer from FPakPlatformFile::OpenRead, with path, chunk list, position, max, and last-activity timestamp.
  • As an artifact analyst, I want seek hooks for compressed and plain FPakFileHandle<…>::Seek to update the tracked position.
  • As an artifact analyst, I want read hooks for compressed and plain FPakFileHandle<…>::Read to capture destination buffers at the tracked offset, appending chunks and advancing position/max, so that a full file is reassembled.
  • As an artifact analyst, I want maxRead to skip oversized individual reads, so that memory use is bounded.
  • As an artifact analyst, I want a sweep timer (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.
  • As an artifact analyst, I want flushed files written to the pak dump directory honouring pakMax and pakMaxPerHandle skip limits, reporting the reason.
  • As an artifact analyst, I want path sanitisation that strips leading ../ and slashes, converts backslashes, and clamps each segment to safe characters and a length limit, so that dumps cannot escape the output root.
  • As an artifact analyst, I want path-collision detection that warns when two distinct source paths map to the same local file.
  • As an artifact analyst, I want mkdirp to create needed dump directories, with logging on success/failure.
  • As an artifact analyst, I want DUMP.text to write string dumps (with textDump gating) and fall back to send() when the file write fails.
  • As an artifact analyst, I want DUMP.bin to write binary dumps honouring maxBinary, and fall back to send() on failure.
  • As an instrumentation engineer, I want Part B startup to log module base/size, Frida version, architecture, a warning if the arch is not arm64, and the resolved PKG/OUT_ROOT/dump directories.
Page 10 of 15

4. User Personas

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).

Page 11 of 15

5. Core User Flows

Flow A — Attach-mode CVar & FConfig capture (Instrumentation Engineer)

  1. Inject the script into a running target that already has libUE4.so loaded.
  2. Script detects ATTACH mode and calls start(already, true).
  3. Environment is dumped (Frida/process/module facts).
  4. Calibration resolves the offset (via vtableOverride or known build); on failure, hooks abort unless installIfCalibrationFails is set.
  5. Existing console map is enumerated; type vtables are located; help offsets are verified per bucket.
  6. Entries are logged and recorded; cvars.json is written (debounced).
  7. Native CVar hook and FConfig hooks are installed (STAGE ≥ 3).
  8. Newly registered CVars are drained and emitted; FConfig events stream to console and fconfig.json.
  9. Engineer can call dump(), save(), unhook(), or unhookfconfig() over RPC, or rely on autoUnhookMs.

Flow B — Spawn-mode early capture (Instrumentation Engineer)

  1. Script runs before libUE4.so is loaded; SPAWN mode is detected.
  2. A 200 ms poll, a call_constructors hook, and dlopen/android_dlopen_ext hooks watch for the module.
  3. On first detection, start(mod, false/true) runs once (guarded by started).
  4. Flow A steps 3–8 proceed.

Flow C — Config read/write tracing (Artifact Analyst)

  1. Engineer enables the relevant FCONFIG toggles (read/get/set/write/combine/hierarchy/other).
  2. As the game reads or mutates configuration, events are recorded with section, key, ok, and value (type-appropriate, truncated).
  3. Events appear on console as [FConfigFile] <method> … and accumulate in fconfig.json.
  4. Analyst inspects fconfig.json to reconstruct configuration access order and values.

Flow D — Pak/content extraction (Artifact Analyst)

  1. Engineer runs Part B with dump.enabled.
  2. Symbol hooks log hot file/IO functions; fixed offsets are probed.
  3. On FPakPlatformFile::OpenRead, a handle is tracked; seek/read hooks reassemble content chunk-by-chunk at tracked offsets.
  4. Idle or reused handles are flushed to the pak dump directory (subject to size limits), with text/bin dumps written where configured.
  5. Analyst reviews dumped files and the log for the file/IO sequence.

Flow E — Output recovery (Instrumentation Engineer)

  1. JSON writers try the cached path, then package-scoped candidate paths.
  2. If all fail, the JSON is printed to console between delimiters for external capture.
  3. For text/binary dumps that fail to write, send() is used as fallback.
Page 12 of 15

6. Visuals, Colors and Theme

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:

  • Format: monospace, line-oriented console output; one record per line; prefix tags in square brackets ([DBG:cat], [ue4], [FConfig], [FConfigFile], [json], [fconfig.json], [reg:<type>], [existing:<type>], [pak dump]).
  • Palette: terminal-native (no colour styling imposed by the script); emphasis conveyed by prefix tokens and symbols ([+], [-], [!], [*], [i]) rather than colour.
  • Timestamps: relative t+Ns / padded t.xxx t<tid> prefixes so lines align in a monospace column.
  • Data blocks: JSON emitted as pretty-printed (2-space indent) UTF-8 text, with console fallback wrapped in <<<…JSON delimiters.
  • Artifacts: 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.

7. Signature Design Concept

The toolkit's signature concept is a dual-channel, confidence-annotated console registry:

  • Two capture channels — enumeration of the pre-existing 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.
  • Confidence is first-class. Every recorded entry carries its capture 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.
  • Everything is budgeted. Heap scans, native ring buffers, event buffers, value/array lengths, per-symbol rate limits, and dump sizes all have explicit caps and counters (dropped, timeouts, skips), so the tool degrades observably instead of silently.
  • Declarative hooking. Part B expresses its coverage as a single TABLE of (name, signature, return, symbol, options) rows, making the instrumentation surface auditable at a glance.

8. Interaction Model & Motion Direction

  • Control model: configuration is by editing top-level constant blocks (CONFIG, FCONFIG, DBG, STAGE, Part B CONFIG) before injection; runtime control is through the RPC surface (dump, save, unhook, unhookfconfig).
  • Event model: hook-driven and callback-based; listeners fire onEnter/onLeave, and native registrations arrive asynchronously through a ring buffer drained on a fixed interval.
  • Motion/rhythm: output is batched and debounced rather than immediate — console lines buffer and flush after 250 ms, 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.
  • Termination: hooks can end by explicit RPC teardown or by the autoUnhookMs timer; teardown always performs a final drain and a final JSON write before detaching.
  • Failure transparency: unmet prerequisites, failed attachments, timed-out scans, and dropped captures each emit a distinct, greppable line.
Page 13 of 15

9. Non-Functional Requirements

  • Target platform: Android, arm64 (the toolkit warns when Process.arch !== 'arm64', noting signatures and offsets are written for arm64).
  • Runtime: Frida agent (JavaScript API, Interceptor, CModule/Gum, Memory.scanSync, NativeFunction, Thread.backtrace).
  • Performance budgets: heap scan chunk 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.
  • Memory bounds: 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.
  • Robustness: all reader, hook-handler, scan, and dump operations are wrapped so a single failure logs and continues rather than aborting the agent; symbol attachment failures are collected and reported, not fatal.
  • Fidelity/provenance: records must preserve raw flag values, set-by indices, and capture source, with explicit notes distinguishing read values from defaults and guesses from resolved enum names.
  • Idempotency: start runs once (started guard); native and FConfig installers are idempotent (installed/fconfigInstalled guards); path caching avoids repeated path probing.
  • Data safety: all dump paths are sanitised and confined under the app-scoped output root; path collisions are reported.
  • Portability of offsets: build-specific behaviour is isolated to configurable constants (vtableOverride, knownBuild, marker offsets, Part B OFFSETS), so new builds are supported by editing constants rather than code.

10. Tech Stack

The accepted delivery shape is a single injectable instrumentation script — no frontend, backend, database, or identity layers are required.

  • Language: JavaScript (ES, 'use strict') executing in the Frida runtime.
  • Inline native module: C source compiled at runtime via Frida CModule (incorporating gum/guminterceptor.h) for the CVar registration ring buffer.
  • Instrumentation framework: Frida Interceptor.attach, NativeFunction, Memory.scanSync/Memory.alloc, Process.enumerateRanges/enumerateModules, Module.findGlobalExportByName, DebugSymbol/Thread.backtrace, rpc.exports.
  • Target module: libUE4.so (Unreal Engine 4, arm64).
  • Host integration: Android dynamic linker (linker/linker64 call_constructors), dlopen/android_dlopen_ext.
  • Platform file APIs used for output: Frida File (read/write/flush/close), and Java.perform + java.io.File (mkdirs) for directory creation.
  • Output formats: JSON (pretty-printed, 2-space indent) and raw text/binary dumps.
Page 14 of 15

11. Assumptions and Constraints

  • Offsets, signatures, and vtable overrides are specific to the analysed arm64 UE4 build; other builds require constant updates.
  • Calibration depends on either a provided vtableOverride or a configured knownBuild; with neither, calibration reports ok: false and hook installation is skipped unless installIfCalibrationFails is set.
  • Instance discovery assumes the 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.
  • Type resolution assumes the marker/getter table matches the target build; getter failures degrade value reading but not enumeration.
  • setBy names are a UE4 enum assumption (setByGuess) until resolved from the game (SET_BY_GAME / TOPBYTE_CHECK).
  • Help-text offset is discovered at runtime and verified per bucket; unverified buckets fall back to the CVar offset.
  • FConfig value capture for FText is recorded as the placeholder <FText>; unread/unsupported values are explicitly marked.
  • Pak dumping depends on the relevant FPakPlatformFile, FPakFileHandle, seek, and read symbols being present; missing symbols are logged and skipped.
  • Dump output relies on the app-scoped external files directory being writable; otherwise the JSON console fallback is used.
  • Part B's fixed OFFSETS probes require the address to fall inside an executable range of the module, or the probe is rejected.
  • The delivered script is debug-oriented (a large set of debug categories and verbose logging), so output volume must be managed with the debug flags, rate limits, and size caps.
Page 15 of 15

12. Glossary

  • CVar — console variable; a named engine configuration value with a type, value, flags, and help text.
  • Console command — a registered console entry that is not a value-bearing CVar; bucketed as command.
  • FConsoleManager — the engine object owning the console map (TMap) of CVars and commands.
  • TMap — Unreal's hash map; here, the console registry, described by data, num, max.
  • vptr / ZTV / vtable — the virtual table pointer and its table; used as a scan pattern to find instances and classify types.
  • delta — the runtime offset adjustment applied to static offsets and signatures for the loaded build.
  • vtableOverride / knownBuild — configuration allowing a build's vtable offset and size/delta to be pinned instead of scanned.
  • FConfigFile — the engine's configuration file object; its read/combine/get/set/write/hierarchy methods are hooked.
  • Flag bits — per-entry bitfield; known bits include Cheat (0x01), CreatedFromIni (0x04), ScalabilityGroup (0x80).
  • setBy — the origin that set a CVar (e.g. Constructor, Scalability, GameSetting, Commandline, Console), decoded from the flags' top byte.
  • CModule — Frida's facility for compiling and running inline C, used for the native registration ring buffer.
  • Ring buffer — the fixed-capacity native buffer capturing (name, obj) at AddConsoleObject.
  • Hot hook — a hook that logs only on entry with rate limiting; both — a hook logging enter and leave.
  • Pointer pattern / signature — a byte sequence (here, a little-endian pointer) used by Memory.scanSync.
  • Pak / FPakFileHandle — Unreal's packaged file container and the handle through which its content is read, seeked, and reassembled.
  • PKG — the target application package name, auto-detected from /proc/self/cmdline, used to build output paths.
  • OUT_ROOT — Part B's output root: /storage/emulated/0/Android/data/<PKG>/files.
  • RPC — the exported remote surface (dump, save, unhook, unhookfconfig).
  • STAGE — activation-level constant gating feature groups (STAGE ≥ 3 enables native CVar and FConfig hooks).
  • Dropped — a counter incremented when a bounded buffer discards data (native ring buffer or FConfig event buffer).
  • Stats summary — the periodic per-symbol call/drop report emitted every statsMs.

No completed page designs yet.

Completed design pages will appear here when they are ready to preview.

Landing: Review available artifacts
Artifact Export: Open exported artifacts
Console Registry: Review exported cvar registry
Console Registry: Check flag and set-by provenance
Console Registry: Confirm unread values marked
FConfig Trace: Reconstruct config access order
FConfig Trace: Inspect truncated values
FConfig Trace: Check dropped event counts
Pak Dumps: Review reassembled pak files
Pak Dumps: Check dump path sanitisation
Pak Dumps: Watch for path collisions
Pak Extraction: Review hook coverage and stats
Pak Extraction: Check missing symbol reports
RPC Control: Request a fresh dump
RPC Control: Request artifact save
RPC Control: Handle save failure via console capture
Runtime Control: Rely on auto-unhook for final export

No completed page designs yet.

Completed design pages will appear here when they are ready to preview.

Landing: Review available artifacts
Artifact Export: Open exported artifacts
Console Registry: Review exported cvar registry
Console Registry: Check flag and set-by provenance
Console Registry: Confirm unread values marked
FConfig Trace: Reconstruct config access order
FConfig Trace: Inspect truncated values
FConfig Trace: Check dropped event counts
Pak Dumps: Review reassembled pak files
Pak Dumps: Check dump path sanitisation
Pak Dumps: Watch for path collisions
Pak Extraction: Review hook coverage and stats
Pak Extraction: Check missing symbol reports
RPC Control: Request a fresh dump
RPC Control: Request artifact save
RPC Control: Handle save failure via console capture
Runtime Control: Rely on auto-unhook for final export