		Tutorial for Lazarus unreversable algo part 2
		---------------------------------------------

By TSCube
---------

note : this one is NOT for newbies ;)

"If I didn't miss something really big you must be quite a l33to if you crack this one."

Don't be afraid of this phrase : you don't have to be a l33to to crack this crackme : it took me 
only two hours to do it.



+-------+
| Intro |
+-------+

The protection used is very interesting : Lazarus made it easy for us to crack it, but you'll 
soon see that a few modifications can make it VERY hard to crack.

The idea here is to enable the 'surprise' (about->surprise). 
When a serial is entered, the crackme generates a 'patch.com' file which will patch (incredible 
isn't it ?) the crackme in order to enable the surprise.
The patch will ALWAYS be generated, but it will ONLY work if the serial is correct !

In fact, the surprise is not so surprising because you just have to look in the Dead Listing to 
see what it is ! :(



+--------------------------+
| Part1 : the first serial |
+--------------------------+

Go to About->Register : enter any name (it's not used in the serial generation routine).

Now comes the first difficulty (if we can call it like that) : you have to enter a valid
first_serial to ungray the third edit box.

At first I tried playing with HMEMCPY, but it didn't give anything. 

Finally, I decided to find where my first serial was stored in memory... here is how to do it :

1) enter any serial : "11223344"
2) 'BPX HMEMCPY' and hit F12 until you're back in crackme code (disable the breakpoint before hitting F12)
3) 'S 0 L FFFFFFFF "11223344" (search for serial in memory)
4) note the first memory address (@CD9F54 for me)
5) 'BPM CD9F54'
6) go back to the crackme and modify the serial
7) SICE pops : disable breakpoint and hit F12 until you're back in crackme code

Eventually, you'll land here :

:004023B8 55                      push ebp
:004023B9 8BEC                    mov ebp, esp
:004023BB 83C4D4                  add esp, FFFFFFD4
:004023BE 53                      push ebx
:004023BF 8BD8                    mov ebx, eax
:004023C1 B8CC2D4500              mov eax, 00452DCC
:004023C6 E8154B0400              call 00446EE0
:004023CB 66C745E40800            mov [ebp-1C], 0008
:004023D1 33D2                    xor edx, edx
:004023D3 8955FC                  mov dword ptr [ebp-04], edx
:004023D6 8D55FC                  lea edx, dword ptr [ebp-04]
:004023D9 FF45F0                  inc [ebp-10]
:004023DC 8B83C8020000            mov eax, dword ptr [ebx+000002C8]
:004023E2 E8AD580200              call 00427C94
:004023E7 8D4DFC                  lea ecx, dword ptr [ebp-04] -> offset of first_serial
:004023EA 51                      push ecx

* Possible StringData Ref from Data Obj ->"fakeserial"
                                  |
:004023EB BA712D4500              mov edx, 00452D71
:004023F0 8D45F8                  lea eax, dword ptr [ebp-08]
:004023F3 E86CED0400              call 00451164
:004023F8 FF45F0                  inc [ebp-10]
:004023FB 8D55F8                  lea edx, dword ptr [ebp-08]
:004023FE 58                      pop eax
:004023FF E818EE0400              call 0045121C
:00402404 50                      push eax
:00402405 FF4DF0                  dec [ebp-10]
:00402408 8D45F8                  lea eax, dword ptr [ebp-08]


hum... what is this "fakeserial" string ? => Right, it's the first serial !!!

Type it, and the third edit box will ungray itself.



+---------------------------------------------+
| Part2 : understanding the protection scheme |
+---------------------------------------------+

Enter any value, then BPX HMEMCPY, then F12 a few times and you'll land here :


:0040247B 90                      nop
:0040247C 55                      push ebp
:0040247D 8BEC                    mov ebp, esp
:0040247F 81C4F8FDFFFF            add esp, FFFFFDF8
:00402485 53                      push ebx
:00402486 56                      push esi
:00402487 57                      push edi
:00402488 8945CC                  mov dword ptr [ebp-34], eax
:0040248B B8202E4500              mov eax, 00452E20
:00402490 E84B4A0400              call 00446EE0
:00402495 66C745E01400            mov [ebp-20], 0014
:0040249B 33D2                    xor edx, edx
:0040249D 8955FC                  mov dword ptr [ebp-04], edx
:004024A0 8D55FC                  lea edx, dword ptr [ebp-04]
:004024A3 FF45EC                  inc [ebp-14]
:004024A6 8B45CC                  mov eax, dword ptr [ebp-34]
:004024A9 8B80CC020000            mov eax, dword ptr [eax+000002CC]
:004024AF E8E0570200              call 00427C94
:004024B4 66C745E00800            mov [ebp-20], 0008
:004024BA 33F6                    xor esi, esi
:004024BC BB01000000              mov ebx, 00000001 => counter initialisation
:004024C1 EB50                    jmp 00402513


begin_loop_1
-------------

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040251E(C)
|
:004024C3 66C745E02000            mov [ebp-20], 0020
:004024C9 33C0                    xor eax, eax
:004024CB 8945F8                  mov dword ptr [ebp-08], eax
:004024CE 8D55F8                  lea edx, dword ptr [ebp-08]
:004024D1 FF45EC                  inc [ebp-14]
:004024D4 8B4DCC                  mov ecx, dword ptr [ebp-34]
:004024D7 8B81CC020000            mov eax, dword ptr [ecx+000002CC]
:004024DD E8B2570200              call 00427C94
:004024E2 8BFB                    mov edi, ebx
:004024E4 57                      push edi
:004024E5 8D55F8                  lea edx, dword ptr [ebp-08]
:004024E8 52                      push edx
:004024E9 E8F2EB0400              call 004510E0
:004024EE 83C408                  add esp, 00000008
:004024F1 8D45F8                  lea eax, dword ptr [ebp-08]
:004024F4 E84BED0400              call 00451244
:004024F9 037DF8                  add edi, dword ptr [ebp-08]
:004024FC 8D45F8                  lea eax, dword ptr [ebp-08]
:004024FF 4F                      dec edi
:00402500 0FBE17                  movsx edx, byte ptr [edi] -> serial[i]
:00402503 03F2                    add esi, edx -> adds ASCII value
:00402505 BA02000000              mov edx, 00000002
:0040250A FF4DEC                  dec [ebp-14]
:0040250D E8C6EC0400              call 004511D8
:00402512 43                      inc ebx -> counter++

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004024C1(U)
|
:00402513 8D45FC                  lea eax, dword ptr [ebp-04]
:00402516 E819ED0400              call 00451234
:0040251B 40                      inc eax
:0040251C 3BD8                    cmp ebx, eax
:0040251E 7CA3                    jl 004024C3

end_loop_1
-----------

Ho my god, all these lines only to add the ASCII values of the second serial !
The two important lines are @402500 and @402503 : they add the ASCII values of the second_serial
in ESI


:00402520 0FAFF6                  imul esi, esi
:00402523 81C639300000            add esi, 00003039

ESI = sum_of_ascii_values^2 + 0x3039

:00402529 66C745E00800            mov [ebp-20], 0008
:0040252F BB01000000              mov ebx, 00000001 -> init counter
:00402534 EB53                    jmp 00402589


begin_loop_2
--------------

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00402594(C)
|
:00402536 66C745E02C00            mov [ebp-20], 002C
:0040253C 33C0                    xor eax, eax
:0040253E 8945F4                  mov dword ptr [ebp-0C], eax
:00402541 8D55F4                  lea edx, dword ptr [ebp-0C]
:00402544 FF45EC                  inc [ebp-14]
:00402547 8B4DCC                  mov ecx, dword ptr [ebp-34]
:0040254A 8B81CC020000            mov eax, dword ptr [ecx+000002CC]
:00402550 E83F570200              call 00427C94
:00402555 8BFB                    mov edi, ebx
:00402557 57                      push edi
:00402558 8D55F4                  lea edx, dword ptr [ebp-0C]
:0040255B 52                      push edx
:0040255C E87FEB0400              call 004510E0
:00402561 83C408                  add esp, 00000008
:00402564 8D45F4                  lea eax, dword ptr [ebp-0C]
:00402567 E8D8EC0400              call 00451244
:0040256C 037DF4                  add edi, dword ptr [ebp-0C]
:0040256F 8D45F4                  lea eax, dword ptr [ebp-0C]
:00402572 4F                      dec edi
:00402573 0FBE17                  movsx edx, byte ptr [edi]
:00402576 0FAFD3                  imul edx, ebx
:00402579 2BF2                    sub esi, edx

ESI = ESI - serial[i]*(i+1)

:0040257B BA02000000              mov edx, 00000002
:00402580 FF4DEC                  dec [ebp-14]
:00402583 E850EC0400              call 004511D8
:00402588 43                      inc ebx

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00402534(U)
|
:00402589 8D45FC                  lea eax, dword ptr [ebp-04]
:0040258C E8A3EC0400              call 00451234
:00402591 40                      inc eax
:00402592 3BD8                    cmp ebx, eax
:00402594 7CA0                    jl 00402536

end_loop_2
------------

Again, the important lines of this second loop are @402573 , @402576 and @402579

At that point, ESI contains a magic value which can be computed like that :

char serial[50] = "11223344"
int magic=0;
for (unsigned int i=0;i<strlen(serial);i++) magic = magic + serial[i];
magic = magic * magic + 0x3039;
for (i=0;i<strlen(serial);i++) magic = magic - serial[i]*(i+1);




:00402596 56                      push esi
:00402597 BEA02B4500              mov esi, 00452BA0
:0040259C 8DBDF8FDFFFF            lea edi, dword ptr [ebp+FFFFFDF8]
:004025A2 B974000000              mov ecx, 00000074 -> 116*4 + 1 = 465 bytes
:004025A7 F3                      repz
:004025A8 A5                      movsd
:004025A9 A4                      movsb
:004025AA 5E                      pop esi
:004025AB 66C745E00800            mov [ebp-20], 0008
:004025B1 33D2                    xor edx, edx -> init counter
:004025B3 8D85F8FDFFFF            lea eax, dword ptr [ebp+FFFFFDF8]

From that point, every time you enter a serial, a 'patch.com' file will be generated.
Check it's size : it's 465 bytes long.
This file is included in the serial and the above code makes a copy of the bytes of this patch
before XORING them in the next loop :


begin_loop_3
-------------

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004025C5(C)
|
:004025B9 8BCE                    mov ecx, esi
:004025BB 3008                    xor byte ptr [eax], cl -> CL = lower byte of magic value
:004025BD 42                      inc edx
:004025BE 40                      inc eax
:004025BF 81FAD1010000            cmp edx, 000001D1 -> 0x1D1 = 465 bytes
:004025C5 7CF2                    jl 004025B9

end_loop_3
-----------

This third loop is the core of the serial check routine. Let me explain in details what's
happening :

Somewhere in the crackme, there is an array of 465 bytes. When a serial is entered, a magic value
is computed, and then the lower byte of this magic value is XORED with these 465 bytes. 
Then, the 465 XORED bytes are used to create the 'patch.com' file.

=> The 'patch.com' will be valid ONLY if the magic value is correct. Else, it will crash
when you'll run it.


Here is the end of the serial check routine, where the 'patch.com' is generated :

* Possible StringData Ref from Data Obj ->"w"
                                  |
:004025C7 68862D4500              push 00452D86

* Possible StringData Ref from Data Obj ->"patch.com"
                                  |
:004025CC 687C2D4500              push 00452D7C
:004025D1 E8AE600400              call 00448684
:004025D6 83C408                  add esp, 00000008
:004025D9 8BF0                    mov esi, eax
:004025DB 85F6                    test esi, esi
:004025DD 743E                    je 0040261D
:004025DF 66C745E00800            mov [ebp-20], 0008
:004025E5 33DB                    xor ebx, ebx
:004025E7 8DBDF8FDFFFF            lea edi, dword ptr [ebp+FFFFFDF8]



+--------------------------------+
| Part3 : the Patch brute forcer |
+--------------------------------+

As the lower byte of the magic_value is used to XOR the 465 bytes, the crackme is able to
generate 255 different 'patch.com' files. Only one of these files will be the good one.

We can now write a brute forcer that will generate all these 255 files. To do that, we need
the initial 465 bytes (before the XOR loop).
Here is a way to get them :
1) BPX 4025B9 (begin of loop 3)
2) enter any serial
3) SICE pops -> 'R ESI 0' (<=> magic_value = 0)
4) let the crackme run

This time, the bytes of 'patch.com' won't be modified, because when you XOR something with
0x00, it doesn't change anything.

I renamed the file to 'patch_ini.com' and I wrote the following 'Patch Brute Forcer' :

<-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><->
<-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><->

#include <stdio.h>

int main(void)
{
	FILE* input;
	FILE* output;
	char original_bytes[465]; // because patch_ini.com contains 465 bytes
	char xored_bytes[465];
	char xored_name[50];

	input=fopen("patch_ini.com","rb");
	if (!input) { puts("error while opening file"); return 1;}

	fread(original_bytes,sizeof(char),465,input); // read 465 bytes from patch_ini.com

	for (int i=0;i<256;i++)
	{
		for (int j=0;j<466;j++) xored_bytes[j] = original_bytes[j] ^ i;
		sprintf(xored_name,"%d.com",i);

		output = fopen (xored_name,"wb");
		if (!output) { puts("error while opening file"); return 1;}

		fwrite(xored_bytes,465,sizeof(char),output); // write xored bytes into file
		fclose(output);
	}

	_fcloseall();
	return 0;
}

<-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><->
<-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><->

This proggy will generate 256 potential patch files (from 0.com to 255.com).

Now the boring part starts : you have to execute them all until you find the good one !
When you'll find it, you'll see the following lines :

Opening  File    : Done!
Checking Filesize: Done!
Patching File    : Done!

OK, I'll save you a lot a time --> the good patch is 140.com

Now, run 140.com, then run the crackme and you'll see the surprise !!!



+---------------------------------+
| Part4 : the Serial brute forcer |
+---------------------------------+

the good patch is 140.com, that means that the lower byte of the magic_value must be equal
to 140 !!!

At least, here is the Serial brute forcer :


<-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><->
<-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><->

#include <stdio.h>
#include <string.h>

int main(void)
{
	char buffer[50];
	unsigned int magic;

	for (unsigned int i=0;i<0xFFFFFFFF;i++)
	{
		magic=0;
		sprintf(buffer,"%u",i); // converts i to string

		for (unsigned int j=0;j<strlen(buffer);j++) magic += buffer[j];
		magic = (magic * magic) + 0x3039;
		for (j=0;j<strlen(buffer);j++) magic = magic-buffer[j]*(j+1);

		if ((magic&0xFF)==140) // check is lower byte of magic value is equal to 140
		{
			printf("Possible serial = %u",i);
			getchar();
		}
		
	}

	return 0;
}

<-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><->
<-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><-><->

There are lots of possible serials for this crackme : this brute forcer only generates serials 
composed of numbers.

name : TSCube
first_serial : fakeserial
second_serial : 499 (I took the first one)


+-------+
| Outro |
+-------+

Now imagine that :

1) The first serial is checked using hashing algos (RSA, Blowfish)
2) The crackme is able to generate 4294967296 'patch.com' files

Do you imagine that ? Then, you understand how such a protection can quickly become
*really* hard !


    ________     _______     _______
   /__   __/\   /  ____/\   /  ____/\
   \_/  /\_\/  /  /\___\/  /  /\___\/
    /  / /    /  /_/_     /  / / 
   /  / /    /____  /\   /  / /
  /  / /     \___/ / /  /  / /
 /  / /     ____/ / /  /  /_/_
/  / /     /_____/ /  /______/\
\__\/      \_____\/   \______\/ 21/05/2000

www.tscube.cjb.net