Oct 23, 2014 • Piotr Kordy

At Gunpoint

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