Case file 02

Reading a Game That Cannot Run

Package, ARM/Thumb, symbol, and resource views became a bounded evidence corpus—not a source-code substitute.

Guiding question:How can static package, native, and resource facts become defensible behavior?

Question 01 — How much can metadata really say?

The package exposed several independent static views: Android manifest and signing metadata, app-owned Java and JNI boundaries, one stripped ARM library, printable strings, resource geometry, and surviving symbols. Agreement among views mattered more than any single tool.

Artifact

libgame.so is ELF32 little-endian ARM EABI5 for ARM v5TE. Application functions are predominantly Thumb; the low symbol-address bit identifies Thumb state and the instruction address is normalized with rawAddress & ~1. GNU ARM and LLVM configured for Thumbv5TE were used as independent instruction views.

EvidenceCLM-NATIVE-PROFILE

Method

The deterministic native projection contains exactly 713 explicitly allowlisted, auto-indexed functions. Of those, 553 have direct calls, 684 have numeric constants, and 91 have high-confidence allocated-data string cross-references.

Those numbers describe enrichment fields, not 713 manual semantic reviews. All 713 records have review state auto-indexed; automatic indexing is a map for review, not evidence that a person understood every function.

Contract or decision

Curated public text may describe symbols, addresses, ARM/Thumb rules, constants, calls, strings, and subsystem boundaries. It does not publish instruction bytes, decompiler dumps, analyzer databases, or private paths. Decompiler-like output and disassembly metadata are never labeled original C++ source.

EvidenceCLM-NATIVE-PRODUCT-SURFACE

Proof

Analyzer v3 regenerates the corpus from registered hashes and requires byte-for-byte equality for curated projections. A separate 862-resource census contains 784 PNG, 59 WAV, 3 MP3, and 16 fonts. The reconciliation later classifies 761 consumed, 100 reviewed excluded, one unsupported, and zero unknown dispositions.

EvidenceCLM-ASSET-COUNTS EvidenceCLM-NO-EXTERNAL-GAME-CONFIG

Limit

Static analysis cannot reveal an observed frame, waveform, draw interleaving, or historical device behavior. Indirect calls without a resolved target remain outside the direct-call count. Asset presence does not prove runtime use, historical intent, or redistribution rights.

Next step

The corpus becomes useful when a skeptical reader can follow one fact through the resulting reconstruction.

Stable, shareable chain

Follow one claim from source to proof

Each node is a normal deep link. Selecting it keeps the upstream source, downstream verification, evidence status, and limit in the same reading context.

Seven connected nodes: source APK, derived view, labeled claim, reviewed contract, clean-room TypeScript owner, deterministic test or probe, and reconstruction runtime proof.
Seven connected nodes: source APK, derived view, labeled claim, reviewed contract, clean-room TypeScript owner, deterministic test or probe, and reconstruction runtime proof.
  1. Source

    SRC-APK-001 · hash-identified immutable APK

    Status: recovered

    What it does not prove: No original-runtime observation.

  2. Derived view

    DER-NATIVE-CORPUS-001 · reproducible static corpus

    Status: recovered

    What it does not prove: No native bytes are published.

  3. Claim

    CLM-CLASSIC-BLADE-QUERY

    Status: recovered

    What it does not prove: Product meaning of tag 1437 remains unknown.

  4. Contract

    DER-CLASSIC-PHYSICS-001 · reviewed physics contract

    Status: reviewed

    What it does not prove: Not original C++ source.

  5. Owner

    TypeScript domain + ClassicPhysicsAdapter

    Status: clean-room

    What it does not prove: Does not embed or call libgame.so.

  6. Test

    Adapter tests + DER-PHYSICS2D-EQUIVALENCE-001

    Status: measured

    What it does not prove: Measures the reconstruction backend only.

  7. Runtime

    Android debug + Web Mobile H5

    Status: measured

    What it does not prove: Does not prove historical-runtime identity.

Complete evidence-chain table
LayerArtifact or decisionStatusWhat it does not prove
SourceSRC-APK-001 · hash-identified immutable APKrecoveredNo original-runtime observation.
Derived viewDER-NATIVE-CORPUS-001 · reproducible static corpusrecoveredNo native bytes are published.
ClaimCLM-CLASSIC-BLADE-QUERYrecoveredProduct meaning of tag 1437 remains unknown.
ContractDER-CLASSIC-PHYSICS-001 · reviewed physics contractreviewedNot original C++ source.
OwnerTypeScript domain + ClassicPhysicsAdapterclean-roomDoes not embed or call libgame.so.
TestAdapter tests + DER-PHYSICS2D-EQUIVALENCE-001measuredMeasures the reconstruction backend only.
RuntimeAndroid debug + Web Mobile H5measuredDoes not prove historical-runtime identity.

Question 02 — How does one native fact become safe production behavior?

The representative blade/Physics2D path crosses units, frame timing, query order, filtering, object lifecycle, implementation ownership, and backend proof. It is narrow enough to inspect end to end and rich enough to expose every boundary.

Artifact

Static evidence recovers a PTM ratio of 32 legacy Cocos world units per Box2D metre, gravity (0,-10), and a single variable Step(frameDt * worldSpeed, 10, 10) while physics is active. Blade input owns four touch slots, extends each eligible segment, then raycasts forward and reverse after the physics step.

EvidenceCLM-CLASSIC-PHYSICS-UNITS EvidenceCLM-CLASSIC-BLADE-QUERY

Method

The callback continues through all hits. Results are processed in collected order, with null body metadata, node tag 1437, and disabled-cut objects filtered out. The apparent duplicate guard compares storage addresses rather than fixture values, so the reviewed fidelity default retains repeated fixture occurrences from the two ray directions.

Contract or decision

Creator receives public world coordinates and applies PTM once. The rewrite therefore does not divide ray coordinates by 32 a second time. Pure TypeScript owns deterministic rules and Creator Physics2D owns the engine boundary. Any body/component/node destruction requested during step, contact, or ray work is deferred until the world is unlocked.

Proof

The pinned @cocos/box2d@1.0.2 probe passes trajectory rows at 1/120, 1/60, and 1/30 with iterations 10/10; forward/reverse raycasts preserve the measured repeated sequence; bilateral contact filters pass; direct destroy is rejected while locked; queued destruction succeeds after Step.

Representative blade / Physics2D trace

One rule, four accountable lanes

Select a lane or replay the order. The complete trace remains visible below without JavaScript, and every transformation keeps its evidence status and limit.

1 · Evidence

Cross-checked ARM/Thumb metadata

  1. PTM: 32 legacy Cocos world units = 1 Box2D metre.
  2. One variable Step(frameDt * worldSpeed, 10, 10) while physics is active.
  3. Forward then reverse raycasts preserve order and repeated fixture occurrences.
  4. Body destruction waits until the world is unlocked.

Verification or limit: DER-NATIVE-CORPUS-001 · CLM-CLASSIC-PHYSICS-UNITS · CLM-CLASSIC-BLADE-QUERY

Stage limit: Disassembly metadata is not original C++ source; the original runtime was never observed.

2 · Contract

Reviewed behavioral boundary

  1. Creator receives world coordinates; PTM 32 is not applied a second time.
  2. Gameplay filters exclude null user data, tag 1437, and disable-cut objects.
  3. Forward results precede reverse results without sorting or collider deduplication.
  4. Every lifecycle mutation crosses the after-step queue.

Verification or limit: DER-CLASSIC-PHYSICS-001 · DER-CLASSIC-CUT-SCORE-001

Stage limit: The product meaning of tag 1437 and unsafe native behavior remain unresolved.

3 · Build

Clean-room TypeScript ownership

  1. classic-physics-rules.ts and classic-variable-step.ts own pure rules.
  2. classic-physics-adapter.ts owns PhysicsSystem2D, synchronization, and PTM.
  3. blade-input-controller.ts and classic-cut-query.ts own four tracks and two queries.
  4. Creator public gravity (0,-320) world units/s² represents (0,-10) m/s².

Verification or limit: Cocos Creator 3.8.8 + TypeScript

Stage limit: The build does not embed, call, or mechanically translate the APK or libgame.so.

4 · Proof

Deterministic tests and backend probe

  1. Trajectory passes at 1/120, 1/60, and 1/30 with 10/10 iterations.
  2. Ray result sequence is right, left, right, left; repeats are retained.
  3. Bilateral contact passes and direct destroy is rejected while locked.
  4. Queued destruction succeeds after Step returns.

Verification or limit: DER-PHYSICS2D-EQUIVALENCE-001 · adapter/backend/contact/raycast/lifecycle tests

Stage limit: This measures the reconstruction; originalRuntimeObservation = false.

Complete static trace
StageFacts and ownershipVerification or limit
1 · EvidencePTM: 32 legacy Cocos world units = 1 Box2D metre. One variable Step(frameDt * worldSpeed, 10, 10) while physics is active. Forward then reverse raycasts preserve order and repeated fixture occurrences. Body destruction waits until the world is unlocked.DER-NATIVE-CORPUS-001 · CLM-CLASSIC-PHYSICS-UNITS · CLM-CLASSIC-BLADE-QUERY. Disassembly metadata is not original C++ source; the original runtime was never observed.
2 · ContractCreator receives world coordinates; PTM 32 is not applied a second time. Gameplay filters exclude null user data, tag 1437, and disable-cut objects. Forward results precede reverse results without sorting or collider deduplication. Every lifecycle mutation crosses the after-step queue.DER-CLASSIC-PHYSICS-001 · DER-CLASSIC-CUT-SCORE-001. The product meaning of tag 1437 and unsafe native behavior remain unresolved.
3 · Buildclassic-physics-rules.ts and classic-variable-step.ts own pure rules. classic-physics-adapter.ts owns PhysicsSystem2D, synchronization, and PTM. blade-input-controller.ts and classic-cut-query.ts own four tracks and two queries. Creator public gravity (0,-320) world units/s² represents (0,-10) m/s².Cocos Creator 3.8.8 + TypeScript. The build does not embed, call, or mechanically translate the APK or libgame.so.
4 · ProofTrajectory passes at 1/120, 1/60, and 1/30 with 10/10 iterations. Ray result sequence is right, left, right, left; repeats are retained. Bilateral contact passes and direct destroy is rejected while locked. Queued destruction succeeds after Step returns.DER-PHYSICS2D-EQUIVALENCE-001 · adapter/backend/contact/raycast/lifecycle tests. This measures the reconstruction; originalRuntimeObservation = false.

Limit

The backend probe proves recovered-contract-to-reconstruction-backend equivalence. It does not observe or identify the original runtime. The product meaning of tag 1437, exact native RNG draw interleaving, and memory-unsafe electric-contact layout remain explicit limits.

Next step

The Play route exposes the resulting reconstruction only after an explicit load action.