# Rev 0 (re, 728p, 23 solved)
In the task we get a simple code:
```python#!/usr/bin/env python3
import flagchecker
print("Enter Flag: ")inp = input()if flagchecker.CheckFlag(inp):    print("Way to Go!")else:    print("Bad Boy!")```
And a [native library](https://raw.githubusercontent.com/TFNS/writeups/master/2020-04-25-IJCTF/rev0/flagchecker.so) to reverse.
## Reversing the library
Flag checking logic is at `0x00100a41`.The logic is pretty clear:
1. User input is collected2. Input is encoded into form of some arrays3. Input is collapsed into a single number4. This number is compared with some constant
### Input encoding stage 1
First step creates some arrays:
```cencoded_input_list = PyList_New((long)input_length);i = 0;while (i < input_length) {  long_value1 = PyLong_FromUnsignedLong(1);  long_value2 = PyLong_FromUnsignedLong(1);  list2 = PyList_New(2);  PyList_SetItem(list2,0,long_value1);  PyList_SetItem(list2,1,long_value2);  PyList_SetItem(encoded_input_list,(long)i,list2);  i = i + 1;}```
Which is pretty much just creating lots of arrays `[1,1]`.
Then:
```cj = 0;while (j < input_length) {  k = 0;  while (k < 8) {    input_char = *(char *)(j + user_input);    list2_ = PyList_GetItem(encoded_input_list,(long)j,(long)j);    long_value3 = PyList_GetItem(list2_,1);    long_value4 = PyList_GetItem(list2_,0);    added_longs = PyNumber_Add(long_value4,long_value3);    PyList_SetItem(list2_,(input_char >> (k & 0x1f) & 1U ^1),added_longs);    k = k + 1;  }  j = j + 1;}```
This is basically:
```pythonlist2 = [1, 1]for i in range(8):    added_longs = list2[0] + list2[1]    list2[(ord(input_char) >> (i & 0x1f) & 1 ^ 1)] = added_longs```
performed for each character of the input.
Notice that since this is done character by character, we don't really need to figure out how to `invert` this logic.We can simply create a lookup table of all possible values:
```pythondef encode_array(input_char):    list2 = [1, 1]    for i in range(8):        two = list2[0] + list2[1]        list2[(ord(input_char) >> (i & 0x1f) & 1 ^ 1)] = two    return list2
reference = {tuple(encode_array(char)): char for char in string.printable}```
This way we can immediately recover the character from such array.
### Input encoding stage 2
Next step is:
```clong_value5 = PyLong_FromUnsignedLong(0);i_ = 0;while (i_ < input_length) {  local_a68 = PyList_GetItem(encoded_input_list,(long)i_,(long)i_);  long_value3 = PyLong_FromUnsignedLong(0x551);  long_value5 = PyNumber_Multiply(long_value5,long_value3,long_value3);  long_value3 = PyList_GetItem(local_a68,0);  long_value5 = PyNumber_Add(long_value5,long_value3,long_value3);  long_value3 = PyLong_FromUnsignedLong(0x551);  long_value5 = PyNumber_Multiply(long_value5,long_value3,long_value3);  long_value3 = PyList_GetItem(local_a68,1);  long_value5 = PyNumber_Add(long_value5,long_value3,long_value3);  i_ = i_ + 1;}```
This performs simple:
```pythonx = 0for i in range(len(data)):    list2 = encoded_input_list[i]    x = x * 0x551 + list2[0]    x = x * 0x551 + list2[1]return x```
Where `encoded_input_list` is the array we got in previous step.If we look at the last step, the final value will be `0x551*x + y`.It's clear that we can therefore just get mod 0x551 to get back `y`.But this property propagates from the start, so we can do mod 0x551 until we recover all numbers:
```pythondef decode_single_pair(number):    y = number % 0x551    number = (number - x) / 0x551    x = number % 0x551    number = (number - y) / 0x551    return y, x, number
def decode(number):    rest = number    results = []    while rest != 0:        a, b, rest = decode_single_pair(rest)        results.append([a, b])    return results[::-1]```
## Recovering comparison constants
Now the last step is just comparison with some constant:
```cconstant_long = PyLong_FromString(&local_228,0,0x10);result = PyObject_RichCompare(constant_long,long_value5,2,long_value5);```
Ghidra made this a bit messy, so it was faster to grab the constant from the debugger.We just run python in gdb, break on `PyLong_FromString` and inspect the pointer at RAX `x/100s 0x7ffffffed7800` to get: `0xc8ec454b3ac5971259b9ec147b62f0543f37a526f4247aed6d318ff4ae3461d79ea5fda8f8632ddc3162f0b4cdb879d3ded85857a900785bbe250be80102e7ae2afd33cf074a9bf5058329e6fda96911e2694463378374a90d4e4e250327c4a0614ba51d4cf396f8a6b9f48f4a8a54e24fce4734b5833fe155ef66155475f6f86a5accd890c9143ba1c12f10515c9e682da44b41a83f49a1494df131f0bd4017cb5fb790d3c2eb183`
# Flag
Now we just run our decoder and get: `IJCTF{r4t10n4l$_4r3_c0unt4bl3_calk1n_w1lf_tr33_n0t_st3rn_br0c0t!}`