|
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.
|
|