Part III: Licenses
Before reading this essay, if you have not already done it, you would be well advised to read +Aitor's two preceding works:
Reverse Engineering MATLAB 5 - Part II: InstallShield Packages Encryption
As I wrote presenting the first essay of this serie: "let's hope that +Aitor's other essays of a series of at least three will follow rash..." Well, they did!
That's how the light gets in
Third part of this series about reverse engineering MATLAB 5.
We've already got MATLAB 5 running (with or without the dongle ;) and are able to decrypt/decompress/examine/install *all* the CD contents, but ... ... although you can install all the *forbidden* toolboxes, most of them are *license protected* and will not run ... of course, it can be solved ;).
Aurrera with it!
Trying to show different approaches in this series, I thought about using dead-listing for this part ... At the first I processed the main program (MATLAB.EXE) with W32Dasm (faster than IDA, useful for fast approaches), but after a few minutes disassembling it hanged my system, so I put it in the hands of IDA ... well, here comes what I said you about patience ... after more than 35 hours disassembling (486 DX4/100, 16 Mb RAM) I'd got a 94 Mb dead list archive ... amazing, uhm? In order to completely check the license protection system we'll make the program work without licenses of any kind, so first thing we'll do is deleting the license file 'LiCENSE.DAT' (if you're not sure, rename it to 'LiCENSE.OLD' or whatever you want). Now let's run the program ... suddenly a message box appears:
"License.dat file not found"Well, the first obstacle ... let's take a look at our 'tiny' MATLAB.EXE dead list: 6C18B3 aLicense_datFil db 'License.dat file not found.',0 ;DATA XREF: sub_41BB6C+13E [41BB6C+13E = 41BCAA]41BC14 push 4000h 41BC19 lea eax, [ebp+var_A4] 41BC1F push eax 41BC20 mov eax, offset aLicense_dat ; "License.dat" 41BC25 push eax 41BC26 call cs:OpenFile ; try to open it 41BC2D cmp eax, 0FFFFFFFFh ; is the file present? 41BC30 jz short loc_41BC94 ; no, error box and exit 41BC32 lea eax, [ebp+var_9C]
[chunk of code ommited, not interesting for us ... by the moment]41BC94 loc_41BC94: 41BC94 cmp ds:dword_6ED6F0, 0 41BC9B jz short loc_41BCA2 41BC9D call sub_441544 41BCA2 push 10h 41BCA4 mov eax, offset aFatalError_0 41BCA9 push eax 41BCAA mov eax, offset aLicense_datFil ;Error message 41BCAF push eax 41BCB0 push 0 41BCB2 call cs:MessageBoxA ;Error box 41BCB9 push ds:dword_6EC5D6 41BCBF call j_lc_free_job 41BCC4 add esp, 4 41BCC7 push 0FFh 41BCCC call exit It doesn't need any explanations, uhm? Our next step is obvious, let's try the following patch: 41BC26 call cs:OpenFile ; try to open 'license.dat' 41BC2D cmp eax,-1 ; is the file present? 41BC30 jmp 41bc32 ; yes, it's always present ; jump to the next sentence, [EB 00] = [90 90], ; try not to use NOPs, remember +ORC's ... Let's run again MATLAB and test the patch ... it works, but a new error box appears: "Checkout MATLAB failed"Go back to the dead list:
6C1913 aCheckoutMatlab db 'Checkout MATLAB failed.',0 ;DATA XREF: sub_41BB6C+1D9^o
[41BB6C+1D9 = 41BD45]41BCD4 push 1 41BCD6 call sub_41B300 41BCDB add esp, 4 41BCDE push 4000h 41BCE3 mov eax, offset unk_6EC5DA 41BCE8 push eax 41BCE9 push 0 41BCEB push 1 41BCED mov eax, offset unk_6C14AC 41BCF2 push eax 41BCF3 mov eax, offset aMatlab 41BCF8 push eax 41BCF9 push ds:dword_6EC5D6 41BCFF call j_lc_checkout ;yet another check 41BD04 add esp, 1Ch 41BD07 mov [ebp+var_4], eax 41BD0A cmp [ebp+var_4], 0 ;EAX=0 ? 41BD0E jz short loc_41BD6F ;Yes, good guy! 41BD10 cmp ds:dword_6ED6F0, 0 41BD17 jz short loc_41BD1E 41BD19 call sub_441544 41BD1E loc_41BD1E: 41BD1E cmp [ebp+var_4], 0FFFFFFFCh 41BD22 jnz short loc_41BD3D 41BD24 push 10h 41BD26 mov eax, offset aFatalError_0 41BD2B push eax 41BD2C mov eax, offset aMaximumNumbe_0 41BD31 push eax 41BD32 push 0 41BD34 call cs:MessageBoxA 41BD3B jmp short loc_41BD54 41BD3D loc_41BD3D: 41BD3D push 10h 41BD3F mov eax, offset aFatalError_0 41BD44 push eax 41BD45 mov eax, offset aCheckoutMatlab ;Error message 41BD4A push eax 41BD4B push 0 41BD4D call cs:MessageBoxA ;Error box 41BD54 loc_41BD54: 41BD54 push ds:dword_6EC5D6 41BD5A call j_lc_free_job 41BD5F add esp, 4 41BD62 push 0FFh 41BD67 call exit Another obvious patch, let's try this: 41BCFF call j_lc_checkout ;go and check 41BD04 add esp, 1Ch 41BD07 mov [ebp+var_4], eax ;store EAX 41BD0A cmp [ebp+var_4], 0 ;EAX was zero? 41BD0E jmp short loc_41BD6F ;it doesn't matter, unconditional jump Run the program, the patch works but a new message appears: License file can't be readbut this time program doesn't kick you off, you enter the application, test it with a few demos, everything works fine ... anyway, let's remove this annoying error box: 6C192B aLicenseFileCan db 'License file can',27h,'t be read.',0 ;DATA XREF: sub_41BB6C+236^o [41BB6C+236 = 41BDA2]0041BD6F mov eax, offset aMatlab 0041BD74 push eax 0041BD75 push ds:dword_6EC5D6 0041BD7B call j_lc_get_config ;license file check 0041BD80 add esp, 8 0041BD83 mov [ebp+var_18], eax 0041BD86 cmp [ebp+var_18], 0 ;EAX=0 ? 0041BD8A jnz short loc_41BDB6 ;No, good guy! 0041BD8C cmp ds:dword_6ED6F0, 0 0041BD93 jz short loc_41BD9A 0041BD95 call sub_441544 0041BD9A loc_41BD9A: 0041BD9A push 10h 0041BD9C mov eax, offset aFatalError_0 0041BDA1 push eax 0041BDA2 mov eax, offset aLicenseFileCan ;Error message 0041BDA7 push eax 0041BDA8 push 0 0041BDAA call cs:MessageBoxA ;Error box 0041BDB1 jmp loc_41BECE Sorry, this is too obvious even for a beginner ... please, work a little ;). Well, we have got MATLAB running without the license file (LiCENSE.DAT) ... Next step will be to install the forbidden toolboxes and see what happens ... Now we make a complete 'legal' installation, with all the 'legal' available toolboxes. Patch your W32SSi.DLL if you don't want run with the dongle (or if you haven't got it at hand ;), and delete/rename LiCENSE.DAT. You're ready for the 'final attack' ... Run MATLAB, try DEMOS from the command line ... you'll get something like this: +----------------------------------+ | Flexible License Manager | +----------------------------------+ | | | client: Cannot find license ... | | | +----------------------------------+Search the string in the MATLAB.EXE dead list, but no success ... where could be this bitch? Yes, taking in account the whole protection system used in the program, I don't think these lazy programmers could waste their time encrypting strings ... the string is placed in other file, to be more concrete, it's placed in another program ... Take a look at your MATLAB directory, nothing suspicious (apart from our known W32SSi.DLL) ... go to the Window$ SYSTEM directory and see what you find: lmgr325a.dll, 2227.840 byteswith the same date of almost all the rest of MATLAB files !! Take a quick look inside this file ... nice view, uhm? COPYRIGHT (C) 1988-1996 by Globetrotter Software, Inc. This software has been provided pursuant to a License Agreement containing restrictions on its use. This software contains confidential information of Globetrotter Software Inc. and is protected by copyright and other law. It may not be copied or distributed in any form or medium, disclosed to third parties, reverse engineered or used in any manner not provided for in said License Agreement except with the prior written authorization from Globetrotter Software, Inc. @(#) FLEXlm 5.0a (lmgr.a), Copyright (C) 1988-1996 Globetrotter Software, Inc. (About these 'scarecrow' rhetoric, please see the ob duh) ... and a few lines below: port1 sentinel system.ini port2 sentinel system.ini port3 sentinel system.ini port4 sentinel Superpro: Decrement to zero! SuperPro: Function code: %x UTRegister UTUnRegister KERNEL32.DLL HASPUT16.DLL NETAPI32.DLL Netbios FreeEnvironmentStringsA GetVersionExA \\.\HASP There is no doubt, it is our file :). Sentinel SuperPro, HASP, ports ... what happens with all this cram? Well, this is an extended system among expensive commercial software. It comes ready to work with Sentinel/HASP dongles, checks the authenticity of the licensed software (at least that's its aim ;) and provides the user a way for licensing by connecting to a server ... OK, back to work ... There must be (at least) one point in the MATLAB.EXE code where it calls our new friend, LMGR325A.DLL. Read what the error box said "Cannot find the license file" ... try a little ZEN ... It couldn't find the file, so it tried to open it with no success ... do you catch it? Run MATLAB, and run a demo from one of the must-be-licensed toolboxes, eg: QFTDEMO. Fire up Soft-iCE and put a breakpoint in CreateFileA, and let the demo run ... after a few seconds Soft-ICE pops up, you're just in the KERNEL!CreateFileA. PRET a little until you get back to LMGR325A: 10026004 push 0 10026006 lea ecx, [ebp+var_1C] 10026009 push edi 1002600A push [ebp+var_8] 1002600D push ecx 1002600E push [ebp+var_10] 10026011 push [ebp+var_C] 10026014 push [ebp+arg_0] 10026017 call ds:CreateFileA ;try to open the file 1002601D cmp eax, -1 ;No success? 10026020 mov edi, eax 10026022 jnz short loc_10026049 ;Yes, file exists! 10026024 add esi, 42h 10026027 call ds:GetLastError ;Error treatment 1002602D push eax 1002602E call sub_1001F08E 10026033 add esp, 4 10026036 push esi 10026037 call sub_100209C0 1002603C add esp, 4 1002603F mov eax, -1 10026044 jmp loc_100261A0 10026049 loc_10026049: 10026049 push edi 1002604A call ds:GetFileType ;Get file type ;) 10026050 test eax, eax ;Succesful? 10026052 jnz short loc_10026080 10026054 push edi [... and so on ...] PRET a little more until you land in MATLAB code: 41AE10 push 38h 41AE15 call sub_4399B7 41AE1A push ebx 41AE1B push esi 41AE1C push edi 41AE1D push ebp 41AE1E mov ebp, esp 41AE20 sub esp, 8 41AE26 push 4000h 41AE2B mov eax, offset unk_6EC5DA 41AE30 push eax 41AE31 push 0 41AE33 push 1 41AE35 mov eax, offset unk_6C14AC 41AE3A push eax 41AE3B mov eax, [ebp+arg_10] 41AE3E shl eax, 2 41AE41 push ds:off_6EC506[eax] 41AE47 push ds:dword_6EC5D6 41AE4D call j_lc_checkout ;Wonderful, isn't it? --> 41AE52 add esp, 1Ch 41AE55 mov [ebp+var_4], eax 41AE58 mov eax, [ebp+var_4] 41AE5B mov [ebp+var_8], eax 41AE5E mov eax, [ebp+var_8] 41AE61 mov esp, ebp 41AE63 pop ebp 41AE64 pop edi 41AE65 pop esi 41AE66 pop ebx 41AE67 retn Tracing this code a few more instructions you got this: 41AF14 push [ebp+var_C] 41AF17 call sub_41AE10 --> 41AF1C add esp, 4 41AF1F mov [ebp+var_10], eax ;store EAX 41AF22 cmp [ebp+var_10], 0 ;EAX was zero? 41AF26 jnz short loc_41AF4F ;No, bad guy! 41AF28 mov eax, [ebp+var_C] 41AF2B shl eax, 2 41AF2E mov dword ptr ds:unk_6EC56E[eax], 1 41AF38 mov eax, [ebp+arg_10] 41AF3B shl eax, 2 41AF3E mov edx, ds:dword_6EC56A 41AF44 add eax, edx 41AF46 mov edx, [ebp+var_8] 41AF49 not edx 41AF4B and [eax], edx 41AF4D jmp short loc_41AF5F 41AF4F loc_41AF4F: ;Bad guy way 41AF4F mov eax, [ebp+var_C] 41AF52 mov edx, [ebp+arg_14] 41AF55 mov [edx], eax 41AF57 mov eax, [ebp+var_10] 41AF5A mov [ebp+var_14], eax 41AF5D jmp short loc_41AF71 ;Kick off 41AF5F loc_41AF5F: ;Good guy way 41AF5F inc [ebp+var_C] 41AF62 shl [ebp+var_8], 1 41AF65 jmp loc_41AEC9 ;Execution continues 41AF6A loc_41AF6A: 41AF6A mov [ebp+var_14], 0 41AF71 loc_41AF71: 41AF71 mov eax, [ebp+var_14] 41AF74 mov esp, ebp 41AF76 pop ebp 41AF77 pop edi 41AF78 pop esi 41AF79 pop ebx 41AF7A retn It looks so stupid you can believe it ;) ... let's try a fast patch: 41AF17 call sub_41AE10 41AF1C add esp, 4 41AF1F mov [ebp+var_10], eax ;store EAX 41AF22 cmp [ebp+var_10], 0 ;EAX was zero? 41AF26 jmp 41AF28 ;Always good guy Test it, it works ... but this is Matlab's code, if we could patch the DLL instead it would be great, uhm? 1000A550 ; Exported entry 34. lc_checkout 1000A550 public lc_checkout 1000A550 lc_checkout proc near 1000A550 1000A550 arg_0 = dword ptr 0Ch 1000A550 arg_4 = dword ptr 10h 1000A550 arg_8 = dword ptr 14h 1000A550 arg_C = dword ptr 18h 1000A550 arg_10 = dword ptr 1Ch 1000A550 arg_14 = dword ptr 20h 1000A550 arg_18 = dword ptr 24h 1000A550 push esi 1000A551 push edi 1000A552 mov esi, [esp+8+arg_0] 1000A556 push 17h 1000A558 push esi 1000A559 call l_getattr 1000A55E add esp, 8 1000A561 cmp eax, 2A34h 1000A566 jz short loc_1000A582 1000A568 cmp dword ptr [esi+4], 0FFFFFFD8h 1000A56C jz short loc_1000A57C 1000A56E mov dword ptr [esi+4], 0FFFFFFD3h 1000A575 mov dword ptr [esi+1Ch], 70h 1000A57C loc_1000A57C: 1000A57C mov eax, [esi+4] 1000A57F pop edi 1000A580 pop esi 1000A581 retn All we have to do is make this routine always return EAX=0, let's patch it: 1000A550 xor eax,eax 1000A552 retn Test it, it works fine. Now try installing *any* other toolbox, everything works well ... Well, as you can see through this series about reversing Matlab 5, how much fun give us these lazy programmers!! Reversing one only program you've had the opportunity to check: * Dongle protections, cracking W32SSi.DLL (Win32 DLL for ACTIVATOR & ACTIVATOR/M). * Encryptions, discovering a simple 4 byte XOR table, and coding a little tool of the trade to decrypt all the InstallShield encrypted files in the Matlab 5 CD. * License protection, cracking LMGR325A.DLL (FLEXlm v5.0a DLL), another commercial system. Of course, there are a lot of things to do, eg. test the program under Window$ NT (with some surprises ;), delve deep inside the FLEXlm DLL routines (this looks nice), study the encryption routines inside W32SSi.DLL (a real challenge), or decompile the InstallShield installation script (thanx NaTzGUL for such a great tool) and crack the serial check and even the whole limited toolboxes installation ... it depends on you ... Hope you have learned something reading this essays, hope to learn from yours soon ;) ...
Like many other contributors to this pages English is not my mothertongue ... ... sorry for any inconvenience, be patient ;).
Greetings to all the reverse engineers from Euskal Herria (Basque Country) ... ... jotake irabazi arte !
(c) 1998 by +Aitor and the +HCU. All rights reserved.