How to crack a PC-based FlexLm license manager
student
Not Assigned
30 October 1998
by pilgrim
Courtesy of Reverser's page of reverse engineering
fra_00xx
981030
Pilgrim
0100
NA
PC
A 'target unrelated' nice intermediate essay. Read and enjoy.
There is a crack, a crack in everything That's how the light gets in
Rating
()Beginner (x)Intermediate ( )Advanced ( )Expert


How to hack a PC-based FlexLm license manager.

Written by pilgrim


Introduction

This article was inspired by the tutorial by SiuL+Hacky ( siulflex.htm ) on how to hack XprismPro 1.0
The above program ran on Linux, but my target ran on Windows 95/NT The aim of this tutorial is to expand on some of the ideas in the first tutorial and to detail the differences encountered on the PC.

Tools required
W32DASM 8.9: everywhere
Flexlm programmers kit: http://www.flexlm.com

Essay

1) Get hold of the flexlm programmers kit
==========================================

This is obtainable from www.flexlm.com
It needs a key to decrypt the file. 
S+H details how to crack it, or ask FlexLm.

Once you've got it installed the main files of interest are:

lm_code.h    : This is where you want to put in all the target key information
lm_client.h  : Contains useful function prototypes and error codes
GenLic32.exe : this program checks the keys and generates licenses for you.

I'd also recommend reading the html manual.

2) Find the easy information using lc_init()
============================================

Using W32DASM, decompile your target application and 
the vendor daemon DLL it uses ( e.g. lmgr326a.dll )

Load up the target EXE and set break points wherever the lc_init()
function is called.
Run your target until it breaks.

Looking at the prototype for lc_init in lm_client.h we see:

lm_extern API_ENTRY lc_init lm_args((LM_HANDLE_PTR job, 
                                     LM_CHAR_PTR vendor_id, 
                                     VENDORCODE_PTR vendor_key,
                                     LM_HANDLE_PTR_PTR job_id));

job will be NULL as it's the first one.
job_id will be a pointer for the job structure to be filled by the
function.

The things of interest for us are the vendor_id and vendor_key.
Vendor_id is just a text string.

Again looking in lm_client.h we see:

typedef struct vendorcode5 {
                            short type;    /* Type of structure */
                            unsigned long data[2]; /* 64-bit code */
                            unsigned long keys[4]; 
                            short flexlm_version;
                            short flexlm_revision;
                            char flexlm_patch[2];
                            char behavior_ver[LM_MAX_BEH_VER + 1];
                          } VENDORCODE5,  FAR *VENDORCODE_PTR;

#define LM_MAX_BEH_VER  "06.0"

In the above structure, 
data[0] = encryption seed 1 XORed with vendor key 5
data[1] = encryption seed 2 XORed with vendor key 5
keys[0..3]  = vendor keys 1 to 4
behavior_ver[] = string containing FlexLm version ( in this case = "06.0" )

So all the stuff above will be pushed onto the stack prior to calling lc_init.

Looking at the disassembly we see:

8B0F                    mov ecx, dword ptr [edi]
57                      push edi
68C88D5200              push 00528DC8      <- pointer to code structure
* Possible StringData Ref from Data Obj ->"VENDOR"
68E45A5200              push 00525AE4      <- pointer to vendor ID
string
51                      push ecx
* Reference To: LMGR326A.lc_init, Ord:0034h
E865E30600              Call 004A9BD8

OK, so we've got the vendor ID string ( in this case "VENDOR" )

And looking at memory address 00528DC8 we see the code structure:

[00528DC8] - 00000004  ....
[00528DCC] - ab5e32e5  .?^.    <- seed 1 XORed with key5
[00528DD0] - 7bc6313d  =1.{    <- seed 2 XORed with key5
[00528DD4] - fc62965d  ].l.    <- key 1
[00528DD8] - 853df75c  \7=.    <- key 2
[00528DDC] - 2f324f23  #O:.    <- key 3
[00528DE0] - 1133e43b  ;.3.    <- key 4
[00528DE4] - 00000006  ....    <- version and revision
[00528DE8] - 36300069  i.06    <- patch and behaviour_ver
[00528DEC] - 0000302e  .0..    <- 

So we've got 4 keys and two XORed encryption keys.

4) Find your feature names
==========================

You need these to make up a working license file.
Clear the break-points on lc_init() function calls and set breaks on
calls to lc_checkout.

Looking at lm_client.h again we see:

lm_extern API_ENTRY lc_checkout lm_args((LM_HANDLE_PTR job, 
                                const LM_CHAR_PTR feature,
                                const LM_CHAR_PTR  version, 
                                int nlic, 
                                int flag, 
                                const VENDORCODE_PTR key, 
                                int dup));

The call looks like:

6800400000              push 00004000
68C88D5200              push 00528DC8                <- code structure 
6A00                    push 00000000
8D442410                lea eax, dword ptr [esp+10]
6A01                    push 00000001
50                      push eax                     <- version 
51                      push ecx                     <- feature name
52                      push edx
* Reference To: LMGR326A.lc_checkout, Ord:0022h
E834AA0600              Call 004A9BDE

OK, so we've got a feature name.
Now have a look round and look for similar names, your target may use
more than one.

5) Make your first license.dat file
===================================

Modify the lm_code.h file to contain the encryption seeds, and vendor
keys 1 to 4.
Set vendor key 5 to 0 for now.

Run genlic32.exe
If it throws up an error message then you haven't typed in the keys
correctly in lm_code.h

Enter the feature name as found above.
Click on 'permanent' and 'run anywhere' so you don't need a server
daemon running.
Click on 'make license', fill in the filename license.dat and click
'Make license'

Have a look at the licence file, it'll look something like:

FEATURE full_spam_feature <- feature name
VENDOR <- vendor ID
1.000 <- version
permanent <- never expires
uncounted <- no need for a server
0AF0103F59E2 <- file checksum
HOSTID=ANY <- run on any machine

6) Finding vendor key 5
=======================

Preamble...
Like S+H, I didn't believe vendor 5 could be unknown by the daemon, 
it had to be made on the fly.
It appears to be made up of all 4 vendor keys and the vendor name.
So it could be a checksum for the vendor info?
FlexLm provides the 5 keys based on your vendor name, so they'll want
to checksum it somehow.
If you get keys 1 to 4 or the vendor id wrong in lm_code.h then
genlic32.exe won't like it.
...

OK this bit is more tricky, but keep at it and you'll get there.

Start W32DASM again and load your target ready to read your nice new 
license file.
Break on lc_checkout in your target EXE.
Load up the daemon DLL ( in the active DLLs window double-click on the
daemon DLL ).
Start single-stepping through.
There's lots of calls to undocumented functions, but keep stepping
into them.

Here's the edited highlights of how it went for me:

Read and check the licence.dat file:
l_validversion(), l_compare_version() check the version in the license file
l_date(),l_extract_date() extract the date from the checksum 
( permanent gets converted into 1-jan-0 )
l_start_ok() start date is OK
l_host() OK 'cos it's ANY

Then we got into some functions with lots of XORs.
This looks good as we want to XOR our two encryption seeds.
We can see the keys 1,2,3 and 4 and the vendor ID getting read and XORed
Then we hit some code:

E8C2080100              call 10021160                 <- get vendor key 5 in ebx
83C40C                  add esp, 0000000C
8B4704                  mov eax, dword ptr [edi+04]   <- seed1 from license.dat
33C3                    xor eax, ebx                  <- seed1 XOR key5  
8D4DA8                  lea ecx, dword ptr [ebp-58]   
51                      push ecx
8945AC                  mov dword ptr [ebp-54], eax   <- store seed1
8B4708                  mov eax, dword ptr [edi+08]   <- seed2 from license.dat
8B7D0C                  mov edi, dword ptr [ebp+0C]
33C3                    xor eax, ebx                  <- seed2 XOR key5
8945B0                  mov dword ptr [ebp-50], eax   <- store seed2
8D4754                  lea eax, dword ptr [edi+54]
50                      push eax
:100108BC 56                      push esi
* Reference To: LMGR326A.l_extract_date
:100108BD E8D642FFFF              call 10004B98

So we've just got key5, and the XORed seeds1 and 2

7) Make your final license.dat
==============================

In lm_code.h, replace your two seeds and key5
Run genlic32.exe and make your completed licence file.


Final Notes
As Siul+Hacky mentioned, the only security here is that of secrecy. Thanks to Siul+ for the initial hard work.

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

You are deep inside reverser's page of reverse engineering, choose your way out:

redhomepage redlinks redsearch_forms red+ORC redstudents' essays redacademy database
redreality cracking redhow to search redjavascript wars
redtools redanonymity academy redcocktails redhttp://fravia.org/ideale.htm">antismut CGI-scripts redmail_reverser
redIs reverse engineering legal?