Log in

View Full Version : impossible crackme #2 :]


orp
November 30th, 2006, 17:48
hi,

i've attached a little crackme. im not using code obfuscation, import wrapping or antidebugging stuff at all, but im pretty sure the exe isn't patchable.

any feedback is appreciated

thx


if it won't run because of missing dlls, please download mfc redistributables from http://www.microsoft.com/downloads/details.aspx?FamilyId=32BC1BEE-A3F9-4C13-9C99-220B62A191EE&displaylang=en

0rp
December 20th, 2006, 15:53
ok, second try

this time its a b s o l u t l y impossible to patch it (beware sarcasm)

well, it should be harder

ive changed the backend, opcode encryption isn't used anymore, so all opcodes are plain in the vmdata.

the checkfunc is the check export

the resultmessages are also plain in the vmdata

try to change the messages, or the try to patch the "algorithm" (make it accepting different numbers)

the sourcecode this time is:

Code:
void strcpy(data dest, data src)
{
for (int i = 0; src[I] != 0; i++)
dest[I] = src[I];
dest[I] = 0;
}

void __export check(int key, data result)
{
if (key == 42)
strcpy(result, "oh, youve keygenned me";
else
strcpy(result, "hmmh, no, try 42";
}

0rp
December 20th, 2006, 16:14
sourcecode of testcon:

ZaiRoN
December 21st, 2006, 13:54
Well done Orp, things are getting hard! Maybe, it's really impossible to patch... Let's see

Maximus
December 24th, 2006, 20:30
I gave it a very quick look, 0rp, because you said it's a VM.
But since I am ve-e-ery lazy, I would like to ask you a thing. I found your 'test' instruction block, and this is my question:

What's happen if I hook&log all the calls to that instruction, and then start 'flipping' every bad boy of it back re-executing it, until I get a good result?
:P

ZaiRoN
December 26th, 2006, 17:18
Orp: I patched the Good/Bad boy jump, is this a valid solution?
(If yes I'll explain how I did it.)

0rp
December 27th, 2006, 15:45
wow ZaiRoN, you are hardcore

i knew crcing only one dword of each input is bad idea, but i couldnt imagine it could be exploited like this

congratulations

and yes, i will fix this issue :]

0rp
December 27th, 2006, 15:47
and i would like to read your explanation

0rp
December 27th, 2006, 15:51
Quote:
[Originally Posted by Maximus;63359]I gave it a very quick look, 0rp, because you said it's a VM.
But since I am ve-e-ery lazy, I would like to ask you a thing. I found your 'test' instruction block, and this is my question:

What's happen if I hook&log all the calls to that instruction, and then start 'flipping' every bad boy of it back re-executing it, until I get a good result?
:P


logging the vm is prolly the best way to see how it works. but be carefully with your hooks, since they will break some crcs and make it crash

what do you mean with "flipping every bad boy of it back re-executing it" ?

Maximus
December 27th, 2006, 16:11
eheh, i discovered CRC the bad way, when the error reporting kindly requested to start ^^

then i re-traced manually and 'noted' them eheh

ZaiRoN
December 27th, 2006, 16:38
This time the problems arise when you have to change one or more bytes because the entire VM instructions are surrounded by a nasty anti-patch check. I don't describe the VM used in the crackme but I'll focus my attention over the instruction I want to patch, the good/bad boy conditional jump:
Code:
0041562B mov ecx, [ebx+eax] ;
0041562E mov eax, [ebx+50h] ; Take the parameters needed by the current test instruction
00415631 mov edx, [ebx+eax] ;
; Virtual Machine instruction
00415634 xor eax, eax
00415636 cmp ecx, edx ; compare the right and the fake serial
00415638 jnz short loc_41563B ; Jump if serial is not right
0041563A inc eax ; Here if the serial is right
; Store the result into the Virtual Machine
0041563B mov ecx, [ebx+4Ch]
0041563E mov [ebx+ecx], eax
The idea is to patch the conditional jump at 415638 letting it to accept any serial, the new instruction would be:
Code:
75 00 jnz 0040563A
If you try to patch the instruction the crackme won't run anymore because an exception will occour. As I said before there are some anti-patch checks; the crackme uses the VM instructions in his anti-patch cheching routine and you can't patch the VM's instructions. So, what can I do? The first thing to do is to start looking at the code which lead me to the snippet above:
Code:
0040D8DB mov eax, [esi] ; esi = 41555B
0040D8DD mov ecx, 8
0040D8E2 mov edx, [esi+ecx*4] ; Takes dword from 41557B to 41555F
0040D8E5 xor edx, [ebx+28h] ; [ebx+28h] is updated after each VM instruction
0040D8E8 add edx, [ebx+14h] ; [ebx+14h] = 40CF60, it's always the same value
0040D8EB xor eax, [edx] ; xor eax with a dword taken from the VM data
0040D8ED loop loc_40D8E2 ; The loop is used to find out the offset of the next instruction
0040D8EF pop dword ptr [ebx+28h]
0040D8F2 add eax, [ebx+14h] ; eax = 40CF60 + value_obtained_from_the_loop
0040D8F5 jmp eax ; jump to the check serial snippet
This is the last part of the VM instruction that preceed the check I showed you above. Obviously the snippet above is called many times (because an instruction is called many times ) and each time the loop (40D8E2/40D8ED) extracts the offset of the next instruction. The next instruction address is obtained adding the offset to the base address (which is 40CF60). Well, seems to be unpatchable or atleast very hard to patch but there's a little flow in it.

Maybe you can't patch a byte of a generic VM instruction but you can surely patch something else, I'm talking about the dwords from 41555F to 41557B. Firstly these bytes are not inside a VM instruction, they won't be executed; secondly they are not used in the code, I mean they are not used in the various anti-patch routines. So, I can change them a little. I don't need to change all the bytes, one dword is enough.

The idea is to create a new VM instruction, almost similar to the one I wanted to patch. The new instruction will have:
Code:
75 00 jnz 0041563A
instead of:
Code:
75 01 jnz 41563B
In this way I always pass through the good boy. I'll add the new instruction's bytes starting from address 409704.
Now, let's see how can I do such a change. First of all, it's better to look at the last iteraction of the loop:
Code:
xor edx, [ebx+28h] <-- 24CA1F46 ^ [41555F] = 24CA1F46 ^ 24CA4311 = 5C57
add edx, [ebx+14h] <-- 5C57 + 40CF60 = 412BB7
xor eax, [edx] <------ D8EEEC32 ^ [412BB7] = D8EEEC32 ^ D8EE6AB9 = 868B
add eax, [ebx+14h] <-- 868b + 40CF60 = 4155EB
Ok, this is the normal situation. As I said before the new instruction is at 409704 so if I want to find the new value of [41555F] I have to go backward:
Code:
409704 - 40CF60 = FFFFC7A4
FFFFC7A4 ^ D8EEEC32 = 27112B96 <--- I'll put 0x27112B96 at [409700]. It's the new [412BB7]
409700 - 40CF60 = FFFFC7A0
FFFFC7A0 ^ 24CA1F46 = DB35D8E6 <-- I'll put 0xDB35D8E6 at [41555F]
Crackme solved!

0rp
January 11th, 2007, 18:19
in case any1 is interested, i gave up

theres a very simple way to remove even the strongest crcing: simply redirect all used opcodes to new opcodes, that basically do the same, but use a backup for crcing

those new opcodes could do anything, like logging, or inversing conditions or stuff, and i dont have an idea how to prevent this

i could make life harder with using obfuscation, but security by obscurity doesnt solve the problem

0rp
January 30th, 2007, 17:09
ok mister

this is the last try. now its even more impossible than ever before.

whats different:
- each vm-step has its own opcode-code
- each opcode is encrypted
- to decrypt opcode i, you need opcode i-1, since nobody else knows the key
- to get the key of opcode i, opcode i-1 needs to crc the vm, the crcresult, together with some reminder value makes the decryption key

now please proof me that i've overseen something.
again.

p.

reverser
February 1st, 2007, 08:49
Well, I'm not sure what I was supposed to do here, but after patching check()'s first argument from 123h to 2ah(=42) I've got this:
---------------------------
mhmmhm
---------------------------
oh, youve keygenned me
---------------------------
OK
---------------------------

Is that all?

0rp
February 1st, 2007, 13:58
no, the challenge is to patch the checkfunc itself, and make it accepting all numbers

reverser
February 2nd, 2007, 12:41
Don't know if this counts, but I made a little script which decrypts all encrypted code and fixes up the jumps between chunks. After that it's enough just to patch one conditional jump (at .40F95C).

0rp
February 2nd, 2007, 14:29
hehe, yes, your little script counts

mh

looks like i need to make the codeflow less static

mhmhm