Hacker handle: 0xc3

## Dumping
The loaded inner executable is obviously a dynamic binary, so my idea is to break when the dynamic loader is entered which loads the inner executable, as the file would have to be somewhat valid at that time.

Breaking at `dl_main` tells us the binary is probably around `0x400000`, given that the program header starts at `0x400040`. When looking at the memory map, there seem to be mappings all the way from `0x400000` to `0x505000`, so that seems like a logical range to dump.

### Patching the binary
Dumping the data from `0x400000` to `0x505000` yields an ELF binary, but it is broken. Firstly, the endianness is wrong; Setting `EI_DATA` to `ELFDATA2LSB` helps `readelf` a bit, but doesn't completely fix it. Changing the ELF machine type from `0x3` to `0x3e` is also needed as this is supposed to be a 64-bit binary. These seem to be parts of the ELF header that the dynamic loader doesn't care much about (they are probably checked for earlier in the loading stage, perhaps in the kernel). Lastly, when loaded into memory, the ELF segments are not in the same place as in the binary, so we need to remove this inconsistency. Removing `0x1000` bytes after `0x26E8` in the dumped file puts the sections back in the right place and makes the program run, now only having it complain about not being genuine.

## Analysis in Ghidra
Analysing the patched binary in Ghidra and telling it to disassemble from the entry point yields some useful information. The entrypoint is at `0x1930`, `main` seems to be at `0x1260`, and consists of a bit of initialisation along with a read-eval-print loop. Looking at the decompilation output (which is only displayed when we toggle the "eliminate unreachable code" checkbox in the decompiler's analysis options; it otherwise complains), the password is easily revealed to be `IHTLIAWXZOOOXJNIRTDE`, and some checks are visible that check whether the software is genuine. These checks seem to be based on using `getauxval` to read data from the `auxv` auxiliary arguments vector and checking whether the returned data is correct. Especially the `AT_FLAGS` parameter seems to be important.

The read-eval-print loop accepts a number of commands, which act as follows:

- `password`: simply displays a password prompt whose input is stored for later use.
- `connect`: checks whether the password matches. if it doesn't, exit early with an error. if it does, compute a "unique connection id" (which actually ends up being a misleading name, but it is used later) using the value of the `AT_FLAGS` parameter. Then, it initialises `cURL`, decrypting the URL (which is not unique at all, it's [http://130.37.198.66:8000/Recording.mp3](http://130.37.198.66:8000/Recording.mp3)) from its location at `0x23e0`.
- `download`: checks whether the stored password is still correct, curl is initialised, and the "unique id" still satisfies the condition that it satisfies after the loop in `connect`. If all is well, it uses indirect calls which rely on the value of the `AT_FLAGS` parameter to print a unique recording id (the hex value of the connection id) and initialize the output filename (`unique_id` in hex + '.mp3'). Then, it uses `cURL` to actually download the file.
- `help`: shows help.
- `exit`: exits.

### Anti-unpacking checks

At `0x1323`, the binary checks whether the value for `AT_FLAGS` is zero, if so, it will give a warning saying that the software is not genuine.

Simply setting it to a non-zero value is not enough, however; as described in the previous section, the value for `AT_FLAGS` is used to compute a "unique ID" by doing some bit mangling (the loop from `0x1541` onwards does this), and this unique id is validated in the `download` case, where the `AT_FLAGS` value is also used to compute addresses for indirect calls. Hence, the value at least needs to be somewhat correct. The flags value that is used when running from the packer is `0x0458f06a39725182`, so I've written a small fixup which replaces the `AT_FLAGS` value with that.

### The fixup
The fixup (`fixup.s`) consists of an initialisation function (the type used in `.init_array`), which takes the three parameters `argc, argv, envp` and uses `envp` to find the auxiliary vector. It then patches the `AT_FLAGS` value to be the same as the value found in the packed environment.

Afterwards, it jumps to the original initialisation function (there's an original one at `0x1a10` that (maybe?) does something with transactional memory stuff?). This is really the hackiest part and the reason the fixup is actually a piece of assembly; it knows where it is loaded and it knows where the original initialisation is relative to it, so it computes a relative jump and does that at the end of the function instead of having a normal epilogue.

The actual installation of the fixup, along with the patching of the other parts of the binary, is done in `fixer.py`, which is described in the following section along with the rest of the automation.

## Automation
The complete process from dumping the binary to downloading the audio from Perseverance is automated through a series of scripts. Running `./run_complete.sh` or `make run` will go through all parts of the process.

- First, it runs gdb plus the script file `gdbscript` to extract the binary and store it in `inner.unpatched`. The script adds a catchpoint on the mmap syscall and runs the packer until the dynamic loader (ld-2.33.so) is loaded. At this point, the binary is in a state where it can be extracted, and so the memory range described above is dumped to `RoveConnectCTL.unpacked.unpatched`.
- Then, the fixup is assembled and the fixing script `fixer.py` is ran. This fixes up the ELF header, puts the sections back in the right place, and installs the fixup. The fixup is installed in the data segment, but this is usually read-write (i.e. not executable). We make it read-write-execute instead by setting the appropriate flags in the program header. Then, we fix up the relocation information that is used to set the address of the initialisation function. Lastly, the fixup is actually inserted at `0x3020` in the binary. The fixed up binary is written to `RoveConnectCTL.unpacked`.
- Finally, we can simply run the unpacked binary, feeding it the `input` file that downloads the audio from Perseverance.
