UGFLEX - The Saga continues
flexlm after two years again...
student
Not Assigned
1.5.2002
by macilaci
published by tsehp
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

"Of course you're dying. We're all dying. Where the devil else do you think you're heading?"
UGFLEX - The Saga continues
flexlm after two years again...
Written by macilaci


Introduction
Solidedge - a well designed mid range CAD system. I'm not lying, kidding or something like this...
It's truly good CAD application and I don't know why, EDS (the manufacturer) is releasing this for
free. Again I found it on a magazine's cover CD. Not bad, I thought, but my license generator screw
up this time...



Tools required
Debugger (SICE, OllyDbg - this one is quite good!), Wdasm or IDA, Flexlm SDK 7.2 or above (not necessary), some recent info (essays from Pilgrim, Nolan Blender etc.)

Target's URL/FTP
http://www.ugsolutions.com, http://www.solid-edge.com

Program History
Macromedia bought Globetrotter. Since 1999 were made some changes, but as you will see they aren't so significant. Some additional work around the vendorcode structure, but still easy to defeat...

Essay
Let's go on. After some initial sniffing (Bounschecker may help you) you can discover the dynamic
link library which opens and reads your license file (selicense.dat). You said you didn't created
a license file? Well, I think there's in your directory almost empty license file. Of course is
the license key missing.... It looks like this:

FEATURE SOLIDEDGECLASSIC sedemon 11.0 permanent uncounted \
	123456789ABC HOSTID=ANY ISSUER="I don't know"

Let's look around. Our ugflex.dll is missing and was replaced by another, less suspicious name.
Of course I'm speaking about jutil.dll, but what: I've discovered a MAP file of this library.
The format is following:

  Address         Publics by Value              Rva+Base     Lib:Object

 0001:00000010       _JSetVACallback@4          5a001010 f   auto.obj
 0001:00000040       ?IsAutomationEnabled@@YAHXZ 5a001040 f   auto.obj
 0001:00000050       ?IsLicenseValidForAutomation@@YAHXZ 5a001050 f   auto.obj

In order to use this MAP file with idasym.exe remove the Rva+Base and Lib:Object columns. Then use
the created sym file with symbol loader (it will be easier to set up breakpoints and of course
understanding what's going on).

	From the past we know that the actual checking of the license is inside the LC_CHECKOUT routine
(extracted from flexlm reference manual):
lc_checkout()
SYNTAX   status = lc_checkout( job , feature , version , num_lic , flag ,code , dup_group )
DESCRIPTION
	Checks out one (or more) license(s) of the specified feature. If the process that
	calls lc_checkout() exits in any manner, then the checked-out license will be
	returned for re-use by another user. For TCP clients, the resulting checkin is
	immediate.
	Place the call to lc_checkout() in an executable that is active whenever the user
	is using the feature. If flag is specified as LM_CO_WAIT, then the process
	will wait until the number of licenses requested for this feature are available.
	The license file must specify a version that is greater than or equal to the
	version in the lc_checkout() call.
	If the license file is counted, that is, if the number of users specified on the
	FEATURE line is non-zero, lc_checkout() will request the license from a
	license server. If the number of users on the FEATURE line is uncounted, it
	will grant permission based on the contents of the license file onlyŠhostid,
	version, expiration date, etc.

The _lc_checkout at 5a04cf70 is present. Good place to break. Looking for feature names we can bulid
up our license file using above format. For correctness I will provide all feature names:
SOLIDEDGECLASSIC, SOLIDEDGEADVANCEDPAR, SOLIDEDGEXPRESROUTE, SOLIDEDGEFEATURERECO, SOLIDEDGEXPAND3D,
 SEWEBPUBLISHER, SOLIDEDGEHANDBOOK, SOLIDEDGEMANAGER (note: some features like expand3d are checked
out in another executable - we speak about it later).
Looking further you might pass the l_good_lic_key routine. The _lc_checkout hits three times and
the _l_good_lic_key just once. Suspicious? It is. Here are some code snippets from IDA:

5A04DA6C loc_5A04DA6C:                           ; CODE XREF: _lm_start_real+343j
5A04DA6C                 mov     edx, [ebp+arg_14]
5A04DA6F                 push    edx			; the vendorcode struct (this time improved - encrypted)
5A04DA70                 mov     eax, [ebp+var_20]
5A04DA73                 push    eax
5A04DA74                 mov     ecx, [ebp+arg_0]	; our license information
5A04DA77                 push    ecx
5A04DA78                 call    _l_good_lic_key	; go and check it
5A04DA7D                 add     esp, 0Ch
5A04DA80                 test    eax, eax
5A04DA82                 jnz     short loc_5A04DA89     ;this should be familiar to you :-)

You ran the part.exe and nothing happens? Well, that's because you didn't run the seiges.exe as I did.
They places some antidebug features into a part.exe. They've learned something. But just to make
intrigues. An idea got by a brainstorming? It's funny.
And are we interested in this way? I don't believe it. Let us run seiges.exe. It seems,
they left it behind. Running seiges.exe and setting eax to nonzero you'll get status = ok.
Patching the executable isn't very effective, so we look further:


5A04E995                 add     edx, 54h
.
.
5A04E99C                 push    eax
5A04E99D                 call    _l_extract_date
.
.
5A04E9B1                 push    ecx                ;our vendorcode structure
5A04E9B2                 mov     edx, [ebp+var_CC]
5A04E9B8                 push    edx		    ;feature name
5A04E9B9                 mov     eax, [ebp+arg_4]
5A04E9BC                 push    eax
5A04E9BD                 mov     ecx, [ebp+arg_0]
5A04E9C0                 push    ecx
5A04E9C1                 call    _l_ckout_crypt

Tracing this routine we see that _l_ckout_crypt does some important work. There are some new keys too.
Here are changing only the seed values. Seeing that the keys weren't changed, we may suppose that these
keys are now decrypted, but the seed values are still hidden in some way. Further tracing shows us
the _real_crypt routine (scary name, isn't it?)

5A050B44                 mov     eax, [ebp+arg_0]
5A050B47                 push    eax
5A050B48                 call    _real_crypt    
5A050B4D                 add     esp, 10h

After some time of tracing I guessed that _real_crypt does the work. I felt it like a heartbeat. This name
sounds like invitation: " Come and discover. "
Some snippets from real crypt:
.
.
5A050ECB                 push    ecx
5A050ECC                 call    _l_getattr              ; get license attributes
.
.
5A05106A                 push    eax
5A05106B                 call    _l_good_bin_date        ; date
.
.
5A0510DA                 mov     edx, [ebp+arg_0]
5A0510DD                 push    edx
5A0510DE                 call    _move_in_hostid	; move in hostid from license file
.
.
5A051456                 push    offset aDup_group ; "DUP_GROUP" ;DUP_GROUP=UHD means the duplicate 
										grouping is 
								  (DUP_USER|DUP_HOST|DUP_DISPLAY), 
										so for a user on the same host and display, 
										additional uses of a feature do not consume 
										additional licenses. 

5A05145B                 mov     eax, [ebp+arg_4]
5A05145E                 mov     ecx, [eax+94h]
5A051464                 push    ecx
5A051465                 call    _addi				 ;add that to license
.
.
5A051855                 push    ecx
5A051856                 call    _l_ckout_string_key             ;SO WHAT ABOUT THIS?
5A05185B                 add     esp, 18h

The _l_ckout_string_key took my attention. The local variables are filled each after other (loc.5A052CFF and below),
instead to be filled from table. This could prevent an attacker from building an automatic key extactor (it's just
my hypothesis). Anyway, it is a pretty unefficient way to store information. And of course, the only call reference
to this routine did it too.

5A052902 _l_ckout_string_key proc near           ; CODE XREF: _real_crypt+AD1p


5A052902                 push    ebp
5A052903                 mov     ebp, esp
5A052905                 sub     esp, 1E4h
.
.
.
5A053755                 call    _our_encrypt2                          ;some new scary names (james bond would be better...)
5A05375A                 add     esp, 4
5A05375D                 jmp     short loc_5A05376C
5A05375F ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
5A05375F
5A05375F loc_5A05375F:                           ; CODE XREF: _l_ckout_string_key+E43j
5A05375F                                         ; _l_ckout_string_key+E4Cj
5A05375F                 push    offset byte_5A0C5820
5A053764                 call    _our_encrypt				;the second encrypt
.
.
.
5A05384B                 mov     ecx, [ebp+var_188]
5A053851                 add     ecx, 1
5A053854                 mov     [ebp+var_188], ecx
5A05385A
5A05385A loc_5A05385A:                           ; CODE XREF: _l_ckout_string_key+F47j
5A05385A                 mov     edx, [ebp+var_188]
5A053860                 cmp     edx, [ebp+var_18C]
5A053866                 jge     loc_5A0539E0
5A05386C                 mov     eax, [ebp+var_188]
5A053872                 mov     cl, [ebp+eax*2+var_168]
5A053879                 mov     [ebp+var_1CC], cl
5A05387F                 call    ds:__p___mb_cur_max
5A053885                 cmp     dword ptr [eax], 1
.
.
.
5A0539CB                 xor     eax, eax
5A0539CD                 mov     al, byte_5A0C5820[edx]                   ; finally - compare license
5A0539D3                 cmp     ecx, eax
5A0539D5                 jz      short loc_5A0539DB			  ;go and compare the next byte
5A0539D7                 xor     eax, eax				  ;bad key
5A0539D9                 jmp     short loc_5A053A01			  
5A0539DB ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
5A0539DB
5A0539DB loc_5A0539DB:                           ; CODE XREF: _l_ckout_string_key+10D3j
5A0539DB                 jmp     loc_5A05384B				;loop back

It is a similar loop like in the version seven. We can now get our key for this and remaining features and go asleep.
The location at 5A0C5820 is the loc where the key is actually generated by program. At this point I would like to explain
the key generation. Our license (when it has proper format) is scrambled in some way without the license key (remember the
addi function?) and stored in memory. Now the program has to compute the correct vendor seeds (getting through lm_job and 
i don't know what else) and mix it up with our scrambled license information with the help of the four vendor keys. This 
will be done at location 5A0C5820. Unfortunately there, where is the license compared.
We would like to extract the seeds. Doing a bpm 5A0C5820 w we see these locations:

.
.
5A053334                 mov     byte_5A0C5820[ecx], al          ;here we go
5A05333A                 jmp     short loc_5A0532F9
5A05333C loc_5A05333C:                           ; CODE XREF: _l_ckout_string_key+A0Dj
5A05333C                 cmp     [ebp+var_188], 0

Tracing this code more than once from loc 5A05333C we discover the actual seed computing:

5A0533EA                 xor     eax, ebx		;compute the right seed
5A0533EC                 push    eax			;push it to stack
5A0533ED                 call    sub_5A053AD3
5A0533F2                 add     esp, 4
5A0533F5                 mov     [ebp+seed_one], eax
5A0533FB                 mov     edx, [ebp+seed_one]
5A053401                 and     edx, 0FFh
.
.
5A0534C9                 add     eax, 1
5A0534CC                 mov     [ebp+var_10], eax
5A0534CF                 mov     [ebp+seed_one], 3D4DA1D6h   ;hiding the seed
.
.
5A053548                 push    eax			;push the second seed
5A053549                 call    sub_5A053AD3
5A05354E                 add     esp, 4
5A053551                 mov     [ebp+seed_two], eax
5A053557                 mov     edx, [ebp+seed_two]
.
.
5A053628                 mov     [ebp+var_10], eax
5A05362B                 mov     [ebp+seed_two], 3D4DA1D6h  ;hide it!
5A053635                 jmp     loc_5A053735

Hiding the seed prevents the attacker from extracting the seeds with tools like memory dumpers. The seed extraction
must be done at these locations and at a runtime (in flexlm 6 it was just simple xor with vendorkey 5 and seeds stored
within the executable). So these are new improvements of ver 7.2 versus 6: The keys with seeds are now encrypted and
stored in the executable. Both, the keys and the seeds have to be extracted at a runtime (the easiest way).
	Let's summarize:
        LC_CHECKOUT ---
		      |
		      |
		      _l_good_lic_key---                           /*encrypted keys*/
				       |
				       |
				       _l_ckout_crypt---	   /*deciphered keys*/
						       |
						       |
						       _real_crypt---
								    |
								    |		
							            _l_ckout_string_key---
											 |
											 |
											 5A0533EA  /*compute first seed*/
											 |
											 5A053547  /*compute second seed*/
											 |
											 5A0539DB <-										             
										     	 |	   |
										          5A0539CD---  /*license compare*/
											 |
											--
Now we have to feed our lm_code.h and compile lmcrypt to get the damn thing work. Using the 3D4DA1D6h byte pattern we
look now for similar location within the AddInlm.dll. We need actually only the LC_CHECKOUT for feature names. I will
let it out as an exercise for you. Corresponding locations were found using this and some other patterns for these
executables (useful for those who don't have the flexlm SDK):
jutil.dll       	AddInlm.dll     	Selicwiz.exe
5A0533EC		046CAEDC		 00428C6C
.
5A0539CD		046CB4BD		 0042924D

The origin of the above code is the object lm_ckout.obj winthin the lmgr.lib library.





Final Notes
"But they have witnesses who will swear you did. They can get all the witnesses they need simply by persuading them
that destroying you is for the good of the country. And in a way, it would be for the good of the country."



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, don't come back.

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


redhomepage redlinks redsearch_forms red+ORC redhow to protect redacademy database
redreality cracking redhow to search redjavascript wars
redtools redanonymity academy redcocktails redantismut CGI-scripts redmail_fravia+
redIs reverse engineering legal?