Malwarebytes CrackMe 2 by hasherazade9 minutes read
Tha crackme is created by @hasherazade for malware analysts.
You can download it from here
Environment and tools used
During the analysis, I used the following tools:
NOTE: I recommend you to use
flare-floss instead of a
The main file is one with no extension:
another, but that’s not the plain source code, it’s the compiled one.
We can decompile it with
uncompyle6. Occasionally, the main python file that is packed with
PyInstaller does not contain the magic number -
0x03 0xF3 0x0D 0x0A 0x00 0x00 0x00 0x00, we need to append the magic number (if there is none) and decompile the file using
NOTE: we need to append ".pyc" extension, otherwise "uncompyle6" complains
Now we have the source code:
At the first stage, it checks login, password, and PIN.
We clearly see that
hackerman and the password’s
MD5 hash is
42f749ade7f9e195bf475f37a44cafcb, we can use an online decryptor tool to get the password:
PIN to generate
key value and checks
MD5 hash for the value, at online databases there is no entry for
fb4b322c518e9f6a52af906e32aee955, so we need to brute-force one (assume that
PIN is 4 bytes long and only numeric values from 0 to 9):
My script to brute-force
Stage 1 solved:
decode_and_fetch_url it decrypts the URL and downloads the image:
get_encoded_data to extract data from the image, and
is_valid_payl to check if the data is PE executable:
After that, it allocates memory, copies the data and jumps to
allocated_mem + 2 location via
call instruction (seems like the downloaded file contains shellcode functionality):
We need to analyze the decrypted file. Just dump the PE file while debugging the source.
The shellcode starts from the third byte of the file:
NOTE: base address of the file might be different on different screenshots. The important part is RVAs.
To debug the second stage file, we pause debugging source code at
MR() call (transfer call), attach a debugger to the
python.exe process and set
EIP to allocated memory:
Instructions at the beginning are used to jump to
NOTE: 0x7BA0000 is the base address of the file in the memory
base+0x6E0 it builds
IAT (import address table )
After getting all necessary function addresses, it jumps to
OEP (Original Entry Point) of the PE file (it’s
call esi at the near end of
There is tons of unnecessary code, the most important part for us, starts at
It registers two vectored exception handlers,
VEC_Handler_set_enviroment_var sets the current process ID as
mb_chall environment variable for the process and returns
0 - EXCEPTION_CONTINUE_SEARCH
EIP - instruction pointer by 6 (a.k.a skip next 6 bytes of instructions) and returns
0xFFFFFFFF - EXCEPTION_CONTINUE_EXECUTION
There is an anti-debug trick using
INT 3 (0xCC) instruction.
INT 3 trick
Let’s say we have following code:
INT3 - EXCEPTION_BREAKPOINT occurs an attached debugger has the chance to handle the exception, if there is no a debugger attached, registered
SEH executes, if any debugger implicitly handles the exception, it just skips one instruction
0xCC and continues execution, we can use this method to change our program behavior under some debuggers.
WinDbg implicitly handles
INT 3 exception:
If there is no a debugger attached, which handles the exception, we can use the
SEH handler to change the code execution path, by modifying
EIP register (as shown at the code snippet above)
IDA Pro gives us the chance to decide which way is preferable to us:
INT 3 is used to execute the
msg_sorry_failed function if the execution happens under a debugger:
If there is no debugger, which handles the exception, the
crackme skips the next 6 bytes and continues execution from
enum_windows__HERE function, which creates a new thread and executes
enumWindProc for each top-level window and checks if a window name contains
If so, it changes the window title to
"Secret Console is waiting for the commands..."
After that, it enumerates child windows and checks if the content contains the
If so, it loads
actxprxy.dll and overwrites the first 0x269 bytes with encoded/encrypted/compressed data:
NOTE: click here to read more about
We did it.
Stage 2 solved:
Gets address of the recently loaded module, calculates and checks the checksum, decompresses the overwritten data and
XORs with a user entered key:
level3_colors is used to get a key from a user in form of an
R G B color code:
After decoding the data, it tries to execute the data using
exec command, the
exec method executes the dynamically created program, which is either a string or a code object, simple example:
The challenge is that we should guess correct the
R G B sequence to decrypt the data and execute it.
My brute-force script is the following:
data variable is part of the encrypted data (there is no need to decrypt whole data to guess the correct sequence), and it the checks if the result is a printable string:
Stage 3 solved:
R - 128,
B - 0,
G - 128
Thank you @hasherezade for such an interesting crackme.
Any feedback would be greatly appreciated.
Discuss on Reddit