ReversingScripting

1 year ago - 101 views

4 - Electronics Research Lab

This challenge is about reversing what a piece of C code does. We get a file with a bunch of function calls and need to look at what exactly it does behind the scenes. Myself being a noob at C programming, I was a bit intimidated by the challenge and doubted if I could solve it. But using logical thinking and looking up documentation online it was a very doable challenge.

The Challenge

After downloading and extracting the zip we get a file called chal.c containing lots of function calls to some gpio library:

C

#include <stdbool.h>

#include "hardware/gpio.h"
#include "hardware/structs/sio.h"
#include "pico/stdlib.h"

int main(void)
{
    for (int i = 0; i < 8; i++) {
        gpio_init(i);
        gpio_set_dir(i, GPIO_OUT);
    }
    gpio_put_all(0);

    for (;;) {
        gpio_set_mask(67);
        gpio_clr_mask(0);
        sleep_us(100);
        gpio_set_mask(20);
        gpio_clr_mask(3);
        sleep_us(100);
        gpio_set_mask(2);
        gpio_clr_mask(16);
        sleep_us(100);
        ... // About 120 lines of this
        gpio_set_mask(2);
        gpio_clr_mask(117);
        sleep_us(100);

        gpio_put_all(0);
        sleep_ms(500);
    }

    return 0;
}

There was also a file called pico.uf2. I'm did not use this in my solution but it can probably be used to solve the challenge in a different way.

Analysing

I was interested in what all these function calls were in the for loop. Looking at the first value it looks like possibly an ASCII value, and converting it to ASCII results in the capital letter C. All the previous flags were in the format CTF{...} so the first character being a C is pretty likely.
But the rest of the numbers seem not to be in any ASCII range, meaning we need to do more digging.

Searching the function name gpio_set_mask and gpio_clr_mask on Google gives us documentation on what they do.
From gpio_set_mask() I found that the set function sets all bits in the mask given as the argument to high or 1.
And gpio_set_mask() does a similar thing but instead sets all the bits in the mask to low or 0.
Then you can see the value that it is changing as a global variable, that all the functions work on.
Now it also makes sense why the rest of the values don't seem like ASCII, because we keep changing bits of the previous value, iterating on it over and over.
It is likely that every time the sleep_us function is called we have a value to read and a letter of the flag.

Solution

Now we can use something like Python to do this for us and display the letter each time through the whole code.
To simulate gpio_set_mask(), by setting all bits of our global variable to high if the mask has a 1 in that place, we can simply use an OR gate with the two. In Python, this is the | operator. So we can simply use value |= mask to do this operation.
Next, we need to simulate gpio_set_mask(), by settings all the bits of our global variable to low if the mask has a 1 in that place. We can again use a simple NAND gate because this will first invert the mask, and then set all bits that are 0 in the mask to 0 in the global value. In Python, this is also simple to do with value &= ~mask because ~ inverts the value bitwise, and then the & to AND the two values together. Finally, we can use the sleep_us() function to print the current value as an ASCII value. And don't forget to set the end of the print statement to an empty string as Python automatically adds newlines after every print.

Combining all this with the function calls we get the following script:

Python

value = 0

def gpio_set_mask(mask):
    # Set high
    global value

    value |= mask

def gpio_clr_mask(mask):
    # Set low
    global value

    value &= ~mask

def sleep_us(_):
    print(chr(value), end="")

gpio_set_mask(67)
gpio_clr_mask(0)
sleep_us(100)
gpio_set_mask(20)
gpio_clr_mask(3)
sleep_us(100)
gpio_set_mask(2)
gpio_clr_mask(16)
sleep_us(100)
gpio_set_mask(57)
gpio_clr_mask(4)
sleep_us(100)
gpio_set_mask(0)
gpio_clr_mask(25)
sleep_us(100)
gpio_set_mask(5)
gpio_clr_mask(2)
sleep_us(100)
gpio_set_mask(18)
gpio_clr_mask(65)
sleep_us(100)
gpio_set_mask(1)
gpio_clr_mask(2)
sleep_us(100)
gpio_set_mask(64)
gpio_clr_mask(17)
sleep_us(100)
gpio_set_mask(2)
gpio_clr_mask(0)
sleep_us(100)
gpio_set_mask(1)
gpio_clr_mask(6)
sleep_us(100)
gpio_set_mask(18)
gpio_clr_mask(65)
sleep_us(100)
gpio_set_mask(1)
gpio_clr_mask(0)
sleep_us(100)
gpio_set_mask(4)
gpio_clr_mask(2)
sleep_us(100)
gpio_set_mask(0)
gpio_clr_mask(0)
sleep_us(100)
gpio_set_mask(64)
gpio_clr_mask(16)
sleep_us(100)
gpio_set_mask(16)
gpio_clr_mask(64)
sleep_us(100)
gpio_set_mask(2)
gpio_clr_mask(4)
sleep_us(100)
gpio_set_mask(0)
gpio_clr_mask(3)
sleep_us(100)
gpio_set_mask(9)
gpio_clr_mask(0)
sleep_us(100)
gpio_set_mask(0)
gpio_clr_mask(1)
sleep_us(100)
gpio_set_mask(0)
gpio_clr_mask(8)
sleep_us(100)
gpio_set_mask(8)
gpio_clr_mask(0)
sleep_us(100)
gpio_set_mask(65)
gpio_clr_mask(24)
sleep_us(100)
gpio_set_mask(22)
gpio_clr_mask(64)
sleep_us(100)
gpio_set_mask(0)
gpio_clr_mask(0)
sleep_us(100)
gpio_set_mask(0)
gpio_clr_mask(5)
sleep_us(100)
gpio_set_mask(0)
gpio_clr_mask(2)
sleep_us(100)
gpio_set_mask(65)
gpio_clr_mask(16)
sleep_us(100)
gpio_set_mask(22)
gpio_clr_mask(65)
sleep_us(100)
gpio_set_mask(1)
gpio_clr_mask(6)
sleep_us(100)
gpio_set_mask(4)
gpio_clr_mask(0)
sleep_us(100)
gpio_set_mask(66)
gpio_clr_mask(21)
sleep_us(100)
gpio_set_mask(1)
gpio_clr_mask(0)
sleep_us(100)
gpio_set_mask(0)
gpio_clr_mask(2)
sleep_us(100)
gpio_set_mask(24)
gpio_clr_mask(65)
sleep_us(100)
gpio_set_mask(67)
gpio_clr_mask(24)
sleep_us(100)
gpio_set_mask(24)
gpio_clr_mask(67)
sleep_us(100)
gpio_set_mask(2)
gpio_clr_mask(8)
sleep_us(100)
gpio_set_mask(65)
gpio_clr_mask(18)
sleep_us(100)
gpio_set_mask(16)
gpio_clr_mask(64)
sleep_us(100)
gpio_set_mask(2)
gpio_clr_mask(0)
sleep_us(100)
gpio_set_mask(68)
gpio_clr_mask(19)
sleep_us(100)
gpio_set_mask(19)
gpio_clr_mask(64)
sleep_us(100)
gpio_set_mask(72)
gpio_clr_mask(2)
sleep_us(100)
gpio_set_mask(2)
gpio_clr_mask(117)
sleep_us(100)

This goes through all the code and prints the flag character by characters resulting in the challenge flag!
CTF{be65dfa2355e5309808a7720a615bca8c82a13d7}