Cracking the Corel/Elan commercial protection scheme

For many months now I’ve been seeing messages in usenet groups from lamers
begging for cracks for Corel trial applications.
I have yet to see a  working crack for any Corel trial product (except for one
which I have been  unable to test – if you have made a working crack then please
accept my  apologies), and I used to spend many hours attempting to crack
this scheme when I first started cracking. I failed :-).
However, recently someone posted a  message to the +HCU mailing list asking
about this protection scheme – I had  actually already intended to write a
short essay on what I already knew about  the protection scheme, but I instead
began to discuss the various aspects  of the protection with other list
subscribers, notably Noose and base+metal.
Armed with my new-found knowledge, together with the information I had
already accumulated, I began to work on a generic crack, which is what I
will describe in this essay.

Corel have been releasing quite a large number of their applications on a
30-day trial basis, including WordPerfect 7, WebMaster Suite, Corel 
Draw 7, Corel Suite 8 etc. This may seem unusual to anybody familiar with
Corel’s disgraceful business practises (while they are appalling, it
should  be noted that Corel’s behaviour pales into insignificance when
placed alongside that of its rival, Micro$oft, who seem to seek nothing
less than world domination!), and until they (and other) software companies
have a change of heart and start giving their software away cheaply or
freely (a change that I regret I do not expect to be made), us +crackers
will continue to crack their protection schemes inside-out, and anyway
warez groups will continue to thrive (Corel apps are all, complete and
registered, pushed around inside the warez sites even BEFORE they appear
in the shops… that’s the sad truth for the protectors)

OK, so lets get started on the crack proper. I will use WordPerfect 7
30-day trial version…but you will find that things should be very much
the  same with *any* (fairly recent) Corel trial application.
This is because  Corel, in their blind and stupid greed, decided to buy
a commercial ‘licensing management’ package, doubtless sold as ‘uncrackable’.
Well, as we  know, and +ORC said, *nothing is uncrackable*.
So, dear protectionists, don’t  even try – just make it cheap, or even better,
free for single user… if your program is good (a big if) you’ll make enough
money from professional user.
This protection scheme is  made by a company called Elan (how do I know?
Just browse around the target  EXE file with your favourite hex/text editor,
you’ll soon see it all over the  place), who seem to specialise in
protectionist software.
Let’s hope that we can become their Nemesis, and continue to sound the
death-knell of all commercial protection schemes…

Anyway, I took a look at Elan’s web page (http://www.elan.com) and found a
page in which they brag (not without cause, it must be said) about the
strength of their protection.
Here are a few excerpts (courtesy of  Elan):

—————————————————————-
"Demo licensing allows you to count down usage over time. This is particularly
useful for demo, or evaluation software. Instead of  distributing a product that
isn’t fully functional, you offer a demo key that  allows a fully functional
product to be fairly evaluated, then "times out" in whatever time period you
choose.
ɬan goes a step further and ensures that the customer can’t "fool" the demo
key by setting back the system clock."

"The user should not be able to forge (increase) the number of licenses by
cracking the license file encryption. We’ve chosen a cryptographic encoding
for the code and key. Both also include checksums and other encodings to
further avoid tampering. It is highly unlikely  that this coding could be
cracked without a very major and costly cryptographic effort by the customer."

"The user should not be able to create fake clients that return licenses or a fake manager that
issues free licenses. The application and  license manager process both authenticate each other
by sending encrypted  messages back and forth. Neither the client nor the manager will accept
messages from an invalid manager or client."

"For "time-bombed" applications: The user should not be able to run an
application after its expiration date. An optional expiration date 
may be included in the key, which we believe to be highly tamper-proof. 
It will, for instance, stop users from setting back system clocks in 
order to artificially extend a timed license."

"The developer should be able to determine the ultimate level of    
security required. ɬan uses the DES ("Data Encryption Standard")          
encryption algorithm, the same algorithm the US governement uses for         
highly sensititive information. Elan is also one of the few
companies  to obtain an export license for DES."
—————————————————————-

So, this tells us quite a few interesting things about the protection, and
basically confirms our suspicions…

Now, having established its origins, I want to first discuss the behaviour of
this protection. If you have tried to make a dead listing of the  target you
will find that WD32Dasm chokes with a message to the effect that the EXE header
is non-standard, and the data references will therefore no be shown.
This means that there are no strings such as ‘Evaluation’ or ‘Trial’ that
we can search for in the dead listing (nevertheless, you should make a dead
listing anyway, as we’ll refer to it later)…I’m not certain whether this
resistance to disassembly is intentional, or whether it is a side effect of
the way that the protection scheme is applied – from what I’ve been able
to gather (from the Elan website, what Noose found out from a helpful
Elan salesman and my own observations), it seems as though some sort of
‘wrapper’ is applied to the target, most likely *after* compilation.
This argument  is, IMHO, strengthened by the fact that the protection code
for *all* the  Corel products I have come across is almost identical.
The wrapper behaves  very much like a packer might – except that it checks
the date before ‘unpacking’ the original program code.

This unusual approach to protection is actually comparatively secure.
The current date is checked with the install date – if your time isn’t up,
the code proper for the application is loaded and off you go. If however,
your time is up (e.g. the time limit has expired) the application code is
never loaded at all!
So the code is actually self-modifying (in a way).
Hmm…this means that we can’t simply jump over the time checks – instead it
is necessary to delve deeper.
Another benefit (for the protectionists) of  this scheme is that there is *no*
‘go-ahead-nice-guy’ jump!
Instead the  current date/time seems to be encrypted in some way and the
resulting data  used in a *massive* jump tree which is traversed *hundreds*
of times in the protection. Again, you can’t jump over this code, because hidden
in this mess is  the code that loads the proper application (assuming your time
isn’t up).

OK, I hope I haven’t confused you too much – if you haven’t understood all
the above then suffice it to say that the protection scheme is quite difficult
and  calls for a ‘different approach’ in order to reverse it.

Now, assuming you have installed a Corel trial app, set your clock forward 30
days (or back even a minute!) and then try to run the application. Of course,
it doesn’t work. Now set the clock back again and try to run the program.
You’ll find that it still doesn’t work…obviously the protection has
set some value in either a file somewhere or in the monstrous registry. 
Using Regmon and Filemon, you’ll find that the relevant keys/files are:

HKEY_LOCAL_MACHINESystemSOFTWARERBO (and all values it contains)

and a ‘LIC’ file somewhere on your hard drive (either the windowssystem directory
or in the same directory as the protected application). 
This LIC file seems to always be named ‘123.LIC’ where ‘123’ are any
different numbers. For example, with WordPerfect 7, the file is called ‘101.LIC’
and located in the windowssystem directory.
For Corel Suite 8, the file  is called ‘110.LIC’ etc.
If you take a look at this key you’ll see it  looks very much like the below:

—————————————————————-
! # DO NOT EDIT/COPY/MOVE/TOUCH THIS FILE! # DOING SO WILL INVALIDATE
THE KEY! 1495759114997400190218696156651151

G 1 localhost 29409528605026735253388754988463352615578602168050745868
63420417881207022485101836949246508084229387790741495533 9551540371980384961018021882475297
—————————————————————-

The advertising from the Elan website claims it uses DES encryption etc.
– it may be that the LIC file format could be decoded and a ‘universal’
one distributed, but I’ve not got the time for all that 🙂

Every time you run the protected program, it writes to both the registry *and*
the LIC file…so when it expires, both are ‘corrupted’. To get the program
running again you’ll have to delete the registry key
‘HKEY_LOCAL_MACHINESystemSOFTWARERBO’ *and* replace the LIC file
with the original one from the CD-ROM or wherever you installed the trial
from. You’ll also have to set the date back to around the same time as you 
acquired the trial version – the reason for this is that the LIC file stores
a set of dates (thoroughly encrypted, of course) between which the trial
application may run, a sort of ‘window’ in time…these dates are read by
the  protection code (so you can’t just replace the LIC file whenever it
expires, unless you also set the date back – and delete the registry keys).

Let’s summarise what we now know:

1) The code is self-modifying, much like an EXE packer
2) Both a license file and registry keys are used
3) There is set ‘time window’ in which we may run the protected  program
4) The protection takes even minutes and seconds into account (try  it!)
5) Setting the date back doesn’t work 🙂

Taking all the above into account, you might think ‘why not use a loader, such
as the Date Cracker by +gthorne?’ – well, you could use such  a program, and it
might work, but only if you also found a way to  change the minutes etc…don’t
forget that if you use a loader, all the files  you save will have the wrong
date etc.
All in all, not a very elegant  solution.

Instead, I propose a somewhat brutal, but nevertheless perhaps more appropriate
(IMHO) solution – why not edit the protection code that fetches the date, and
force it to return the same date each time? If you have cracked a lot of
time-trial programs before, or have looked at the entry essays for the
1998 +HCU, you’ll probably know that many programs use a single function
to retrieve the current date/time and encode it somehow (I believe there
may be a standard MFC function which is often used – can anyone confirm this?).
Now, as you also are probably aware, parameters are passed to functions via
the stack (in C/C++ at least) – this means that before the call to the
encode date function, we should see a good few ‘PUSH’ instructions.
These  will be pushing the necessary values (e.g. second, minute, hour,
day, month,  year) onto the stack, where they will be retrieved by the
called function. 
So we can simply locate these pushes and ‘hardwire’ our own dates into the
push instructions instead.

If you step though the program code (of whichever Corel app you use) you’ll
see that after each call to KERNEL32.GetLocalTime there are indeed a 
lot of pushes, and a call that returns a value that is suspiciously like an 
encoded date…look through your dead listing for ‘GetLocalTime’ (there is 
probably just one) and a few lines after you’ll see the code I mean:

:007FB596 25FFFF0000         and eax, 0000FFFF
:007FB59B 50                 push eax                ; push  seconds
:007FB59C 33C0               xor eax, eax
:007FB59E 668B442426         movax, word ptr [esp+26]   ; load  minutes
:007FB5A3 50                 push eax                 ; push  minutes
:007FB5A4 8B442428           mov eax, dword ptr [esp+28] ; load  hours
:007FB5A8 25FFFF0000         and eax, 0000FFFF
:007FB5AD 50                 push eax                ; push  hours
:007FB5AE 33C0               xor eax, eax
:007FB5B0 668B44242A         mov ax,word ptr [esp+2A]   ; load  day
:007FB5B5 50                 push eax                 ; push day
:007FB5B6 33C0               xor eax, eax
:007FB5B8 668B44242A         mov ax, wordptr [esp+2A]    ; load  month
:007FB5BD 50                 push eax                 ; push month
:007FB5BE 8B44242C           mov eax, dword ptr [esp+2C] ; load  year
:007FB5C2 25FFFF0000         and eax, 0000FFFF
:007FB5C7 50                 push eax                ; push  year
:007FB5C8 E8F3190000         call 007FCFC0              ; encode date
:007FB5CD 8B8C24F0000000     mov ecx, dword ptr [esp+000000F0]
:007FB5D4 83C41C             add esp, 0000001C
:007FB5D7 85C9               test ecx, ecx
:007FB5D9 7402               je 007FB5DD
:007FB5DB 8901               mov dword ptr [ecx], eax

You can imagine the call (in C) might look something like this:

encode_date(DWORD day, DWORD month, DWORD year,
            DWORD day, DWORD hour, DWORD minute, DWORD second);

So this is where the date/time is encoded (including the seconds!) – all we
need to do now is change the code to push our own values, in this 
case a valid date/time with the license file ‘time window’ that I mentioned 
earlier.
To find the ‘time window’ if you don’t already know it, try a date 
near to when the magazine from which you got the CD was distributed. 
Assuming, as an example, that a valid date within the ‘time window’ for
Corel WordPerfect 7 was 20/6/96 (20th of June 1996), we would alter the above
code to look like the below:

:007FB596 33C0              xor eax, eax      ; set seconds to 0
:007FB598 90                nop
:007FB599 90                nop
:007FB59A 90                nop
:007FB59B 50                push eax          ; push seconds
:007FB59C 33C0              xor eax, eax
:007FB59E66B80000           mov ax, 0000      ; set minutes to  0
:007FB5A2 90                nop
:007FB5A3 50                push eax          ; push minutes
:007FB5A4 B800000000        mov eax, 00000000 ; set hours to 0
:007FB5A9 90                nop
:007FB5AA 90                nop
:007FB5AB 90                nop
:007FB5AC 90                nop
:007FB5AD 50                push eax          ; push hours
:007FB5AE 33C0              xor eax, eax
:007FB5B0 66B81E00          mov ax, 001E      ; set day to 30
:007FB5B4 90                nop
:007FB5B5 50                push eax          ; push day
:007FB5B6 33C0              xor eax, eax
:007FB5B8 66B80600          mov ax, 0006      ; set month to 6  (June)
:007FB5BC 90                nop
:007FB5BD 50                push eax          ; push month
:007FB5BE 33C0              xor eax, eax
:007FB5C0 66B8CC07          mov ax, 07CC      ; set year to  1996
:007FB5C4 90                nop
:007FB5C5 90                nop
:007FB5C6 90                nop
:007FB5C7 50                push eax          ;push year
:007FB5C8 E8F3190000        call 007FCFC0     ; encode date
:007FB5CD 8B8C24F0000000    mov ecx, dword ptr [esp+000000F0]
:007FB5D4 83C41C            add esp, 0000001C
:007FB5D7 85C9              test ecx, ecx
:007FB5D9 7402              je 007FB5DD
:007FB5DB 8901              mov dword ptr [ecx], eax

So, we push zeros for the hours, minutes and seconds, and we push a
valid day/month/year (one that falls in the ‘time window’) – so every time 
the protection calls this routine it will return the very same encoded 
date each time! BTW, my patching above is rough and ready, with many 
unnecessary nops (0x90) in it – you should of course try to patch code using
few (if  any) nops. I’ll leave this as a short exercise for ASM newbies, they
can try to tidy up my patch a bit, make it more elegant 🙂

Don’t forget, this scheme is applied after the program is created, so the code
is *exactly* the same for each application protection with the Elan scheme,
making it very easy for us +crackers to crack…I suspect we  will soon see
a new ‘improved’ version of this scheme though…wait and see…

Thus we demonstrate once more how useless another (probably expensive)
protection scheme in the reality is.
There are still some (minor) limitations with this crack however;
* you must delete the registry key
‘HKEY_LOCAL_MACHINESystemSOFTWARERBO’, and all values it contains.
* You’ll also need to replace the  appropriate LIC file with the original,
‘uncorrupted’ copy.
So long as you do that, and then patch the application before running it
again, it will never expire and you’re free to evaluate it as long as you
feel necessary (not that you would of course, as that would be illegal 😉

I’ll tell you what, let’s take this a step further and write a little C
program to search the application for the code we need to patch  (remember,
it will be the *same* for every Corel/Elan application – which could be
convenient!), and then patch it with the desired date.
Following is the code to my ‘generic crack’, it’s pretty simple but it
works fine (sorry if the formatting  gets messed up…):
/* START PATCH.C */

#include<stdio.h>
#include<stdlib.h>

#define TRUE 0      /* a few constants to make the */
#define FALSE 1     /* code more readable 🙂      */
#define TLEN 7      /* length of target string     */

/* the patch data */ 
unsigned char patch[]={0x33, 0xC0, 0x90, 0x90, 0x90, 0x50, 0x33, 0xC0,
                       0x66, 0xB8, 0x00, 0x00, 0x90, 0x50, 0xB8, 0x00,
                       0x00, 0x00, 0x00, 0x90, 0x90, 0x90, 0x90, 0x50,
                       0x33, 0xC0, 0x66, 0xB8, 0x00, 0x00, 0x90, 0x50,
                       0x33, 0xC0, 0x66, 0xB8, 0x00, 0x00, 0x90, 0x50,
                       0x33, 0xC0, 0x66, 0xB8, 0x00, 0x00, 0x90, 0x90,
                       0x90, 0x50};

int cmp(char *buf, char *target);
void getdate(void);

void main(int argc, char *argv[])
{
 FILE *fp;

 unsigned char buf[TLEN];
 /* below is the target string we will seach for */
 unsigned char target[TLEN]={0x89, 0x4E, 0x0C, 0x8B,
            0x44, 0x24, 0x20};

 int c;
 
 long int location = 0;
 long int pos = 0;
 int match = 0;
 int found = TRUE;

 printf(&quot;Generic crack for *ALL* Corel trial applications, copyright
1997, +ReZiDeNt

&quot;);
 
 if(argc <2) { printf("Usage: PATCH.EXE <TARGET.EXE>
&quot;);
  exit(0);
 }

 fp=fopen(argv[1],&quot;r+b&quot;);
 if(!fp)
 {
  printf(&quot;ERROR: Unable to open file
&quot;);
  exit(0);
 }
 
 getdate();
 printf(&quot;
Searching – please wait, this may take some time…
&quot;);

 while((c=fgetc(fp)) != EOF)
 {
  if(c == target[0])
  {
   pos=ftell(fp);
   ungetc(c, fp);
   if(fread(buf, sizeof(buf)+1, 1, fp) != NULL);
   {
    found = cmp(buf, target);
    
    if(found == TRUE)
    {
     match++;
     if(match == 1)
      location = ftell(fp);
    }
    else
     fseek(fp, pos, SEEK_SET);
   }
  }
 }

 if(match == 0)
  printf(&quot;ERROR: No match found
&quot;);
 if(match == 1)
 {
  printf(&quot;Target found! Patching…&quot;);
  fseek(fp, location, SEEK_SET);
  fwrite(&amp;patch, sizeof(patch), 1, fp);
  printf(&quot;
All done!&quot;);
 }
 if(match &gt; 1)
  printf(&quot;ERROR: More than one location was found
&quot;);

 fclose(fp);
}

/* we can’t use strcmp because there might be null chars */
int cmp(char *buf, char *target)
{
 int j=0;
 while(j<tlen) { if(*buf++ !="*target++)" return FALSE; j++; } return TRUE; } /* get the date and validate it */ void getdate() { int day, month, year; int leap; int invalid="FALSE;" /* patch[28]="=" day */ /* patch[36]="=" month */ /* patch[44-45]="=" year (reverse byte order!) */ printf("Enter day (dd): "); scanf("%d",&day); printf("Enter month (mm): "); scanf("%d",&month); printf("Enter year (yyyy): "); scanf("%d",&year); /* is it a leap year? */ if((year % 4)="=" 0) leap="TRUE;" else leap="FALSE;" /* only allow a four-digit year */ if(year > 1900 || year> 9999)
  invalid = TRUE;   

 if(month <1 || month> 12)
  invalid = TRUE;

 switch(month) {
   case 1,
        3,
        5,
        7,
        8,
       10,
       12 : {
     if(day &gt; 31 || day <1) invalid="TRUE;" } ; break; case 2 : { if(leap="=" TRUE && day> 29 || day <1) invalid="TRUE;" if(leap="=" FALSE && day> 28 || day <0) invalid="TRUE;" } ; break; default : { if(day < 1 || day> 30)
     invalid = TRUE;
                                  }
   }    
 /* insert the new values into the patch string */
 if(invalid == FALSE)
 {
  patch[28] = day;
         patch[36] = month;
  /* reverse byte order of year  */
  /* (quick and nasty method) :-)*/
  asm {
   mov ax, year;
   mov patch[45], ah;
   mov patch[44], al;
  }
 }
 else
 {
  printf(&quot;ERROR: Invalid date entered
&quot;);
  exit(0);
 }
}

/* END PATCH.C */

If you’re looking for the compiled version of this crack then try the below URL:

http://rezident.home.ml.org/cracks.html

It is perhaps worth mentioning that this ‘brute force’ approach could be used
to reverse almost *any* Windoze-based time-trial application.
Of  course, most time-trial protections are pitifully weak, and it’s easier to
find  the ‘go-ahead-nice-buyer’ jump (and you’ll learn more) – but if you
come  accross a protection that can’t be beaten any other way, this method
should work.

Keep Cracking! +ReZiDeNt

Greetz to: 
All +HCU’kers, Noose, base+metal, Aesculapius, +trurl, Fravia+
and of course +ORC (and anyone I forgot)!

Kaynak: www.woodmann.com/fravia
belgesi-1099

Belgeci , 2422 belge yazmış

Cevap Gönderin