# Mental adventure: call the orderlies (PIC, 490p, 9 solved)
This is another PIC challenge to work on.We have the same kind of [PIC binary](https://raw.githubusercontent.com/TFNS/writeups/master/2020-03-01-AeroCTF/mental_orderlies/Smth.HEX), and we can again load it to ghidra selecting PIC16F as architecture.Apart from the binary we also get a [video](https://raw.githubusercontent.com/TFNS/writeups/master/2020-03-01-AeroCTF/mental_orderlies/EncryptedMessage.mp4).
We can see there the display showing some characters.We can scrap those to get `{W7C0RC9JERQ2RW42J{VUXUVFS`.
The code is surprisingly similar to the one from `beginning`.We have almost identical loop, but this time there are 2 changes:
```c  DAT_DATA_0024 = param_1;  while( true ) {    DAT_DATA_0025 = FUN_CODE_0f00(DAT_DATA_0024);    DAT_DATA_0020 = -0x56 - (DAT_DATA_0025 ^ 0x87);    FUN_CODE_0016();    FUN_CODE_000e();    if (DAT_DATA_0025 == 0) break;    DAT_DATA_0024 = DAT_DATA_0024 + '\x01';  }  return DAT_DATA_0025;```
First difference is that result of `FUN_CODE_0f00` functions is now modified by `DAT_DATA_0020 = -0x56 - (DAT_DATA_0025 ^ 0x87);` before it reaches `FUN_CODE_0016`.This we can easily invert by:
```python0xFF & (-(val + 0x56) ^ 0x87)```
Second twist comes from the `FUN_CODE_0f00` function itself.In the first problem this function was pretty much sending plaintext flag data.Here it got patched and returns only 0.
So we need to figure out the values supplied by this function by looking at the display.
It took us a while to understand how `FUN_CODE_0016` is connected with the display, but finally we noticed that on the video the display has two sets of input bits (top and bottom), and the function is doing things like:
```asm                             LAB_CODE_0028                                   XREF[1]:     CODE:0022 (j)          CODE:0028 20  08           MOVF       DAT_DATA_0020 ,w                                 = ??       CODE:0029 09  3a           XORLW      #0x9       CODE:002a 03  1d           BTFSS      STATUS ,#0x2       CODE:002b 31  28           GOTO       LAB_CODE_0031       CODE:002c 36  30           MOVLW      #0x36       CODE:002d 87  00           MOVWF      FSR1H       CODE:002e 88  30           MOVLW      #0x88       CODE:002f 88  00           MOVWF      BSR       CODE:0030 75  29           GOTO       LAB_CODE_0175```
Notice that the decompiler lies a bit here, because it only shows the fact that `BSR` is set, and shows this as return value of the function.In reality each block stores 2 outputs -> `FSR1H` and `BSR`, exactly as many as the display expects to get.
We could type down the bits flashing for every character shown on display, convert them to numbers and then look for given combinarion in `FUN_CODE_0016` but that's extremely tedious.Instead we decided to use what we learned from the first binary.From the first binary we know what value is returned by `FUN_CODE_0f00` when we want to display certain character, eg `0xa` for `A`.
We can therefore generate the whole mapping from the first binary:
```0 0x00 0x3f 0x441 0x01 0x18 0x042 0x02 0x36 0x883 0x03 0xfc 0x084 0x04 0x19 0x885 0x05 0xed 0x886 0x06 0xef 0x887 0x07 0x38 0x008 0x08 0xff 0x889 0x09 0xfd 0x88A 0x0a 0xfb 0x88B 0x0b 0x3c 0x2aC 0x0c 0xe7 0x00D 0x0d 0x3c 0x22E 0x0e 0xe7 0x80F 0x0f 0xe3 0x80G 0x10 0xef 0x08H 0x11 0xdb 0x88I 0x12 0xe4 0x22J 0x13 0xde 0x00K 0x14 0x03 0x94L 0x15 0xc7 0x00M 0x16 0xdb 0x05N 0x17 0xdb 0x11O 0x18 0xff 0x00P 0x19 0xf3 0x88Q 0x1a 0xff 0x10R 0x1b 0xf3 0x98S 0x1c 0xed 0x88T 0x1d 0xe0 0x22U 0x1e 0xdf 0x00V 0x1f 0xc3 0x44W 0x20 0x1b 0x50Y 0x22 0x00 0x25Z 0x23 0xe4 0x44{ 0x24 0x00 0xa2} 0x25 0x00 0x2a_ 0x26 0x04 0x00```
The way to read this table, is that if display shows for example `V` it means the input was `0x1f` and `FSR1H` and `BSR` were set to `0xc3` and `0x44`.
X was for some reason missing, so we had to get this one character the hard way.
We turne this into map:
```pythonmapping = {}for line in data.split("\n"):    x = line.split(" ")    mapping[x[0]] = x[1]```
Now for character we will know the value that was passed.
Notice that `FUN_CODE_0016` actually does not look the same!The `FSR1H` and `BSR` are the same in each consecutive block, but the conditions are shuffled.So we need one more mapping, which we can simply generate by running `print(map(lambda x:int(x,16),re.findall("==\s*(.*)\)", data)))` over the ghidra decompiled function.
This gives us `mapping2 = [7, 2, 9, 4, 3, 12, 5, 14, 1, 16, 17, 4, 11, 6, 21, 8, 23, 18, 25, 20, 13, 28, 15, 30, 0, 24, 19, 26, 35, 22, 37, 32, 33, 34, 27, 36, 29, 38]`
This means for example that if the `mapping` returns us value `k` the real input passed to `FUN_CODE_0016` was `mapping2[k]`.
Now we need to decode the flag:
```pythondef decode(val):    return 0xFF & (-(val + 0x56) ^ 0x87)
out_mapping = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ{}_"data = '{W7C0RC9JERQ2RW42J{VUXUVFS'
res = ''for c in data:    if c is not 'X':        res += out_mapping[decode(mapping2[int(mapping[c], 16)])]    else:        res += '?'print(res)```
And we get `AERO{NOTHING_NEW_HAD2?2D}0`
Keep in mind we were missing mapping for `X` but we got it directly from the video, and it was mapping to `F` so the flag is `AERO{NOTHING_NEW_HAD2F2D}`