This challenge was on reverse engineering. The binary is 32bit MZ-PE executable for Windows.
Summary: reverse engineering, crypto
The given file is packed by easy algorithm. It is xored by 0x2d and also has additional anti-reverse trick as jump in the middle of the instructions. It looks like this:
As you can see at the picture above, from VA .00407000 to .0040700C that anti-reverse trick:
push esi // save esi in stack
add esi, 005EB9090 // pseudo command. It is consist of needed bytes
jz .000407005
jnz .000407005 // in any cases we jump to 407005 – in the middle of cmd: add esi, 005EB9090
add esi, 005eb9090 changes to
.00407005: EB05 jmps .00040700C // it is jmp into instruction too
.00407007: 74FC jz .000407005
.00407009: 75FA jnz .000407005
.0040700B: E95E64A118 jmp 018E1D46E
jmp 018E1D46E change to
.0040700C: 5E pop esi // get saved before esi from stack
.0040700D: 64A118000000 mov eax,fs:[000000018] // it is real command
We can bypass this trick for that we should patch it (just everywhere change bytes):
5681C69090EB0574FC75FAE95E64A118
To
90909090909090909090909090909090
So, after unpack and patch procedure we have quite comprehensible C++ compiled sample.
If you have been careful it also would be working and be “hex-raysable” =)
Program has several main functions:
- Drop driver from itself to “C:\WINDOWS\Temp\ReverMe1.sys”
- Create and start service “ReverMe1”
- Make DeviceIoControl request with first command line argument in parameters
- Get result from service and compare its first 8 bytes with “b1cc4893”
file = (FILE *)open(“C:\\WINDOWS\\Temp\\ReverMe1.sys”, 33537, 448);
if ( (signed int)file >= 0 )
{
write(file, &driver_emb, 7808);
close(file);
CreateService(“C:\\WINDOWS\\Temp\\ReverMe1.sys”);
StartService();
strncpy(&buff, argv[1], 0x200u);
hDevice = CreateFileA(“\\\\.\\ReversMe1″, 0xC0000000u, 0, 0, 3u, 0x80u, 0);
DeviceIoControl(hDevice, 0x9C40E003u, &buff, 0x200u, &buff, 0x200u, (LPDWORD)&bytesReturned, 0);
CloseHandle(hDevice);
if ( memcmp(&buff, “b1cc4893″, 8u) )
printf(“Sorry noob, just try again ;-)\n”);
else
printf(“Nice job ! You found me :-)\nValid the hash : %s\n”, &buff);
ret = 0;
}
If you execute this several times and look to the results, it would be obviously some kind of hash calculation. The fact that hash has a size 16 bytes (32 in text) hints that it is md5 algorithm.
But if you compare md5 of your input string with result from driver it will be different. May it be modified md5?
There are two possible ways (mat be more, but we found two =) ):
- First method which was proposed by me =)
Just reverse driver and get answer! I will describe this way in detail in next post.
- Second method which was proposed by vos:
Input different data and try to understand what kind of hash is it
Now I describe vos method and in next post you can find detail describing about me one.
For easily do set of inputs-outputs, we should patch unpacked file there (from jnz to jz):
Now we will have hash in output everytime!
I found the interesting set of input-output pairs:
11111 – b59c67bf196a4758191e42f76670ceba
111111 – b59c67bf196a4758191e42f76670ceba
Hm, hashs are same. Let’s try input more “1”
1111111111111111 – b59c67bf196a4758191e42f76670ceba
Less:
1111 – b59c67bf196a4758191e42f76670ceba
111 – 63813da8e6d495818746b94d6d9b8382
Op, Hash changed! Could it be hash only from first 4 bytes? Let’s try!
1111HelloWorld – b59c67bf196a4758191e42f76670ceba
It is same! How about md5 form “1111”?
md5(“1111”) = b59c67bf196a4758191e42f76670ceba
Yes, we get it. Program calculates md5 form first 4 input bytes. All what we need is just to bruteforce md5 for 4 symbol string and find one which has first 4 bytes equal “b1cc4893”
Not so hard isn’t it?
So, key:
Input: OwnM
MD5: b1cc4893de3b7d9401d30f2f5890df12
1 ping
[…] It is second part of CrackMe task describing. First one you can find there […]