Intro
Hi again. First, sorry for delaying this post so much, but i am currently so busy, that barely i am finding time for something more than necessities. Anyways, here comes the post about keygenning the CONFidence 2012 Crackme…
In contrary to my previous post (focused on obtaining the key) now i will focus on analysis of the obfuscated algorithm used in generating MMX instructions. I assume, that you read my previous post, so if not – please refer to it.
If you don’t care about tutorial, just want to see the keygen – it’s here:
Tools used
- ImmunityDbg
Analysis
As we know, the MMX instructions are stored in a piece of memory starting at 403090. Generation of MMX instructions comes directly before the call to it, so it’s easy to spot. Before, the piece of memory from 403090 to 4044d0 is cleared (with RtlZeroMemory).
Pay attention at arguments, which are passed to the generating function (40118A). Content of EBX is pretty obvious – it is a pointer to the memory to be filled (304090). But in ESI there is 403000 and it means…
The piece of memory, where the hashes are stored. From 403000 to 40300f there is a copy of hash#1 (md5 of the given username). It is important information – this hash will be used in generating MMX instructions.
So, lets follow inside the generating function. Before the user-specific instructions will be genetated, first the MMX prolog is decrypted.
Six dwords, stored at memory addresses from 417a8 are XOR-ed with 45534554. And the result is:
Looks familiar? Yeah, it was easy, but now the real fun begins… 🙂
Some initial values are set. ECX = 100h = 256… If you remember, there are 256 blocks of MMX instructions, so it may have something to deal with it…
Then it comes to processing of the hash#1. This part is slightly obfuscated, so i will explain it.
004010B6 $ 56 PUSH ESI 004010B7 . 52 PUSH EDX 004010B8 . 8B7424 0C MOV ESI,DWORD PTR SS:[ESP+C] ; Unpacked.00403000 004010BC . 8B16 MOV EDX,DWORD PTR DS:[ESI] ; EDX = DS:[403000] 004010BE . 81E2 87000000 AND EDX,87 004010C4 . 0F9BC2 SETPO DL [...] 004010EA . 33C0 XOR EAX,EAX 004010EC . D126 SHL DWORD PTR DS:[ESI],1 004010EE . D156 04 RCL DWORD PTR DS:[ESI+4],1 [...] 004010F6 > D156 08 RCL DWORD PTR DS:[ESI+8],1 004010F9 . D156 0C RCL DWORD PTR DS:[ESI+C],1 [...] 0040111A > 13C0 ADC EAX,EAX 0040111C . 33C2 XOR EAX,EDX 0040111E . 0906 OR DWORD PTR DS:[ESI],EAX 00401120 . 5A POP EDX 00401121 . 5E POP ESI 00401122 . C2 0400 RETN 4
As we see, the piece of memory containing hash#1 is modified after each execution of those instructions. Value of EAX is modified – it changes according to the content of memory at 403000 – that’s how the value of hash influences the process of generating MMX instructions. But obviously, we need to know details… The question is, how exectly every MMX instruction is generated and what is the connection between it and the hash/processed hash?
The previously described function is called twice. The result of first call is stored in EDX. (I will denote this function as get_cmd_base).
00401125 $ 52 PUSH EDX 00401126 . 56 PUSH ESI 00401127 . 8B7424 0C MOV ESI,DWORD PTR SS:[ESP+C] ; ESI = 403000 0040112B > 51 PUSH ECX ; bgn#1 [...] 0040114C . 59 POP ECX 0040114D . 56 PUSH ESI 0040114E . E8 63FFFFFF CALL Unpacked.004010B6 ; modify memory at 403000 00401153 . 8BD0 MOV EDX,EAX ; EAX = result of function at 4010B6 00401155 . 56 PUSH ESI 00401156 . E8 5BFFFFFF CALL Unpacked.004010B6 ; modify (again) memory at 403000 0040115B . 8D0450 LEA EAX,DWORD PTR DS:[EAX+EDX*2] [...] 00401181 . 85C0 TEST EAX,EAX 00401183 >^74 A6 JE SHORT Unpacked.0040112B ; ;goto #bgn1 00401185 . 5E POP ESI 00401186 . 5A POP EDX 00401187 . C2 0400 RETN 4
Then, the first result is multiplied by 2 and added to second result in EAX.
DWORD get_cmd_base(BYTE *hashBuffer) { DWORD eax, edx; do { edx = process_hash(hashBuffer); eax = process_hash(hashBuffer); eax = eax + edx * 2; } while (eax == 0); return eax; }
What are the possible valueas of EAX?
EAX = EAX + EDX * 2
where right side EAX and EDX are results from 403000 modifying function. So, EAX, EDX can take a value either 0 or 1. Means left side EAX (res) is:
| EAX | EDX | res | ------------------- | 0 | 0 | 0 | | 1 | 0 | 1 | | 0 | 1 | 2 | | 1 | 1 | 3 | -------------------
If EAX == 0, then everything is repeated once again – (after some obfuscation) we go back to the same piece of code. If EAX != 0, then instruction is generated on its base.
Below is how the first instruction comes. The first instruction is MOVQ [MM6/MM7], [MM0/MM1]
0040120A > 56 PUSH ESI 0040120B . E8 15FFFFFF CALL Unpacked.00401125 00401210 . D1E8 SHR EAX,1 00401212 . F7D8 NEG EAX 00401214 . 83E0 01 AND EAX,1 [...] 0040122B > 8BEB MOV EBP,EBX [...] 0040124B > 81E5 00070000 AND EBP,700 00401251 . C1ED 05 SHR EBP,5 00401254 . 81CD C6000000 OR EBP,0C6 0040125A . 33E8 XOR EBP,EAX [...] 0040147D $ 8BC5 MOV EAX,EBP 0040147F . C1E0 18 SHL EAX,18 [...] 004014A5 . 0D CC0F7F00 OR EAX,7F0FCC ; MOVQ MMx, MMy 004014AA . C1C8 08 ROR EAX,8 004014AD . 8907 MOV DWORD PTR DS:[EDI],EAX 004014AF . 83C7 03 ADD EDI,3 [...] 004014D0 > 8BC3 MOV EAX,EBX 004014D2 . C1E8 1F SHR EAX,1F 004014D5 . 33D8 XOR EBX,EAX 004014D7 . C3 RETN
And then, generating next instruction: MOVQ [MM7/MM6],[MM2/MM3/MM4/MM5].
The choice of first register depends on the previous. if previously we had MOVQ MM6,[…] now there must be MOV MM7,[…]. The second choice is independent.
00401284 . 81CB 00000080 OR EBX,80000000 [...] 004012A8 > 8BC3 MOV EAX,EBX 004012AA . 83E0 07 AND EAX,7 004012AD . C1E0 03 SHL EAX,3 004012B0 . 81E5 C7000000 AND EBP,0C7 004012B6 . 0BE8 OR EBP,EAX 004012B8 . 83F5 01 XOR EBP,1 [...] 0040147D $ 8BC5 MOV EAX,EBP 0040147F . C1E0 18 SHL EAX,18 [...] 004014A5 . 0D CC0F7F00 OR EAX,7F0FCC ; MOVQ MMx, MMy 004014AA . C1C8 08 ROR EAX,8 004014AD . 8907 MOV DWORD PTR DS:[EDI],EAX 004014AF . 83C7 03 ADD EDI,3 [...] 004014D0 > 8BC3 MOV EAX,EBX 004014D2 . C1E8 1F SHR EAX,1F 004014D5 . 33D8 XOR EBX,EAX 004014D7 . C3 RETN
Third instruction:
As we know, 3-rd, 4-ty and 5-th instructions are various. Here we see from where this variety comes. The call to an instruction generating procedure is done to various places in memory, depeending on EAX.
004012DE > 56 PUSH ESI ; Unpacked.00403000 004012DF . E8 41FEFFFF CALL Unpacked.00401125 [...] 00401307 . 8BEB MOV EBP,EBX 00401309 . 83E5 07 AND EBP,7 0040130C . 81CD F0000000 OR EBP,0F0 00401312 . FF1485 6D14400>CALL DWORD PTR DS:[EAX*4+40146D] 00401319 . E8 07000000 CALL Unpacked.00401325 ; //after #3
EAX = {1, 2, 3}
[EAX*4+40146D] = {401471, 401475, 401479}
EAX = 1 -> call 4015A6
EAX = 2 -> call 4016C3
EAX = 3 -> call 4014D8
As we see, in each of these 3 cases, the function at 401125 is called. It leads, after some obfuscation, again to 40114D (described above, which result is “res”). Then, the “res” is used in further operations. After deobfuscation it is:
If EAX = 1
004015A6 $ 56 PUSH ESI ; Unpacked.00403000 004015A7 . E8 79FBFFFF CALL Unpacked.00401125 004015AC . 8AE0 MOV AH,AL 004015AE . 80E4 01 AND AH,1 004015B1 . C0E4 04 SHL AH,4 004015B4 . 80CC EF OR AH,0EF [...] 004015DA . 8AD0 MOV DL,AL 004015DC . 80E2 02 AND DL,2 004015DF . D0E2 SHL DL,1 004015E1 . 80CA FB OR DL,0FB [...] 00401602 > 22D4 AND DL,AH [...] 00401618 > 8AF0 MOV DH,AL 0040161A . 80E6 01 AND DH,1 0040161D . F6DE NEG DH [...] 00401642 . 56 PUSH ESI 00401643 . E8 DDFAFFFF CALL Unpacked.00401125 00401648 . 22F0 AND DH,AL 0040164A . 32D6 XOR DL,DH [...] 0040166A > 8BC5 MOV EAX,EBP 0040166C . 0FB6D2 MOVZX EDX,DL 0040166F . 0FB6C0 MOVZX EAX,AL 00401672 . C1E0 10 SHL EAX,10 00401675 . C1E2 08 SHL EDX,8 [...] 00401691 > 33C2 XOR EAX,EDX 00401693 . 35 0F0000CC XOR EAX,CC00000F 00401698 . 8907 MOV DWORD PTR DS:[EDI],EAX 0040169A . 83C7 03 ADD EDI,3 [...] 004016BB > 8BC3 MOV EAX,EBX 004016BD . C1E8 1F SHR EAX,1F 004016C0 . 33D8 XOR EBX,EAX 004016C2 . C3 RETN
If (EAX = 2):
004016C3 $ 51 PUSH ECX 004016C4 . 56 PUSH ESI 004016C5 . E8 5BFAFFFF CALL Unpacked.00401125 004016CA . 8AC8 MOV CL,AL [...] 004016D1 > 80E1 01 AND CL,1 004016D4 . B4 01 MOV AH,1 004016D6 . D2E4 SHL AH,CL 004016D8 . F6D4 NOT AH 004016DA . C0C4 04 ROL AH,4 [...] 00401700 24 02 AND AL,2 00401702 F6D0 NOT AL 00401704 D0C0 ROL AL,1 00401706 22E0 AND AH,AL [...] 0040172B 8BCD MOV ECX,EBP 0040172D 25 00FF0000 AND EAX,0FF00 00401732 0FB6C9 MOVZX ECX,CL 00401735 C1E1 10 SHL ECX,10 00401738 0BC1 OR EAX,ECX 0040173A 35 0F0000CC XOR EAX,CC00000F [...] 0040175D > 8907 MOV DWORD PTR DS:[EDI],EAX 0040175F . 83C7 03 ADD EDI,3 00401762 . 8BC3 MOV EAX,EBX 00401764 . C1E8 1F SHR EAX,1F 00401767 . 33D8 XOR EBX,EAX 00401769 . 59 POP ECX 0040176A . C3 RETN
If (EAX =3)
004014D8 $ 56 PUSH ESI 004014D9 . E8 47FCFFFF CALL Unpacked.00401125 [...] 004014DE . D0E8 SHR AL,1 004014E0 . 8AD0 MOV DL,AL 004014E2 . C0E2 05 SHL DL,5 [...] 00401503 > 56 PUSH ESI ; Unpacked.00403000 00401504 . E8 1CFCFFFF CALL Unpacked.00401125 00401509 . 8AF0 MOV DH,AL 0040150B . 8BC5 MOV EAX,EBP 0040150D . C0E8 03 SHR AL,3 [...] 00401533 > 24 07 AND AL,7 00401535 . 0C F0 OR AL,0F0 00401537 . 32D0 XOR DL,AL [...] 00401557 > 56 PUSH ESI ; Unpacked.00403000 00401558 . E8 C8FBFFFF CALL Unpacked.00401125 0040155D . 0C 70 OR AL,70 [...] 00401573 > C1E0 08 SHL EAX,8 00401576 . 0C 0F OR AL,0F 00401578 . C1E2 10 SHL EDX,10 0040157B . 33C2 XOR EAX,EDX [...] 004015A0 . 8907 MOV DWORD PTR DS:[EDI],EAX 004015A2 . 83C7 04 ADD EDI,4 004015A5 . C3 RETN
As we see, when the EAX = 3 some 4-byte instruction is created (like PSLLD MM6,2
). Other two cases creates 3-byte instructions (like PSUBW MM6,MM3
).
Fourth instruction:
0040132D > 56 PUSH ESI 0040132E . E8 F2FDFFFF CALL Unpacked.00401125 [...] 00401351 > 8BEB MOV EBP,EBX 00401353 . 83E5 07 AND EBP,7 00401356 . 81CD F8000000 OR EBP,0F8 0040135C . FF1485 6D14400> CALL DWORD PTR DS:[EAX*4+40146D]
– then if follows analogicaly like 3-rd.
Fifth
[...] 00401377 > 81E3 FFFFFF7F AND EBX,7FFFFFFF 0040137D . 56 PUSH ESI ; Unpacked.00403000 0040137E . E8 A2FDFFFF CALL Unpacked.00401125 00401383 . D1E8 SHR EAX,1 [...] 004013A8 . F7D8 NEG EAX 004013AA . 83E0 09 AND EAX,9 004013AD . BD F7000000 MOV EBP,0F7 004013B2 . 33E8 XOR EBP,EAX [...] 004015A6 $ 56 PUSH ESI ; Unpacked.00403000 004015A7 . E8 79FBFFFF CALL Unpacked.00401125 004015AC . 8AE0 MOV AH,AL 004015AE . 80E4 01 AND AH,1 004015B1 . C0E4 04 SHL AH,4 004015B4 . 80CC EF OR AH,0EF [...] 004015DA . 8AD0 MOV DL,AL 004015DC . 80E2 02 AND DL,2 004015DF . D0E2 SHL DL,1 004015E1 . 80CA FB OR DL,0FB [...] 00401602 > 22D4 AND DL,AH [...] 00401618 > 8AF0 MOV DH,AL 0040161A . 80E6 01 AND DH,1 0040161D . F6DE NEG DH [...] 00401642 . 56 PUSH ESI ; Unpacked.00403000 00401643 . E8 DDFAFFFF CALL Unpacked.00401125 00401648 . 22F0 AND DH,AL 0040164A . 32D6 XOR DL,DH [...] 0040166A > 8BC5 MOV EAX,EBP 0040166C . 0FB6D2 MOVZX EDX,DL 0040166F . 0FB6C0 MOVZX EAX,AL 00401672 . C1E0 10 SHL EAX,10 00401675 . C1E2 08 SHL EDX,8 [...] 00401691 > 33C2 XOR EAX,EDX 00401693 . 35 0F0000CC XOR EAX,CC00000F 00401698 . 8907 MOV DWORD PTR DS:[EDI],EAX 0040169A . 83C7 03 ADD EDI,3 [...] 004016BB > 8BC3 MOV EAX,EBX 004016BD . C1E8 1F SHR EAX,1F 004016C0 . 33D8 XOR EBX,EAX 004016C2 . C3 RETN
Sixth:
004013EB > 8BC3 MOV EAX,EBX 004013ED . C1E8 05 SHR EAX,5 004013F0 . 83F0 08 XOR EAX,8 004013F3 . 83E0 38 AND EAX,38 004013F6 . C1ED 03 SHR EBP,3 [...] 0040141C 83E5 07 AND EBP,7 0040141F 0BE8 OR EBP,EAX 00401421 81CD C0000000 OR EBP,0C0 [...] 004015A6 $ 56 PUSH ESI ; Unpacked.00403000 004015A7 . E8 79FBFFFF CALL Unpacked.00401125 004015AC . 8AE0 MOV AH,AL 004015AE . 80E4 01 AND AH,1 004015B1 . C0E4 04 SHL AH,4 004015B4 . 80CC EF OR AH,0EF [...] 004015DA . 8AD0 MOV DL,AL 004015DC . 80E2 02 AND DL,2 004015DF . D0E2 SHL DL,1 004015E1 . 80CA FB OR DL,0FB [...] 00401602 > 22D4 AND DL,AH [...] 00401618 > 8AF0 MOV DH,AL 0040161A . 80E6 01 AND DH,1 0040161D . F6DE NEG DH [...] 00401642 . 56 PUSH ESI ; Unpacked.00403000 00401643 . E8 DDFAFFFF CALL Unpacked.00401125 00401648 . 22F0 AND DH,AL 0040164A . 32D6 XOR DL,DH [...] 0040166A > 8BC5 MOV EAX,EBP 0040166C . 0FB6D2 MOVZX EDX,DL 0040166F . 0FB6C0 MOVZX EAX,AL 00401672 . C1E0 10 SHL EAX,10 00401675 . C1E2 08 SHL EDX,8 [...] 00401691 > 33C2 XOR EAX,EDX 00401693 . 35 0F0000CC XOR EAX,CC00000F 00401698 . 8907 MOV DWORD PTR DS:[EDI],EAX 0040169A . 83C7 03 ADD EDI,3 [...] 004016BB > 8BC3 MOV EAX,EBX 004016BD . C1E8 1F SHR EAX,1F 004016C0 . 33D8 XOR EBX,EAX 004016C2 . C3 RETN
After that…
00401454 . C0C3 04 ROL BL,4 00401457 . 81F3 00010000 XOR EBX,100 ; ECX = 100h 0040145D . 49 DEC ECX ; ECX = 0FFh 0040145E .^0F85 88FDFFFF JNZ Unpacked.004011EC
and navigation goes back to generation of first instruction. As we see, ECX is decremented – exactly 256 blocks of 6 instructions are generated.
The full MMX Generating code for any given login You can find in attached example: Generator.cpp
Keygenning
The MMX Generator was a missing piece of puzzle. Other pieces are described in my previous post. Now we must put them together and the keygen is ready!
But as we know, the generated MMX instructions must be reversed. There are two things to be done about it:
- Reversing the last (6-th instruction) in every block
- Reversing the order of blocks (first block must be the last and so on)
Ok, let’s do it one by one.
Reversing the last (6-th instruction) in every block:
The set of possible instructions occuring in the 6-th line is: {PADDB, PADDW, PADDQ, PSUBB,PSUBW, PSUBQ, XOR}. Three type of addition (add BYTE, add DWORD, add QWORD), analogical substractions and XOR. Reversing table will look like this:
PADDB -> PSUBB PADDW -> PSUBW PADDD -> PSUBD PSUBB -> PADDB PSUBW -> PADDW PSUBD -> PADDD XOR -> XOR
But we can operate on opcodes only. The representation of following instruction is:
PADDB = 0xfc PADDW = 0xfd PADDQ = 0xfe PSUBB = 0xf8 PSUBW = 0xf9 PSUBQ = 0xfa XOR = 0xef
So, when the 6-th instruction is generated, we must substitute one opcode by another – representing reversed operation. Take a look at the code generating 6-th instruction in Generator.cpp:
Instruction6: MOV EAX,EBX SHR EAX,5 XOR EAX,8 AND EAX,0x38 SHR EBP,3 AND EBP,7 OR EBP,EAX OR EBP,0xC0 call get_cmd_base MOV AH,AL AND AH,1 SHL AH,4 OR AH,0xEF MOV DL,AL AND DL,2 SHL DL,1 OR DL,0xFB AND DL,AH MOV DH,AL AND DH,1 NEG DH call get_cmd_base AND DH,AL XOR DL,DH MOV EAX,EBP MOVZX EDX,DL MOVZX EAX,AL SHL EAX,0x10 SHL EDX,8 XOR EAX,EDX XOR EAX,0xCC00000F MOV EDI, bufIndex MOV DWORD PTR buffer[EDI], EAX ADD bufIndex,3 MOV EAX,EBX SHR EAX,0x1F XOR EBX,EAX RET
thus, instruction in EDX should be reversed before the XORing wih EAX (line 332). It can be done easyli:
if (EDX == 0xef) -> don’t do anything (it’s XOR)
else if (EDX EDX += 4
else -> EDX -= 4
I hope everything is clear 🙂
Reversing the order of blocks
We must fill the buffer of blocks from the back to front. Here the only problem is, we don’t know the exact length in bytes of a single block, because instructions{3, 4} can be either of 3 or of 4 bytes. That’s why we have to reserve memory for the maximal case and fill the gaps with NOPs (0x90).
Then, adding RET at the end of the buffer, and we can call the generated code as a function, from within assembler code. Mind that the keygen must be compiled with DEP (Data Execution Prevention) switched off (eventualy you can set this page of memory executable by VirtualProtect).
It’s time to look at the Keygen.cpp!
//---------------------------------------------------------------------------
// the code published under Creative Commons (CC-BY-NC) license
// author: hasherezade (https://hshrzd.wordpress.com)
// the keygenerator for ESET CrackMe, CONfidence2012 (http://2012.confidence.org.pl)
// remarks: compile with DEP disabled
//---------------------------------------------------------------------------
#include <windows.h>
#include <iostream>
using namespace std;
BYTE hsh[16];
BYTE hashes[4][16];
BYTE output[16];
/*
maxBlock =
6 instructions total:
instruction[1,2,5,6] -> 3 bytes
instruction[3,4] -> 3 or 4 bytes -> max 4 bytes
+ 1 byte -> NOP at the end of 6-th instruction (padding)
*/
const DWORD maxBlock = 4 * 3 + 2 * 4 + 1;
const DWORD bufMax = maxBlock * 256;
BYTE buffer[bufMax];
DWORD bufIndex = bufMax - maxBlock;
DWORD blockStart = bufMax;
//----------------------------------------
typedef struct {
ULONG i[2];
ULONG buf[4];
unsigned char in[64];
unsigned char digest[16];
} MD5_CTX;
typedef void (WINAPI *t_MD5Init)(
MD5_CTX *context
);
t_MD5Init MD5Init;
typedef void (WINAPI *t_MD5Update)(
MD5_CTX *context,
const unsigned char *input,
unsigned int inlen
);
t_MD5Update MD5Update;
typedef void (WINAPI *t_MD5Final)
(
MD5_CTX *context
);
t_MD5Final MD5Final;
char revrs(int a)
{
a += 0x41;
if (a >= 'A' && a <= 'Z')
return a;
a += 6;
return a;
}
void decode_chunks()
{
int V = 0x29, i = 0;
WORD* out = (WORD*)output;
while (i < 8) {
WORD chunk = out[i];
i++;
//printf("\n%4X",chunk);
int x,y,z;
int a;
z = chunk % V;
a = chunk / V;
y = a % V;
x = a / V;
printf("%c%c%c", revrs(x), revrs(y), revrs(z));
}
}
//----------------------------------------
void call_generated()
{
memset(output,0,16);
void* generated = (void*)buffer;
_asm {
EMMS
MOVQ MM0,QWORD PTR hashes[0]
MOVQ MM1,QWORD PTR hashes[8]
MOVQ MM2,QWORD PTR hashes[0x10]
MOVQ MM3,QWORD PTR hashes[0x18]
MOVQ MM4,QWORD PTR hashes[0x20]
MOVQ MM5,QWORD PTR hashes[0x28]
call generated
MOVQ QWORD PTR output[0], MM0
MOVQ QWORD PTR output[8], MM1
};
}
void genetrateReversed()
{
memset(buffer, 0x90, bufMax);
__asm {
push ebp
mov EBX, 0x42
mov ECX, 0x100
jmp start
process_hsh:
PUSH ESI
PUSH EDX
MOV EDX, dword ptr hsh[0]
AND EDX,0x87
SETPO DL
XOR EAX,EAX
SHL dword ptr hsh[0],1
RCL DWORD PTR hsh[4],1
RCL DWORD PTR hsh[8],1
RCL DWORD PTR hsh[0xC],1
ADC EAX,EAX
XOR EAX,EDX
OR DWORD PTR hsh[0],EAX
POP EDX
POP ESI
RET
get_cmd_base:
PUSH EDX
PUSH ESI
bgn1:
call process_hsh
MOV EDX,EAX
call process_hsh
LEA EAX,DWORD PTR DS:[EAX+EDX*2]
TEST EAX,EAX
JE bgn1
POP ESI
POP EDX
RET
Instruction1:
call get_cmd_base
SHR EAX,1
NEG EAX
AND EAX,1
MOV EBP,EBX
AND EBP,0x700
SHR EBP,5
OR EBP,0xC6
XOR EBP,EAX
MOV EAX,EBP
SHL EAX,0x18
OR EAX,0x7F0FCC
ROR EAX,8
MOV EDI, bufIndex
MOV DWORD PTR buffer[EDI], EAX
ADD bufIndex,3
MOV EAX,EBX
SHR EAX,0x1F
XOR EBX,EAX
RET
Instruction2:
OR EBX,0x80000000
MOV EAX,EBX
AND EAX,7
SHL EAX,3
AND EBP,0xC7
OR EBP,EAX
XOR EBP,1
MOV EAX,EBP
SHL EAX,0x18
OR EAX,0x7F0FCC
ROR EAX,8
MOV EDI, bufIndex
MOV DWORD PTR buffer[EDI], EAX
ADD bufIndex,3
MOV EAX,EBX
SHR EAX,0x1F
XOR EBX,EAX
RET
case1:
call get_cmd_base
MOV AH,AL
AND AH,1
SHL AH,4
OR AH,0xEF
MOV DL,AL
AND DL,2
SHL DL,1
OR DL,0xFB
AND DL,AH
MOV DH,AL
AND DH,1
NEG DH
call get_cmd_base
AND DH,AL
XOR DL,DH
MOV EAX,EBP
MOVZX EDX,DL
MOVZX EAX,AL
SHL EAX,0x10
SHL EDX,8
XOR EAX,EDX
XOR EAX,0xCC00000F
MOV EDI, bufIndex
MOV DWORD PTR buffer[EDI], EAX
ADD bufIndex,3
MOV EAX,EBX
SHR EAX,0x1F
XOR EBX,EAX
RET
case2:
PUSH ECX
call get_cmd_base
MOV CL,AL
AND CL,1
MOV AH,1
SHL AH,CL
NOT AH
ROL AH,4
AND AL,2
NOT AL
ROL AL,1
AND AH,AL
MOV ECX,EBP
AND EAX,0xFF00
MOVZX ECX,CL
SHL ECX,0x10
OR EAX,ECX
XOR EAX,0xCC00000F
MOV EDI, bufIndex
MOV DWORD PTR buffer[EDI], EAX
ADD bufIndex,3
MOV EAX,EBX
SHR EAX,0x1F
XOR EBX,EAX
POP ECX
RET
case3:
call get_cmd_base
SHR AL,1
MOV DL,AL
SHL DL,5
call get_cmd_base
MOV DH,AL
MOV EAX,EBP
SHR AL,3
AND AL,7
OR AL,0xF0
XOR DL,AL
call get_cmd_base
OR AL,0x70
SHL EAX,8
OR AL,0x0F
SHL EDX,0x10
XOR EAX,EDX
MOV EDI, bufIndex
MOV DWORD PTR buffer[EDI], EAX
ADD bufIndex,4
RET
Instruction3:
call get_cmd_base
MOV EBP,EBX
AND EBP,7
OR EBP,0x0F0
the_switch:
cmp eax, 1
jne c2
jmp case1
c2:
cmp eax, 2
jne c3
jmp case2
c3:
cmp eax, 3
jne c4
jmp case3
c4:
RET
Instruction4:
call get_cmd_base
MOV EBP,EBX
AND EBP,7
OR EBP,0x0F8
jmp the_switch
RET
Instruction5:
AND EBX,0x7FFFFFFF
call get_cmd_base
SHR EAX,1
NEG EAX
AND EAX,9
MOV EBP,0xF7
XOR EBP,EAX
call get_cmd_base
MOV AH,AL
AND AH,1
SHL AH,4
OR AH,0xEF
MOV DL,AL
AND DL,2
SHL DL,1
OR DL,0xFB
AND DL,AH
MOV DH,AL
AND DH,1
NEG DH
call get_cmd_base
AND DH,AL
XOR DL,DH
MOV EAX,EBP
MOVZX EDX,DL
MOVZX EAX,AL
SHL EAX,0x10
SHL EDX,8
XOR EAX,EDX
XOR EAX,0xCC00000F
MOV EDI, bufIndex
MOV DWORD PTR buffer[EDI], EAX
ADD bufIndex,3
MOV EAX,EBX
SHR EAX,0x1F
XOR EBX,EAX
RET
Instruction6:
MOV EAX,EBX
SHR EAX,5
XOR EAX,8
AND EAX,0x38
SHR EBP,3
AND EBP,7
OR EBP,EAX
OR EBP,0xC0
call get_cmd_base
MOV AH,AL
AND AH,1
SHL AH,4
OR AH,0xEF
MOV DL,AL
AND DL,2
SHL DL,1
OR DL,0xFB
AND DL,AH
MOV DH,AL
AND DH,1
NEG DH
call get_cmd_base
AND DH,AL
XOR DL,DH
MOV EAX,EBP
MOVZX EDX,DL
MOVZX EAX,AL
SHL EAX,0x10
call reverseInstruction6
SHL EDX,8
XOR EAX,EDX
XOR EAX,0x9000000F ;// i want NOP at the end of the last instruction (instead of INT 3: XOR EAX,0xCC00000F)
MOV EDI, bufIndex
MOV DWORD PTR buffer[EDI], EAX
ADD bufIndex,3
MOV EAX,EBX
SHR EAX,0x1F
XOR EBX,EAX
RET
reverseInstruction6:
;/*
; 0xfc -> 0xf8 (PADDB -> PSUBB)
; 0xfd -> 0xf9 (PADDW -> PSUBW)
; 0xfe -> 0xfa (PADDD -> PSUBD)
;
; 0xf8 -> 0xfc (PSUBB -> PADDB)
; 0xf9 -> 0xfd (PSUBW -> PADDW)
; 0xfa -> 0xfe (PSUBD -> PADDD)
;
; 0xef -> 0xef (reversed XOR is XOR)
;*/
cmp EDX, 0xef
je revEnd
cmp EDX, 0xfc
jb r1
SUB EDX,4
jmp revEnd
r1:
ADD EDX,4
revEnd:
RET
start:
push ebx
mov ebx,blockStart
sub ebx, maxBlock
mov blockStart, ebx
mov bufIndex, ebx
pop ebx
call Instruction1
call Instruction2
call Instruction3
call Instruction4
call Instruction5
call Instruction6
ROL BL,4
XOR EBX,0x100
DEC ECX
JNZ start
pop ebp
};
BYTE ret = 0xc3;
buffer[bufMax-1] = ret;
}
int main(){
//load
int i;
HMODULE hCryptdll = LoadLibraryA("Cryptdll.dll");
if (hCryptdll==NULL) return (-1);
MD5Init = (t_MD5Init)GetProcAddress(hCryptdll, "MD5Init");
MD5Update = (t_MD5Update)GetProcAddress(hCryptdll, "MD5Update");
MD5Final = (t_MD5Final)GetProcAddress(hCryptdll, "MD5Final");
//Get input
const int MAX = 33;
char input[MAX];
printf("Name:\n");
scanf("%[ A-Za-z]s", input); //including space
int len = strlen(input);
MD5_CTX md5;
MD5Init(&md5);
MD5Update(&md5,(const unsigned char *)input, len);
MD5Final(&md5);
memcpy(hsh, md5.digest, 16);
//other hashes
memcpy(hashes[0], md5.digest, 16);
char backup[16];
memcpy(backup, md5.digest, 16);
int x;
for (x = 1; x < 3; x++) {
MD5Init(&md5);
MD5Update(&md5,(const unsigned char *)backup, 16);
MD5Final(&md5);
memcpy(hashes[x], md5.digest, 16);
memcpy(backup, md5.digest, 16);
}
//---
genetrateReversed();
call_generated();
printf("\nRegistration key:\n");
decode_chunks();
printf("\n\n---\n");
system("pause");
return 0;
}
Colored with dumpz.org
Hey
Good job with crackme. I read your solution and instantly noticed this:
// remarks: compile with DEP disabled
It’s caused by this lines:
BYTE buffer[bufMax];
void* generated = (void*)buffer;
call generated
You can just do VirtualProtect with PAGE_EXECUTE to get it work flowlessly with DEP.
It would work on xpsp3 without that because ther’s no PAE kernel loaded at default.
Pozdr
Sure VirtualProtect will help. But i wanted to keep the solution as small and simple as possible, using only functions directly related to the problem.