Roulette — CSCML2020(500 pts.)

1byte
6 min readJul 3, 2020

--

So, we get an exe file and as usual we have to find the flag. Like every reverse engineering challenge, we need to understand what we’re looking at. So let’s do the usual thing, and initially use some tools to help us look at the data in a better way. To detect if it’s packed, I used Detect It Easy, which is probably one of the best packer detectors around.

Detect it easy doesn’t detect packing

The next tool we’re going to use is PEStudio which will display some general infomation about the executable file. We can see the sections look quite normal, and by looking at the entropy we don’t have suspicion for packed code in any of the sections.

Sections of the roulette.exe file

Okay, nothing else seems to stick out, and the strings / imports don’t reveal much of what’s going on. Resource Hacker doesn’t find any interesting resources except for the normal one we can see in quite new executables.

Next thing we’ll do it pop the program inside ida, and try to statically reverse engineer it. When we pop the roulette.exe file inside IDA we notice the start function looks a little odd, and if you’re dealing with this for the first time, it can be quite confusing.

The start function

Luckily for us IDA knows to mark this code as __SEH_prolog4, which means this isn’t code generated by the user, and usually code before the main function does some setup and later on jmp s or call s the main function at the end. So we scroll to the end when we see the following:

The end of the start function

Again, IDA comes in for the rescue, and labels argv and argc for us, which can probably tell us sub_4030A0 is the actual main function. So we label it main and continue.

The main function

Okay, so we can see that the program should be used with program_name flag , we can also deduce that sub_401010 is printf. So we relabel and continue snooping around. While inspecting the main code, we can see some weird function (sub_403180) being called with constant arguments which returns a function that gets called. Let’s relabel it weird_function for easier detection.

We try to reverse engineer that function, but the code is quite complex and looks pretty obfuscated. (I did notice usage of the PEB though :) )

sub_403180

Okay, so I think we’re done with the static analysis and we can start dynamically analysing this. We open the roulette.exe file in x32dbg, and give it a command line option of flag{AAAAAAAAAAAAAAAAAAAAAAAAAAAAA} . So press “Run to user code” -> Look for the main function and break in it.

So let’s inspect the first function which gets called in the process:

sub_4032d0

Look at that! Our weird function is also used here, let’s step into this function and try to see what’s going on. I step over until I reach the weird_function call:

Stepping over 1 more time reveals the function’s actual usage. We step over 1 more time and look at the registers.

Ah! So that weird obfuscated function actually returns pointers to winapi functions. That’s pretty cool! We can step over all the other function calls and use it to relabel the variables which get set to the result of this function. (I relabeled the function to be calledget_func , and relabeled every variable with its proper function)

sub_4032d0

After relabelling the functions, it’s super clear what this function does. It opens a handle to the current process’ file (Little tip, when you notice the value 260 in strings / char[] always think about the GetModuleHandle function or any file interactions, since 260 represents the MAX_PATH constant, which specifies how large paths can be), so let’s relabel this function get_current_exe_handle and continue.

Let’s dive into the sub_4033a0 function. Small note: IDA can sometimes misinterpret function declarations, and misintrepret function parameters. So in order to fix this we need to lookup the function definition in MSDN and actually fix it. After casting the function to our desired type, we need to right click whenever the function gets called, and select “Force cast”.

After labelling everything, the flow looks like this:

GetFileSize (currentExe) -> Allocate space in heap -> Read current exe and put inside allocated space in heap -> xor data read with character from flag -> Allocate more space in heap -> Create temporary file and insert its name into the allocated heap space -> Get handle to temporary file -> Write into temporary file (what we read from the exe)

So we can label this function create_temp_modified_exe_file , 1 more function to go and we’re almost done :) Let’s inspect the sub_4035d0 function.

sub_4035d0

Wow, it’s pretty simple! It calls the createprocessA function with the commandline arguments: <tmp_file_name> <our_flag> . Later on in the function it actually tries to wait until the process ends, and if the process ends with a status code different than an OK status code, the function actually returns 0, which means we failed. So let’s call this function verify_flag

Now, let’s see what the temporary file contains, we run the roulette.exe file with the flag{AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA} parameter. (remember the xor uses the character in the 40th index)

So in order to inspect the temporary file, we set a breakpoint before the DeleteFileA function (and before the createprocessA function just for comfortability) and run it.

Opening the .tmp file in IDA

Uhm… Looks like the temporary file is corrupted or something. Remember that most functions start with the push ebp; mov ebp, esp prolog? And we also remember our exe file gets XORed with the 40th index of our flag, we know XOR is reversible. We know the first opcode got calculated in the following way:

first_opcode = our_exe_file ^ flag[40]

We want first_opcode to be 0x55 (since 0x55 is push ebp ), so we have 2 equations and we have to solve them

first_opcode = our_exe_file ^ flag[40] and 0x55 = our_exe_file ^ ?

Since XOR is reversible, our_exe_file = 0x55 ^ ? therefore first_opcode = 0x55 ^ ? ^ flag[40] => ? = first_opcode ^ flag[40] ^ 0x55 So let’s try calculating the unknown variable and see if we get some valid code.

Undefined start function

So we undefine the first opcode in order to see its value, it’s 0x79. so first_opcode=0x79 , next remember flag[40]=A=0x41 , so ?=0x55 ^ 0x41 ^ 0x79 = 109 = 'm'. Now let’s try doing the same thing with flag[40]=m

New .tmp file after using flag[40] = ‘m’

Wow! This looks just like our exe’s code, so we probably have to do this recursively for all .tmp files that come out of this tmp file, so I wrote a script that does exactly what we did.

For some unknown reason* the script gives a ` after the p3 , but it’s an easy fix from ` => _. So it’s pretty easy to do :)

*EDIT: I discovered the last stub actually is just an exit() so it doesn’t contain the push ebp; mov ebp, esp prolog we were talking about.

The script’s code:

Thank you for reading :) And thanks to the challenge’s creator. Make sure to follow him Omer Katz (@omerk2511 — twitter handle)

--

--

1byte

Just a person who likes hacking things. Feel free to tweet at me @guysudai1 and this is my team: https://ctftime.org/team/27128