|
Code Archaeology with ElanLM
Reviving functions from the past
|
|
Jan 2001
|
by
pilgrim
|
|
|
Courtesy of Fravia's page of reverse engineering
|
slightly edited
by +Tsehp
|
|
There is a crack, a crack in everything That's how the light gets in
|
|
Rating
|
( )Beginner (x)Intermediate ( )Advanced ( )Expert
|
|
Using historic Unix object code to reveal function names within Intel-based ElanLM code.
Analysing the ElanLM licensing code, applying to SPSS products to give full non-expiry keys.
Code Archaeology with ElanLM
Reviving functions from the past
Written by
pilgrim
This started as a natural progression from the FlexLm and SentinelLM analyses.
Both securities were based, back in the dark old days of 1995, on the ElanLm from Elan Computing Inc.
But 6 years is a long time on the web, and the project turned more into an archaelogical dig.
SoftICE 4.05
Icedump 6.021
Ida 4.0.4
Hiew 6.40
Quine's IDA IDC to convert IDB to PAT
Various SPSS products, most notibly SPSS 10.1 base, all available from ftp.spss.com
Hmm, the grandfather of both FlexLM and SentinelLM, dates back to 1995 and further.
Initial research
First thing to do with a non-trivial crack is get a thorough grounding in the targets licensing
mechanism. Search the web to the best of your ability.
Unfortunately, www.elan.com can reveal no clues since the take-over by sentinel,
but many people have used ElanLM in the past.
There are many traces of ElanLM scattered over the web - install instructions, tech notes,
marketing docs.
I came up with a good amount of data: some function prototypes;
a simplistic explanation of how to incorporate the licensing code into an application;
some UNIX object code containing ElanLM code;
and many, many license codes for various SPSS products - most, but not all, of which had expired.
Initial install attempt
Let's start with the SPSS10.1base demo, available from the SPSS ftp server.
It's a single compressed installshield EXE, so clean out your windows/temp folder, start the
installation process and watch the files appear in your temp folder.
Copy these and scrap the original EXE, we can use the decompressed setup.exe to re-install.
Have a look in the setupntr.inf and we see:
VersionMajor=10
VersionMinor=1
PrestampedName=Evaluation Version
PrestampedOrg=SPSS
PrestampedSerialNo=123456
PrestampedLicense=47142 99766 32600 66848 08170 26408 52332 722
Here we see the SPSS version, 10.1, and default install data.
We can comment all of these out and the installer will ask us for the info.
The installer will then check the key validity and let us know what, if anything, we've licensed.
This is useful for key-testing later..
The installer shows us that the license key shown expires 1/1/2001
Once installed have a look around the files and we see traces of the ELanLM code.
Dissassemble, and we don't get much - no Elan function names and not a lot to help us.
We do see some *.lic files which is where the ElanLM stores it's licensing info.
Initial research shows that the filename is something like 20.lic where 20 is a feature name.
Host-locking data and time data is stored encrypted in the lic files to prevent tampering and time
manipulation expiry avoidance techniques.
The initial research revealed that a program supplied by SPSS called licrenew.exe
can be used to renew licenses - this sounds just what we want,
and it can be found on the SPSS ftp server.
Pass our prestamped license key into licrenew.exe and we get the same license file -
so it seems to work.
Pass garbage in and it complains.
Dissassemble and we still don't see much.
How to get some useful Elan function names? ...
UNIX object code analysis
In my initial research I found some UNIX object code containing ElanLM code.
It looks like some old graphics library called CAVE used Elan and so required
the user to link in the Elan library to their final release code.
If we dissassemble the code with IDA we don't get Intel assembler,
but we do get lots of Elan function names, constant strings and data.
We also see some filenames, embedded in the code.
If we get IDA to generate a MAP file, we can see all the functions, for example, the first few:
0002:00029F80 elm_message
0002:0002A594 elm_valid
0002:0002AF20 elm_numkeyhostid
0002:0002B010 elm_shorthostid
0002:0002B0E0 elm_hostxtod
Now, have a look at the object code with your favourite hex editor.
Way past the function names for elm_message etc we see file headers, for example:
@(#)message.c 1.24 5/2/95 Copyright (c) 1995 Elan Computer Group, Inc
$Id: valid.c 1.15 1995/12/01 22:04:30 von Exp $ ELAN
@(#)nkhost.c 1.5 5/2/95 Copyright (c) 1995 Elan Computer Group, Inc.
@(#)shostid.c 1.5 5/2/95 Copyright (c) 1995 Elan Computer Group, Inc.
@(#)hostxtod.c 1.11 5/2/95 Copyright (c) 1995 Elan Computer Group, Inc.
Now it seems a fair assumption to me that the elm_* functions are in the same order
as the order of the files compiled into the library.
So now what you can do is take your MAP file and guess which files the functions came from.
At the same time I recorded the function sizes.
What for? Well..
Apply the UINX file information to the Intel EXE
Looking at licrenew.exe with our favorite hex editor, we don't see function names,
but we DO see the same file headers, constant string and data as in the UNIX object code.
So now we can start taking intelligent guesses to name the function in licrenew.exe
Approaches I took were:
functions are grouped together in the same files;
function sizes will be in similar proportions in the Intel and Unix code;
debug printfs can indicate function names, or variable names;
error messages are grouped in numeric order;
This is where the Interactive part of IDA comes into it's own -
functions, variables, constants can be renamed as we attempt to find their true identity.
For example, we see
push offset aElm_hostidGeth ; "elm_hostid: gethostname failed"
So it's a fair assumption that the function this code is in is elm_hostid().
This is in hostid.c, surrounded by elm_ether() and elm_pick_hostcode().
Note that there are some differences - Unix sockets are replaced by Winsock for example.
Perservere, dear cracker, and you'll end up with most functions identified.
ElanLM FLIRT Signatures
Quine has an IDA IDC to convert IDB to PAT files which then be used to generate a SIG file.
http://skyscraper.fortunecity.com/epson/928/menu.htm
This needs modifying for IDA 4.04:
for 4.04+ find/change this line to this (AskFile() has changed a bit):
pat_name = AskFile(1,"*.pat", "Choose where to save the .pat file:");
( Thanks to the owl, Fravias message board )
So take our licrenew.exe in IDA and run the IDC script - we get a sig file.
Apply to another EXE containing elm code and we see the functions - the sig works well.
Softice Symbols
Get IDA to generate a MAP file
Use softices util16\msym.exe to convert this into a sym file
Use symbol loader to get it into softice.
( file open module, open our SYM file, then module load )
Ctrl-D into softice and do a sym to see all our lovely function names.
IceDump
The analysis below makes use of IceDump a lot.
First ensure that softice is loading the kernel32 symbols,
then run the version of IceDump to match your Softice version.
Get your softice screen as required and
/SCREENDUMP [filename]
to dump your screen to a file.
An excellent tool - thanks guys.
ElanLM code analysis
Finally! time for some code analysis. Let's start with licrenew.exe.
Enter our eval license for SPSS10.1 base and watch the program roll..
In Softice, bpx _main
_main():
...
:00401013 689AA10000 push 0000A19A <- "Enter license code:"
:00401018 E877040000 call 00401494
...
017F:00401040 CALL _fgets <- this gets the licence string entered
We see the licence string being cleaned up - white space removed
And here we see that the first number must be 3 or 4 - I use 4 for subsequent work:
:00401B34 8A02 mov al, byte ptr [edx]
:00401B36 3C33 cmp al, 33 <- '3'
:00401B38 7408 je 00401B42
:00401B3A 3C34 cmp al, 34 <- '4'
:00401B3C 0F85AA000000 jne 00401BEC
We then see elm_key() being called, which in turn calls elm_unbuildkey():
elm_key():
...
:00406D71 50 push eax <- 0
:00406D72 51 push ecx <- points to empty space
:00406D73 52 push edx <- license string without the first '4'
:00406D74 E827530000 call 0040C0A0 <- elm_unbuildkey
:00406D79 83C40C add esp, 0000000C <- eax = ffffff2 = Code or license key corrupt Error
:00406D7C C3 ret
so elm_unbuildkey analyses and separates the big key entered.
Let's look at this:
elm_unbuildkey():
First clear some structure entries, then:
:0040C10D 50 push eax <- license string without the initial '4'
:0040C10E 6A01 push 00000001
:0040C110 E89BFAFFFF call 0040BBB0 <- elm_kiko
This returns eax pointing to zeros if we entered a random key,
or a DECRYPTED key for the eval license.
For our eval key we see: 3009810396900134041123456101160
Key encryption
Above we see elm_kiko() decrypts the key.
If we see where else this is called we find within the big elm_genmultikey() function:
loc_4078D4: ; CODE XREF: elm_genmultikey+B18
lea eax, [esp+468h+var_200] <- string to encrypt
push eax
push 0 <- encrypt, not decrypt
call elm_kiko
add esp, 8
test eax, eax <- did we encrypt OK?
jz short loc_40790D ; No: Error: unable to encrypt - invalid characters
Our helpful error message shows this was an attempt to encrypt -
passing 0 into elm_kiko is encrypt, a 1 is decrypt.
So if we enter our eval key into licrenew, bpx on elm_unbuildkey() as before,
then just before the call to elm_kiko() modify the [eax] license key to our decrypted key,
and mod the push 1 to push 0, call elm_kiko(), and we get our original encrypted eval key.
So our assumptino is correct, that we can encrypt as well as decrypt with elm_kiko().
How about we modify licrenew.exe to just pass a string through kiko for us?
Take a copy of licrenew.exe and call it something else, I used kiko.exe.
Starting at the _main() function, we modify the code as shown
by the lines starting with >
_main()
:00401000 55 push ebp
:00401001 8BEC mov ebp, esp
:00401003 81ECA00D0000 sub esp, 00000DA0
:00401009 53 push ebx
:0040100A 56 push esi
:0040100B 57 push edi
:0040100C 8D859CFEFFFF lea eax, dword ptr [ebp+FFFFFE9C]
:00401012 50 push eax
:00401013 689AA10000 push 0000A19A <- "Enter license code:"
:00401018 E877040000 call 00401494
:0040101D 83C408 add esp, 00000008
:00401020 8D859CFEFFFF lea eax, dword ptr [ebp+FFFFFE9C]
:00401026 50 push eax
:00401027 E8C4F10000 call 004101F0 <- printf
:0040102C 83C404 add esp, 00000004
:0040102F 68501F4200 push 00421F50
:00401034 6803010000 push 00000103
:00401039 8D8574F6FFFF lea eax, dword ptr [ebp+FFFFF674]
:0040103F 50 push eax <- storage space for the string to be entered
:00401040 E85BF30000 call 004103A0 <- gets()
:00401045 83C40C add esp, 0000000C
;
; This code parses the input string for the 0x0A we get at the end of a string
; when we enter a string from DOS
; elm_kiko() wants a null-terminated string without the 0x0A
; so we search the entered string for 0x0A, replace it with a null-terminator
; then move onto elm_kiko.
; Note that elm_kiko can't cope with white-space, or non-numeric ASCII chars,
; so we must be careful when entering our key to encrypt, or we could do
; some extra string manipulation here
;
>00401048 8BD8 mov ebx, eax
>0040104A 8A0B mov cl, byte ptr [ebx]
>0040104C 80F900 cmp cl, 00
>0040104F 7E14 jle 00401065
>00401051 80F90A cmp cl, 0A
>00401054 7509 jne 0040105F
>00401056 B100 mov cl, 00
>00401058 880B mov byte ptr [ebx], cl
>0040105A E906000000 jmp 00401065
>0040105F 43 inc ebx
>00401060 E9E5FFFFFF jmp 0040104A
>00401065 50 push eax <- our null-terminated key
>00401066 6A00 push 00000000 <- encrypt
>00401068 E843AB0000 call 0040BBB0 <- elm_kiko()
>0040106D 83C408 add esp, 00000008
>00401070 50 push eax <- the encrypted string
>00401071 6880F04100 push 0041F080 <- "%s"
>00401076 E875F10000 call 004101F0 <- printf
>0040107B 83C408 add esp, 00000008
>0040107E E905040000 jmp 00401488 <- exit licrenew gracefully
We could apply a similar technique to get licrenew to printf the decrypted key for us -
easier than using softice all the time.
Key analysis
We have 3 0 0981 0396 9001 340 41 123456 1011 60 from our eval key.
I decrypted all the other example keys just to aid analysis.
We can keep entering our keys into the SPSS setup, hit update and see what's been licensed.
We immediately see that 41 123456 1011 60 is vendordata - it's used by SPSS, not ElanLM
We always have 41 to start with.
123456 is the serial number
1011 is version major/minor = 10.1.x
The last 60 is something to do with license type: beta/expiry etc.
Even with a non-expiry Elan license, with 60 SPSS demo still expires,
setting this to 00 ensures SPSS doesn't expire.
Playing around, we find that the 9001 is installation date.
If we set this to 0000 the feature is not installed.
We can leave this at 9001 which is fine.
Don't know what the 0981 is - maybe another date? Leave it alone and all works fine.
The 0396 is expiry date - set this to 0000 and we don't expire.
340 is the feature number.
If we change this to 341, encrypt using kiko,
and enter into the license check during setup we see SPSS tables is now enabled,
and we get 341.lic created.
We can repeat this for features 340 to 349 and get 10 keys which will enable all features.
An example, for SPSS base:
3009810000900134041123456101100
kiko() gives
7088280247423058332415325997637894495
We can modify the setupntr.inf to
PrestampedLicense=47088280247423058332415325997637894495
and we get a non-expiry install for SPSS base.
Remember to add the initial 4 to the encrypted key.
Multikey generation, variable feature length
We want to enable ALL features in one license key - not one at a time,
and some of the example licenses show us how.
For example, a decrypted SPSS8 license:
5 7 1 0981 4503 0999 20 0999 0999 0999 0999 0999 0999 0999 0999 41 123456 0891 00
Here we see 9 install dates, max/min of 8.9.x, a feature code of 20.
Let's analyse elm_unbuildkey to see what the first few bytes of the key show.
I stepped through this function a few times with different example licenses until
it became clear what was happening:
elm_unbuildkey proc near ; CODE XREF: elm_key+34p
var_129 = byte ptr -129h
kiko[0] = dword ptr -128h
var_124 = dword ptr -124h
var_120 = dword ptr -120h
num_features = dword ptr -11Ch
lic_num_size = dword ptr -118h
....
loc_40C4AB: ; CODE XREF: elm_unbuildkey+402j
mov eax, [kiko[0]]
cmp byte ptr [eax], 35h <- First key byte = '5'
jnz short loc_40C4C4
movsx eax, byte ptr [eax+1] <- get next key byte
add [kiko[0]], 2 <- skip past the 1st 2 bytes
sub eax, 2Eh
mov [num_features], eax <- store number of features
The initial key byte value of 8 through to 5 are optional pre-processed options.
5 sets the number of features in the license.
Then we process the 'basic' key bytes 4 through to 1.
loc_40C4C4: ; CODE XREF: elm_unbuildkey+412j
mov eax, [kiko[0]] <- get the next key byte
movsx eax, byte ptr [eax]
sub eax, 31h ; switch 4 cases
cmp eax, 3
ja short loc_40C4DA ; default - returns an error
jmp ds:off_40C8C0[eax*4] ; switch jump
loc_40C4EA: ; CODE XREF: elm_unbuildkey+433j
; case 0x31
mov [lic_num_size], 2 ; <- store the number of digits in the lic feat
mov esi, 1
add [kiko[0]], esi <- skip to the next key byte
jmp short loc_40C567
loc_40C522: ; CODE XREF: elm_unbuildkey+433j
; DATA XREF: .text:0040C8C0o
mov eax, [kiko[0]] ; case 0x33
mov esi, 1
movsx eax, byte ptr [eax+1] <- get the byte after the '3'
add [kiko[0]], 2 <- skip 2 key bytes
sub eax, 2Dh <- value 0 = 3, value 9 = 6
mov [lic_num_size], eax <- store the number of digits in the lic feat
So here we see the first 5 specifies a pre-processor option to set the number of features
in the licencse.
The 2nd '7' specifies there are to be 9 licences in total
The 3rd '3' specifies we want to set the number of bytes in the feature number
The 4th '0' equates to 3 bytes in the feature number
If the 3rd number is '1' then we use a 2-digit feature number
So we can now generate a new SPSS10 license:
5 = set number of features
8 = 10 features in total ( we'll need 10 start dates, one before the base feature,
the rest after )
3 = specify number of digits in the feature
0 = 3 digits in the feature
5 8 3 0 0981 0000 9001 340 9001 9001 9001 9001 9001 9001 9001 9001 9001 41123456101100
gives 222282608671903167996825549038212929714167861036383605982050880007377471204
or, in the setupntr.inf,
PrestampedLicense=4222282608671903167996825549038212929714167861036383605982050880007377471204
Other SPSS product examples, finding the necessary feature information
For a valid license we need to specify the correct: serial number, feature names, max/min version.
In most cases these are easy to find as a default demo license is stored somewhere.
In some cases they're nowhere to be seen, but we can still find them.
I've included a few more SPSS products as examples:
AllClear50
==========
In setup.inf we have PrestampedLicense=49485 54156 08930 52050 84840 79032 15097 638
Decrypts to 3 1 0981 0396 9001 9820 41 000001 0501 60
Feature is 9820, max/min versions are 05/01
So we want to modify the last 60 to 00 so we're not a demo, and mod the 0396 so we don't expire
3 1 0981 0000 9001 9820 41000001050100
PrestampedLicense=43307007972097661508429170770144999453
SPSS smart viewer 8.01
======================
No obvious keys found. Run setup and it asks for a license key.
Try the SPSS 8.0 License: 468049156968732379626154602660600787424952101346701081234801981928987
Filemon shows us:
_ins0432 Read C:\WINDOWS\TEMP\_ISTMP2.DIR\SETUPSUP.DLL
_ins0432 Open C:\WINDOWS\TEMP\_ISTMP2.DIR\LICENSES\20.LIT
So Setupsup.dll ( which contains elan code ) makes 20.lit, which I think is really 20.lic,
as the SPSS 8.0 license we used had features 20 to 29.
Later we see:
_ins0432 Open C:\WINDOWS\TEMP\_ISTMP2.DIR\LICENSES\9620.LIC NOTFOUND
So the base feature is 9620
Looking in setup.inf we see:
RegistryRoot=SPSS Viewer\8.0
VersionMajor=8
VersionMinor=0
VersionPatch=1
So the revision in the vendor ID is 0801
5 8 3 1 0981 0000 9001 9620 9001 9001 9001 9001 9001 9001 9001 9001 9001 41123456080100
5831098100009001962090019001900190019001900190019001900141123456080100
kiko gives 046191825875167947935245019779276161192875682000862007970152571542109479130
PrestampedLicense=4046191825875167947935245019779276161192875682000862007970152571542109479130
Sys Stat 10
===========
It installs OK, with a license, feature number 59880.lic
If we have a look in windows\temp whilst installing, we see in value.shl:
PRESEEDED_LICENSE=40878 77246 26891 47740 93000 62535 09778 59948
licrenew gives: 3 2 0981 0396 9001 59880 41 314159 1001 60
OK, we see an expiry date, 0396, demo key at the end = 60 and feature is 59880
modify to 3 2 0981 0000 9001 59880 41314159100100
kiko gives 251251566587714581702049453290517566975
So try 4251251566587714581702049453290517566975
To finish the crack, we'll need to modify value.shl in _user1.cab
Setup is Install shield 5.10.145.0
So let's get busy with i5comp: decompress the cab, modify value.shl, recompress the cab file.
And we're done - no demo, no expiry.
SPSS10 off the internet
=======================
Just found this on an ftp server somewhere. No file_id.diz, no NFO.
PrestampedSerialNo=657180
PrestampedLicense=30074 30750 07417 16797 48104 5071
Decrypts to 5 2 1 0981 0000 9001 00 0000 9001 9001 41 657180 100120
2nd feature, 01.lic, won't be installed as the install date is 0000
And this only licenses 3 options. Hmmm, not all there?
OK, let's try with our previous SPSS 8 license with a modified major/minor version,
feature, and number of features:
5 8 1 0981 0000 0999 00 0999 0999 0999 0999 0999 0999 0999 0999 0999 41 123456 1001 20
kiko gives: 5311719179070095658993395656839187074789471947090477410971955008341900857
And that's everything licensed now.
A surprisingly simple licensing mechanism to crack, once we've got the function names sorted out.
Seems strange to include the encryption as well as decryption code in release code,
but who's complaining?
Again, thanks to the good guys out there in internet land who continue to share the knowledge.
... still looking for the light ...
pilgrim
I wont even bother explaining you
that you should BUY this target program if you intend to use it for a
longer period than the allowed one. Should you want to STEAL this
software instead, you don't need to crack its protection scheme at all:
you'll find it on most Warez sites, complete and already regged,
farewell, don't come back.
You are deep inside Fravia's page of reverse engineering,
choose your way out:
homepage
links
search_forms
+ORC
how to protect
academy database
reality cracking
how to search
javascript wars
tools
anonymity academy
cocktails
antismut CGI-scripts
mail_Fravia+
Is reverse engineering legal?