"1001 Killer Internet Marketing Strategies" v1.3
[Reversing essay]

Subject: Cracking
Target: 1001 Killer Internet Marketing Strategies v1.3
URL: http://www.killertactics.com
Author: BlackB
Date: 2000-07-25
Tools used: SoftICE, Borland C++ v5.02
Difficulty (scale 1-5): 2

Before starting!
This essay is for knowledge purposes only!!
Software developers spend much time in making their programs. They live from the money we give them!
Please buy good software!!
I. Introduction
Hello.
This essay is made as a result of a mail I got from a person that asked me for help for this program. Just to show you that if you send a polite email with the best intentions, I do such things ;-)
However....I throw many of those requests away as most of them, in the end, come down to only one thing: a crack or a serial. And in that case your mail will be for maximum 5 seconds on my computer's harddisk.
This essay won't only show you where you can find a valid serial, but also will show you how to write a keygen for it.
II. About the protection
Some limitations, option to enter username and unlockcode.
III. Cracking it

Run the program :-) Before I started reversing it, I had read some of the articles, and I must admit that it's very interesting! The mind of a general internetsurfer is completely reversed, therefore it's also an excellent guide on how to protect yourself and others against the aggressive commercial advertisement on the net. Someone ever said: "To beat your enemy, you first have to know your enemy"....and sure this program helps.

Anyway, I would explain how to crack this program ;-) Click on the little key picture in the right. A window appears where you can see a: fixed serial, namebox, fixed publication title and registration code box. I suspect that the serial generated in the caption of the registration window is not really fixed, but differs from computer to computer.
Ok, now enter your name or nickname, enter a bogus registration code. Notice that the registration code should be 12 chars long, as that's the maximum allowed to type in the box.
In SoftICE set a breakpoint on hmemcpy: bpx hmemcpy. Now click the 'OK' button and SoftICE pops up. Press F12 (=execute until 'ret') until you come into the main code. It looks like this:

Start partial code

0137:0045ACDB  MOV       EAX,[EBP-24]
0137:0045ACDE  LEA       EDX,[EBP-20]
0137:0045ACE1  CALL      0045B850
0137:0045ACE6  LEA       EAX,[EBP-20]
0137:0045ACE9  MOV       EDX,0045B030
0137:0045ACEE  CALL      0040377C

.....etc.....

End partial code

Start tracing the instructions with F10. There are much unimportant instructions that do basic tests, like checking if the username is minimum 3 chars long and that sort of stuff.
At a certain moment you come across these instructions:

Start partial code

0137:0045AE73  MOV       ECX,[EBP-10]
0137:0045AE76  MOV       EDX,[EBP-08]
0137:0045AE79  MOV       EAX,[EBP-04] (1.)

0137:0045AE7C CALL 0045B998
(2.) 0137:0045AE81 LEA EDX,[EBP-20] 0137:0045AE84 MOV EAX,[EBP-1C] 0137:0045AE87 CALL 0045BA88 (3.) 0137:0045AE8C MOV EAX,[EBP-20] 0137:0045AE8F MOV EDX,[EBP-0C] 0137:0045AE92 CALL 00403884 0137:0045AE97 JNZ 0045AFB5

End partial code

(1.) These three MOV instructions load our username, fixed serial, and the string "1001 Killer Internet".
Therefore the next call is pretty suspicious, as it will probably process the loaded items. Therefore you can also know that all the other instructions before are not important as they never load so many important data before calling a procedure.

(2.) And as I predicted, this call does some 'magic' calculations ....let's take a look inside ;-) Trace into that call (F8) and trace further (F10) until you see this:

Start partial code

0137:0045B9F1  MOV       DL,[EBX+EAX-01]
0137:0045B9F5  MOV       EAX,[EBP-08]
0137:0045B9F8  XOR       ECX,ECX
0137:0045B9FA  MOV       CL,[EBX+EAX-01]            <- CL= char of string1
0137:0045B9FE  CMP       BYTE PTR [EBP+0C],00
0137:0045BA02  JZ        0045BA0E
0137:0045BA04  MOV       EAX,[EBP-0C]
0137:0045BA07  MOVZX     EAX,BYTE PTR [EBX+EAX-01]  <- EAX= char of serial
0137:0045BA0C  JMP       0045BA13
0137:0045BA0E  MOV       EAX,00000001
0137:0045BA13  MOV       ESI,[EBP+10]               <- ESI= string2
0137:0045BA16  MOVZX     ESI,BYTE PTR [EBX+ESI-01] 
0137:0045BA1B  MOV       [EBP-10],ESI               <- EBP-10= char of string2  
0137:0045BA1E  MOV       ESI,ECX                    <- ESI= char of string1
0137:0045BA20  XOR       ESI,EDX                    <- ESI= string1[ebx] XOR username[ebx] 
0137:0045BA22  XOR       ESI,[EBP-10]               <- ESI= ESI XOR string2[ebx]   
0137:0045BA25  XOR       ESI,EAX                    <- ESI= ESI XOR serial[ebx]
0137:0045BA27  TEST      ESI,ESI
0137:0045BA29  JNZ       0045BA30
0137:0045BA2B  MOV       ESI,000000FF
0137:0045BA30  LEA       EAX,[EBP-14]
0137:0045BA33  MOV       EDX,ESI
0137:0045BA35  CALL      00403710
0137:0045BA3A  MOV       EDX,[EBP-14]
0137:0045BA3D  MOV       EAX,EDI
0137:0045BA3F  CALL      0040377C
0137:0045BA44  INC       EBX
0137:0045BA45  CMP       EBX,0D                     <- Processed all 12 chars?
0137:0045BA48  JNZ       0045B9EC                   <- No: jump, Yes: don't jump.

End partial code

Explanation:

first of all let me explain my variables I declared myself:
username= BlackB
serial= 2393-1455123 (123 is added at the end btw)
string1= 1001 Killer
string2= 123456789012

All these strings are arrays of characters. That means that username[1] equals B and that serial[3] equals 9 and that string2[10] equals 0 and that string1[6] equals K.....you get the point?

In previous code snippet, EBX is the counter. It's used to check if the end of the 12 chars is reached AND used to select a certain character. If EBX==1 then serial[ebx] equals 2. If EBX==4 then username[ebx] equals c. Got it? :)
Now go back to the code snippet and try to understand what it does.

You did that? You still don't understand? Okay, let me translate this assembler snippet into some kind of English or pseudo programming language:
First assume the variables I declared above in yellow.

equal ebx to 1
declare a variable named 'result'
while ebx does not equal 13 repeat following instructions:
(
result= string1[ebx] XOR username[ebx]
result= result XOR string2[ebx]
result= result XOR serial[ebx]
increase ebx with 1
)

When everyting is executed, the variable 'result' will contain a 12-char long string that will be used in the next call to generate a valid registration code.

(3.) As I just mentioned, this call generates the real registration code.
Trace into that call (=F8). You should see this:

Start partial code

0137:0045BAEE  JMP       [EDX*4+0045BAF5]            <- EDX is counter now, startvalue is 1
This instruction jumps to the table you can see below. ...
0137:0045BB32 MOV DWORD PTR [EBP-10],0000000E 0137:0045BB39 JMP 0045BB93 0137:0045BB3B MOV DWORD PTR [EBP-10],00000009 0137:0045BB42 JMP 0045BB93 0137:0045BB44 MOV DWORD PTR [EBP-10],0000000F 0137:0045BB4B JMP 0045BB93 0137:0045BB4D MOV DWORD PTR [EBP-10],00000003 0137:0045BB54 JMP 0045BB93 0137:0045BB56 MOV DWORD PTR [EBP-10],00000005 0137:0045BB5D JMP 0045BB93 0137:0045BB5F MOV DWORD PTR [EBP-10],00000001 0137:0045BB66 JMP 0045BB93 0137:0045BB68 MOV DWORD PTR [EBP-10],00000012 0137:0045BB6F JMP 0045BB93 0137:0045BB71 MOV DWORD PTR [EBP-10],0000000D 0137:0045BB78 JMP 0045BB93 0137:0045BB7A MOV DWORD PTR [EBP-10],00000008 0137:0045BB81 JMP 0045BB93 0137:0045BB83 MOV DWORD PTR [EBP-10],0000000C 0137:0045BB8A JMP 0045BB93 0137:0045BB8C MOV DWORD PTR [EBP-10],00000013 0137:0045BB93 XOR EBX,EBX 0137:0045BB95 MOV BL,AL <- Put first char of variable 'result' into BL 0137:0045BB97 ADD EBX,[EBP-10] <- Add the table nr. to it 0137:0045BB9A CMP EBX,5A <- From here to 0045BBB4 all calculations are made
to convert the char in BL into a valid char for
the registration code
0137:0045BB9D JLE 0045BBA7 0137:0045BB9F SUB EBX,19 0137:0045BBA2 CMP EBX,5A 0137:0045BBA5 JG 0045BB9F 0137:0045BBA7 CMP EBX,41 0137:0045BBAA JGE 0045BBB4 0137:0045BBAC ADD EBX,19 0137:0045BBAF CMP EBX,41 0137:0045BBB2 JL 0045BBAC 0137:0045BBB4 LEA EAX,[EBP-18] 0137:0045BBB7 MOV EDX,EBX 0137:0045BBB9 CALL 00403710 0137:0045BBBE MOV EDX,[EBP-18] 0137:0045BBC1 LEA EAX,[EBP-14] 0137:0045BBC4 CALL 0040377C 0137:0045BBC9 INC ESI 0137:0045BBCA CMP ESI,0D 0137:0045BBCD JNZ 0045BAC2 <- If not all 12 chars processed: jump and repeat

End partial code

The only thing that may be confusing here is the table. Let me explain:

EDX is a counter that has startvalue 1. It's used to point to the first char of our string variable 'result'. Everytime the calculations for that first char are finished, EDX is increased with 1. So, in the next loop, EDX will be 2 and it will point to the second char of the string variable 'result'. Hope that's clear enough.

Everytime a loop is executed, a number is added to every char of our variable 'result'.
However, that number is not fixed. It's differs every time the loop is executed.
This is quite obvious as if EDX==2, it will execute: "jmp [2*4 + 0045BAF5]" and execute "0137:0045BB32 MOV DWORD PTR [EBP-10],0000000E", which moves the hex value '0E' into EBP-10.
Next loop, EDX will be 3, and so it will execute: "jmp [3*4 + 0045BAF5]" and that will jump to "0137:0045BB3B MOV DWORD PTR [EBP-10],00000009".

I wrote that table down on paper:

loop01 value: 6
loop02 value: E
loop03 value: 9
loop04 value: F
loop05 value: 3
loop06 value: 5
loop07 value: 1
loop08 value: 12
loop09 value: D
loop10 value: 8
loop11 value: C
loop12 value: 13

(note that all these values are HEX values!)

The rest of the instructions only make an upcase character. You only have to be able to translate it into a programming language to make your keygen. I won't explain how I translated it into C++ as I assume you can if you're a programmer. And if you're not programmer you can't make keygens.

Start keygen c++ code

#include <iostream.h>
#include <string.h> 
#include <iomanip.h>

char table[12]={0x6, 0xE, 0x9, 0xF, 0x3, 0x5, 0x1, 0x12, 0xD, 0x8, 0xC, 0x13};
char string1[12]={"1001 Killer "};
char string2[12]={"123456789012"};

char serial[12];
unsigned char result[13];
char username[12];
int i=1;

void readln(char *s)
{
 int i=0;
 char ch;
 cin >> resetiosflags(ios::skipws);
 while (cin >> ch, ch!='\n') s[i++] = ch;
 s[i]='\0';
}


void main(void)
{
 cout << "Keygen for \"1001 Killer Internet Marketing Tactics\" by BlackB [EVC] 2000" << endl;
 cout << "Enter username: ";
 readln(username);
 while (strlen(username) < 3 || strlen(username) > 12)
  {
   cout << "Username must be at least 3 characters and max. 12 characters long!" << endl;
   cout << "Re-enter username:";
   readln(username);
  }
 cout << "Enter serial (appears in left top corner of reg window):";
 cin >> serial;
 while (strlen(serial) != 9)
  {
   cout << "Length of serial should be 9!" << endl;
   cout << "Re-enter serial:";
   cin >> serial;
  }
 strcat(serial,"123");

 for (i;(12-strlen(username));i++)
  {
   strcat(username, " ");  //Add spaces, as they are used to generate the unlock code.
  }

 for (i=0;i<=11;i++)
  {
   result[i]= string1[i]^username[i];
   result[i]= result[i]^string2[i];
   result[i]= result[i]^serial[i];
  }

 for (i=0;i<=11;i++)
  {
   result[i]=result[i]+table[i];
   if (result[i] <= 0x5A)
    {
     while (result[i] < 0x41)
      {
       result[i]+=0x19;
      }
    } else               //else: if result[i] > 0x5A
       {
        result[i]-=0x19;
        while (result[i] > 0x5A)
         {
          result[i]-=0x19;
         }
       }
  }

 cout << "Your registration code is: " << result << endl;
 cout << "Enjoy!" << endl;
}

End keygen c++ code

If you don't want to keygen this program, and just want to know where the serial is created: just follow this tutorial, don't mind if you don't understand the keygen algorithms, and find the real unlock code after the two loops in the two calls have completed....should be a one minute job ;)

Oh yea, before I forget: your registration information is stored in X:\WINDOWS\HMVIEWER.INI. Note that it's encrypted.
Removing the file will unregister you again ;-) I found out by using FileMon on the program......obviously :P

Finished again.....

IV. In the end

When you're done reversing this application, take your time to read the valuable information inside it. It's really worth the time.
Greets goto FishMAN. Hope you learned something with this tutorial.

greets

The Blackbird

Endnote:
Essay written by The Blackbird © 1999-2000
This essay can be freely distributed/ published/ printed etc... as long as no modifications are made.