Reverse Engineering
Amber (600 pts)
Description
-
Solution
Given PE file, open it using IDA.

Main function not detected, but it still easy to find since start function is common start function.


So sub_401530 is main function, set breakpoint on that function. Set breakpoint at 0x0040165F and step instruction to enter the function.

call near ptr unk_1E7210

edx+4 == 0x1e000d
So function unk_1E7210 do self modification by doing some operation such as substract, xor, rol, and add.

From image above we can see that the code is different after mov edi,edi. Lets disassemble again code after mov edi,edi by pressing c on address 0x1e000d.

Continue the process by stepping instruction we will get into looping at 0x1e0028.

Loop instruction will do looping until ecx is 0. So we can said that it will overwrite value until 0x1e0029 (edx + 0x17). If we set breakpoint on those address the debugger will error, so the idea is set hardware breakpoint on 0x1e002a and continue the process.

Now the values start from 0x1e002a are different again.

Scrolling down i saw valid PE file, dump it using IDC.
dump_pe.exe actually a valid PE and consist of some functions but since it written dynamically there are some imported function not detected. So i choose to continue current debugginer. Disassemble code again and do step instruction again.

Continue the process until call near ptr unk_1e7031.

sub_1E717C: resolve function based on hash value
After manually check what function called, here is the summary
Next, set breakpoint on last instruction on sub_1F7033 (0x01F7177).

Step into sub_1f71fd again and set breakpoint on 0x01F720E.

Step into on call edi and do step over so we will not get into call unk_7FE71CB2.

Now we are on start function of new executable sub_7FE71737.


Again, we can find which one main function by manually validating it.

Set breakpoint on new main function then continue the program.

Rename all function. Original function name can be found by double click the address.

Function func_closehandle, return_const_1 - return_const_4 basically do try catch with anti debug mechanism. The possibility of the value returned only two, if there is no exception will be A and if there is exception will be B. So we can conclude that it is possible to brute it. At the end we need to find the correct key and ciphertext to get the flag through RC4 decryption. Because there are so many anti debug check, the easy way to solve it just by bruteforcing all possibility (key, key2, key3, key4, key5). key-key5 actually one key (contiguous memory location/no null byte between variable location), it divided to 5 variables because decompiler mechanism.

Flag: ASCWG{What_A_ReverseEngineering_Beast_13337_-_-}
Awaken (900 pts)
Description
Given assembly code below
Solution
Since the assembly code not too long we can reconstruct the code to another programming language such as python. Here is my implementation on python
We can see that the input processed each one byte so basically we can do bruteforce one byte to get the valid flag. Here is modified code i used to do bruteforce
Flag: ASCWG{What_do_you_see_before_it_is_over?_998bd0d4}
Guess The Flag (900 pts)
Description
Given ELF 64 bit file
Solution
When we open the main function it show something like fake validation because it always return wrong key

So the next step, i checked the init_array to see whether there is suspicious function called before actual main function.

We can see on image above that there is function_main (0x13A1) in init_array.

There are puts and scanf on that function and we can implement the xor process to knowing the value printed out.
We can confirm that the printed out string is same like in actual main function. Then, we just need to set breakpoint on that address to make sure that our input actually processed on 0x13A1 not in main function.
Function v17 processed our input and the function created during runtime. Opcode of function v17 stored on 0x4080.

We can directly convert the opcode to instruction by pressing c in IDA.

function loc_408B xoring the byte on index i with index i-1 then stored it on i (basically like self modifying code). We can reimplement the function to make the rest instruction valid.

Opening new binary, now we can convert the opcode to valid instruction on address 0x40be. On address 0x40bc we can see that there is instruction ud2, basically this instruction trigger crash child process to back to parent process inside while looping (0x1ba1). There are also another instructions that trigger the same condition such as sys_kill and int 3 (as shown in image below)

During the competition i do debugging and modified some function name inside while looping to make it easier to do static analysis.
We can see that there are some ptrace function called inside while looping with different first argument which are
PTRACE_GETREGSPTRACE_SETREGSPTRACE_PEEKTEXTPTRACE_POKETEXT
Next step i did was tracing those ptrace call including dump all the argument by utilizing preload library.
Compile the source code using command below
After that just run binary like command below then there you can see the trace result on log.txt

Based on the trace log, the binary doing self modification again by modify its next instruction and back to that instruction to continue the process. Besides that it also take value on some register then processed it on parent process. The first thing i do was patching the actual opcode (from POKETEXT ptrace) to the binary so we can get the all valid instruction.

Next, after getting the correct instruction we need to what values passed to the parent process. Set breakpoint on address that call fork function

To dive in child process we need to change follow-fork-mode to child


On call rdx we need to step instruction to know what values will be

Okay, so in the last instruction before back to the parent process there are 3 register that have values.
Now, we back again to parent process and check which instruction processed those values.

As we can see on image above that the first values processed on parent process is same like in child process. During the competition, my approach is parsing the instruction using gdb scripting. Here is the script i used to parse the instruction
There are some invalid instruction on result but it obvious and we can clear it manually. After getting valid instruction then i created vm for those instructions. Since the validation processed our values each byte we can easiy bruteforce it to get the flag.
Flag: ASCWG{N0w_1_4m_B3c0m3_D34th_500861fd8}
Last updated