mirror of
https://github.com/morluto/rea.git
synced 2026-11-05 06:45:22 +00:00
[GH-ISSUE #5112] [Feature] Resolve Unity IL2CPP method addresses and emit Ghidra seeds (follow-up to #3784) #3150
Closed
opened 2026-10-31 00:37:12 +00:00 by bsakaguchi
·
12 comments
No Branch/Tag specified
main
codex/procedure-reference-stacked
release-please--branches--main--components--rea-agents
release-please--branches--main--components--rea-agents--release-notes
codex/kuna-independent-retry
codex/byte-search-overlay-coverage
codex/open-failure-target-receipt
codex/kuna-xref-evidence
codex/ghidra-ambiguous-procedure-recovery
codex/function-source-bundle
codex/trace-function-integration-prototype
codex/snapshot-source-closure
codex/recorded-evidence-array-pages
codex/evidence-recovery-redesign
codex/trace-feature-address-scope
codex/call-discovery-scope
codex/ghidra-literal-candidate-evidence
codex/decompile-directory-independent-retry
codex/retry-provenance-base
codex/value-flow-capability-experiment
codex/ghidra-containing-instruction
cursor/readme-discord-button-ef9f
dependabot/github_actions/actions/setup-node-7.1.0
dependabot/github_actions/actions/upload-artifact-7.0.2
dependabot/npm_and_yarn/npm-minor-and-patch-d8d97ce6df
codex/kuna-1989
fix/8559-native-ui-fixture-ownership
fix/8555-go-verifier-mcp-ownership
codex/provider-capability-recovery
fix/8642-rizin-target-stdin
codex/ghidra-memory-effect-scope
codex/ghidra-annotation-entry-selector
codex/ghidra-readonly-recovery
codex/ghidra-regex-verifier-recovery
codex/evidence-discovery-view-guidance
fix/8545-bulk-append-overflow
fix/8428-navigation-refusal-alternatives
codex/address-context-recovery
codex/matching-member-limitations
codex/unknown-scope-contract
codex/evidence-view-guidance
feat/8373-native-trace-views
codex/ghidra-snapshot-verifier-binding
codex/elf-export-visibility
codex/evidence-view-recovery
codex/native-reference-cli-help
codex/provider-candidate-observation-scope
codex/kuna-session-verification
codex/ghidra-switch-lifetime-guidance
codex/pseudocode-paging-discovery
codex/clarify-evidence-view-support
codex/kuna-xrefs-selector-recovery
codex/context-capacity-recovery
codex/evidence-closure-large-links
codex/same-function-evidence-identity
codex/ghidra-verifier-inspected-jdk
codex/audit-guided-workflows
codex/crash-prompt-retained-dossiers
codex/analysis-view-error-recovery
codex/kuna-verifier-target-selection
codex/ghidra-selected-project-call-coverage
codex/docs-native-analysis-scope
codex/ghidra-java-socket-boundary
codex/ghidra-retained-snapshot-verifier
codex/ghidra-search-inventory-facts
fix/8284-zero-argument-parameter-bindings
fix/8198-ui-action-handler-offset
fix/8257-elf-entry-label-identity
fix/8304-deferred-output-schema-projection
fix/8277-call-path-computed-target-uncertainty
fix/pr-8089-conflicts
fix/ci-static-duplicate-export
dependabot/npm_and_yarn/lint-staged-17.6.0
dependabot/github_actions/actions/download-artifact-8.0.2
dependabot/npm_and_yarn/write-file-atomic-8.0.0
dependabot/npm_and_yarn/canonicalize-5.1.0
dependabot/github_actions/actions/cache/restore-6.1.0
dependabot/npm_and_yarn/toon-format/toon-4.4.0
dependabot/github_actions/actions/deploy-pages-5.0.1
codex/review-fixes-pr-2403
codex/review-fixes-pr-2400
codex/process-terminal-width
codex/test-brittleness-cleanup
verify/7167-browser-connect-macos
fix/7167-browser-connect
feat/native-matching-allowance-setting
feat/browser-scenario-dry-run
test/managed-caller-parameters-20261024
codex/parser-fortythird-boundaries
fix/6926-pinvoke-platform-decorations-20261023
fix/6889-har-body-encoding-20261023
fix/6888-sqlite-schema-budget-20261023
fix/dependency-security-gates-6708
cursor/evidence-overwrite-rebase-b4ac
feat/4057-verify-native-exports
fix/windows-acl-observer-overhead-20261022
cursor/erlang-beam-restack-4476
cursor/pe-certificate-review-bf32
fix/6116-javascript-application-fs-errors
fix/6061-unmapped-runtime-script-unknown
feat/browser-scenario-summary
fix/pe-certificates
codex/verify-3407
cursor/rebase-5699
cursor/rebase-5352
cursor/rebase-5600
cursor/fix-cli-schema-omission-10a8
codex/audit-hopper-shutdown-reasons-20261021
fix/demangle-swift-omitted-record
fix/nib-boolean-value-types
cursor/cancellation-partial-observation-a5ac
fix/ib-object-limit-reasons
fix/electron-fuse-limit-advice
fix/kuna-doctor-dangling-cache
fix/fixed-budget-refusal-advice
fix/js-ipc-listener-dedup
fix/js-return-member-provenance
fix/dmg-integrity-retry-advice
fix/ida-doctor-readiness
fix/kuna-version-probe-output-drain
fix/legacy-swift-runtime-name-matching
fix/dylib-lazy-load-commands
fix/browser-scenario-startup-cancel
fix/swift-nested-punycode-classification
fix/compare-unselected-scopes
fix/objc-method-budget-coverage
fix/dmg-mounted-root-observations
audit/ci-tests-20261019-round2
release/6.7.0
fix/wabt-cleanup-retry-resolution
fix/electron-fuse-elf-pe-architecture
fix/native-plist-descriptor-ownership
fix/kuna-caller-cleanup-ownership
experiment/atomic-codemode-20261016
review/first-contributor-3776
fix/call-resolution-full-read-cycles
fix/member-mutation-selection-repeat
experiment/atomic-re-tools-20261015
perf/member-mutation-lazy-origins
perf/static-network-mutation-index
fix/hopper-startup-lifecycle
audit/3050-windows-proof-20261015
feat/windows-window-capture-2183
audit/3049-windows-proof-20261015
audit/3735-macos-fixtures-20261015
fix/batch-decompile-null-pseudocode
fix/kuna-inventory-honors-jobs
experiment/browser-codemode-tool-design-20261015
fix/hopper-clean-runtime-argv
codex/review-2049-27f1b367
review-fixes/pr-2787-routing
fix/3360-scoped-this-emitters
fix/3367-replaced-global-effects
fix/3838-compact-any-value-items
test/hopper-download-probe-20261015
codex/windows-runtime-creation-red-green-20261015
codex/windows-readonly-root-red-green-20261015
codex/windows-root-share-red-green-20261015
codex/exp-1685-win-mcp-startup
codex/bug-sweep-20261015
investigate/2190-windows-package-phases
investigate/3543-macos-cli-deadline
perf/3281-reverse-tools-feedback-quality
fix/3406-hopper-doctor-fixture
fix/3341-wrapper-require-test-context
fix/3301-owned-uninstall-fixtures
fix/3164-compiler-input-ownership
fix/pcap-cleanup-stdout-newline-20261014
perf/interface-builder-summary
codex/review-fixes-pr-1977
fix/ghidra-effective-jvm-platform
fix/docs-turkish-rust-link-20261013
fix/main-maintenance-ci-20261010
fix/recover-binary-session-process-effects
codex/review-fixes-pr-2457
codex/ci-required-cancellation-gate
fix/main-format-baseline-20261013
fix/setup-preserve-entry-fields
cursor/restore-main-checks-1ffc
fix/ghidra-bridge-hashmap-import
codex/shared-ci-jadx-json-default-20261013
codex/shared-ci-ghidra-test-groups-20261013
codex/shared-ci-java-fixture-format-20261013
codex/fix-intrinsic-invocation-boundaries
test/release-preflight-reusable-jobs
test/js-parameter-provenance-expectation
fix/linux-hopper-verification-current
test/2419-ghidra-elf-probe-size
followup/pr-1544-native-ida
codex/fold-pr-2230-contribution
docs/readme-responsible-use
fix/issue-2064
fix/issue-2050
fix/issue-2053
fix/issue-1968
fix/issue-1945
experiment/codemode-bridge-20261011
fix/tool-effects-negative-wording-1904-20261012
fix/1842-electron-interop-provenance
feat/recover-javascript-multi-input
refactor/website-i18n-prep
fix/nativeaot-pe-virtual-extent
fix/browser-verifier-ci-hang
fix/pe-resources-input-selection
docs/beginner-friendly-guides
docs/beginner-setup-guide
fix/javascript-analysis-worker-1563
fix/1649-ghidra-duplicate-names
fix/javascript-export-keys-integration-1369
test/maintenance-boundary-contracts-20261011
review/javascript-export-keys-1369
review/process-live-progress-1483
test/javascript-1495-growth-ratio
fix/ci-escape-timing
docs/normalized-terminal-geometry-1450
release/6.3.0
archive/release-6.3.0-pr1381
release/6.2.0
fix/electron-preload-dynamic-override
fix/javascript-self-referential-bundler-edges
release/6.1.0
cursor/grok-client-cherry-pick-0b56
feat/signature-posture
feat/dyld-shared-cache
feat/artifact-integrity-policy
feat/pkg-inventory
release/6.0.0
chore/sync-release-5.0.0
release/5.0.0
cursor/cloud-agent-node-787e
fix/javascript-xhr-open-endpoints
review/pr-711-realpath-fallback-wording
cleanup/replay-confinement
codex/test-suite-performance
codex/issue-foundations
codex/address-open-issues-2026-07-20
agent/javascript-vite-rollup-esbuild-adapters
agent/process-cleanup
agent/triage-integration
agent/unknown-commands-registry
feat/mcp-identity-metadata
morlvps/issue_cleanup
codex/installer-redesign
morl/roadmap-investigation-core
morl/roadmap-investigation-docs
release-please--branches--main--components--rea
rea-agents-6.8.0
rea-agents-6.7.0
rea-agents-6.6.0
experiment/atomic-codemode-wait-runtime-20261016
rea-agents-6.5.0
rea-agents-6.4.0
rea-agents-6.3.0
rea-agents-6.2.0
rea-agents-6.1.0
rea-agents-6.0.0
rea-agents-5.0.0
rea-agents-4.1.0
rea-agents-4.0.1
rea-agents-4.0.0
rea-agents-3.2.1
rea-agents-3.2.0
rea-agents-3.1.0
rea-agents-3.0.0
rea-agents-2.7.0
rea-agents-2.6.0
rea-agents-2.5.1
rea-agents-2.5.0
rea-agents-2.4.0
rea-agents-2.3.0
rea-agents-2.2.0
rea-agents-2.1.0
rea-agents-2.0.0
rea-agents-1.7.0
rea-agents-1.6.0
rea-agents-1.5.0
rea-agents-1.4.0
rea-agents-1.3.0
rea-agents-1.2.0
rea-agents-1.1.0
rea-agents-1.0.0
rea-agents-0.5.0
rea-agents-0.4.0
rea-agents-0.3.0
rea-0.2.1
rea-0.2.0
Labels
Clear labels
area: bridge
area: bridge
area: build
area: build
area: build
area: cli
area: domain
area: evidence
area: mcp
area: native
area: providers
area: runtime
area: server
area: setup
area: tests
bug
design
documentation
enhancement
enhancement
enhancement
experiment
help wanted
i18n
invalid
P0: critical
P1: high
P2: medium
P2: medium
P2: medium
P3: low
performance
provider-request
pull-request
Mirrored from GitHub Pull Request
question
roadmap
triage
No labels
area: bridge
area: bridge
area: build
area: build
area: build
area: cli
area: domain
area: evidence
area: mcp
area: native
area: providers
area: runtime
area: server
area: setup
area: tests
bug
design
documentation
enhancement
enhancement
enhancement
experiment
help wanted
i18n
invalid
P0: critical
P1: high
P2: medium
P2: medium
P2: medium
P3: low
performance
provider-request
pull-request
question
roadmap
triage
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".
No due date set.
Dependencies
No dependencies set.
Reference
morluto/rea#3150
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @alexlanghart on GitHub (Oct 18, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/5112
Before submitting
Area
Native analysis or decompilation
Current limitation
For a Unity IL2CPP build, Ghidra-backed REA tools see
GameAssembly.dll/libil2cpp.soas an unnamed native binary: every method isFUN_*, every metadata pointer and string literal isDAT_*. The names exist inglobal-metadata.dat, and #3807 (first slice of #3607, scoped in #3784) inventories them, but #3784 explicitly leaves out "linking metadata toGameAssemblyorlibil2cpp.so: method addresses, RVAs, symbol injection" as needing its own scope decision. This issue asks for that decision.REA already has the injection half:
REA_GHIDRA_SEED_FILEcreates named functions and labels before auto-analysis. What is missing is producing those seeds from IL2CPP metadata plus the binary's code/metadata registration tables.Use cases
Asking "how does feature X work" questions of a shipped Unity game or app. Today the only route is to run Il2CppDumper outside REA and convert its
script.jsoninto a seed file by hand.Observed on a commercial Unity game (Unity 2022.3, metadata v31, Windows x64, 60 MB
GameAssembly.dll, 17 MBglobal-metadata.dat), REA 6.5.0, Ghidra 12.1.4, JDK 21, WSL2:CodeRegistration/MetadataRegistrationand wrotescript.jsonin ~9 s (220,389 method entries, 124,086 unique method addresses after identical-code folding, 130,048 known method starts).functionseeds (124,086 named, e.g.Class$$Method) and 65,080labelseeds (*_TypeInfo,Method$...,StringLiteral_...).rea decompile --provider ghidrawith that seed file,REA_GHIDRA_STARTUP_TIMEOUT_MS=5400000,GHIDRA_HEADLESS_MAXMEM=9G: seed outcome "9908 functions created, 120140 already present, 0 failed; 65080 labels applied, 0 failed". 23 min 56 s wall, 7.6 GB peak RSS.FUN_*/DAT_*to named callees,*_TypeInfo/Method$...references and readable string-literal labels.thisand parameters stay untyped, so field access is still*(param_1 + 0xb8)and has to be mapped by hand from the dumped field offsets.Desired outcome and success criteria
A static, offline route from a caller-selected IL2CPP binary +
global-metadata.datto Ghidra names, for example:REA_GHIDRA_SEED_FILEformat (or apply equivalent seeds directly to a session), marking names as metadata-derived rather than Ghidra discoveries, as seed limitations already do.this/field layouts from metadata (what Il2CppDumper'sil2cpp.hprovides), which is the biggest remaining readability gap.Success: the measured case above reproduces with no external dumper, and an unsupported version, encrypted metadata or an unlocatable registration returns a typed failure, not partial names.
Expected interaction with targets
Read existing files or captured data
Target and scope details (optional)
Builds on #3807's v29/v31/v39 decoder. Out of scope: decryption or de-obfuscation, runtime dumping, patching. The game used for the measurements is not shared.
Verification available so far
I have a prototype or observed results
Verification details (optional)
Prototype pipeline: Il2CppDumper
script.json→ seed TSV →REA_GHIDRA_SEED_FILE. Validation: zero seed failures, and spot-checked method addresses match the dumper'sdump.cs. No ground-truth symbols exist for the target, so naming correctness beyond the dumper's output is not independently verified.Alternatives considered
set_addresses_namesafter opening: 124k renames through MCP after a 24 min analysis; seeds before analysis are cheaper and also create functions Ghidra missed (9,908 here).ghidra_with_struct.pyon a persistent project: gives typed structs, but REA cannot open a pre-analysed project (#1048, #3751).Possible direction
A provider like #3807's that also reads the native binary, plus an output mode that writes a seed file and a summary of resolved, folded and unresolved methods. #2811 (Delphi VMT → Ghidra seeds) is the same pattern for another runtime and could share the seed-emission contract.
References
docs/installation.md→ "Ghidra import language and analysis seeds"@8rulerstar commented on GitHub (Oct 18, 2026):
Thanks for the measurements; they answer the open question in #3784 better than my self-built samples did.
I have a local prototype of this on top of #3807, not opened as a PR while #3784's scope is undecided:
s_methodPointersper code-gen module) for Mach-O and ELF; ELF appliesR_AARCH64_RELATIVE/R_X86_64_RELATIVEfirst. Checked against symbols: macOS arm64 builds of Unity 2021.3.45f2, 2022.3.30f1, 2022.3.62f3 and 6000.0.84f1 (10,698 / 11,010 / 11,022 / 14,511 methods, all addresses equal to the dSYM), and Android arm64 and x86-64 2022.3.62f3 (10,057 / 10,057 equal tolibil2cpp.sym.so). 32-bit images and Mach-O chained fixups fail as unsupported.--ghidra-seeds PATHwritesNamespace.Type$$Methodfunction seeds in theREA_GHIDRA_SEED_FILEformat at Ghidra's default load base. On the Android arm64 build: 10,031 created, 26 already present, 0 failed, andrea function libil2cpp.so 'Sample.Player.Slot$$Add'resolves and decompiles by name.# folded <address> <kept> also <names>line per group and a count in the result. My builds show no folding, so this is unit-tested only; your MSVC build is where it matters.Not done: PE is parsed but not checked on a real Windows build, and typed
this/fields are out of scope. If a maintainer agrees with the direction here, I can open it as a follow-up PR after #3807, PE verification included.@XinwangTao commented on GitHub (Oct 19, 2026):
Strong +1 for making this a first-class REA scope instead of an external Il2CppDumper + hand-rolled converter pipeline. Naming every FUN_/DAT_ from global-metadata.dat is the single highest-leverage step for Unity IL2CPP reversing.
One practical concern from the numbers you posted: with 130k method seeds and a 15 MB seed file, seed injection already dominates startup (9908 created vs 120140 already present suggests re-running against an analysed project still churns through the full file). I'd ask for a dedup/idempotency contract in the seed producer — e.g. skip seeds whose target address already has a non-FUN_ name, and allow feeding the seed file in chunks or by address range so incremental analysis doesn't re-pay the full injection cost each time.
@alexlanghart commented on GitHub (Oct 19, 2026):
@8rulerstar Thanks, that's further along than I expected. I can help with the PE gap: the build I measured is Windows x64 (MSVC), metadata v31, and folding is substantial there. Il2CppDumper's
script.jsonlists 220,389 method entries but only 124,086 unique method addresses. If you share the branch, I can run your--ghidra-seedsoutput against it and report the address agreement with Il2CppDumper (matching, differing, missing) plus the folded-group counts, without sharing the binary itself.@alexlanghart commented on GitHub (Oct 19, 2026):
@XinwangTao A clarification on the numbers: that was a single fresh import, not a re-run. Seeds are applied once in a pre-script before auto-analysis, and "120,140 already present" means Ghidra's PE loader had already created those functions from the exception directory (
.pdata) before the seed script ran. I didn't time seed injection separately, so I can't say it dominates; most of the ~24 min was default auto-analysis.Paying the full cost on every session is the real issue, and that's #1048/#3751 (reusing analyzed programs) rather than seed idempotency. For what it's worth, I'm running a patch for that on my fork:
feat/ghidra-gzf-reuse. It addsREA_GHIDRA_PROGRAM_ARCHIVE_DIR: the first session saves the analyzed program as a.gzfkeyed by target SHA-256 + analysis profile digest, and later sessions import it with-noanalysisinto the usual ephemeral project (the bridge still checks the executable digest and the stored key). On this target the second open went from 26 min 53 s / 7.5 GB peak to 21.6 s / 1.9 GB, with byte-identical decompilation. It also addsREA_GHIDRA_SEED_DIRfor per-target seed files. Not proposed as a PR; just a data point for #1048.@arielfikru commented on GitHub (Oct 19, 2026):
An Android/ELF data point to go next to the Windows x64 one. The ratio flips here: on a stripped ARM64
libil2cpp.so, the seeds create almost every function instead of topping up what the loader already found.Target: a commercial Unity 2022.3 Android game (
libil2cpp.so, ELF64 AArch64ET_DYN, stripped, 45 MB). Il2CppDumperscript.json(105,678ScriptMethod). Run on REA main ate4c3d7239, Ghidra 12.1.4, JDK 21, macOS arm64, usingrea decompile --provider ghidrawithREA_GHIDRA_SEED_FILE,REA_GHIDRA_STARTUP_TIMEOUT_MS=5400000andGHIDRA_HEADLESS_MAXMEM=9G.Addresses)Three things this adds for the scope decision:
.pdata, the seeds are the function boundaries. Ghidra's ELF loader found 128 functions on its own; the other 99.9% came from the seed file. So for ELF the address-resolution step is not an optional extra on top of analysis. It decides whether the methods exist as functions at all.ET_DYNat0x100000, so each seed isRVA + 0x100000. A resolver inside REA would need to take the base from the loaded program for ELF, the same way asImageBasefor PE, rather than writing RVAs. With the right base, 0 seeds fell outside initialized memory.Output quality,
HumanCustomer$$GetPatienceMax: 65 lines of pseudocode with the method names,*_TypeInfoandMethod$...labels resolved (game_Player__GetUseCustomerItem,java_util_Vector<object>__Size(..., Method_java_util_Vector<HumanClerk>_Size__)). The logic matches what I recovered by hand earlier: base 200, or 400 with an item, plus a percentage from each clerk's skill 14. The il2cpp throw stub at the end was flagged no-return by default auto-analysis, and REA reports it as a terminal-call limitation. In an earlier pipeline of mine without auto-analysis, those stubs were not no-return and the decompiler ran into the next function, so default analysis matters here. I checked only this one function under REA, not the whole binary.Not investigated: default analysis also logged 2,562
GccExceptionAnalyzer"Failed to disassemble" errors in0x02a2xxxx. I can't say yet whether they come from the seeds or from the file itself.The converter is about 40 lines of Python (unique
ScriptMethodaddresses named, first name wins; the remainingAddressesentries unnamed;ScriptMetadata,ScriptMetadataMethodandStringLiteral_<n>as labels; whitespace in names replaced, since the seed format rejects it). If a--ghidra-seedsbranch appears, I can run it against this build and report address agreement with Il2CppDumper. I won't share the binary.@8rulerstar commented on GitHub (Oct 19, 2026):
@alexlanghart @arielfikru thanks, both offers are very welcome. The branch is here, on top of #3807 (not a PR; it waits for the scope decision in #3784):
https://github.com/8rulerstar/rea/tree/exp/il2cpp-ghidra
For Android, pass
libil2cpp.soas--binary.report.jsonis an Evidence envelope.normalized_result.method_addresseshas one{address, rva}per method index at link-time addresses,nullwhen the module records no body (abstract, extern and most generic methods).seeds.tsvhas oneNamespace.Type$$Methodfunction seed per address at Ghidra's default load base:ImageBasefor PE, and0x100000for an ELF linked at 0, as @arielfikru noted above. That is why seed addresses can differ fromaddressin the report. An Il2CppDumperScriptMethodaddress plus that base should equal a seed address. Use--seed-base 0x...if you import at another base. Shared addresses add# folded <address> <kept> also <names>lines. An existing seed path is refused before decoding.Before asking you, I checked PE on the one public Windows IL2CPP build I could find: Between Two Worlds 1.0.5 (MIT, Unity 2023.2.13f1, metadata version 29). It found a real bug: this build pads strings with
0xFF, so a module name had no NUL in front of it and linking failed; that is fixed on the branch. After the fix, the branch links 43,198 methods at 34,485 unique addresses, and every one of those addresses carries the same method name in Il2CppDumper'sscript.json. Il2CppDumper lists 57,109 unique addresses; the other 22,624 hold only names with a generic argument list (<...>). Folding puts 10,448 methods on 1,735 shared addresses.One build I could not link: that game's Linux x86-64
GameAssembly.sohas every module record but no staticcodeGenModulespointer in its data or relocations. Il2CppDumper fails on it too. The branch fails closed withcode-registration-not-found.What would help most from your builds: address agreement with Il2CppDumper among non-generic methods (matching, differing, missing), the folded-group count, and any failure reason with the Unity version.
@alexlanghart commented on GitHub (Oct 19, 2026):
@8rulerstar Ran
exp/il2cpp-ghidra(554ffa1c9) on the Windows x64 build: Unity 2022.3, metadata v31, MSVC, 60 MBGameAssembly.dll. It linked in 5.8 s (1.0 GB peak) and found the code-gen module array with no failures.script.json(RVA +ImageBase0x180000000): 111,771 match, 0 differ, 0 missing, 0 extra. That includes 7,584 explicit interface implementations (…$$System.Collections.Generic.IEnumerator<System.Object>.get_Current).# foldedlines.I didn't run Ghidra with these seeds; the comparison was address-level only. I can do a seeded decompile if that would help.
@arielfikru commented on GitHub (Oct 19, 2026):
@8rulerstar I ran
exp/il2cpp-ghidra(554ffa1c9) on the Android build from my earlier comment (Unity 2022.3, metadata version 31; the arm64-v8alibil2cpp.sois the same file, sha2569fc9d76e…). As-is it fails to link because of a zero-filled method pointer array. With a small local patch it links, and every seed agrees with Il2CppDumper.1. As-is:
code-gen-modules-not-foundChecked against the binary with my own ELF reader, independent of the branch:
methodPointerCountmethodPointersR_AARCH64_RELATIVEUnityEngine.Purchasing.AppleCore.dll0x29436e8(.data.rel.ro)0x2b2b9f0in.bssAssembly-CSharp.dll(for comparison)0x284adf8(.data.rel.ro)0x29d0918in.dataThe record exists, its name pointer is a normal relative relocation, and the count matches. The array sits in
.bssbecause the iOS-only purchasing assembly has no bodies on Android: six zero pointers, never written to the file.findModuleskeeps a candidate only ifisMapped(image, pointers, count * 8), which accepts file-backed ranges only, so the one real record is dropped. Getting past that, the pointer table then fails withinvalid-method-pointer: ... method pointer 0 is not file mapped, becausereadPointerreturnsnullfor zero-fill.2. Local patch (+17/−2 in
src/il2cpp/Il2cppBinaryFile.ts)An
isZeroFilled(image, address, size)helper overimage.container.zero_fills, used in two places:findModulesalso accepts an array that lies entirely in a zero-fill range, and the pointer table reads a zero-filled slot as0n(no body, same path as other null entries) instead ofnull. The branch's 7 il2cpp test files (83 tests) andtsc --noEmitpass with it. Diff below; happy for you to take it or do it differently. A fixture for it would need a module whose array lies pastp_fileszin a PT_LOAD.patch
3. Agreement with Il2CppDumper (patched, arm64-v8a)
method_addressesnull)System.Action<bool>$$.ctor,System.HashCode$$Add<int>)# foldedlines: 0; consistent with my earlier observation that this toolchain doesn't fold)Comparison: Il2CppDumper
ScriptMethod.Address + 0x100000against the seed address, and the seed name in the set of Il2CppDumper names at that address. "Generic instance" means a type or method argument list remains after compiler-generated names (<>c,<X>b__,<X>d__,k__BackingField) are stripped. Linking took about 2 s.4. armeabi-v7a (same APK): fails closed as documented
@8rulerstar commented on GitHub (Oct 19, 2026):
@arielfikru thank you very much for taking the time to run this and for tracking it down so precisely. It was a real bug, and your diagnosis was exactly right. I've fixed it in 233ca4d38, following the same approach as your patch: a method pointer array that lies wholly inside zero-fill is now accepted, and its slots are read as methods without bodies. I also added an ELF fixture whose second module keeps its array past
p_filesz, and checked that the new test fails if either half of the fix is reverted. Thank you as well for the armeabi-v7a check.@alexlanghart thank you again for the Windows numbers. Before asking you for anything more, I'm running a seeded Ghidra decompile on the public Windows build myself, so that I can say concretely what to look for. I'll follow up here once I have the result.
@8rulerstar commented on GitHub (Oct 19, 2026):
@alexlanghart following up as promised: I ran a seeded Ghidra 12.1.4 decompile on the public Windows build (Between Two Worlds 1.0.5, 34 MB
GameAssembly.dll).With
REA_GHIDRA_SEED_FILEset,rea decompilefoundIngameDebugConsole.DebugLogManager$$ShouldRemoveLogEntryToShowby name, and Ghidra named the function at its seed address0x180c5ca60IngameDebugConsole_DebugLogManager__ShouldRemoveLogEntryToShow(each.and$becomes_). Without seeds, the same address shows up asFUN_180c5ca60with the same body. This is one function on one build, so it shows the seed path works on PE, not that every seed applies.Each run took about 9 minutes, over the default 5.5-minute startup limit, so I raised
REA_GHIDRA_STARTUP_TIMEOUT_MS(to 3 hours; @arielfikru's 90 minutes above is also plenty). Larger builds need a limit above their own analysis time.There is nothing more I need from your build for this. Thanks again for the address check.
@8rulerstar commented on GitHub (Oct 20, 2026):
#3784 was closed by the #3807 merge, so I've opened the follow-ups as drafts:
--ghidra-seeds, stacked on #5326.#5327 includes the zero-fill fix based on @arielfikru's diagnosis of the
.bssmethod pointer array, with a fixture for it. For PE, @alexlanghart's Windows x64 comparison (111,771 match, 0 differ against Il2CppDumper) is cited next to the public Between Two Worlds build. Each method row now sayscode,no-bodyorunknowninstead of a bare null. Generic method instances will follow in a separate PR.@XinwangTao commented on GitHub (Oct 20, 2026):
Thanks @alexlanghart for the clarification — that reframes the cost concern: if the 120k "already present" were created by the .pdata loader before the seed script, then seed injection is a cheap top-up on PE, and the real repeat-session cost belongs to program reuse (#1048/#3751), not to seed idempotency. Agree that a gzf-keyed reuse cache is the right lever there.
@arielfikru's ELF data point makes the scope decision much stronger: on stripped ELF the seeds are the function boundaries (99.9% created), so for Android IL2CPP the address-resolution step is not an optimization but the core capability. The RVA + load-base (0x100000) note is a good trap for the resolver design.
Great to see exp/il2cpp-ghidra validated on both PE (111,771 name matches, folding groups working) and ELF (58,901 seeds agreeing with Il2CppDumper, zero-fill fix in 233ca4d). I'd encourage opening this as a follow-up PR after #3807 lands — the PE and ELF evidence together covers the decision well.