How to crack Business Card Designer Plus v5.00b
("The Maths behind a Key Generator")
by plushmm
(25 July 1997)
Courtesy of Fravia's page of reverse engineering
	
Well, a pretty interesting essay: how to quickly identify the expected input of 
a protection scheme (basing on Windoze's "c" compilation constraints)... some sound 
elements of reverse engineering here, and a serious lesson for all shareware programmers!	
How to crack Business Card Designer Plus v5.00b
 
(The Maths behind a Key Generator)
 
by plushmm
(25 July 1997)
It is my idea to discuss about Key Generators since I notice that very few 
crackers have written Essays about how to go about creating them.  
As such, this is my first attempt at writing one that deals with that 
subject matter. 
You can obtain our target from: http://www.camdevelopment.com 
Run the program, choose Register, and bpx on GetDlgItemTextA. 
Softice snaps, and you're tracing.  
If you display the contents of the registers (indirect addressing of 
course), you come across this: 
 
* Possible StringData Ref from Data Obj ->"BCD5-@??????-CAM1" 
				 
We now know that our input must be 17 chars long, and is checked against 
the above "sample". Think about it now.  What does "?" normally mean?  
Any value right?  So then what does the "@" mean then?  Probably some 
kinda checksum! 
Anyway, we break into Softice here: 
* Reference To: USER32.GetDlgItemTextA, Ord:0000h 
:00492C45 E8E9470000     Call 00497433              ;here 
:00492C4A 8B4B19         mov ecx, dword ptr [ebx+19] 
:00492C4D 51             push ecx 
:00492C4E E851EDFFFF     call 004919A4              ;key checking routine 
:00492C53 59             pop ecx 
:00492C54 85C0           test eax, eax 
:00492C56 0F8EEA000000   jle 00492D46               ;evil jump-but don't patch 
  
Tracing into the key checking routine (00492C4E), we arrive here... 
Note:  From now, we assume that the key we input is "BCD5-ABCDEFG-CAM1" 
Remember also that the "sample" given is            "BCD5-@??????-CAM1"  
...skipping non-important code... 
...and going straight into the key calculation routine...
:00491A88 8B55F8          mov edx, dword ptr [ebp-08] 
:00491A8B 0FBE0A          movsx ecx, byte ptr [edx] 
:00491A8E 83F940          cmp ecx, 00000040    ;checking against the "sample" to
                                               ;see if we reached "@" (40 hex="@") 
:00491A91 7542            jne 00491AD5                 ;dont jump if "@" is true 
:00491A93 0FBE0B          movsx ecx, byte ptr [ebx]    ;ecx = B 
:00491A96 0FBE4301        movsx eax, byte ptr [ebx+01] ;eax = C 
:00491A9A 03C8            add ecx, eax                 ;ecx = B+C 
:00491A9C 0FBE5302        movsx edx, byte ptr [ebx+02] ;edx = D 
:00491AA0 03CA            add ecx, edx                 ;ecx = B+C+D 
:00491AA2 0FBE4303        movsx eax, byte ptr [ebx+03] ;eax = E 
:00491AA6 03C8            add ecx, eax                 ;ecx = B+C+D+E 
:00491AA8 0FBE5304        movsx edx, byte ptr [ebx+04] ;edx = F 
:00491AAC 03CA            add ecx, edx                 ;ecx = B+C+D+E+F 
:00491AAE 0FBE4305        movsx eax, byte ptr [ebx+05] ;eax = G 
:00491AB2 03C8            add ecx, eax                 ;ecx = B+C+D+E+F 
:00491AB4 8BC1            mov eax, ecx                 ;eax = ecx...preparing to mod 
:00491AB6 B91A000000      mov ecx, 0000001A            ;1A is the quotient...1A = 26
                                                       ;decimal which is the spanning 
													   ;length of the Alphabet (A-Z)! 
:00491ABB 99              cdq                          ;make 64 bit 
:00491ABC F7F9            idiv ecx           ;division done...edx has the remainder 
:00491ABE 83C241          add edx, 00000041            ;0 <= edx <="25." 41="A" ... ;therefore we get an Uppercased Alphabet! :00491AC1 8BCA mov ecx, edx ;ecx, the checksum, is an ;Uppercased Alphabet :00491AC3 8A43FF mov al, byte ptr [ebx-01] ;This is A :00491AC6 84C0 test al, al :00491AC8 7407 je 00491AD1 :00491ACA 0FBED0 movsx edx, al :00491ACD 3BCA cmp ecx, edx ;Compare our "first" input "A" ;with the correct checksum :00491ACF 7404 je 00491AD5 ;is equal...then good guy...jump :00491AD1 33FF xor edi, edi ;if edi="0" then bad guy :00491AD3 EB12 jmp 00491AE7 We see that the only values that matters are "ABCDEFG". Ok...lets see what the checksum should be: sum="B" +"C"+"D"+"E"+"F"+"G"="19B" (hex addition) remainder="19B" mod 1A="15" checksum="41+15" in ascii Since "A" <> "V", therefore we're the bad guys!  Therefore...changing our "A" to "V" 
will get you regged. 
Want the Reg Key to include +HCU? 
sum       = "_" + "+" + "H" + "C" + U" + "_" = 1C9 
remainder = 1C9 mod 1A    = F 
checksum  = 41+F          = 50 = "P" in ascii 
Therefore a valid Reg Code would be "BCD5-P_+HCU_-CAM1" 
Wanna have "Plushm" in the Reg Code? 
checksum  =   "P"   =    50 - 41  = F 
sum       =   "l"+"u"+"s"+"h"+"m" = 229 
remainder = 229 mod 1A            = 7 
checksum - remainder              = F-7 = 8 
Therefore any character in the equation 8 + 1A(n), where n is any positive integer, will be
valid.  Lets choose "<", since "<"="8" + 1A(2)="3C" ascii. Therefore another equally valid Reg Code "could.class" tppabs="http://fravia.org/could.class" be "BCD5-Plushm<-CAM1" Anyway, here's the (main) Reg calculation code (in Pascal)...have fun! 
plushmm -= RiP'97 =-
 
  RegCode := 'BCD5-@??????-CAM1'; 
  WriteLn; 
  i := 6; 
  Randomize; 
  value := 0; 
  Writeln('Press <S> for something special...'); 
  Writeln; 
  TemChar := ReadKey; 
  If UPCASE(TemChar) <> 'S' Then            {Random letters used} 
     Repeat 
           i := i+1; 
           TemInt := Random(26)+65; 
           Value := Value + TemInt; 
           TemChar := Chr(TemInt); 
           RegCode[i] := TemChar; 
     Until i = 12 
  else 
     Repeat                                  {Built your own Key!} 
           i := i+1; 
           Write('What do you want your Reg Key to be :'); 
           TemChar := ReadKey; 
           Writeln(TemChar); 
           RegCode[i] := TemChar; 
           TemInt := Ord(TemChar); 
           Value := Value + TemInt; 
     until i = 12; 
  Remainder := Value mod 26; 
  RegCode[6] := Chr(Remainder+65); 
  Writeln; 
  Write('Your registration code is:'); 
  Writeln(RegCode); 
(c) plushmm 1997. All rights reserved.
   
You are deep inside fravia's page of reverse engineering,  
choose your way out:
homepage 
 
links  
anonymity  
+ORC 
students' essays 
tools 
cocktails 
antismut 
search_forms 
mailFraVia 
is reverse engineering legal?