14 KiB
Main Game Behavior Notes
Scope
Target:
/games/pokemon_pro/game
Derived analysis artifacts:
analysis/static-triage/game.strings:strings -a -t x /games/pokemon_pro/game.analysis/static-triage/game.objdump-p.txt:objdump -p /games/pokemon_pro/game.
Ghidra project:
- Project
stern, program/games/pokemon_pro/game.
Static caveat: this page is based on rootfs files, strings with offsets, and targeted Ghidra decompilation. It does not include live machine or hardware validation.
Main Game Binary
Confirmed type:
/games/pokemon_pro/gameis a stripped AArch64 PIE executable, 52,829,400 bytes.- SHA-256:
1e5becb85840d0cc7a1d334b7cc43bdb83e51c7c7f8243bead8db679e9ffb22d.
Dynamic dependencies from objdump -p include:
libcrypto.so.3libcurl.so.4libusb-1.0.so.0libgpiod.so.2libEGL.so.1,libGLESv2.so.2,libdrm.so.2,libgbm.so.1libgstapp-1.0.so.0,libgstvideo-1.0.so.0,libgstreamer-1.0.so.0libavcodec.so.59,libavformat.so.59,libavfilter.so.8,libavutil.so.57
Topper Connection and Authentication
The Pokemon topper is represented as an optional Magikarp node-board/mechanism subsystem, not as a USB or network accessory in the evidence reviewed here.
Evidence from /games/pokemon_pro/game strings:
0x258bf30:AD_MAGIKARP_TOPPER_SERIAL_NUMBER_KEY0x258f808:MAGIKARP TOPPER SERIAL NUMBER KEY0x2594a70:Adjustments related to Magikarp Topper.0x2594a98:Magikarp Topper0x25a03c8:Press Select for Magikarp Topper Calibration0x25a03f8:Magikarp Topper Node Board Not Signed0x25a0420:Magikarp Topper Mech Needs Calibration0x25a0448:Magikarp Topper Mech is Disabled0x25b8388:Topper Servos (Optional)0x25b83a8:Topper LEDs (Optional)0x25ce291:Cannot detect Magikarp Topper.0x25ce2b9:Check Interlock switch and cable connections0x25d2f20:Magikarp Node Board Device:0x25d2f3c:Calibrated %d %d %d %d %d0x25d2f74:Not Calibrated0x25f3100:31MagikarpTopperNodeBoardSettings
Inference: the topper connects over the SPIKE node-board bus as one or more node devices, with servos and LED channels exposed to the game. Use is gated by node detection, a node-board signature check, and calibration state. The AD_MAGIKARP_TOPPER_SERIAL_NUMBER_KEY string maps to a serial-derived node-board key path; see topper-serial-key-emulator.md for the recovered 0xfc command and XOR key algorithm.
Topper Node Registration Communication
The Magikarp topper registration/authentication path appears to reuse the generic SPIKE node-board registration path. Static evidence supports this sequence:
-
The game powers and scans the node bus during startup. In Ghidra,
FUN_0090bb00toggles node-bus power/control helpers, calls a node locator (FUN_0090aff0), and updates the expected-node table withFUN_007cbee0(..., 0x20, 2). -
FUN_0090aff0clears a 32-byte discovery buffer, polls node addresses throughFUN_00a23450, stores each discovered address, acknowledges it withFUN_00a26690(address), and marks it throughFUN_00a26700(address, 1). -
Discovered node records live in a global 32-entry table beginning at
DAT_033c0258.FUN_007cbd10(start_address)returns the next present board record.FUN_008e7090formats the diagnostic inventory from this table as:%2d: ver %d.%d.%d, part %s%c, serial %d-%d-%dThe formatted fields come from the board record: node address at offset
0x00, firmware version bytes at0x24..0x26, part string at0x38, part suffix at0x37, and serial fields at0x58,0x5a, and0x5c. -
For each discovered board whose status is
2,FUN_0090bb00callsFUN_00a2b410(address, out_status).FUN_00a2b410sends a node command frame with:byte 0: address | 0x80 byte 1: 0x01 byte 2: 0xff byte 3: 0x08The response is treated as two 32-bit status words.
FUN_0090bb00stores an inverted view of bit0x80000from the second word intoDAT_03431830[address]. -
If board byte
0x9eis not already set,FUN_0090bb00callsFUN_0090a9c0(board_record). This helper performs additional board provisioning/configuration checks. It sends several node commands through the shared frame senderFUN_00a22aa0, including commands0x14,0x40,0x44,0x46,0x48,0x72,0xf2, and0xf8depending on board state. It also reads 64 bytes of board data viaFUN_00a2aad0, which issues repeated command0xf2reads in 8-byte chunks:byte 0: address | 0x80 byte 1: 0x02 byte 2: 0xf2 byte 3: offset byte 4: 0x08 -
FUN_0090a9c0sets board-record flag bit0x4000when its probe/provisioning checks find the board in the unsigned/problem state. The node-board test UI separately enumerates these boards:FUN_00853f80printsUnsigned Board #%dwhen the same flag bit is set. -
After the per-board checks,
FUN_0090bb00calls runtime/configuration helpers includingFUN_00a25290,FUN_007c7b40,FUN_006b4b40,FUN_008cc100,FUN_008eb840, andFUN_007c0710.FUN_006b4b40is the recurring node-board service loop; it sends command frames for runtime/config/device operations such as0x40,0x41,0x42,0x43,0x45,0x4d, and0xf4.
For the topper specifically:
- The topper is exposed to the game as
MagikarpTopperNodeBoardSettings,TopperMech,Topper Servos (Optional),Topper LEDs (Optional), and named servo/LED devices such asSERVO HEAD,SERVO TAIL, andETOPPER ... LED .... - The topper test/calibration UI uses the generic node-board state. It can display
Cannot detect Magikarp Topper.,Magikarp Topper Node Board Not Signed,Magikarp Topper Mech Needs Calibration, orMagikarp Topper Mech is Disabled. - The calibration details callback at
FUN_006a9380reportsMagikarp Node Board Device: Calibrated %d %d %d %d %dusing adjustment IDs0xa6through0xaa, orMagikarp Node Board Device: Not Calibratedif the calibration predicate fails.
Interpretation: the game communicates with the topper control board as a SPIKE node-board at a discovered node address. Registration is not a cloud registration exchange and not a USB/network exchange; it is a local node-bus handshake. The game discovers the board, reads identity/status/version/part/serial fields, sends a status command (0xff), reads additional 64-byte board data with command 0xf2, and then marks the board as signed/usable or unsigned/problem via board-record flags. The recovered Magikarp-specific serial key path reads 16 bytes with command 0xfc and computes (word0 ^ word1 ^ word2 ^ word3) & 0x7fffffff; details and a MicroPython emulator are documented in topper-serial-key-emulator.md.
Stuck-Ball and Lost-Ball Handling
The game has explicit ball-search, lost-ball, and trough replacement behavior.
Evidence from /games/pokemon_pro/game strings:
0x258b878:AD_LOST_BALL_RECOVERY0x258eaa0:Serve a new ball in the event of a lost/stuck ball.0x2595ea0:AUD_TOTAL_BALL_SEARCH_STARTS0x2595ec0:AUD_TOTAL_LOST_BALL_FEEDS0x2595ee0:AUD_TOTAL_LOST_BALL_GAME_STARTS0x25981c0:Total count times the game attempted to find a stuck ball via ball search.0x2598220:Total count times the game determined a stuck ball was lost, and was replaced with a ball from the trough.0x25982a8:Total count times the game determined a stuck ball was lost while starting a game.0x25aba50:SELECT: TROUGH TEST0x25abaa8:%d : Ball%P1//s/% Missing0x25ada30:BALL MISSING0x25ada90:LOCATING BALLS0x25beaf0:TROUGH JAM0x25beb18:SHOOTER LANE
Targeted Ghidra decompilation:
- String
0x026cdee0,%s: MD_EVENT_STABLE - balls_on_playfield = %d, endball_count = %d\n, is referenced byFUN_005e4f20. FUN_005e4f20handlestrough_event_handlerstable events. It computesballs_on_playfieldfrom the total balls in game minus the stable count of balls in devices, logs the number of balls in the trough andendball_count, then pushesballs_on_playfieldinto game state through virtual calls.- For
MD_EVENT_KICK, the same function fires the trough eject coil using a strength adjustment. - For
MD_EVENT_ENDBALL, it logs whether endball processing will be ignored or processed.
Behavior summary: when the game cannot find a ball, it starts ball search and records the event. If it decides the ball is lost/stuck and lost-ball recovery is enabled, it serves a replacement ball from the trough and records a lost-ball feed. If all balls dispensed onto the playfield are physically stuck and no ball returns to a device/trough, static evidence says the game will continue treating those balls as on the playfield, then eventually show missing/locating-ball or device-malfunction paths. It cannot create more replacement balls once the trough is depleted; operator intervention is required to recover the physical balls.
Unexpected Extra Balls
Confirmed behavior:
- The multiball-device subsystem validates impossible device states such as
Too many balls locked,Too many balls in device,Bad lock count after lost ball, andMultiball device system is not stableat offsets0x259eba0,0x259ebe8,0x259ebc8, and0x259ed38. - The trough event handler calculates and propagates a live
balls_on_playfieldcount on stable events. - Game diagnostic text exposes
FG_VALID_PLAYFIELD_ACHIEVED_THIS_BALLat0x259fa88and0x25a4120.
Inference: the game logic does track physical ball accounting and detects inconsistent ball counts in devices. I did not find a distinct string or decompiled branch named "unexpected extra ball on playfield." A loose extra ball on the playfield would be reflected in balls_on_playfield once the trough/device counts stabilize, but the static evidence found here does not prove a special penalty, tilt, or operator alert solely for an unexpected extra playfield ball.
Hidden Buttons and Debug Controls
Accessible without opening the cabinet:
0x258d460: Home Team can be used by holding the left flipper after setup.0x258e138: restart behavior can be allowed by holding the start button.0x258e190: end current game by holding Start plus Left Flipper.0x2597e98: audit text counts games ended by holding left flipper and start.0x25a33b0:HOLD BOTH FLIPPER BUTTONS FOR MORE GAME MODES0x25a3868:HOLD BOTH FLIPPER BUTTONS FOR MENU0x25a5bb8:PRESS BOTH FLIPPER BUTTONS TO SELECT PLAYER0x25a5c38:HOLD BOTH FLIPPER BUTTONS TO MOVE PLAYER BACK TO ROSTER0x25a5e50:HOLD BOTH FLIPPER BUTTONS TO REMOVE GUEST FROM HOME TEAM™0x25a6140:Scan QR to log in or hold left flipper to activate Home Team™
Debug/test controls found in the binary:
0x258c768:AD_DEBUG_MENU_SHOW0x2590af0:DEBUG MENU SHOW0x2590bd8:Test Only: Award Magikarp Letters0x2590c20:Test Only: Start Pikachu vs. Magikarp0x2590c90:GODOT ASSET DEMO0x2590ce0:POKEMON PREVIEW0x2590d40:GODOT PROGRESSION TEST0x259fa40:FG_TEST_MENU_SHOW_DEBUG_ADJUSTMENTS0x259fa68:FG_TEST_MENU_SHOW_DEBUG_AUDITS
Conclusion: I found player-accessible hold/press combinations for login, player selection, game-mode UI, ball launch, restart, and end-game. I did not find evidence of a cabinet-closed secret sequence that directly opens operator diagnostics or debug commands. Debug/test items exist, but the names indicate they are gated by service/test-menu feature flags or adjustments rather than exposed as a hidden public button sequence.
QR Scanner and QR Input Handling
The QR scanner appears as a SPIKE node-board peripheral, not as host-side camera decode logic.
Evidence:
0x25b8418:QR Scanner0x25b8a40:QR SCANNER BACKLIGHT0x25b8a58:QR SCANNER STATUS READY0x25b8a70:QR SCANNER STATUS STRING0x25b8a90:QR SCANNER STATUS ENCODED DATA0x25b8ab0:QR SCANNER STATUS MISSED STRING0x25b8ad0:QR SCANNER STATUS OVERRUN0x25b8af0:QR SCANNER STATUS UNSUPPORTED_AP0x25b8b18:QR SCANNER STATUS FIFO OVERRUN0x25b8c00:QR SCANNER STATUS NO READER0x25dd3e8:Check QR scanner RJ45 nodebus cable0x25dd410:Check QR scanner ribbon cable0x25e26e8:/connectivity/qr_code_storage/0x25e2708:wifi_qr_code
Targeted Ghidra decompilation:
FUN_00913720builds QR scanner status/diagnostic display text. It explicitly choosesCheck QR scanner RJ45 nodebus cableorCheck QR scanner ribbon cabledepending on scanner/node state.- No host-side QR decode library strings such as
zbar,quirc,qrencode, orlibcamerawere found in the game strings.libusb-1.0.so.0is linked, but the QR scanner strings point to nodebus status and cabling.
Insider Connected scan flow evidence:
0x25dd568:ScannedUserAccountUUID0x25dedd0:QET_SCANNED_USER_ACCOUNT0x25de1a0:Authenticating player with back-end server.0x25de1d0:Failed to begin construction of PLAYER_AUTHENTICATE message.0x25ecf18:PLAYER_AUTHENTICATE0x25d3b10:user_uuid0x25df370:{ "machine_uuid": "%s", "user_uuids": [0x25dfa20:/api/v2/game/player_properties0x25e0cc8:Server response to retrieve_player_properties has no body; returned error status %s.0x25e0d20:Server response to retrieve_player_properties has invalid JSON; returned error status %s.0x25e0d80:Server response to retrieve_player_properties has invalid user %s.
Targeted Ghidra decompilation:
FUN_00914520maps netgame action0x10toScannedUserAccountUUID.FUN_00919250maps queue entry type7toQET_SCANNED_USER_ACCOUNTand0x1ftoQET_RETRIEVE_PLAYER_PROPERTIES.FUN_0092d270handles the retrieve-player-properties response. It parses JSON, extractsuser_uuid, converts it withuuid_copy/uuid_unparse, checks whether the UUID maps to a known player object, and logsinvalid JSON,no body, andinvalid userfailures.
Security assessment: the game treats scanned login data as a UUID/account identifier and sends it through the connectivity agent to Stern back-end authentication and player-property APIs. The recovered response-handling path validates JSON shape and user identity against the local player/account model before applying properties. I did not find a static evidence path where arbitrary QR text is directly executed as a command, file path, SQL statement, or shell input. The scanner also reports encoded-data, overrun, unsupported-AP, FIFO-overrun, and no-reader status states. Remaining uncertainty: this pass did not recover the exact QR payload parser or maximum input length checks, so QR input should be considered partially assessed rather than proven memory-safe.