PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Making a Keygen in C



meckl
03.02.2008, 10:33
Making a Keygen in C

http://milw0rm.com/papers/132


================================================== ============================================
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]