TUTORIAL #1
Published by +Tsehp |
TOOLS NEEDED: |
|
THINGS YOU NEED TO KNOW: |
|
INTRODUCTION: |
Today we are going to learn how to make a crappy bruteforcing keygen type thingy for a high end app. We begin by going to www.microstrategy.com to learn alittle about wtf this product is... "MicroStrategy is world's leading provider of enterprise DSS software, which allows decision-makers to perform sophisticated analyses across large volume of data. MicroStrategy provides an integrated suit of decision support development and administrative tools, application servers and runtime interfaces that enables the construction of leading edge DSS applications.The Microstrategy API's, for developers to create software addons and companions for the Microstrategy 7.1 suite of products." Ok, now that we know alittle about this product, lets run the Install Shield setup. After hitting the "NEXT" button a few times we come across a serial dialog, the serial dialogs "NEXT" button is grayed out. Sometimes programs that have Install Shield installations have a serial dialog that is grayed out until all the fields are filled in, so lets try filling in the fields: Very interesting... Most likely the serial checking routines are in a DLL file that gets extracted to your temporary directory once you run the Install Shield setup. Most serial checks for Install Shield installers are done through external DLLs. Lets close up the Installer and lets start viewing the Install Shield script. |
||||||
ANALYSIS: |
Now lets make a copy of the setup.ins (rename it to setup). Open up "Windows Installshield Decompiler" and open up setup. Once the decompiling has finished goto the "Misc" menu and select "DLL Imports", we are going to see if the installer is using a external DLL to handle the serial checking. In the DLL Imports section we see the following are being called in this Install Shield script: Prototype BOOL KERNEL32.GetVersionEx
(LIST/POINTER ) Lets take a look at which DLL Libraries are being called
Ok, now lets look at the function names for the unknown DLLs. The function names in MAInTls don't suggest anything suspicous so we can forget about it. MAInst only has 1 function that gets used in this script and its called "fnSerialkey", the name of this function sounds very suspicous. Lets browse through the script until we find a reference to that function: <LABEL_0074> REF: 00002A70 000062C5 00006916 | 00004180: 00B6 START OF FUNCTION (6*StrLocals + 5*NumLocals) 000041A5: 0128 IF (StrLength (StrLocal[0001]) != 0000000E) THEN 000041C5: 012F Return (00000000) 000041C6: 0000 ENDIF 000041E2: 0128 IF (MAInst.fnSerialkey (StrLocal[0001]) <= 00000000) THEN 00004202: 012F Return (00000000) 00004203: 0000 ENDIF 0000420F: 012F Return 00004211: 011D NumLocal[0005] = NumLocal[0002] & 01000000 0000421E: 0128 NumLocal[0005] = NumLocal[0005] > 00000000 00004230: 00B7 Return (NumLocal[0005]) 00004235: 00B8 END OF FUNCTION () Lets analyze the above snippet. "StrLocal[0001]" is most likely the serial key that you type in. First it does a "StrLength" function on the serial to see if the length is equal to 0x0E. If its not equal to that, it'll return with 0. If it is equal to 0x0E, it will begin to call up the "fnSerialkey" function with the "StrLocal[0001]" variable. If the "fnSerialkey" function returns 0 or less, then that most likely means the function has failed just like the "StrLength" compare, it's returning with 0. Go back into wisdec and test out this theory. Change the <= to >= and in script.ins. Once your back in the serial dialog, type in 14 (0x0E) random keys and hit the "NEXT" button. It should take you to the next set up of the installation. This proves what we have suspected all along. Here is what the dialog should look like when you have passed the serial dialog: The text inside "Current Settings:" might be different if you're installing this app for the first time. |
||||||
GETTING DLLS: |
Ok, now that we know whats going on, we have to actually get the MAInst DLL file. When Install Shield installers run, they create a little folder in your temp folder (C:\Windows\Temp for me) and they dump out all there support files in there. Run the setup program. Once it starts up, get into Windows Explorer or whatever you use and go into your temp folder. Once inside your temp folder, look for folders that look like this "ISTMP???.DIR". If you have more then 1 folder that looks like that then look through all of them until you find MAInst.DLL file. For me this file was located in C:\WINDOWS\TEMP\_ISTMP1.DIR\_ISTMP0.DIR. Once you find this file, copy it to a safe place and finally exit the installation. When your done this process copy your setup file over the setup.ins that you modified. |
||||||
THE ALGO: |
I spent about an hour converting the algo to C only to see that reversing it to make a legit keygen is gay and a waiste of my time. So what we're going to do is exploit the developers stupidity. Load the DLL exports of MAInst.dll into Soft-Ice. After you've done that set a breakpoint on "fnSerialkey". Run the installer and enter in a fake 14 char serial to just get a feel for what the algos like. It looks very long and gay doesn't it? No problem because we're going to make a bruteforcer for this crap. I'm not going to copy/paste the entire algo here but i'll paste significant parts that need to be arranged for the bruteforcer. Here is what the fnSerialkey looks like when you first get into it: 10001310 mov eax, [esp+arg_0] <--- Move char pointer into EAX 10001314 push eax <--- Push the char pointer into stack 10001315 call sub_1000146C <--- Calls the algo here 1000131A add esp, 4 1000131D retn 4 Moving into the algo call we see serial length checks: 10001482 mov eax, [ebp+arg_0] <--- Move serial char pointer into EAX 10001485 push eax <--- Push the serial char pointer into stack 10001486 call _strlen <--- Calls the strlen to get serial string length 1000148B add esp, 4 1000148E mov [ebp+var_10], eax <--- Save it 10001491 cmp [ebp+var_10], 9 <--- Is the serial length 9? 10001495 jz short loc_100014A5 <--- Jump if it is (GOOD) 10001497 cmp [ebp+var_10], 0Eh <--- Is the serial length 14? 1000149B jz short loc_100014A5 <--- Jump if it is (GOOD) 1000149D or eax, 0FFFFFFFFh <--- Serial length is invalid 100014A0 jmp loc_10001772 <--- Jumps to a ret at the end of the function Ok, so now we have discovered that the algo accepts both 9 char serials and 14 char serials but Install Shield makes it so that it only accepts 14 char serials. Maybe because they wanted to make it backwards compatible for older versions or someshit? I really don't know. After we follow the path of execution some more we come up to this little nugget: 100014A5 cmp [ebp+var_10], 0Eh <--- Compares lenght to 14 once again 100014A9 jnz short loc_100014C1 <--- This check is for 9 char serials 100014AB mov ecx, [ebp+arg_0] <--- Gets serial char pointer again 100014AE movsx edx, byte ptr [ecx+9] <--- Gets the 9th byte 100014B2 cmp edx, 2Dh <--- Compare 9th byte to 0x2D (-) 100014B5 jz short loc_100014C1 <--- If it is 0x2D (-) then jump (GOOD) 100014B7 mov eax, 0FFFFFFFEh <--- Set as bad serial 100014BC jmp loc_10001772 <--- Jumps to a ret at the end of the function Now we have alittle more information about the format of our serial. It has to be 14 chars long and the 9th char has to be a "-". So basically we have a serial looking like this "????????-????". After going through the algo some more we notice that the first 8 chars of the serial must be all numbers and the last 4 chars can be numbers or letters. So to clarify even more the serial looks like this "NNNNNNNN-LLLL" (N = Numbers, L = Letters or numbers). After tracing down a little more we see something very special: 10001623 mov ecx, [ebp+var_18] <--- Gets DWORD that was calc'd by the algo 10001626 xor ecx, 0B73BBh <--- Xor it by 0xB73BB 1000162C mov [ebp+var_18], ecx <--- Put it back 1000162F 1000162F loc_1000162F: 1000162F cmp [ebp+var_18], 80000h <--- Compare DWORD xored above to 0x8000 10001636 jbe short loc_10001642 <--- Jump if below or equal (GOOD) 10001638 mov eax, 0FFFFFFFDh <--- Set as failed serial 1000163D jmp loc_10001772 <--- Jumps to a ret at the end of the function The crap in [ebp+var_18] is calculated at 1000158C. Its pretty straight forward but too long to list. It loops through each of the 4 chars at the end of the serial doing the follwoing:
Here is the C source for calculating 4 valid chars for the end of the serial: void topSerialize() { char topSerial[] = "0000"; long shiftVar = 0; long newVar = 0; long temp = 0; while(true) { shiftVar = 0; newVar = 0; temp = 0; topSerial[0] = rand()%(0x5A-0x30)+0x30; topSerial[1] = rand()%(0x5A-0x30)+0x30; topSerial[2] = rand()%(0x5A-0x30)+0x30; topSerial[3] = rand()%(0x5A-0x30)+0x30; for( int i = 0; i < 4; i++ ) { if ( topSerial[i] > 0x29 && topSerial[i] < 0x3A || topSerial[i] > 0x40 && topSerial[i] < 0x5B) { temp = topSerial[i]; if ( temp >= 0x30 && temp <= 0x39 ) temp -= 0x30; if ( temp >= 0x41 ) temp -= 0x37; shiftVar <<= 5; shiftVar += temp; newVar++; } } if ( ((shiftVar ^ 0xB73BB) <= 0x80000) && newVar == 4 ) break; } } Now we have the most important parts of the algo that we need to make a keygen bruteforcer thingy! |
||||||
THE C CODE: |
Here is the C Code. What we do here is we take MAInst.DLL and we load it up, then we use our "topSerialize" function to generate a good last 4 chars for the serial. Once that has been generated it will start incrementing numbers 1 by 1 until "fnSerialkey" function returns something higher then 0. Once the keygen bruteforcer thingy recieves a value higher then 0, it will take the serial code and output it to the screen for the cheapass warez addict to use for his lameass company. Here it is! (REMEBER TO HAVE MAInst.DLL IN THE KEYGEN FOLDER OR YOUR SYSTEM FOLDER!!!): #include <windows.h> #include <iostream.h> #include <stdio.h> #include <stdlib.h> #include <conio.h> #include <string.h> char topSerial[] = "0000"; int serial = 0; void topSerialize() { long shiftVar = 0; long newVar = 0; long temp = 0; while(true) { shiftVar = 0; newVar = 0; temp = 0; topSerial[0] = rand()%(0x5A-0x30)+0x30; topSerial[1] = rand()%(0x5A-0x30)+0x30; topSerial[2] = rand()%(0x5A-0x30)+0x30; topSerial[3] = rand()%(0x5A-0x30)+0x30; for( int i = 0; i < 4; i++ ) { if ( topSerial[i] > 0x29 && topSerial[i] < 0x3A || topSerial[i] > 0x40 && topSerial[i] < 0x5B) { temp = topSerial[i]; if ( temp >= 0x30 && temp <= 0x39 ) temp -= 0x30; if ( temp >= 0x41 ) temp -= 0x37; shiftVar <<= 5; shiftVar += temp; newVar++; } } if ( ((shiftVar ^ 0xB73BB) <= 0x80000) && newVar == 4 ) break; } } void main() { printf("MICROSTRATEGY RUNTIME ENVIROMENT v7.1.309.113 *KEYGEN*\n\n\n"); printf("\n*KEYGEN BY: Tha Great ALI_G!!!\n\n"); srand(GetTickCount()); int result = 0; printf("Loading DLL... "); HMODULE loadedDLL = LoadLibrary("MAInst.dll"); int serialFunc = (int)GetProcAddress(loadedDLL, "fnSerialkey"); if ( loadedDLL == NULL || serialFunc == NULL) { printf("FAILED!\n\n\n"); printf("MAKE SURE YOU HAVE THE MAInst.dll FILE IN THE SAME DIRECTORY AS THIS PATCH"); exit(0); } printf("Done!\nScanning for random valid top serial keys... "); topSerialize(); printf("Done!\nScanning for valid key... "); char mySerial[] = " "; char tempSerial[] = " "; LPSTR strserial = mySerial; int serialLen = 0; unsigned long blah = 00000000; while(true) { memset(&mySerial, 0x00, 0x0D); memset(&tempSerial, 0x00, 0x0D); sprintf(tempSerial, "%i-%s", blah, topSerial); serialLen = strlen(tempSerial); for(int i = 0; i < 0x0E-serialLen; i++) strcat(mySerial, "0"); strcat(mySerial, tempSerial); __asm { push strserial; call serialFunc; mov result, EAX; } if ( result > 0 ) { printf("Done!\nSerial found: %s\n\n", mySerial); _getch(); printf("B00YAKASHA!!\n\n"); break; } serial++; blah++; serialLen = 0; } FreeLibrary(loadedDLL); } Yes, I know its very messy and looks very confusing
and unoptimized but this will generate a serial for you in a fraction
of a second!!! |
||||||
CONCLUSION: |
Welp, we're done. Run this program and it'll give you a random valid key. It's pretty sad to see software developers making it so easy for people like me to do this shit. This is only one of may ways to make a keygen for this program so keep investigating! If you have any questions/comments/ect.. you can contact me at shogo2001@yahoo.com or catch me on IRC, my nickname is vman_ on EFNet. |