Tags: logic-analyzer keylogger hardware atari

Rating: 0

**Description**

> We have a photo and a CSV file. NOTE: The flag does not follow the CTF{...} format, but is clearly marked as the flag. Please add the CTF{...} around the flag manually when submitting.

**Files provided**

- data.7z - archive containing data.csv
- wires.jpg

**Solution**

Looking at the photo given:

We can see a Saleae logic analyser connected via some jumper cables and probes to a chip. The text on the chip reads:

AMI 8327VT
CO12294B-01
CO3051

With a quick search for the above strings, we can identify the chip as [Atari POKEY](https://en.wikipedia.org/wiki/Atari_POKEY). This chip has many functions on the Atari 8-bit computers. It is probably most notable for being a great sound synthesiser chip (for its price and time).

Here is a pin-out diagram for the chip:

Based on the notch in the top-left corner of the chip, we can figure out which pins of the chip are being probed with the logic analyser. In the top-left corner, two probes are connected to the VCC, which should just be a constant +5V (within tolerance).

More importantly, 8 probes are connected to the pins K0, K1, ..., K5, KR1 and KR2. According to [this datasheet](http://krap.pl/mirrorz/atari/homepage.ntlworld.com/kryten_droid/Atari/800XL/atari_hw/pokey.htm#keyboard%20scan), these pins are related to the keyboard scan functionality of the POKEY.

The keyboard can be thought of as an 8x8 grid. Wires connect the rows and the columns of this grid. At each intersection of horizontal and vertical wire, there is a switch (i.e. the keyboard key). To figure out whether or not a particular key is currently being held, its column is pulled high. If the key is held, this connects the column to the row. Then we just check whether the key's row is high.

The above process is automated in the Atari computers with the assistance of the POKEY chip. Three lines (K0, K1, and K2) lead to a 3-to-8 multiplexer, which interprets the three inputs as a binary number and outputs a digital high on one of its eight outputs (connected to the columns of keyboard grid).

Three other lines (K3, K4, and K5) are connected to a 8-way selector. Once again, the three lines are interpreted as a binary number. One of the selector's 8 inputs (connected to the rows of the keyboard grid) are selected based on the binary number and its value is then available as KR1.

Naturally, the computer does not know which keys to check beforehand; all keys need to be checked all the time. So the POKEY emits a repeating binary sequence on its K0 ... K5 pins, decoding a different key everytime the number changes. The numbers change at 15.7 KHz, so with 64 keys in total, this means all the keys of the keyboard are checked roughly every 4ms.

So we know what is going on with the pins that are being probed. Given that we are looking for a flag, we can expect that somebody typed the flag on the Atari keyboard and the logic analyser recorded this interaction happening. Let's finally have a look at the CSV file.

$head data.csv Time [s],Wire6-Analog,Wire7-Analog, Time [s],Wire0-Digital, Time [s],Wire1-Digital, Time [s],Wire2-Digital, Time [s],Wire3-Digital, Time [s],Wire4-Digital, Time [s],Wire5-Digital, Time [s],Wire6-Digital, Time [s],Wire7-Digital 0.000000000000000, 4.768121242523193, 4.773899555206299, 0.000000000000000, 0, 0.000000000000000, 0, 0.000000000000000, 0, 0.000000000000000, 1, 0.000000000000000, 0, 0.000000000000000, 0, 0.000000000000000, 1, 0.000000000000000, 1 0.000008000000000, 4.768121242523193, 4.773899555206299, 0.000000990000000, 1, 0.000065560000000, 1, 0.000194380000000, 1, 0.000451750000000, 0, 0.000452070000000, 1, 0.001480790000000, 1, 1.468471380000000, 0, 2.503182740000000, 0 0.000016000000000, 4.773141384124756, 4.778934478759766, 0.000065230000000, 0, 0.000194070000000, 0, 0.000451450000000, 0, 0.000965990000000, 1, 0.001480440000000, 0, 0.003537600000000, 0, 1.468535670000000, 1, 2.503689840000000, 1 0.000024000000000, 4.773141384124756, 4.773899555206299, 0.000129540000000, 1, 0.000322660000000, 1, 0.000708600000000, 1, 0.001480170000000, 0, 0.002508920000000, 1, 0.005594510000000, 1, 1.472585100000000, 0, 2.507288860000000, 0 0.000032000000000, 4.773141384124756, 4.773899555206299, 0.000193780000000, 0, 0.000451180000000, 0, 0.000965660000000, 0, 0.001994420000000, 1, 0.003537300000000, 0, 0.007651320000000, 0, 1.472649390000000, 1, 2.507799430000000, 1 0.000040000000000, 4.773141384124756, 4.773899555206299, 0.000258100000000, 1, 0.000579770000000, 1, 0.001222810000000, 1, 0.002508600000000, 0, 0.004565780000000, 1, 0.009708230000000, 1, 1.476698830000000, 0, 2.511395640000000, 0 0.000048000000000, 4.778161048889160, 4.778934478759766, 0.000322340000000, 0, 0.000708280000000, 0, 0.001479880000000, 0, 0.003022850000000, 1, 0.005594170000000, 0, 0.011765040000000, 0, 1.476763110000000, 1, 2.511904320000000, 1 0.000056000000000, 4.778161048889160, 4.778934478759766, 0.000386650000000, 1, 0.000836870000000, 1, 0.001737030000000, 1, 0.003537030000000, 0, 0.006622640000000, 1, 0.013821950000000, 1, 1.480812550000000, 0, 2.515507680000000, 0 0.000064000000000, 4.773141384124756, 4.778934478759766, 0.000450890000000, 0, 0.000965390000000, 0, 0.001994100000000, 0, 0.004051280000000, 1, 0.007651030000000, 0, 0.015878770000000, 0, 1.480876830000000, 1, 2.516015620000000, 1 The format is easy enough to parse, but there is a problem - the digital wires are not labelled. Which wire is K0? Which is the KR1 output? Well, K0 through K5 emit a repeating binary sequence, generated by the POKEY that is completely independent of any user input. We should be able to find this sequence easily: In the CSV file, each of the digital wires has its own set of timestamps, and only changes in the detected values are shown. Our first step is to take samples at 15.7 KHz with the correct current values of each of the digital wires. The simplest way I could think of implementing this is to have a separate file reader per wire, reading lines whenever needed, otherwise reporting the last value. One tiny detail you might notice from the pinout diagram above is that pin names are prefixed with ! - we simply need to invert them to get the "actual" value. We still need to pay careful attention to the notation, since sometimes K values are used directly, sometimes !K values are specified. With this we can visualise a sample of the data captured on the digital wires:$ haxe --run VisualiseWires
▌▌▌ ▌▌
▌▌ ▌▌
▌ ▌ ▌▌
▌ ▌▌
▌▌ ▌▌
▌ ▌▌
▌ ▌▌
▌▌
▌▌▌▌ ▌
▌▌▌ ▌
▌ ▌▌ ▌
▌▌ ▌
▌▌ ▌ ▌
▌ ▌ ▌
▌ ▌ ▌
▌ ▌
▌▌▌ ▌
▌▌ ▌
▌ ▌ ▌
▌ ▌

It is quite clear that the first six digital wires are, in order, K0 through K5, since K0 changes the most rapidly, K1 half as fast, and so forth.

Now we simply need to see what number is indicated by K0 ... K5 whenever KR1 (or rather its inverse) goes high. We need to use a table like [this](https://www.atariarchives.org/c3ba/page004.php).

But there is another problem: printing out the keys whenever KR1 is high produces almost unreadable data:

$haxe -main RawCodes -neko rc.n$ neko rc.n
F F F F F L L L L L A G > S CAPS D > A G > S CAPS D > A G > G G G G G ; ; ; ; ;
(etc)

There is a lot of garbage data there, but we can see FLAG in the beginning, which should be a good sign. The problem is that each letter is repeated multiple times. But this actually makes sense - what if a letter is held for longer than a single full keyboard scan? It will be decoded multiple times. Considering the keyboard is fully scanned each 4ms, it is not very surprising that a key press would be registered on multiple scans.

Additionally, we see some data that is not just letters being repeated. Circuits are not perfect, and we can see some glitches as a result of this. Looking through the actual data, it seems many "ghost" keys are registered immediately after "real" keys are pressed. Another useful observation is that the keys that actually spell out the flag are typed relatively slowly.

So let's only print out key presses which happen at least 100ms after any other, and remove duplicates:

$haxe -main Codes -neko c.n$ neko c.n
F L S G ; 8 - B I T - H A R D W S R E - K E Y L O G E R

It is not perfect, but it is close. A got misread as S in the word FLAG, and it seems the same happened in the word HARDWARE as well. The G got de-duplicated in KEYLOGGER with our script. And indeed, probing the pins of the POKEY chip is a form of a hardware keylogger!

CTF{8-BIT-HARDWARE-KEYLOGGER}