4 minutes read

CrackMes are a great way to improve reverse engineering skills. In these series, I’ll try to analyze and solve some medium level CrackMes. Solving similar problems are very helpful for malware analysts.

Today’s CrackMe is [A]dvanced Keygenme by sd333221

Date of Release: 2-24-2007

Download: hybrid-analysis, VirusTotal

I encourage you to do it yourself before reading the solution.

Note: Variables are named by me after analysis.

Thanks to PeStudio , now we know the author ( haxx0r ) and fact that the executable uses Thread Local Storage .

Let’s open in IDA Pro :

In tls-callback it calls GetTickCount and computes value of HIGH_pp from the result:

In GetRand_CPUID_getTick it gets CPU vendor ID using cpuid (EAX=0) , and uses HIGH_pp to compute new value:

After that, it converts the result to string using _itoa .

modify_str contains two parts mix_two_list and modify_cpuid_time :

In mix_two_list it builds a list of bytes(I renamed variable as alpha ) from 0x0 to 0xFF and modifies it using another list of 13337....133371 :

Python implementation of mix_two_list function:

In modify_cpuid_time it uses the value converted from integer to string and modifies this value using alpha list:

Python implementation of modify_cpuid_time :

modify_str is used to encrypt/decrypt computed value before using it.

At the end of tls-callback , it uses two ways to detect debuggers, named as chckDbgr and anotherCheck . chckDbgr uses “guard” pages to detect debuggers and anotherCheck uses FindWindow() and CreateFile() functions, both tricks are explained in The Ultimate Anti-Reversing Reference by Peter Ferrie (must read!)

The CrackMe uses custom base64 alphabet: /+9876543210zyxwvutsrqponmlkjihgfedcbaZYXWVUTSRQPONMLKJIHGFEDCBA but if it detects a debugger it calls ifDebugg__ function, which reverses the alphabet:

That’s tls-callback , in WinMain it sets the result of our old friend GetRand_CPUID_getTick as username, that’s exactly same value what we have in encrypted form.

Let’s analyze CheckSerial function (we are trying to write keygen, don’t patch it)

In CheckSerial function it decrypts the value (Yeah, this is from tls-callback ), decrypted version of text is same as username , both are from GetRand_CPUID_getTick , after decryption it encodes result with base64 but uses custom alphabet, encrypts result once again and encodes result as well, final result is saved in esi register

SerialComp gets our input as a parameter and returns value which should be same as in esi .

SerialComp is some kind of decoding function:

Python REVERSE implementation of SerialComp :

What we know:

It gets value from cpuid and GetTickCount - same as username

and - same as username Encodes the value with base64 using custom alphabet

using custom alphabet Encrypts decoded value

Encodes encrypted value

Main parts of writing keygen are implementing reverse of SerialComp and encryption function (I’m using the built-in support of base64 ).

We have everything we need to write keygen:

Any feedback appreciated.

Twitter: @_qaz_qaz