Category: Reversing

Points: 200

Author: freddy


You’re the sheriff of a small town, investigating news about a gangster squad passing by. Rumor has it they’re easy to outsmart, so you have just followed one to their encampment by the river. You know you can easily take them out one by one, if you would just know their secret handshake..

Download: gunpoint_2daf5fe3fb236b398ff9e5705a058a7f.dat


$file gunpoint_2daf5fe3fb236b398ff9e5705a058a7f.dat
gunpoint_2daf5fe3fb236b398ff9e5705a058a7f.dat: Gameboy ROM: "FLUX", [ROM ONLY], ROM: 256Kbit

Nice, a gameboy ROM. Searching for gameboy emulator gets us Visual Boy Advance as the first result. We need to change the extension to gbc to be able to open the file in the emulator. After running the game for some time or doing options->emulator->speed up toggle, we get:

Gameboy Screen

So probably we need to guess the secret key combination. Fortunately emulator has also dissasembler and IDA is also able to dissaseble the code. Here is some thorough description of Gameboy hardware. The most interesting part is here:

	Name     - P1
	Contents - Register for reading joy pad info
          and determining system type.    (R/W)
       Bit 7 - Not used
       Bit 6 - Not used
       Bit 5 - P15 out port
       Bit 4 - P14 out port
       Bit 3 - P13 in port
       Bit 2 - P12 in port
       Bit 1 - P11 in port
       Bit 0 - P10 in port
     This is the matrix layout for register $FF00:
             P14        P15
              |          |
              |          |
              |          |
              |          |
              |          |
   Example code:
      Game: Ms. Pacman
      Address: $3b1
    LD A,$20       <- bit 5 = $20
    LD ($FF00),A   <- select P14 by setting it low
    LD A,($FF00)
    LD A,($FF00)   <- wait a few cycles
    CPL            <- complement A
    AND $0F        <- get only first 4 bits
    SWAP A         <- swap it
    LD B,A         <- store A in B
    LD A,$10
    LD ($FF00),A   <- select P15 by setting it low
    LD A,($FF00)
    LD A,($FF00)
    LD A,($FF00)
    LD A,($FF00)
    LD A,($FF00)
    LD A,($FF00)   <- Wait a few MORE cycles
    CPL            <- complement (invert)
    AND $0F        <- get first 4 bits
    OR B           <- put A and B together
    LD B,A         <- store A in D
    LD A,($FF8B)   <- read old joy data from ram
    XOR B          <- toggle w/current button bit
    AND B          <- get current button bit back
    LD ($FF8C),A   <- save in new Joydata storage
    LD A,B         <- put original value in A
    LD ($FF8B),A   <- store it as old joy data
    LD A,$30       <- deselect P14 and P15
    LD ($FF00),A   <- RESET Joypad
    RET            <- Return from Subroutine
      The button values using the above method are such:
      $80 - Start             $8 - Down
      $40 - Select            $4 - Up
      $20 - B                 $2 - Left
      $10 - A                 $1 - Right
      Let's say we held down A, Start, and Up.
      The value returned in accumulator A would be $94

If we go to Tools->Dissasemble then we have a fairly good chance we land up in the code that is almost the same. (If not press Next few times) We can see that the result of the key presses are stored in addresses C0A1 and C0A2. Counter at address C0A0 is increased each time we press the correct key. Using Tools->Memory viewer we can see when we press the correct key. The sequence is up, left, down, right, up, left, down, right, B, B A, A.

Flag is tkCXDJheQDNRN

###Other write-ups and resources