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 the software 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        = 56 = "V" 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 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