## Alien Saboteaur  > You finally manage to make it into the main computer of the vessel, it's time to get this over with. You try to shutdown the vessel, however a couple of access codes unknown to you are needed. You try to figure them out, but the computer start speaking some weird language, it seems like gibberish...
## SolutionThis challenge provides us with two files. One executable `vm` and on file called `bin`. First we check the executable with Ghidra.
```c++undefined8 main(int param_1,long param_2)
{  FILE *__stream;  size_t __size;  void *__ptr;  undefined8 uVar1;   if (param_1 < 2) {    printf("Usage: ./chall file");                    /* WARNING: Subroutine does not return */    exit(1);  }  __stream = fopen(*(char **)(param_2 + 8),"rb");  fseek(__stream,0,2);  __size = ftell(__stream);  rewind(__stream);  __ptr = malloc(__size);  fread(__ptr,__size,1,__stream);  fclose(__stream);  uVar1 = vm_create(__ptr,__size);  vm_run(uVar1);  return 0;}```
The `main` is fairly small. It reads the content of a file and passes that to `vm_create`.
```c++undefined4 * vm_create(long param_1,long param_2)
{  undefined4 *puVar1;  void *pvVar2;   puVar1 = (undefined4 *)malloc(0xa8);  *puVar1 = 0;  *(undefined *)(puVar1 + 1) = 0;  puVar1[0x28] = 0;  memset(puVar1 + 2,0,0x80);  pvVar2 = calloc(0x10000,1);  *(void **)(puVar1 + 0x24) = pvVar2;  memcpy(*(void **)(puVar1 + 0x24),(void *)(param_1 + 3),param_2 - 3);  pvVar2 = calloc(0x200,4);  *(void **)(puVar1 + 0x26) = pvVar2;  return puVar1;}
void vm_run(long param_1)
{  while (*(char *)(param_1 + 4) == '\0') {    vm_step(param_1);  }  return;}```
`vm_create` initializes a data structure. The result goes back to `main` and is then passed to `vm_run`. 
`vm_run` is only a loop that calls frequently into `vm_step`. But we can reason about one part of the `vm` structure, since there is a flag that causes the loop to exit.
```c++void vm_step(uint *param_1)
{  if (0x19 < *(byte *)((ulong)*param_1 + *(long *)(param_1 + 0x24))) {    puts("dead");                    /* WARNING: Subroutine does not return */    exit(0);  }  (**(code **)(original_ops +              (long)(int)(uint)*(byte *)((ulong)*param_1 + *(long *)(param_1 + 0x24)) * 8))(param_1)  ;  return;}```
`vm_step` seems to index into a list of function pointers and calls the specified function. Also there is a range check at the top to avoid indexing out of the function table range.
Hex-Rays was nice enough to provide the function table in a clean way
```c++__int64 (__fastcall *original_ops[25])() ={  &vm_add,  &vm_addi,  &vm_sub,  &vm_subi,  &vm_mul,  &vm_muli,  &vm_div,  &vm_cmp,  &vm_jmp,  &vm_inv,  &vm_push,  &vm_pop,  &vm_mov,  &vm_nop,  &vm_exit,  &vm_print,  &vm_putc,  &vm_je,  &vm_jne,  &vm_jle,  &vm_jge,  &vm_xor,  &vm_store,  &vm_load,  &vm_input}; ```
And sure enough, it's a table for some op-codes that are supported by the vm. Next we can investigate a few of the op-functions, e.g. `nop`:
```c++int vm_nop(unsigned int *a0){    unsigned int *v0;  // [bp-0x10]    unsigned long long v1;  // [bp-0x8]    unsigned long long v3;  // rbp
    v0 = a0;    *(a0) = *(a0) + 6;    v3 = v1;    return;}```
This does nothing except incrementing the instruction pointer. By reading a few more of the functions we can come up with a good set of assumptions:
The vm structure looks something like this:
```c++typedef struct vm {	uint32_t eip;       // instruction pointer	bool shutdown;      // shutdown vm	uint32_t mem[128];  // vm memory	uint8_t* cseg;      // vm code segment	uint32_t* stack;    // vm stack	uint32_t esp;       // stack pointer} vm_t;```
Also we know that the image has a header of 3 bytes (we skip this) and then it's a list of operations where each operation is 6 bytes wide. With this we can write our own disassembler.
```c++void (*ops[25])(vm_t*) ={    &vm_add,    &vm_addi,    &vm_sub,    &vm_subi,    &vm_mul,    &vm_muli,    &vm_div,    &vm_cmp,    &vm_jmp,    &vm_inv,    &vm_push,    &vm_pop,    &vm_mov,    &vm_nop,    &vm_exit,    &vm_print,    &vm_putc,    &vm_je,    &vm_jne,    &vm_jle,    &vm_jge,    &vm_xor,    &vm_store,    &vm_load,    &vm_input};
void vm_step(vm_t* vm){    uint8_t op_index = vm->cseg[vm->eip];    if (op_index < sizeof(ops))    {        ops[op_index](vm);    }    else    {        printf("dead");        exit(0);    }}
vm_t vm_create(const uint8_t* buffer, uint64_t len){    vm_t vm;    memset(&vm, 0, sizeof(vm_t));    vm.cseg = calloc(65536, 1);    memcpy(vm.cseg, buffer+3, (size_t)len-3);    vm.stack = calloc(512, 4);    return vm;}
void vm_shutdown(vm_t vm) {    free(vm.cseg);    free(vm.stack);}
int main(){    FILE* fp = NULL;    if (fopen_s(&fp, "bin", "rb") != 0)        return 0;
    uint8_t buffer[1024 * 16+3];    fread(buffer, 1, sizeof(buffer), fp);    fclose(fp);
    vm_t vm = vm_create(buffer, sizeof(buffer));
    while (!vm.shutdown)        vm_step(&vm;;
    vm_shutdown(vm);
    return 0;}```
To thats a bit more readable. Also if we implement all the ops we can even run the image by ourselve and investigate memory snapshots and all the other nice parts. To do this we can provide empty mock implementations for each op code that are just telling us that the functionality is not existing yet:
```c++void vm_div(vm_t* vm) { printf("not implemented div"); exit(0); }void vm_cmp(vm_t* vm) { printf("not implemented cmp"); exit(0); }void vm_jmp(vm_t* vm) { printf("not implemented jmp"); exit(0); }```
Afterwards we run the image and implement one op-code after another. The first one that comes up is vm_putc:
```c++void vm_putc(vm_t* vm) { #if TRACE    trace(vm, "PUTC #%02x", ARG8(1));#else    putchar(ARG8(1));#endif    INC_EIP(1);}```
We also can put in some tracing code to dump the assembly while it's exxecuted. Therefore we can get the whole program flow with all the informations we need for debugging (addresses, values in memory, ...).
After providing all the ops used by the image we get this result:
```bash[Main Vessel Terminal]< Enter keycode> aaaaaaaaaaaaaaaaaaaaaaaaaaaaUnknown keycode!```
This is basically the same as we get if we run the original executable with `./vm bin`. But this time we can inspect the code.
```0000    PUTC #5b0006    PUTC #4d000c    PUTC #610012    PUTC #690018    PUTC #6e001e    PUTC #200024    PUTC #56002a    PUTC #650030    PUTC #730036    PUTC #73003c    PUTC #650042    PUTC #6c0048    PUTC #20004e    PUTC #540054    PUTC #65005a    PUTC #720060    PUTC #6d0066    PUTC #69006c    PUTC #6e0072    PUTC #610078    PUTC #6c007e    PUTC #5d0084    PUTC #0a008a    PUTC #3c0090    PUTC #200096    PUTC #45009c    PUTC #6e00a2    PUTC #7400a8    PUTC #6500ae    PUTC #7200b4    PUTC #2000ba    PUTC #6b00c0    PUTC #6500c6    PUTC #7900cc    PUTC #6300d2    PUTC #6f00d8    PUTC #6400de    PUTC #6500e4    PUTC #2000ea    PUTC #0a00f0    PUTC #3e00f6    PUTC #2000fc    MOV [30], 40000102    MOV [28], 00108    MOV [29], 17010e    INPUT [25]              args: a0114    STORE [30], [25]        args: 4000, 97  -> 97011a    ADDI [30], [30], 1      args: 4000, 1   -> 40010120    ADDI [28], [28], 1      args: 0, 1      -> 10126    JLE 010e, [28], [29]    args: 1, 17```
The first lines are the output `[Main Vessel Terminal]` etc... After this some variables are initialized. Memory location #30 is set to 4000, #28 to 0 and #29 to 17. Then input is queried, the input is stored somewhere and  #30, #28 are incremented. The last operation is a jump back if #28 is less or equal to what #29 holds.
This is basically the input loop, requesting a input of 18 characters from us. 
After the whole input was read the program starts checking the input:```012c    MOV [30], 4100                                      # pointer to keycode0132    MOV [31], 4000                                      # pointer to user input0138    MOV [28], 0                                         # loop counter013e    MOV [29], 10                                        # loop max0144    MOV [27], 169014a    MOV [23], 00150    LOAD [25], [30]         args: 202, 4100 -> 202      # load keycode character0156    LOAD [24], [31]         args: 97, 4000  -> 97       # load user input character015c    XOR [25], [25], [27]    args: 202, 169  -> 99       # xor keycode with 1690162    JE 01d4, [25], [24]     args: 99, 97                # check if result equals user input0168    PUTC #55016e    PUTC #6e0174    PUTC #6b017a    PUTC #6e0180    PUTC #6f0186    PUTC #77018c    PUTC #6e0192    PUTC #200198    PUTC #6b019e    PUTC #6501a4    PUTC #7901aa    PUTC #6301b0    PUTC #6f01b6    PUTC #6401bc    PUTC #6501c2    PUTC #2101c8    PUTC #0a```
By looking at this we can see how the keycode is decrypted and where it is located. We can copy it from the bin (offset 4100) and just decrypt it by xor 169 on every character.
![keycode](https://raw.githubusercontent.com/D13David/ctf-writeups/main/cyber_apocalypse23/reversing/alien_saboteur/image001.png)
```python>>> keycode = [0xCA, 0x99, 0xCD, 0x9A, 0xF6, 0xDB, 0x9A, 0xCD, 0xF6, 0x9C, 0xC1, 0xDC, 0xDD, 0xCD, 0x99, 0xDE, 0xC7]>>> "".join([chr(c^169) for c in keycode])'c0d3_r3d_5hutd0wn'```
Ok, moving forward. If we enter the keycode we get:```bash[Main Vessel Terminal]< Enter keycode> c0d3_r3d_5hutd0wn< Enter secret phrase> asdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdWrong!```
So the keycode was correct, but now we need a passphrase. 
One interessting side note: Parts of the image are encrypted and are only decrypted when the correct keycode is entered. Therefore it's not immediately possible to dump the whole dissassembly although we don't really need the keycode but can also patch JLE on offset 126h to a JUMP or JNE.
Side note two: after checking the keycode a operation called 'inv' is called. This is by far the most complex operation popping some values from the stack and issuing a syscall (101) to ptrace. While this isn't a real blocker with this approach of analysing the challenge, the call is intended as anti-debugging technique as the call will fail to attach a debugger when the binary is already inspected with gdb or likewise. To get around this with an dynamic analysis approach (e.g. stepping the flow with gdb) the bin can be patched by replacing INV with a JMP for exmaple.
```01ec    MOV [15], 001f2    PUSH [15]       args: 001f8    PUSH [15]       args: 00204    INV```
For us, we can directly manipulate the behaviour of the VM allowing us to sidestep the issue and also adding support to run the program on windows. The result is assumed to be 4011, so we write that directly to memory.
```c++void vm_inv(vm_t* vm) { 
    uint32_t v0 = ARG8(1);    uint32_t v1 = ARG8(2);
    vm->esp = vm->esp - v1;
    *((uint32_t*)&vm->cseg[vm->eip + 6 + 2]) = 4011; //syscall(101)
#if TRACE    trace(vm, "INV");#endif    INC_EIP(1);}```
Afterwards the code section is decrypted so programm flow can move on```0288    MOV [30], 119                                   # calculate offset of...028e    MULI [30], [30], 6      args: 119 6 -> 714      # encrypted code section0294    MOV [28], 0                                     # loop counter029a    MOV [29], 1500                                  # block is 1500 bytes wide02a0    MOV [27], 6902a6    LOAD [25], [30]         args: 85, 714   -> 85   # load byte02ac    XOR [25], [25], [27]    args: 85, 69    -> 16   # xor with 6902b2    STORE [30], [25]        args: 714, 16   -> 16   # store byte to same location02b8    ADDI [30], [30], 1      args: 714, 1    -> 715  # increment offset02be    ADDI [28], [28], 1      args: 0, 1      -> 1    # increment counter02c4    JLE 02a6, [28], [29]    args: 1, 1500           # check if end of code section is reached```
The next part is again, outputting text and reading user input. Afterwards the input is tested against some values. Lets break down the code:```038a    MOV [28], 0                                     # loop counter0390    MOV [29], 35                                    # max loop value0396    MOV [30], 4400                                  # pointer to user input039c    MOV [31], 4500                                  # pointer to scramble array03a2    MOV [26], 0                                     # inner loop counter03a8    MOV [27], 35                                    # max inner loop value03ae    LOAD [20], [30]         args: 120, 4400 -> 120  # load user input 03b4    LOAD [21], [31]         args: 19, 4500  -> 19   # load scramble value03ba    PUSH [20]               args: 120               # temporary store user value 03c0    POP [19]                args: 12003c6    MOV [18], 4400                                  # move user input start offset03cc    ADD [18], [18], [21]    args: 4400, 19  -> 4419 # add scramble offset03d2    LOAD [17], [18]         args: 104, 4419 -> 104  # load user value at this offset03d8    STORE [30], [17]        args: 4400, 104 -> 104  # swap both...03de    STORE [18], [19]        args: 4419, 120 -> 120  # ...values03e4    ADDI [26], [26], 1      args: 0, 1      -> 1    # loop increment 03ea    ADDI [30], [30], 1      args: 4400, 1   -> 440103f0    ADDI [31], [31], 1      args: 4500, 1   -> 450103f6    JLE 03ae, [26], [27]    args: 1, 35             # if not finished, scramble ahead03fc    MOV [30], 4400                                  # pointer to user input0402    MOV [31], 4600                                  # pointer to xor table0408    MOV [26], 0                                     # inner loop counter040e    MOV [27], 35                                    # max inner loop value0414    LOAD [20], [30]         args: 53, 4400  -> 53   # load user input041a    PUSH [31]               args: 4600              # xor table offset ...0420    POP [15]                args: 46000426    ADD [15], [15], [28]    args: 4600, 0   -> 4600 # ... + outer loop index042c    LOAD [16], [15]         args: 22, 4600  -> 22   # load xor value0432    XOR [20], [20], [16]    args: 53, 22    -> 35   # xor both caracters0438    STORE [30], [20]        args: 4400, 35  -> 35   # store new value to user input043e    ADDI [26], [26], 1      args: 0, 1      -> 10444    ADDI [30], [30], 1      args: 4400, 1   -> 4401044a    JLE 0414, [26], [27]    args: 1, 35             # if not finished jump back0450    ADDI [28], [28], 1      args: 35, 1     -> 36 0456    JLE 0396, [28], [29]    args: 36, 35            # outer loop```
This looks like something. But it's essencially only a outer loop and two inner loops. The first one scrambles the user input and the second one applies an xor. This is done 36 times and then the user input is surely unrecoginzable. Here's some pseudocode:
```python    for i in range(0,36):        for j in range(0,36):            swap(user_input[j], user_input[scramble_offset[j]])        for j in range(0,36):            user_input[j] = user_input[j] ^ xor_table[i]```
In the last step the program checks if the encoded user input equals the encoded flag:
```045c    MOV [30], 44000462    MOV [31], 47000468    MOV [26], 0046e    MOV [27], 350474    LOAD [15], [30]     args: 108, 4400 -> 108047a    LOAD [16], [31]     args: 101, 4700 -> 1010480    JE 04b6, [15], [16] args: 108, 101```
Now we have all the offsets:* scramble table at 4500* xor table at 4600* encrypted flag at 4700
Grabbing the values from the image the flag can easily be decoded:
```pythonflag = [0x65, 0x5D, 0x77, 0x4A, 0x33, 0x40, 0x56, 0x6C, 0x75, 0x37, 0x5D, 0x35, 0x6E, 0x6E, 0x66, 0x36, 0x6C, 0x36, 0x70, 0x65, 0x77, 0x6A, 0x31, 0x79, 0x5D, 0x31, 0x70, 0x7F, 0x6C, 0x6E, 0x33, 0x32, 0x36, 0x36, 0x31, 0x5D]
xor = [0x16, 0xB0, 0x47, 0xB2, 0x01, 0xFB, 0xDE, 0xEB, 0x82, 0x5D, 0x5B, 0x5D, 0x10, 0x7C, 0x6E, 0x21, 0x5F, 0xE7, 0x45, 0x2A, 0x36, 0x23, 0xD4, 0xD7, 0x26, 0xD5, 0xA3, 0x11, 0xED, 0xE7, 0x5E, 0xCB, 0xDB, 0x9F, 0xDD, 0xE2]
scramble = [0x13, 0x19, 0x0F, 0x0A, 0x07, 0x00, 0x1D, 0x0E, 0x16, 0x10, 0x0C, 0x01, 0x0B, 0x1F, 0x18, 0x14, 0x08, 0x09, 0x1C, 0x1A, 0x21, 0x04, 0x22, 0x12, 0x05, 0x1B, 0x11, 0x20, 0x06, 0x02, 0x15, 0x17, 0x0D, 0x1E, 0x23, 0x03]
for i in range(35,-1,-1):    for j in range(36):        flag[j] = flag[j] ^ xor[i]
    for j in range(35,-1,-1):        tmp = flag[scramble[j]]        flag[scramble[j]] = flag[j]        flag[j] = tmp
print("".join([chr(x) for x in flag]))```
```bash[Main Vessel Terminal]< Enter keycode> c0d3_r3d_5hutd0wn< Enter secret phrase> HTB{5w1rl_4r0und_7h3_4l13n_l4ngu4g3}Access granted, shutting down!```
For the interested, the vm code can be found [`here`](https://github.com/D13David/ctf-writeups/blob/main/cyber_apocalypse23/reversing/alien_saboteur/vm/main.c).
And we have the flag `HTB{5w1rl_4r0und_7h3_4l13n_l4ngu4g3}`.