Cracking PlasmaVis (Making a Keygen in C)

EDB-ID:

13116

CVE:

N/A

Author:

SlimTim10

Type:

papers

Platform:

Multiple

Published:

2007-01-03

==============================================================================================
Cracking PlasmaVis (Making a Keygen in C)
-----------------------------------------
This tutorial is NOT meant for beginners in x86 assembly or C.
==============================================================================================

Please note that readers should have some background knowledge of x86 assembly as well as C.

I decided to make this tutorial specifically on PlasmaVis because it is fairly trivial to
reverse engineer, but great for learning. This tutorial is meant solely for learning purposes.
The techniques described in this tutorial should not be used to steal software. If you enjoy
using software, respect and support the author by purchasing it!

----------------------------------------------------------------------------------------------
Product..............: PlasmaVis Music Visualization
Version..............: PlasmaVis version 1.1.0.3
Vendor...............: Olsen Software (http://www.plasmavis.com/]http://www.plasmavis.com/)
Product Link.........: http://www.plasmavis.com/PlasmaVis.msi
Written by...........: SlimTim10
Required tools.......: C Compiler, Debugger, ASPack 1.12 Unpacker, PE Identifier
----------------------------------------------------------------------------------------------

The tools I will use are, respectively: Dev-C++, OllyDbg, AspackDie 1.2, and PE iDentifier
v0.94. The tutorial is broken up into steps that may be followed for most basic reverse
engineering attempts on products.

=> Run the  target and attempt  to register using false information.  Keep note of the text in
   the error message  that is displayed when the registration fails. In PlasmaVis, the message
   is "Invalid license key. Please verify all inputs and try again." In some cases,  it may be
   necessary to  use the message box's title  (i.e. "PlasmaVis Configuration") if  the message
   string cannot be found.

=> Find out  if the  target  is packed  using  a PE identifier.   If it is,  unpack it  with a
   reliable unpacker. Using PEiD, you can find out that PlasmaVis is packed using ASPack 2.12.
   AspackDie 1.2 will work as an unpacker for PlasmaVis.

=> Now that  the target is unpacked,  begin debugging the unpacked executable with a debugger.
   Using OllyDbg,  find the string reference to the registration error message.   It should be
   located at address 0044F82A.  In OllyDbg, find references to the address (CTRL+R). The only
   reference should  be the  operation code  JNZ SHORT 0044F82A  at address  0044F803.   It is
   evident that  if the condition  above the jump does not set the zero flag,  the bad message
   will be produced.   Looking above that address,  it should be  clear that the  registration
   algorithm begins at 0044F708,  so set a breakpoint at that address and run the application.
   (Press  SHIFT+F9  twice in  OllyDbg after the  application is ran  to pass the exceptions).
   When the target has started up, attempt to register using false information again.  As soon
   as the "Register" button is clicked,  OllyDbg should stop  PlasmaVis due to the breakpoint.
   The  CALL at address  0044F732  will call the function that produces the registration input
   window in PlasmaVis.  Like at the beginning,  enter false information  again and attempt to
   register the target.  In PlasmaVis, it is best to use a different value for each input box.
   For this tutorial, I will use "email", "first", "last", and "test", respectively.

=> Step over each  line in  OllyDbg (F8) while  analyzing the procedure  of each line  and the
   target's progression.  At address 0044F7EA in PlasmaVis, you should notice that each of the
   first three strings are stored in separate registers and then a function is called.  If you
   stepover the CALL opcode,  the next two  values stored in  registers are the  valid license
   key and the value you input as the license key, respectively.  This means that the CALL you
   jumped over called  the function that made the valid license key!   Set a breakpoint at the
   CALL,  which should be address 0044F7F3.   Restart PlasmaVis in OllyDbg and run it until it
   reaches the new breakpoint.  This time,  step into (F7) the opcode instead of stepping over
   it. Now all that is left is to analyze the function and create the key generator in C.

=> First,  each input value is stored in a separate register.  The EAX register holds "email",
   ECX holds "last",  and EDX holds "first".  Then the first two characters of each string are
   extracted and joined together to form a single string (i.e. "emfila").  You may also notice
   that a strange-looking string is going to be used, "qazwsx123*()*()&". Beginning at address
   0044E46B is the main  algorithm in PlasmaVis which produces a valid license key.  For those
   that understand x86 assembly  at a reasonably high level,  you should be able to understand
   the block of code on your own, so skip the next step. Others, read on.

=> This is a representation of what you should see in OllyDbg:

0044E46B  |> 8B45 F0		/MOV EAX,DWORD PTR SS:[EBP-10]
0044E46E  |. 8A4418 FF	        |MOV AL,BYTE PTR DS:[EAX+EBX-1]
0044E472  |. 8B55 EC		|MOV EDX,DWORD PTR SS:[EBP-14]		;  plasmavis.0044E520
0044E475  |. 8A541A FF		|MOV DL,BYTE PTR DS:[EDX+EBX-1]
0044E479  |. 32C2		|XOR AL,DL
0044E47B  |. 25 FF000000	|AND EAX,0FF
0044E480  |. 8D4D C8		|LEA ECX,DWORD PTR SS:[EBP-38]
0044E483  |. BA 02000000	|MOV EDX,2
0044E488  |. E8 2799FBFF	|CALL plasmavis.00407DB4
0044E48D  |. 8B55 C8		|MOV EDX,DWORD PTR SS:[EBP-38]
0044E490  |. 8BC6		|MOV EAX,ESI
0044E492  |. E8 B957FBFF	|CALL plasmavis.00403C50
0044E497  |. 8BC3		|MOV EAX,EBX
0044E499  |. 25 01000080	|AND EAX,80000001
0044E49E  |. 79 05		|JNS SHORT plasmavis.0044E4A5
0044E4A0  |. 48			|DEC EAX
0044E4A1  |. 83C8 FE		|OR EAX,FFFFFFFE
0044E4A4  |. 40			|INC EAX
0044E4A5  |> 85C0		|TEST EAX,EAX
0044E4A7  |. 75 18		|JNZ SHORT plasmavis.0044E4C1
0044E4A9  |. 8B45 F0		|MOV EAX,DWORD PTR SS:[EBP-10]
0044E4AC  |. E8 9757FBFF	|CALL plasmavis.00403C48
0044E4B1  |. 3BD8		|CMP EBX,EAX
0044E4B3  |. 74 0C		|JE SHORT plasmavis.0044E4C1
0044E4B5  |. 8BC6		|MOV EAX,ESI
0044E4B7  |. BA 60E54400	|MOV EDX,plasmavis.0044E560
0044E4BC  |. E8 8F57FBFF	|CALL plasmavis.00403C50
0044E4C1  |> 43			|INC EBX
0044E4C2  |. 4F			|DEC EDI
0044E4C3  |.^75 A6		\JNZ SHORT plasmavis.0044E46B

   The first opcode  simply stores the  string "emfila" in  the EAX register.   Then the first
   letter, "e", is stored in AL (since it is a single character, only one byte is needed). The
   string "qazwsx123*()*()&"  is then stored in the EDX register.  Then the first character of
   that  string, "q",  is stored in DL.  AL is then  computed with DL  using the XOR operation
   (read more here:  http://en.wikipedia.org/wiki/Bitwise_operation#XOR).  The EAX register is
   then computed  with the hexadecimal  0FF value using  the AND operation.  The result of the
   previous expression is  then converted into  a string of  characters and stored  in the EDX
   register.  During this loop function, the EDI register is used as a counter. It is compared
   at the end of each loop  to determine whether it  is still greater than 0.   EDI begins the
   loop as the number of  characters in the "emfila" string (i.e. 6)  and it is decreased by 1
   each time the loop  reaches the "bottom".  The loop continues until  the EDI register is no
   longer greater than 0.

=> In pseudocode, the function would look something like this:

for (EDI = length of EAX; EDI > 0; EDI--) {
	EAX = XOR #(EDI) character of "emfila" with #(EDI) character of "qazwsx123*()*()&"
	//first time: XOR 1st char of "emfila" with 1st char of "qazwsx123*()*()&" (XOR e,q)
	EAX = EAX AND 0FF
	EDI--
}

   The CALL  at address 0044E4DB  calls a simple function  that replaces any "0" characters in
   the string with "Z" characters.  Finally,  the CALL right before the conditional jump (good
   message/bad message)  compares each corresponding  character of the user  input license key
   with the valid license key.

=> The following C code is a snippet that I used in my own PlasmaVis key generator.  It may be
   a spoiler to  those of you who wish to make  an attempt at creating the keygen alone.  Note
   that I  created a GUI keygen,  so it is  not as basic  as if it  were meant  to be run  via
   command-line.

int len_e = GetWindowTextLength(GetDlgItem(hwnd, IDC_EMAIL));
int len_f = GetWindowTextLength(GetDlgItem(hwnd, IDC_FIRST));
int len_l = GetWindowTextLength(GetDlgItem(hwnd, IDC_LAST));

if(len_e > 0 && len_f > 0 && len_l > 0)  {
  if(len_e > 2 && len_f > 2 && len_l > 2) {
    char *buf_e;
    buf_e = (char*)GlobalAlloc(GPTR, len_e + 1);
    GetDlgItemText(hwnd, IDC_EMAIL, buf_e, len_e + 1);
							
    char *buf_f;
    buf_f = (char*)GlobalAlloc(GPTR, len_f + 1);
    GetDlgItemText(hwnd, IDC_FIRST, buf_f, len_f + 1);
							
    char *buf_l;
    buf_l = (char*)GlobalAlloc(GPTR, len_l + 1);
    GetDlgItemText(hwnd, IDC_LAST, buf_l, len_l + 1);
							
    char tmp[] = { buf_e[0], buf_e[1], buf_f[0], buf_f[1], buf_l[0], buf_l[1] };
    char enc[] = "qazwsx123*()*()&";
    int len_k = strlen(tmp);
							
    char key[0];
    int i;
    for (i = 0; i < len_k; i++) {
      if (i == 2 || i == 4)
        SendMessage(key_hWnd, EM_REPLACESEL, 0, "-");
      tmp[i] = tmp[i] ^ enc[i];
      if (tmp[i] < 0x10)
        SendMessage(key_hWnd, EM_REPLACESEL, 0, "Z");
      itoa((int)tmp[i], key, 16);
      strupr(key);
      SendMessage(key_hWnd, EM_REPLACESEL, 0, key);
    }

    GlobalFree((HANDLE)buf_e);
    GlobalFree((HANDLE)buf_f);
    GlobalFree((HANDLE)buf_l);
  } else {
    MessageBox(hwnd, "All fields must be more than 2 characters long!", "Warning", MB_OK);
  }
}


Thank you for  taking the time  to read this  tutorial on cracking  PlasmaVis.   This tutorial
should be used  for educational purposes only.   I am not responsible for  any illegal actions
performed by readers of this tutorial.


Download Resources:

Dev-C++: http://www.bloodshed.net/dev/devcpp.html
OllyDbg: http://www.ollydbg.de/odbg110.zip
AspackDie 1.2: http://www.exetools.com/files/unpackers/win/aspackdie12.zip
PE iDentifier v0.94: http://www.softpedia.com/progDownload/PEiD-Download-4102.html

# milw0rm.com [2007-01-03]