Reverse engineering Serif PagePlus 4 Trial Edition
(Double protections: time & registration number)

by ReZiDeNt

(08 July 1997, slightly edited by Fravia)
Courtesy of Fravia's page of reverse engineering

Newer protection scheme have learned quite a lot: in this target for instance there is no 'bad code entered' message; the text box is simply cleared... "So we need to keep an eye out for when the text box is cleared" teaches ReZiDeNt... and you'll need to "feel" a little the code too (and that's exactly what our art is about :-)

Reverse engineering Serif PagePlus 4 Trial Edition, by ReZiDeNt

Double protections: time *and* registration number


OK folks, here is how I cracked Serif Plus 4 trial version (available on
most cover CDs in Europe from about April/May/June 1997).

For this crack I'm going to use a combination of 'dead listing' (eg
disassembled listings made with WDasm) and 'live cracking' (using SoftICE 3
for Windows 95), so you'll need to have both of these tools. If you don't
have WDasm, download a copy (you'll find it everywhere on the Internet - 
just search) and crack it using the excellent essays inside the 
+HCU's project0. 
If you don't have SoftICE 3 for Windows 95, download the 14 days evaluation version 
from Numega's web site (www.numega.com) and crack it using the 
brilliant +HCU's project2.

Serif's target is interesting (from a cracking point of view) for a number
of reasons. Firstly, there are actually *two* levels of protection
incorporated into this software:

- A registration number

This scheme works in much the same way as the 'Instant Access' scheme
that +ORC discussed in parts C(1), C(2) and C(3) of his excellent tutorial.
Basically, PagePlus, upon loading, presents you with a screen (and a
generated number) which requests you to register your trial copy with Serif.
If you register, you are given a few extra days to evaluate the program
(how generous!), and you no longer see the screen inviting you to
register. However, you will still see a nag screen telling you how many
days you have left of your evaluation period. The idea is that you will
phone Serif and tell them the number generated on the nag screen. They
will then give you a second number which so generously allows you a few more
days of grace. During this process of registering you will also probably
be required to supply a lot of information about yourself - your name,
your address, your habits, lifestyle, likes, dislikes etc. This
information is then used to create a profile of YOU, which is then
passed around (for profit of course) from company to company, agency to
agency, government department to government department etc. Remember,
Big Brother is watching YOU! The government, state, big business etc are
becoming more and more intrusive every day. They already control the
vast majority of the population via the mass media machine which
comprises TV (nearly all of which is brain-destroying propaganda),
newspapers (especially the mind-numbingly stupid, depraved, effete
and deceitful tabloids), radio, films etc. It really is hard to
underestimate the *stupidity* of the average member of the 'electorate',
they gladly vote for whichever fools can tell the biggest lies and are
supported by the mass media. Read +ORCs brilliant tutorials for his
interesting viewpoint on this area - but let's get back to cracking :-)

- A time protection

This allows you XX days (about 21) of use (after you have registered with
Serif), before leaving you high and dry.


So to summarise, there are (at least) two protections to be cracked,
firstly the registration number protection and secondly the time
protection.

Obviously, we must first crack the registration number protection, and
then remove the time protection. So to work...run PagePlus, making a
note of the text strings displayed on the nag screen(eg 'Serif
Registration Wizard', 'You must register this copy of...'). Now lets
search through the directory where we have installed PagePlus for these
strings, using a utility such as grep or sr32. Aha! Where are these
strings to be found? In the PagePlus executable (pp.exe) perhaps? No!
They are located in a DLL file, Srfreg20.dll (take a look at it with the
Borland Resource Workshop). This is another reason why this protection
scheme is interesting...it uses an external DLL to (partly, at least)
hide the protection in. This fact may not be unique or interesting at
all, if it were not for a little software history (which +ORC teaches us
is very important). If you have ever come across any other older trial
versions of Serif software, you would notice that they all (at least all
I have come across) make use of an external DLL named something like
'Srfreg.dll', 'Srfreg16.dll' etc. They also use the same 'Instant
Access' type of protection, requiring you to obtain a number from Serif
before unlocking the program or allowing you a few extra days use. So it
seems that 'Srfreg20.dll' is Serif's own protection scheme...how
interesting...perhaps we ought to investigate some other versions of
this scheme later...

OK, what do we know now? Basically, using (if I may) a somewhat crude
and unrefined Zen, we can assume that PagePlus calls the Srfreg.dll file
upon starting, which then 'snaps' the protection. So it is very possibly
this DLL file that needs to be cracked, and it is certainly worth
investigating. So lets disassemble it in WDasm7. CRASH! WDasm7 for some
reason cannot disassemble the Srfreg.dll file...how odd...some sort of
protection perhaps? Or just coincidence? We could use WDasm8 instead
(which works perfectly, so make a dead listing for use later), but for
now let's try to have a go with SoftICE. BTW, I suggest you get a copy
of SoftICE 3 for Windows 95 - a trial version together with the
documentation (in Adobe Acrobat format) is available - and yes, it has
been cracked! See Fravia's Page of Reverse Engineering for the necessary
tutorial.

Fire up SoftICE, exit (Ctrl-D) and then run PagePlus. When we come to
the registration screen, do a 'BPX USER!GetWindowText', and then enter
any old number (say '1212121212' ;-) before pushing the 'Next' button.
SoftICE snaps at USER!GetWindowText. Push F12 ('P RET') twice to return
to the DLL code. You should see something like below:

1000338D FF1584440110            Call dword ptr [10014484] ; get code
10003393 85C0                    test eax, eax ; anything entered? 
10003395 7F08                    jg 1000339F   ; jumps here if yes...
10003397 33C0                    xor eax, eax
10003399 5F                      pop edi
1000339A 5E                      pop esi
1000339B 83C450                  add esp, 00000050
1000339E C3                      ret


Now step through the code carefully (F10), using F4 ('RS') to see what
is going on in the nag screen. If you observed the behaviour of the nag
screen previously (as you *always* should), you would have found that
there is no 'bad code entered' message; the text box is simply cleared.
So we need to keep an eye out for when the text box is cleared, when we
will be pretty sure the protection has 'snapped'.

So tracing carefully:

1000339F A1BC230110              mov eax, [100123BC] ; to here!
100033A4 8D4C2408                lea ecx, [esp + 08] ; load the code
100033A8 50                      push eax
100033A9 51                      push ecx
100033AA E881050000              call 10003930 ; do something here...
100033AF 83C408                  add esp, 00000008
100033B2 8B0DBC230110            mov ecx, [100123BC]
100033B8 89812C010000            mov [ecx+0000012C], eax
100033BE 8B0DBC230110            mov ecx, [100123BC]
100033C4 83B92C01000000          cmp dword ptr [ecx+0000012C], 000000
100033CB 742A                    je 100033F7 ; jump if ecx+12C == 0
100033CD 8D7C2408                lea edi, [esp + 08]
100033D1 B9FFFFFFFF              mov ecx, FFFFFFFF
100033D6 2BC0                    sub eax, eax
100033D8 F2                      repnz
100033D9 AE                      scasb
100033DA F7D1                    not ecx
100033DC 2BF9                    sub edi, ecx
100033DE 8BC1                    mov eax, ecx
100033E0 C1E902                  shr ecx, 02
100033E3 8BF7                    mov esi, edi
100033E5 8B3DBC230110            mov edi, [100123BC]
100033EB 83C714                  add edi, 00000014
100033EE F3                      repz
100033EF A5                      movsd
100033F0 8BC8                    mov ecx, eax
100033F2 83E103                  and ecx, 00000003
100033F5 F3                      repz
100033F6 A4                      movsb
100033F7 B801000000              mov eax, 00000001 ; to here
100033FC 5F                      pop edi
100033FD 5E                      pop esi
100033FE 83C450                  add esp, 00000050
10003401 C3                      ret

10001BBC E8AF170000              call 10003370 ; we've just been here
10001BC1 83C408                  add esp, 00000008
10001BC4 85C0                    test eax, eax
10001BC6 7450                    je 10001C18 ; jump if eax == 0?
10001BC8 A1BC230110              mov eax, [100123BC]
10001BCD 83B82C01000000          cmp dword ptr [eax+0000012C], 000000
10001BD4 7542                    jne 10001C18 ; or if eax+12c != 0
10001BD6 6844000110              push 10010044
10001BDB 8B3D50440110            mov edi, [10014450]
10001BE1 68EE030000              push 000003EE
10001BE6 56                      push esi
10001BE7 FFD7                    call edi
10001BE9 50                      push eax
10001BEA FF15A4440110            Call dword ptr [100144A4]
10001BF0 68EE030000              push 000003EE
10001BF5 56                      push esi
10001BF6 FFD7                    call edi
10001BF8 50                      push eax
10001BF9 FF15A8440110            Call dword ptr [100144A8]

Aha! The above call clears the text box...so the protection has already
snapped. Lets take a look at those two conditional jumps to 1001C18...

10001BC4 85C0                    test eax, eax
10001BC6 7450                    je 10001C18 ; jump if eax == 0?
10001BC8 A1BC230110              mov eax, [100123BC]
10001BCD 83B82C01000000          cmp dword ptr [eax+0000012C], 000000
10001BD4 7542                    jne 10001C18 ; or if eax+12c != 0

Remember the location [eax+12C]? We saw it before!

100033C4 83B92C01000000          cmp dword ptr [ecx+0000012C], 000000
100033CB 742A                    je 100033F7 ; jump if ecx+12C == 0

Hmm...lets see what happens if we reverse this jump:

A                    (assemble instruction)
JNE 100033F7         (reverse the jump)

Hmm...the program tells us we have chosen not to register at this
moment...perhaps we are being too hasty...let's take another look at the
code.

100033A4 8D4C2408                lea ecx, [esp + 08] ; load the code
100033A8 50                      push eax
100033A9 51                      push ecx
100033AA E881050000              call 10003930 ; do something here...
100033AF 83C408                  add esp, 00000008
100033B2 8B0DBC230110            mov ecx, [100123BC]
100033B8 89812C010000   *******  mov [ecx+0000012C], eax
100033BE 8B0DBC230110            mov ecx, [100123BC]
100033C4 83B92C01000000 *******  cmp dword ptr [ecx+0000012C], 000000

This is interesting...the value stored in eax after the call to 10003930
is moved to the memory location [ecx+12C]. Stepping again to this part
of the code in SoftICE (eg restart PagePlus, break on GetWindowText
again), we see that eax == 0 after the call 10003930. Let's see what
happens if eax == 1. Stop just after the call to 10003930 (put a
breakpoint on 10003930!). Then type:

REAX=1

Now exit from SoftICE and let the program run. 'Thank you for
registering! You now have another 15 days to evaluate PagePlus' etc. So
have we cracked it? Lets go to the help menu and select 'Play Game'.
What happens? A message box informing us that we must register before
playing the game. And SoftICE does not snap, meaning that the above code
is not executed, therefore the protection lies elsewhere and we must
crack deeper. This is why +ORC teaches us to use 'Zen' and 'feel' the
code - don't just reverse every jump in sight, but rather study ('feel')
the code. So back to the listing (make yourself a dead listing with
WDasm8 - not WDasm7, it won't work).

Go back to just after entering the code:

100033A4 8D4C2408                lea ecx, [esp + 08] ; load the code
100033A8 50                      push eax
100033A9 51                      push ecx
100033AA E881050000              call 10003930 ; check this out!
100033AF 83C408                  add esp, 00000008
100033B2 8B0DBC230110            mov ecx, [100123BC]
100033B8 89812C010000   *******  mov [ecx+0000012C], eax
100033BE 8B0DBC230110            mov ecx, [100123BC]
100033C4 83B92C01000000 *******  cmp dword ptr [ecx+0000012C], 000000


So after calling 10003930, the value held in eax is stored in [ecx+12C].
So what does the code at 10003930 do?

10003930 56                      push esi
10003931 6A2D                    push 0000002D
10003933 8B74240C                mov esi, [esp + 0C]
10003937 56                      push esi
10003938 E853240000              call 10005D90
1000393D 83C408                  add esp, 00000008
10003940 85C0                    test eax, eax
10003942 7403                    je 10003947
10003944 8D7001                  lea esi, [eax+01]
10003947 56                      push esi
10003948 E883230000              call 10005CD0
1000394D 83C404                  add esp, 00000004
10003950 8BF0                    mov esi, eax
10003952 8B44240C                mov eax, [esp + 0C]
10003956 8B4828                  mov ecx, [eax+28]
10003959 51                      push ecx
1000395A E8A11F0000              call 10005900
1000395F 83C404                  add esp, 00000004
10003962 3BC6                    cmp eax, esi
10003964 7411                    je 10003977
10003966 56                      push esi
10003967 E874200000              call 100059E0
1000396C 83C404                  add esp, 00000004
1000396F 85C0                    test eax, eax
10003971 7504                    jne 10003977  ; jump if good guy
10003973 33C0                    xor eax, eax  ; set ax to 0!
10003975 5E                      pop esi
10003976 C3                      ret               ; get out of here
10003977 B801000000              mov eax, 00000001 ; thanks nice guy
1000397C 5E                      pop esi 
1000397D C3                      ret         

BPX on the above code (eg 10003973) and select the 'Play Game' command
from the menu. SoftICE snaps! So step up until the 'ret' instruction (eg
10003976) and then type 'REAX=1'. Let the program run and behold, you
can now play a rather sad version of space invaders. :-)

Well, it looks as though we've cracked this first part of the protection
scheme pretty well, so a straightforward and simple patch would be to
replace the following two lines:

10003975 5E                      pop esi
10003976 C3                      ret            

with:

10003975 33C0                    xor eax, eax   

So when the program comes to this point, it will set eax to zero (twice
:-)) and then execute the below code... nice, we cracked this part of the
target rather neatly.

10003977 B801000000              mov eax, 00000001
1000397C 5E                      pop esi 
1000397D C3                      ret     

So fire up your favourite hex editor, open the file 'Srfreg20.dll' and
search for the string:

85C0750433C05EC3

replace it with:

85C0750433C033C0

Of course, we could have cracked it by replacing the 'jne' instruction
(75) with a 'jmp' (EB), and that would have worked just as well - but
then variety is the spice of life ;-)

Make sure you've edited the Srfreg20.dll file as above before continuing
on here (if you don't, the second part of the crack will not work,
and you'll get very confused :-)

So now we move on to the second part of the crack, the time protection
scheme. Let's think about how the time protection scheme might work.
Most likely, the PagePlus installation routine (or PagePlus itself)
saves the date on which PagePlus was installed/first run in the Windows
registry, probably in some encrypted format (so as the user cannot
change it :-) 
A quick browse with Regedit confirms this:

[HKEY_LOCAL_MACHINE\SOFTWARE\Serif\PagePlus\4.0\Registration]
"Name"="User"
"Company"=""
"Free Runs"="0"
"Grace Period"="21"
"Market"="PP4/CS/0697"
"Registration Id"="121212121212"
"Expiry Date"="865753058"
"Trial Reg Date"="864511007"
"Checksum"="2965965"
"CostHi"="0"
"CostLo"="0"
"CostCurr"="$"

How interesting. Even the 'grace period' is there in plain view - 21
days - perhaps we could change that? We could, and it might work, but we
want a more solid, more permanent crack. Let's instead focus on the
'Expiry Date' and 'Trial Reg Date' keys. These obviously hold the
install data and the expiry date in (as we suspected) some encrypted
form. So somewhere in the program (probably within the 'Srfreg20.dll'
file, since that is where the first part of the protection scheme is
hidden), the current (i.e. today's) date is compared with the expiry
date ('Expiry Date'). If the current date is after the expiry date, we
get a nasty message and are thrown out of PagePlus. The current date is
also possibly compared with the install date ('Trial Reg Date'), to
ensure that we haven't been playing around with the registry keys or
system date! :-)

So somewhere the protection must retrieve the current date from the
system, and this is the location that we must find. A search through the
disassembled listing of Srfreg20.dll (which we made earlier with WDasm8,
*not* WDasm7, which won't work) for 'KERNEL32.GetLocalTime' yields just
one location, which is called by quite a few (nine) other locations.

Now change the system date to some time in the future, past the PagePlus
expiry date. Run PagePlus, and you'll see that, surprise, surprise, we 
get a nasty message and are kicked out. :-( 
We don't like much this sort of behaviour, so let's crack it! :-)

Fire up SoftICE again, and do a 'BPX KERNEL32!GetLocalTime'. 
You must have the exports form KERNEL32.DLL loaded in order to do this. 
In order to load the exports, go to the Symbol Loader program (if you 
use SoftICE3 - if you don't, get it!) and look at 
'Edit...SoftICE Initialisation Settings...Exports', 
and add the KERNEL32.DLL file (usually found in'\WINDOWS\SYSTEM\') 
if it's not already there.

OK, so now we have the necessary breakpoint set, and we've changed the
system date to some time in the future, past the expiry date.
Run PagePlus (make sure you have ALREADY hex edited Srfreg20.dll with 
the "first crack" above before continuing!), and you'll see that SoftICE 
pops up on 'KERNEL32!GetLocalTime' eight times (it will pop more than 
that if you are using Symbol Loader) before bringing up the nasty 
'time is up' message and kicking us out. 
We want the last occurrence of KERNEL32!GetLocalTime (the eighth 
KERNEL32!GetLocalTime).
Once SoftICE pops up for the eighth time, step over the program
instructions, using F10. Don't use F8 (step into), because you
would get horribly lost!

We basically want to step over the program instructions until we lose
control and the 'time is up' message is displayed. You'll find that you
lose control at the following call:

100012E7 85C0                    test eax, eax
100012E9 7413                    je 100012FE    
100012EB A1B8230110              mov eax, [100123B8] 
100012F0 50                      push eax
100012F1 E83A3C0000              call 10004F30
100012F6 83C404                  add esp, 00000004
100012F9 E882000000     *******  call 10001380      ; here!
100012FE A1A8210110              mov eax, [100121A8]

The line 'call 10001380' calls the 'time is up' message, and we lose
control of the program. Hmm....look at the conditional jump previous the
call...where does it branch to? The line just after the call to the
message! Could it be this simple to crack?!! BPX on the 'text eax, eax'
instruction (eg 100012E7) and make the program jump to the line just
after the call:

BPX 100012E7
F10               ; move on to the 'je 100012FE' instruction
A                 ; assemble instruction
JMP 100012FE      ; jump always!


The program code should now look like this:

100012E7 85C0                    test eax, eax
100012E9 EB13                    jmp 100012FE        ; always jump...
100012EB A1B8230110              mov eax, [100123B8] 
100012F0 50                      push eax
100012F1 E83A3C0000              call 10004F30
100012F6 83C404                  add esp, 00000004
100012F9 E882000000              call 10001380           
100012FE A1A8210110              mov eax, [100121A8] ; to here!


Now let's exit from SoftICE (Ctrl-D) and let PagePlus run.
KERNEL32!GetLocalTime snaps once more...exit from SoftICE again (Ctrl-D)
and look!!! It snaps on the line we just BPXed on ('test eax, eax').
Exit from SoftICE with yet another Ctrl-D. Lo and behold, up pops
PagePlus, which now runs fine, without any 'time is up message'!
Congratulations, we have now cracked the second and final part of the
protection used by PagePlus. So lets hex edit the changes into the
Srfreg20.dll file to make them permanent. We've already edited it once
before (to crack the registration code part of the protection), so now
all we have to do to complete the crack is to search for the following
string:

85C07413

replacing it with:

85C0EB13

There are most probably better and more elegant methods of cracking  the
above protection scheme, but at the moment I'm sticking with the
'minimum effort - maximum product' school of thought :-). 
But you could always investigate things further and see what you find 
- it may be possible to crack the PagePlus executable (pp.exe) directly 
for example.
As I mentioned earlier, AFAIAA, all of Serif's demos are protected by
the same system (eg hidden in an external DLL file, usually named
something like 'Serifreg.dll' etc.), so you will probably find that
cracking them is now quite easy! :-)


Anyway, good luck - and keep cracking! ;-)

(c) ReZiDeNt, July 1997



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

homepage links red anonymity +ORC students' essays tools cocktails
search_forms mailFraVia

Is reverse engineering legal?