By clicking 4 times on the window, it launch a modal dialog box telling me the sequence is incorrect :
The executable is a nicely looking C# application, one which DotPeek likes to decompile. After some reversing, I’ve located the verification and MessageBox launch function :
The timer routine pop this.m_coll items (representing the clicks coordinates), convert them to hex string and concatenate it into a single hex string array. Then it call <Module>.native_verify. <Module>.native_verify is not referenced anywhere in DotPeek’s decompiled code and the fact that “native” is in the function name probably points to some C++/CLI code embedded in the executable and resolved by a hand-written loader. Instead of trying to locate and reverse the loader, it’s easier to trace it using a debugger.
The issue with debugging C# code is the presence of JIT : unused functions are not compiled to native code instructions until the code flow hits them. JIT mechanism resemble to the lazy page allocation for virtual memory : MEM_COMMIT virtual memory is not actually backed by physical memory until a access memory triggers a #PF. To overcome this issue, I need to actually trigger the timer2_Tick at least once :
Now we can break on <Module>.native_verify and examine what’s going on behind the call. <Module>.native_verify actually calls clr!NDirectImportThunk to resolve a C#/managed binding and call the following function (reversed by IDA) :
Screenshots of IDA graph view are not the best tool for explaining control flow so I’ve schematized the function flow graph :
There are two “external” calls inside this function (as in IDA cannot locate the address) that need to be resolved. The first one is simply a call to wscncpy, but the second one actually does the final verification resulting in a OK/KO return code. IDA cannot resolve the address since the function is located in a JIT page :
Fortunately, IDA can import JIT pages as additional binaries and resolve functions calls based on base address. Inserting the function into allow me to decompile it using HexRays :
HexRays decompiled code is not really human readable, but it does not matter since the extracted code is just meant to be run as a black box. Now that we identified every block in the verification function, let’s go back to the flow graph :
What’s interesting in the verification function is everything coming after the malloc instruction depends only on the 32-bit computed “seed” integer which is derived from the input strings representing the clicks’ coordinates. That means we can try to bruteforce seed values until it returns a correct value. After some HexRays and a ad-hoc C program, I found the following valid seed value : 0x33746715.
Not shown in the schema, but every click coordinates account for only one byte of the computed 32-bit seed value, so we can try to find matching coordinates for each byte of our valid seed :
Using this generated table, I was able to find matching coordinates for the seed : (543, 175), (568, 175), (567, 191), (535, 196). Since I’m lazy and I don’t want to click precise locations every time I’m testing/trying to solve the challenge, I’ve implemented a clicker in Python :
When running the clicker, I got the following modal box :
That was a really neat challenge, which can be quite difficult if you’re not knowledgeable about C# reversing and C#/C++ Windbg managed debugging. As a side note, I think it’s probably possible to black box bruteforce the challenge since every click need to be placed on a 25 pt radius around a particular point which makes a total of (50*2)**4=100000000 combinations for the 4 clicks. You just need to use an automated clicker (autoit or my python script) and one or two correctly placed breakpoints for some guiding feedback.