FlexLock
"... less secure than the rest of FLEXlm"
Written by pilgrim

Introduction

We've looked at FLEXlm and FLEXcrypt, here another FLEXlm based 'security' program bites the dust: FlexLock. It's intended as a shareware demo protection that can easily be licensed. Here's a snippet from the release note for FlexLock :-

NOTE: We've made every effort to make the FlexLock feature secure. However, due to the type of security technology used for FlexLock, it is less secure than the rest of FLEXlm. This is why it is disabled by default. You should only enable FlexLock if the convenience of FlexLock licensing is more important than the reduced security it exposes your product to.

Tools required

W32Dasm, your favourite hex editor.

Target's URL/FTP

The FlexLock SDK is available at ftp.globes.com, or www.globetrotter.com. An example FlexLocked application, Hotz Translator II, is at www.hotz.com.

Program History

FlexLock 1.0 started as a standalone product utilising FLEXlm v6, FlexLock 2.0 has been integrated into FLEXlm v7.

Essay

The quick crack

Install Hotz Translator II. We see flock.dll which is the Flex-Lock DLL. Looking for calls to the DLL we find only one in tranfl.exe. Here's the edited dissassembly with detailed notes for the analysis later :-

:00409160 PUSH EAX <- modeVal
:00409161 PUSH ECX <- challengeVal
:00409162 PUSH 004A5684 <- FL_INSTANCE_NAME "OR5289000"
:00409167 CALL 004422EC <- FLOCKDLL._FL_FLEXlockAPI@12
:0040916C TEST EAX, EAX
:0040916E JNZ 004091B2 <- jump if function ran OK

:004091B2 MOV EAX, DWORD PTR [ESP+38] <- modeVal
:004091B6 CMP EAX, EBP
:004091B8 JZ 004091DA <- modeVal OK?
:004091BA CMP EAX, 2
:004091BD JZ 004091DA <- modeVal = purchased?

:004091DA MOV EAX, DWORD PTR [ESP+0C] <- challengeVal
:004091DE XOR EDI, 40646F84 <- localVal XOR FL_MASKED_CODE
:004091E4 XOR EAX, 40687EA9 <- challengeVal XOR FL_MASK
:004091E9 CMP EDI, EAX <- challengeVal == local val ?
:004091EB MOV DWORD PTR [ESP+0C], EAX
:004091EF JZ 0040920C <- good_guy

:0040920C LEA ECX, DWORD PTR [ESP+14]
:00409210 PUSH ECX
:00409211 MOV ECX, ESI
:00409213 CALL 0047424C <- update license info?
:00409218 TEST EAX, EAX
:0040921A JNZ 00409234 <- good_guy

So patch the first PUSH EAX to be JMP 00409234. This by-passes all license checking and we're done!.

Deeper analysis of the crack

First we'd better download the FlexLock 1.0 SDK. We see it's 32 bit cryptwin encrypted, see previous essays on how to crack this (note this has the extra checksum at the front of the Z file to bypass). Once it's installed we see an example of how to call the API in csamples\main.c Here's the edited highlights :-

#define FL_MASK 0x24f96f82
#define FL_MASKED_CODE (0x33333333 ^ FL_MASK)
#define FL_INSTANCE_NAME "47123001"

	challengeVal = rand();
	localVal = challengeVal;
	intReturned = 
	  FL_FLEXlockAPI( FL_INSTANCE_NAME, &challengeVal, &modeVal );
	if( intReturned == 0 )
		exit( -1 );
	if ( modeVal != FL_PURCHASED )
		exit( -1 );
	challengeVal ^= FL_MASK;
	localVal ^= FL_MASKED_CODE;
	if( localVal != challengeVal )
		exit( -1 );

So we first see a check to ensure the API function ran OK. Then another on modeVal to ensure we're using the 'purchased' mode. Then some sneaky XORs to ensure we've not fiddled with data. The main thing to note is that 0x33333333 is the users 'secret code'. This is used to ensure valid users of the FlexLock SDK cannot easily generate licenses for another FlexLock application without knowing the other 'secret key'.

So we can see the secret key = FL_MASKED_CODE ^ FL_MASK. Looking at Hotz above we see :-

:004091DE XOR EDI, 40646F84 <- localVal XOR FL_MASKED_CODE
:004091E4 XOR EAX, 40687EA9 <- challengeVal XOR FL_MASK

For Hotz this gives secret code = 0x40646F84 XOR 0x40687EA9 = 0x0000C112D. As we'll see later, the key is entered in decimal, which in this case is 79 08 29. What's this? Someones birthday?. So we can see why the first quick crack had to bypass both the function call and the sneaky checks.

Get the FlexLock SDK to work

The FlexLock SDK consists of two components: configedit and makelicence. Reading the accompanying documentation we see they need a FLEXlm license stored in \licenses\license.lic We also see an example license :-

FEATURE FLConfigEdit gsi 1.0 1-jan-0000 0EC3505C1AE9C5EE1D977 
\ VENDOR_STRING=OR5358 HOSTID=123456
ISSUER="GLOBEtrotter 
\ Software, Inc." ck=48 
FEATURE FLMakeLicense gsi 1.0 1-jan-0000 00C65F5710DFEF9B33F77 
\ HOSTID=123456 ISSUER="GLOBEtrotter Software, Inc."ck=39

We can see: the vendor name is gsi (Globetrotter Software Inc.); the two feature names; configedit requires a vendor string.

Let's make a license for the FlexLock SDK. We can see lmgr326a.dll in the FlexLock SDK, so why not try the genlic32 program that comes with the FlexLm 6.1 SDK?, because it doesn't work, that's why not. It generates HOSTID=ANY which the FlexLock programs don't like. But if you make your own license generator, as Vox shows you, then we just get "ANY" which works.

What's the VENDOR_ID for? Well, it seems that the FlexLock tools read the vendor ID and use it as a feature name for the FlexLock key. Finding it is easy, according to the documentation: After the FlexLock operation is activated, an entry is generated in the registry. It is located at :-

HKEY_LOCAL_MACHINE->SOFTWARE->GLOBEtrotter Software Inc.->FlexLock

So run your FlexLocked application then look in the registry for the feature name. In the case of Hotz Translator it's OR5289000, but it's not that easy, the last three digits are the product number. So the vendor ID we require is OR5289. We eventually end up with the licence we need to get FlexLock to run :-

FEATURE FLMakeLicense gsi 1.000 permanent uncounted 2CF67BC10C7B17A4222B "" ANY
FEATURE FLConfigEdit gsi 1.000 permanent uncounted 3C264B61C254B643EAED "OR5289" ANY

Generate a license

Follow the FlexLock SDK instructions and make a FlexLock license for your target. Note in the case of Hotz the product number needs to be 000 to give the desired feature name and the secret code is the one we found above. Run configedit first, then makelicence to generate a key for the FlexLocked target. I ended up with this for Hotz :-

FLEXlock-OR5289000-15937-42877-61858-06522-46939-34028-8035

This can be entered when prompted, or saved in a license.dat file in the targets root directory.

Further analysis

As usual, I dug a little deeper. These are just a few discoveries which may help you. Please feel free to fill in the missing gaps :-). The FlexLock licence above is in what Globetrotter call decimal format. It's generated by lc_cryptstr, when passed a flag LM_CRYPT_DECIMAL, 0x20. If we break on the call to lc_cryptstr during licence generation, remove the LM_CRYPT_DECIMAL we get the readable format of the license file :-

FEATURE OR5289000 FLEXlock 1.000 permanent uncounted
3454EFA72F5E \
	VENDOR_STRING=1889375979 HOSTID=ANY

When saved in the license.dat file this works fine instead of the decimal format. So the feature is defined by our application, vendor name is FlexLock. But what's the vendor string for?. Deeper still... We can easily find the seeds and keys used by FlexLock by breaking on lc_init and finding the key 5 XORs. But looking at lc_set_attr calls we see FlexLock uses a vendor-defined checkout filter. Maybe this has something to do with vendor string?.

Final Notes

It seems the basics behind FLEXlm aren't changing, there are just more and more 'value-added' wrappers applied around the core. Understand the core and you've won. However, FLEXlm _is_ flexible, with lots of sneaky tricks such as vendor- defined encryption. I'm sure this isn't the end. FlexLock seems trivial to crack due to the simple pass/fail return from the single API function call. A chain is only as strong as it's weakest link. FLEXlm is fairly strong. The single API function call is laughably weak.

Thanks go out to all you good people who continue sharing the knowledge.

pilgrim.