Getting the installation password by cracking the Installshield script. |
| |
|
|
|
|
|
by +Tsehp |
fra_00xx 98xxxx handle 1100 NA PC |
This very valuable essay covers in
detail a very useful way to reverse and modify an installshield script,
with more details than my method in my precedent essay concerning c++
builder 4. |
|
|
||
|
This essay describes an alternate method of cracking the Delphi 5 trial installation. Rather than attempt to patch the installation program, a method of deriving a valid installation key will be described.
|
|
|
|
Borland provides a 60 day trial for Delphi 5. The 60 day trial is enforced using SentinelLM, and the keygen process is described fully in CyberHeg's essay on this subject. This essay covers the Installshield part of the crack. The first step is to download the Delphi trial, D5TRIAL.EXE. This is a packed up trial that contains an executable which unpacks the install and generates a unique code which you send to Inprise for an installation key. Start the installer, and wait for it to unpack. At this point, you can click the "Get your System ID to unlock the trial" button in order to get your system ID. This value is supposed to be unique for each system - we will discover later how this value is derived. For now, record this value - we'll get to this later. Next click the "Install Delphi 5 Trial" button. This will start the real installshield installation. Once it's started up, and you're at the welcome screen, look in your %TEMP% dir for recently created directories, typically by going to C:\TEMP then doing a dir /o:d What we're looking for is the installshield "setup.ins" file which, in my last installation, was C:\TEMP\pft37E~tmp\Install\setup.ins Copy this to a location where we can work on it, then try running isdcc on this file. D:\isdccdir>isdcc setup.ins isDcc v1.22, (c) 1998 Andrew de Quincey Unknown function arg at (0x3eb1) Hmm. Not working. Since we're interested in what the program is generally doing at this point, we can get away without an exact translation of the types within the install script. The next step is to patch the isdcc source so that it thinks the unknown function arg is some known type and the decompiler can continue. With some digging and tracing through the source code of isdcc, we see that the unknown token error occurs in parseArg. By tracing the code, we find that the value of argType is being set to type 0 or type 2, and that's causing it to execute the default case. Rather than add new types (which would probably be a more correct approach) the program was patched to force the unknown types to static long so that the decompilation process could continue. So at 1879 of decode.c /* HACK */ if (argType == 0) argType = 0x41; if (argType == 2) argType = 0x41; Now the decompiler can run, and we have a passable decompilation of the target installation. Continuing with the install, when we reach the point where the registration password is entered, enter some numbers - it will come back with "Incorrect Password". If we search the decompiled script for this, it doesn't occur - clearly it must be somewhere else. By digging around in the temporary installation dirs, we find the string in a file called "value.shl" - this appears to be a file which maps constants to strings. Here we find WRONG_PSWD=Incorrect Password So probably we are looking for WRONG_PSWD rather than Incorrect Password. By locating the string, we're close to the area of interest in the installation. The labels are not correct, but we can see where the transfer was supposed to occur. label993: MessageBeep(0); StrLoadString("", "WRONG_PSWD", lString3); MessageBox(lString3, -65535); lNumber1 = lNumber1 + 1; StrLoadString("", "TRIAL_TEXT", lString3); AskText(lString3, "", lString0); lNumber4 = LAST_RESULT; Looking earlier in the code, we can see a location that looks like it should go here: label991: lNumber1 = 0; lString0 = "Taj"; lString2 = SUPPORTDIR ^ "cleanup.dll"; UseDLL(lString2); lNumber2 = LAST_RESULT; CLEANUP.StartLogFile(lString1); lNumber3 = LAST_RESULT; UnUseDLL("cleanup.dll"); StrLoadString("", "TRIAL_TEXT", lString3); AskText(lString3, "", lString0); lNumber4 = LAST_RESULT; StrCompare(lString1, lString0); lNumber5 = LAST_RESULT != 0; lNumber6 = lNumber4 = 1; lNumber5 = lNumber5 && lNumber6; if (lNumber5 = 0) then goto label995; endif; Hmm. lString1 looks like it's being checked against the value asked for in the AskText for TRIAL_TEXT - what is TRIAL_TEXT? TRIAL_TEXT=Please enter the Password you recieved by registering with Borland. If you have not registered please go to www.borland.com/Delphi/trial5/, or call 1-800-453-3375. Looking at the above code, it looks like StartLogFile in cleanup.dll is where the key comes from. Copy the file from the temporary installshield directory, and run IDA against it. ; Attributes: bp-based frame public StartLogFile StartLogFile proc near RootPathName = byte ptr -108h var_105 = byte ptr -105h VolumeSerialNumber= dword ptr -4 outserial = dword ptr 8 push ebp mov ebp, esp add esp, 0FFFFFEF8h push ebx push 104h ; uSize lea eax, [ebp+RootPathName] push eax ; lpBuffer call GetWindowsDirectoryA mov [ebp+var_105], 0 push 0 ; nFileSystemNameSize push 0 ; lpFileSystemNameBuffer push 0 ; lpFileSystemFlags push 0 ; lpMaximumComponentLength lea edx, [ebp+VolumeSerialNumber] push edx ; lpVolumeSerialNumber push 0 ; nVolumeNameSize push 0 ; lpVolumeNameBuffer lea ecx, [ebp+RootPathName] push ecx ; lpRootPathName call GetVolumeInformationA mov ecx, [ebp+VolumeSerialNumber] xor edx, edx mov eax, ecx mov ecx, 3 div ecx mov ecx, eax push 2Bh add ecx, 0Bh push ecx call generate_key mov ebx, eax push ebx push offset aLu ; "%lu" mov eax, [ebp+outserial] push eax call wsprintfA add esp, 0Ch mov eax, ebx pop ebx mov esp, ebp pop ebp retn 4 StartLogFile endp I've edited the names a bit at this point, but at this point it's clear what is happening in this routine. The volume where the windows directory resides is queried for it's serial number. This number is then divided by 3, and 11 (0x0b) is added after, and that give you the number which you have to send to Borland to get an installation key. "generate_key" takes this value and 0x2b, then creates a key which is returned in EAX. Knowing this, we can get the installation key for the machine which we're running the program on, since we can then call StartLogFile with a pointer to char, and then simply print the value out. #include <stdio.h> #include <windows.h> int ((__stdcall *fptr)(char *)); main() { char mylibname[1024]; HINSTANCE myinstance; int retcode; char text1[1024]; strcpy(text1,""); strcpy(mylibname, "cleanup"); myinstance = LoadLibrary(mylibname); if (myinstance == 0) { printf ("Failed loadlibrary.\n"); } /* routine cleans up stack instead of us */ fptr = (int(__stdcall *)(char *)) GetProcAddress(myinstance, "StartLogFile"); if (fptr == 0) { printf ("Failed GetProcAddress.\n"); } retcode = (*fptr)(text1); fprintf(stderr, "Install Code: %s\n", text1); } What if we want a key for another machine though? It would see as if we simply ripped the generate_key routine out, it should generate the correct values given the correct data. If this is done, the program runs, but doesn't produce correct keys. What could be wrong? Checking the encryption tables in the ripped program we find that there are different values there than when running in the provided DLL. By setting a BPM on the table, we find that the initialization code for the DLL calls some routines which update the encryption tables. By calling the initialization routine first, we can initialize the tables, and get the encryption routines to work correctly. #include<stdio.h> #include<string.h> #include<windows.h> extern void real_gen_key(int *, int *); extern void init_tabs1(); main() { char rootpath[1024]; char volbuf[1024]; long volbufsize = 1024; unsigned long serno; long maxcomplen=1024; long fsflags; char fsbuf[1024]; long fsnamesize = 1024; int rcode; unsigned int inser; unsigned int prodkey; char *p; GetWindowsDirectory(rootpath,1024); /* get only directory part */ if (p=strchr(rootpath,'\\')) *++p = '\0'; printf ("Rootpath: %s\n", rootpath); rcode = GetVolumeInformation(rootpath,volbuf,volbufsize,&serno,&maxcomplen,&fsflags,fsbuf, fsnamesize); init_tabs1(); /* the initialization routine ripped from cleanup.dll */ printf ("Serial: %08x\n", serno); printf ("System ID: %u\n", serno/3+11); inser = serno / 3 + 11; /* some magic number ripped from install */ prodkey = 0x2b; real_gen_key(&inser, &prodkey); /* keygen routine ripped from cleanup.dll */ printf ("Installation key for this machine: %lu\n", inser); printf ("Please enter System ID of target machine:\n"); scanf("%lu", &inser); printf ("System ID: %lu\n", inser); prodkey = 0x2b; real_gen_key(&inser, &prodkey); printf ("Installation Key: %lu\n", inser); }
|
This demonstrates how we can generate the installation keys for an installshield protection. Of course, we could have patched the installation as well, but this allows an installation without modifying the original installation files. CyberHeg's excellent essay "No More Rainbow Trials" covers the SentinelLM protection, so read that essay for a full non-expiring Delphi.
|