As part of reversing training, I’m going to go through this years Flare-On challenges. I played during the CTF, however it came during a transitional period for me, and so I wasn’t able to play a lot of it (also I have windows only on my desktop which didn’t help xp). But since I want to become better at reversing, and I consider it a great resource, I want to complete it even if the CTF is over. So looking forward to this journey!
PixelPoker
Running the executable
Once we extract the files from the archive, we get the binary PixelPoker
and a readme
which says:
|
|
Let’s run the executable and find out what they’re talking about :eyes:
Once we run it, we are greeted with a window containing a lot of pixels at the different mouse coordinates of the window. At the top right, we can see the title of the window, which has the form PixelPoker (<pixel x coordinate>/<pixel y coordinate>) - #0/10
. As we move the mouse around, the coordinates change. If we click at a random pixel, the #0
changes to #1
. So we can imagine it’s an attempt counter, and we have 10 chances. If we fail, a message box will pop up with the text Womp womp... :(
and title Please play again!
. The File
and Help
options in the top left don’t offer much help. So let’s start reversing the executable.
Reversing the executable
Once I opened it with IDA
, I saw it was a 32-bit binary. So I opened it with ghidra to get decompilation. Once the binary is analyzed, I opened the entry
function and was dropped into a function with a lot of stripped names. So to find myself in important code, I searched for some of the known strings we have from the program. In the different strings I found where the title messages which where described above. So I clicked on on PixelPoker (%d,%d) - #%d/%d
, and followed it’s XREF into FUN_004012c0
, which returned the function.
Before analyzing it, I quickly pulled up the function call graph, to see the calls made to reach this function, so I could understand the flow of the program better. This function is called only by FUN_00401120
:
|
|
It seems that local_34
is a variable of the WNDCLASSEXA structure, which is set up, and is passed as a memory address to the RegisterClassExW function. As the WinAPI says, RegisterClassExW
registers a window class which can be used when creating a window. The lpfnWndProc
member is a pointer to the main window procedure. This means that whenever we interact with the window defined in this class, FUN_004012c0
will be called.
Before that is FUN_004016f0
. This function can actually be found in the entry
function towards the end:
|
|
Which could have potentially caught my eye because of the base address 0x400000
. So if we rename param1
to something like base_address
, FUN_004016f0
makes more sense. Also from IDA this function was called wWinMain
.
|
|
So we understand the general flow what we care about. wWinMain
is the main function of the program, which calls RegisterCheckClass
. That function registers a window class, which set’s FUN_004012c0
(renamed to GamePixelCheckProcedure
), which is called whenever CallWindowProc is called, according to WinAPI. If we look at the parameters described there, they will be of help (I think) into understanding the check procedure.
A closer inspection on GamePixelCheckProcedure
We see that different pieces of code are executed depending on the value of param_2
. According to WNDPROC (or CallWindowProcA
from before), this parameter holds the message passes to the procedure. The function probably has different checks to perform different operations depending on the message. For example:
|
|
I think sets the values the mouse passes through to the window. This makes sense considering the last number is 10. That makes param_4
the value of the x
axis, sVar1
of the y axis (which makes sense considering it comes from param_4
), and DAT_00413298
a memory section showing how many tries we have attempted. Under that light, we can rename some of the variables.
Below that, if uMsg
is 0x201
is interesting:
|
|
The x
and y
coordinates are loaded into variables, and a check is done for the attempted tries. If we reach 10 tries, we have failed. If we have attempted less than 10 times, attempted_tries
is incremented, and this interesting if
is executed. From what we’ve understood from the decompilation thus far, this checks if the input values for the coordinates is correct, with the correct values being the result of the modulo operation between s_FLARE-On_00412004._0_4_ % DAT_00413280
, and s_FLARE-On_00412004._4_4_ % DAT_00413284
. The s_FLARE-On
data section has the FLARE-On
string stored, while the DAT_
sections have nothing. After I searched a bit if anything is passed into these data sections and found nothing, I decided to use a debugger, since then we would get values for these addresses.
Dynamic analysis
We open x64dbg, and run the PixelPoker
executable so we can attach it. Let’s place a breakpoint at address 0x40146F
which is where attempted_tries
is incremented. A couple of addresses down, div esi
is executed. Based on the documentation for the unsigned divide, the remainder is stored in the edx
register. After that instruction is executed, we can see that 0x5f
is stored into edx
(and 0x02e5
into esi
, sto that was the modulo value). So let’s choose a second pixel, only this time let’s have the x coordinate be 95
, and set a breakpoint at 0x40149B
.
We successfully hit it, and see that the y coordinate is 0x139
, or 313
in decimal. So instead of going back and choosing the correct pixel, let’s just change the value of ebx
for the cmp
instruction, and get the flag. Of course we could have also patched the instructions to pass with any coordinate input.
w1nN3r_W!NneR_cHick3n_d1nNer@flare-on.com
Magic8Ball
The interesting thing about this challenge is that when we extract the executable from the archive, many DLLs come with it.
Running the executable
If we run magic8ball
, we can see that this is another GUI challenge. We are presented with a magic ball, with the window giving us two texts, Press arrow keys to shake the ball
, and Start typing your question (max. 75 characters):
. If we press an arrow key, the ball moves accordingly, and if we enter a string and hit enter, a random message appears at the center of the ball. These are the 2 ways we can interact with the GUI. Let’s proceed to reverse it.
Reversing the executable
If we open it with IDA, again we see that it’s a 32-bit executable. So again we go with ghidra for decompilation. However this time I decided to keep the wWinMain
address from IDA, and start reversing from there. So in ghidra we enter the offset 403680
.
The function is very small, essentially holding only a call to FUN_00403690
. That function is pretty big, with a lot of function calls like GetPRocessHeap
and HeapAlloc
. Potentially it sets up the heap for the rest of the process, but I’m not sure. Amongst all these functions, we see this line uVar4 = FUN_004027a0();
. Since this is the only stripped function, we can imagine it’s part of the original source, and so we proceed and investigate it further.
In it are calls to different functions. Let’s go through them and focus on some important parts
|
|
FUN-0040296d
seems to allocate some memory with malloc
, and returns a pointer to that chunk. Then memset
sets 0’s to that entire memory space, and FUN_004012b0
passes the strings the ball displays into that allocated chunk.
I couldn’t quite understand FUN_004018f0
. It passes a stack address, the string Magic 8 Ball
, and 0xc
which is the length of the string. So inside the function we can change the parameter names accordingly. The interesting part is that the stack address is recognized as the pointer *this
. From Java I remember that this is used in classes to access data internal to each object of the class. So I assume that this function is a generator for a class, and a reference to it’s object is stored into the passed stack address.
After it FUN_00402090
seems to initialize different things, like fonts. Amongst all the things stored at different offsets of the this
pointer, are these values:
|
|
If we turn the hex bytes to chars, we get the string gimme flag pls?
. If we enter it, it won’t give us the flag :(. However it’s something we should keep in mind.
After it, FUN_004024e0
has some very interesting instructions as well:
|
|
What if we enter these arrow keys to the ball? Nothing changes. How about these with the string? That’s indeed enough to get the flag.
In fact, if we were to look at the decompilation a bit better, this makes sense. After all these keyboard arrow checks, it executes
|
|
And if we were to look at FUN_004027a0
, we would understand that the this
pointer of the class object is stored into DAT_00406090
. So what’s passed as param1
to FUN_004024e0
is the object of the class. And as we saw in the previous functions, different values where stored at different offsets. The offset where the gimme flag pls?
string was stored was 0x5c
. The same offset accesses with param1
in strcmp
. So now we can be sure why this works.
U_cRackeD_th1$_maG1cBaLL_!!_@flare-on.com
Even though I solved the challenge I still have a gap into the logic behind reversing c++ classes. I was told by Shad3 that this course is really strong.