			Tutorial for Lazarus unreversable algo part 1
			---------------------------------------------

By TSCube


OK, type any number, then 'BPX HMEMCPY' in SICE, then F12 a few times and you'll land here.
(If you don't know what I'm talking about, this crackme is not for you ;)

:0040159E 8955B8                  mov dword ptr [ebp-48], edx
:004015A1 8945BC                  mov dword ptr [ebp-44], eax
:004015A4 B8C8834400              mov eax, 004483C8
:004015A9 E8E6D40300              call 0043EA94
:004015AE 66C745D00800            mov [ebp-30], 0008
:004015B4 8D45FC                  lea eax, dword ptr [ebp-04]
:004015B7 E878020000              call 00401834
:004015BC 8BD0                    mov edx, eax
:004015BE FF45DC                  inc [ebp-24]
:004015C1 8B4DBC                  mov ecx, dword ptr [ebp-44]
:004015C4 8B81C4020000            mov eax, dword ptr [ecx+000002C4]
:004015CA E84D060200              call 00421C1C

:004015CF 8D45FC                  lea eax, dword ptr [ebp-04] -> @serial
:004015D2 E8D95C0400              call 004472B0 -> strlen
:004015D7 83F80A                  cmp eax, 0000000A -> 10 in decimal

These 3 lines check if serial is 10 characters long

:004015DA 8D45FC                  lea eax, dword ptr [ebp-04]
:004015DD 0F94C2                  sete dl
:004015E0 83E201                  and edx, 00000001
:004015E3 52                      push edx
:004015E4 BA02000000              mov edx, 00000002
:004015E9 FF4DDC                  dec [ebp-24]
:004015EC E87B5C0400              call 0044726C
:004015F1 59                      pop ecx
:004015F2 84C9                    test cl, cl
:004015F4 0F842A020000            je 00401824 -> fuck off

:004015FA 33C0                    xor eax, eax
:004015FC 8945B4                  mov dword ptr [ebp-4C], eax
:004015FF 33D2                    xor edx, edx
:00401601 8955B0                  mov dword ptr [ebp-50], edx
:00401604 EB46                    jmp 0040164C => jumps to middle of checksum loop


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

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401692(C)
|
:00401606 66C745D02000            mov [ebp-30], 0020
:0040160C 8D45F4                  lea eax, dword ptr [ebp-0C]
:0040160F E820020000              call 00401834
:00401614 8BD0                    mov edx, eax
:00401616 FF45DC                  inc [ebp-24]
:00401619 8B4DBC                  mov ecx, dword ptr [ebp-44]
:0040161C 8B81C4020000            mov eax, dword ptr [ecx+000002C4]
:00401622 E8F5050200              call 00421C1C
:00401627 8D45F4                  lea eax, dword ptr [ebp-0C] -> @serial
:0040162A 8B55B0                  mov edx, dword ptr [ebp-50]
:0040162D 42                      inc edx
:0040162E E831020000              call 00401864
:00401633 0FBE08                  movsx ecx, byte ptr [eax]

during this loop, ECX will contain the different ASCII values of the serial

:00401636 014DB4                  add dword ptr [ebp-4C], ecx => compute checksum

:00401639 FF4DDC                  dec [ebp-24]
:0040163C 8D45F4                  lea eax, dword ptr [ebp-0C]
:0040163F BA02000000              mov edx, 00000002
:00401644 E8235C0400              call 0044726C
:00401649 FF45B0                  inc [ebp-50]

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401604(U)
|
:0040164C 66C745D01400            mov [ebp-30], 0014
:00401652 8D45F8                  lea eax, dword ptr [ebp-08]
:00401655 E8DA010000              call 00401834
:0040165A 8BD0                    mov edx, eax
:0040165C FF45DC                  inc [ebp-24]
:0040165F 8B4DBC                  mov ecx, dword ptr [ebp-44]
:00401662 8B81C4020000            mov eax, dword ptr [ecx+000002C4]
:00401668 E8AF050200              call 00421C1C
:0040166D 8D45F8                  lea eax, dword ptr [ebp-08]
:00401670 E83B5C0400              call 004472B0
:00401675 3B45B0                  cmp eax, dword ptr [ebp-50]
:00401678 8D45F8                  lea eax, dword ptr [ebp-08]
:0040167B 0F9FC2                  setg dl
:0040167E 83E201                  and edx, 00000001
:00401681 52                      push edx
:00401682 BA02000000              mov edx, 00000002
:00401687 FF4DDC                  dec [ebp-24]
:0040168A E8DD5B0400              call 0044726C
:0040168F 59                      pop ecx
:00401690 85C9                    test ecx, ecx
:00401692 0F856EFFFFFF            jne 00401606 -> loop

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

The above loop looks difficult, but in fact it only adds the ASCII values of the serial !
(see @401636).
It looks like C++ Builder adds a LOT of garbage code, because it takes only ONE line of 'C' code
to do this !


:00401698 817DB40D020000          cmp dword ptr [ebp-4C], 0000020D => this is the correct checksum
:0040169F 0F857F010000            jne 00401824 -> fuck off

Yeah, you guessed it : the sum of the ASCII values of the serial must be equal to 0x20D
( for an example, "4144444479" is OK)


:004016A5 66C745D02C00            mov [ebp-30], 002C
:004016AB 8D45F0                  lea eax, dword ptr [ebp-10]
:004016AE E881010000              call 00401834
:004016B3 8BD0                    mov edx, eax
:004016B5 FF45DC                  inc [ebp-24]
:004016B8 8B4DBC                  mov ecx, dword ptr [ebp-44]
:004016BB 8B81C4020000            mov eax, dword ptr [ecx+000002C4]
:004016C1 E856050200              call 00421C1C
:004016C6 8D45F0                  lea eax, dword ptr [ebp-10]

:004016C9 8B00                    mov eax, dword ptr [eax] -> EAX points to serial
:004016CB E81C4F0300              call 004365EC -> converts string to hexadecimal value
:004016D0 8945AC                  mov dword ptr [ebp-54], eax -> [EBP-54] = 0xserial

I must say I didn't see immediatly what was the purpose of this call... that's because my
first serial was not a valid integer value !
I had to trace into it to see what was happening.

Never forget that you don't have to trace in every 'call' you see to make a keygen : by looking
at the input & the input values, you can very often guess what's happening.



:004016D3 FF4DDC                  dec [ebp-24]
:004016D6 8D45F0                  lea eax, dword ptr [ebp-10]
:004016D9 BA02000000              mov edx, 00000002
:004016DE E8895B0400              call 0044726C
:004016E3 8B4DAC                  mov ecx, dword ptr [ebp-54]
:004016E6 33C0                    xor eax, eax
:004016E8 894DA4                  mov dword ptr [ebp-5C], ecx -> serial (hexa)
:004016EB 8945A8                  mov dword ptr [ebp-58], eax

:004016EE DF6DA4                  fild qword ptr [ebp-5C]
:004016F1 83C4F8                  add esp, FFFFFFF8
:004016F4 DD1C24                  fstp qword ptr [esp]
:004016F7 E874040400              call 00441B70 -> SQRT

OH MY GOD : FPU ARITHMETIC !!!!

No no : stay with me, this one is easy to solve !

If you look at what this call does, you'll see a stringdata reference to "sqrt" (@441B99)
-> that means this call computes the square root of the serial !


:004016FC 83C408                  add esp, 00000008
:004016FF E84CF10300              call 00440850
:00401704 8945AC                  mov dword ptr [ebp-54], eax -> serial_sqrt (ie square root of serial)



:00401707 66C745D03800            mov [ebp-30], 0038
:0040170D 8D45EC                  lea eax, dword ptr [ebp-14]
:00401710 E81F010000              call 00401834
:00401715 8BD0                    mov edx, eax
:00401717 FF45DC                  inc [ebp-24]
:0040171A 8B4DBC                  mov ecx, dword ptr [ebp-44]
:0040171D 8B81C4020000            mov eax, dword ptr [ecx+000002C4]
:00401723 E8F4040200              call 00421C1C
:00401728 8D45EC                  lea eax, dword ptr [ebp-14]

:0040172B 8B00                    mov eax, dword ptr [eax] -> serial (string)
:0040172D E8BA4E0300              call 004365EC -> string to hexadecimal (same as above)

This is the same thing as @4016C9... and it would have been faster to save the last value,
instead of doing the same conversion again ;)

:00401732 52                      push edx
:00401733 50                      push eax
:00401734 8B45AC                  mov eax, dword ptr [ebp-54] -> serial_sqrt
:00401737 F76DAC                  imul [ebp-54]

EAX = serial_sqrt * serial_sqrt

:0040173A 33D2                    xor edx, edx
:0040173C 3B542404                cmp edx, dword ptr [esp+04]
:00401740 7503                    jne 00401745 -> jump if overflow
:00401742 3B0424                  cmp eax, dword ptr [esp]

this comparison checks if 'serial_sqrt * serial_sqrt' is equal to 'serial'

a few words before going on
---------------------------

I know what you're thinking : "but... of course SQRT(X) * SQRT(X) = X , so why did he made
this comparison ?"

Well, SQRT(X) * SQRT(X) = X ONLY if X is a floating value... but this is not the case here
because we're dealing with INTEGER values.

That means that :
SQRT(9) = 3
SQRT(10) = 3,162 --> 3 (rounded to integer value)
SQRT(11) = 3,316 --> 3 (...)
SQRT(12) = 3,464 --> 3 (...)

So, Lazarus checks here if SQRT(serial) is the EXACT square root of the serial (not a truncated
value).



* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401740(C)
|
:00401745 0F94C1                  sete cl -> CL=1 if SQRT(serial)^2 = serial
:00401748 83C408                  add esp, 00000008
:0040174B 83E101                  and ecx, 00000001
:0040174E 8D45EC                  lea eax, dword ptr [ebp-14]
:00401751 BA02000000              mov edx, 00000002
:00401756 51                      push ecx
:00401757 FF4DDC                  dec [ebp-24]
:0040175A E80D5B0400              call 0044726C
:0040175F 59                      pop ecx
:00401760 84C9                    test cl, cl
:00401762 B902000000              mov ecx, 00000002
:00401767 8B45AC                  mov eax, dword ptr [ebp-54] -> serial_sqrt
:0040176A 33D2                    xor edx, edx
:0040176C F7F1                    div ecx
:0040176E 8945AC                  mov dword ptr [ebp-54], eax
:00401771 834DAC7B                or dword ptr [ebp-54], 0000007B
:00401775 8B45AC                  mov eax, dword ptr [ebp-54]

EAX = (serial_sqrt / 2) OR 0x7B

:00401778 C1E005                  shl eax, 05 -> * 32
:0040177B 8D0480                  lea eax, dword ptr [eax+4*eax] -> EAX = EAX*4 + EAX
:0040177E 8D0480                  lea eax, dword ptr [eax+4*eax]
:00401781 8D0480                  lea eax, dword ptr [eax+4*eax]
:00401784 8D0480                  lea eax, dword ptr [eax+4*eax]
:00401787 8D0480                  lea eax, dword ptr [eax+4*eax]

Remember what I told you about checking the input and the output values ?
Then it's easy to see that :

=> EAX (output) = 3125 EAX (input)

 
:0040178A 8945AC                  mov dword ptr [ebp-54], eax
:0040178D 8145ACA4F52203          add dword ptr [ebp-54], 0322F5A4

EAX = EAX + 0322F5A4 = magic_value

:00401794 66C745D04400            mov [ebp-30], 0044
:0040179A 8D45E8                  lea eax, dword ptr [ebp-18]
:0040179D E892000000              call 00401834
:004017A2 8BD0                    mov edx, eax
:004017A4 FF45DC                  inc [ebp-24]
:004017A7 8B4DBC                  mov ecx, dword ptr [ebp-44]
:004017AA 8B81C4020000            mov eax, dword ptr [ecx+000002C4]
:004017B0 E867040200              call 00421C1C

:004017B5 8D45E8                  lea eax, dword ptr [ebp-18]
:004017B8 8B00                    mov eax, dword ptr [eax] -> serial (string)
:004017BA E82D4E0300              call 004365EC => again

hum... no comment ;)

:004017BF 52                      push edx
:004017C0 50                      push eax
:004017C1 8B45AC                  mov eax, dword ptr [ebp-54] -> magic_value
:004017C4 33D2                    xor edx, edx
:004017C6 3B542404                cmp edx, dword ptr [esp+04]
:004017CA 7503                    jne 004017CF
:004017CC 3B0424                  cmp eax, dword ptr [esp]

this final comparison checks if 'serial' (hexa) is equal to 'magic_value'


* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004017CA(C)
|
:004017CF 0F94C1                  sete cl -> registered if both are equals





////////////////////////////////////////////////////////////
//           UNREVERSABLE ALGO                           //
///////////////////////////////////////////////////////////

The serial is valid if :

1) it's 10 digits long
2) checksum is equal to 0x20D
3) it's a valid integer value
4) SQRT(serial) * SQRT(serial) = serial (integer values)
5) ((SQRT(serial) / 2) OR 0x7B) * 32 * 3125 + 0x322F5A4 = serial

the equation to solve is :

serial = ((SQRT(serial) / 2) OR 0x7B) * 100000 + 0x322F5A4

Now you know why this is called an unreversable algo : you can't solve this equation because it's
not a linear equation. LET'S BRUTE FORCE !!!


/////////////////////////////////////////////////////////
//                  BRUTE FORCER                       //
/////////////////////////////////////////////////////////

#include <stdio.h>
#include <math.h>

// 9c752484 = 2624922756

int main(void)
{
	unsigned int sqroot,magic;
	for (unsigned int i=0;i<0xFFFFFFFF;i++)
	{
		sqroot = (unsigned int)sqrt(i);
		if (sqroot*sqroot !=i) continue;
		magic = (sqroot/2 | 0x7B) * 100000 + 0x322F5A4;
		if (magic==i)
		{
			printf("serial : %x",i);
			getchar();
			return 0;
		}
	}
	return 0;
}


If you're in a hurry, I can tell you that the serial is bigger than 0x90000000 : compile and
run the brute forcer to get it.


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

www.tscube.cjb.net