Skip to content

Add macOS readMtgaCards via heap signature scan#3

Open
dan-blanchard wants to merge 1 commit intomtgatool:mainfrom
dan-blanchard:feat/macos-readMtgaCards
Open

Add macOS readMtgaCards via heap signature scan#3
dan-blanchard wants to merge 1 commit intomtgatool:mainfrom
dan-blanchard:feat/macos-readMtgaCards

Conversation

@dan-blanchard
Copy link
Copy Markdown

Adds a macOS-only readMtgaCards napi export that reads the player's card collection from a running Arena process. This bypasses the existing PAPA/WrapperController walker (which returns 0 for PAPA._instance on current macOS Arena builds) by signature-scanning the heap directly for the Dictionary<int,int> that holds the collection.

How it works

The scanner identifies the card-collection dictionary by its data invariant (no IL2CPP metadata walking required):

  • hash == key (the defining property of Dictionary<int,V> with default EqualityComparer<int>)
  • Keys in Arena card-ID range [1, 200000]
  • Values in ownership range [1, 4]
  • Samples 30 entries per candidate, requires 12+ valid
  • Supports optional MTGA_KNOWN_CARD_IDS and MTGA_VERIFY_QTYS env vars for cross-validation when multiple dictionaries pass

This uniquely identifies the live collection dictionary across 200K+ candidate heap positions.

Why the PAPA walker is broken

PAPA._instance reads as 0 on current Arena builds. The likely cause: IL2CPP has separate static field regions for value-type and reference-type statics, and CLASS_STATIC_FIELDS at offset 0xA8 only reaches the value-type region. The signature scan sidesteps this entirely.

What's included

  • scan_heap_for_cards_dictionary + read_cards_dictionary_entries in macos_backend
  • readMtgaCards napi export (macOS-only)
  • NOTES.md documenting the investigation: IL2CPP memory layout, CardPrintingRecord field table (50 fields with offsets), approaches tried
  • Various diagnostic helpers (find_class_by_direct_scan, find_papa_instance_by_field_verification, probe_card_printing_record, etc.) for future reverse-engineering

Testing

Verified against live Arena on macOS arm64 (Unity 2022.3.62f2):

  • readMtgaCards("MTGA") returns ~4300 unique cards in <1s
  • Card IDs and quantities match what's visible in the Arena UI
  • Deterministic across multiple runs against the same process
  • Requires sudo (for task_for_pid)
  • Returns a clear error when Arena isn't running

🤖 Generated with Claude Code

Bypasses the broken PAPA walker by scanning Arena's heap directly for
the card-collection Dictionary<int,int>. Identifies it via the hash==key
invariant for DefaultEqualityComparer<int>.

Returns ~4300 cards in <1s. Requires sudo for task_for_pid.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant