Commercial protection : Laserlock SPEEnc v 2 (http://www.laserlock.com/)
Editor : Microïds
Release date : FR November 01,
2002
http://www.jeuxvideo.com/articles/0000/00002557_test.htm
Cracking level : [ ] easy [x] intermediate [x]
confirmed [ ] expert
It is preferable to
have practised or cracked game protections such as Safedisc/SecuROM
before reading this tutorial (it also requires knowledge about the PE
file format, manual unpacking and imports rebuilding) and perhaps have read my previous tutorial on Laserlock :p
Tools nedeed :
Softice 4.01
Icedump
Procdump/LordPE
Hiew/Hex Workshop
W32Dasm v8.93
Adump
Masm v8
You must own the original disc of this game or a functional
clone (there is a Laserlock profile in Alcohol 120%), to be able to
apply this tutorial…
Moreover, it is the French version of Tennis Masters Series 2003…
The protected executable file is "Tennis Masters
Series 2003.exe", which will now be called "tms2003.exe"…
OS : Win98 SE.
This tutorial can easily be applied to others
debuggers (OllyDbg, for example) and other OS.
This tutorial is detailed in the following way:
A) Introduction and general information
B) A "cracking" approach
1. Locating OEP
2. Fixing the call Laserlock
3. Rebuilding the imports
4. Cracking the CD-check
C) A "reversing" approach
1. Fixing the "variable" addresses
2. The polymorphic code
3. The code in general
4. Easily locating the OEP
5. Anti-debugging tricks
6. Integrity checks
7. Stuyding SPEEnc layers
8. Cracking Laserlock SPEEnc without original game CD
D) Generalization and conclusion
E) Greetings
A) Introduction and general information :
Laserlock is a commercial protection, created by MLS
LaserLock Inc.
It is characterized by a Laserlok folder (hidden - > they take
us for idiots) on CD's root.
[CD is characterized by a ring quite
visible on center…]
If they believe that in putting an hidden attribute on
important files, we could not see their little game … - > "a pure lamerz
technique" :p
This Laserlok folder contains 5 files : laserlok.in,
laserlok.o10, laserlok.o11, laserlok.o12 and laserlok.o13, all hidden
(~90 Mo!!!) …
Protection is based on these "copy protected" files
(they can't be copied the usual way).
So, protection has just to check
the presence of these files, to determine whether it is disc copy or not.
On the executable file, protection can easily
be detected by editing it with a hexadecimal editor:
Laserlock's guys are cool ; they give us the version of SPEEnc
(here, it is version 2).
On their site (copy from September
2003), Laserlock informed us about its protection (Mommy, I 'm really afraid :p) :
Actually, it is this powerful combination that makes LaserLock protection system so secure, single and applicable, especially when compared to the other protection systems available today!
LaserLock MARATHON is:
- Uncrackable, with No Generic CracksB) "Cracking" Approach :
1. Locating OEP to unpack the executable file :
After two small jump on OEP, we arrive at
0040117B and with a look at the code, which follows, we can already
suspect the executable file to be packed… (see the pushad in
0040119F).
To arrive at the "real" OEP, lets first test the
traditionals bpx APIs (for example, bpx GetVersion)…
Baooom, the PC explodes… lol… No, just a crash…:p
It is thus useless to put any bpx, because of
anti-bpx…
How can we arrive at OEP of our unpacked executable file ?
By putting a bpr 402000 650000 R (memory breakpoint).
Why 402000? Because this way, we avoid
the protection's instructions (from 4010D1 to 40192A)
before the ret in 0040157C
(which enables us to arrive on "variable addresses" code).
Prefer a large range, because
a lot of games do not have their OEP in the neighbourhoods of
401000 (contrary to majority of sharewares executables)…
The 1st break brings us on a LODSB instruction at
00BA73FE :
We disable this bpr by a bd 0 and we put a bpx
00BA7417 to leave this loop…
Shucks! We must not use BPX !!! In this case, we crash at
00BA21FA…
So, prefer a bpm 00BA7417 X (hardware breakpoint).
We reactivate then the bpr by a be 0 and we break this time on REPZ MOVSB instruction in 00BA5078 :
We disable the bpr (bd 0) again and execute the
REPZ MOVSB instruction at 00BA5078 by F10 (Step Over)…
Then reactivate the bpr (be 0) a last time and finally after 1 minute, we get OEP of the unpacked tms2003.exe
;)
Note: An lame method "to find"
the OEP of an unpacked executable file consists in dumping on runtime (so it is decrypted/decompressed), disassembling
this dump and looking in the code for these instructions :
push ebp
mov ebp, esp
It can constitute a check, but nothing more (because
of several occurrences)…
2. Fixing the call Laserlock
If we attentively look at the code on OEP, we have this:
Let us see what there is, inside…
We must thus replace call Laserlock by call API…
Here, we have just to replace FF156077BA00 by
FF1538399000.
e 0064697F 38,39,90,00.
One call fixed ;).
We have just to automate what we have previously done
manually, by a small routine (a "call-fixer").
This constitutes an anti-dump protection. So, if these calls are
not fixed and that we dump, then executable file "will attempt to go" in
memory zones, which do not exist anymore (they were initialized
by protection) and it will irreversibly crash…
You will perhaps remember the "Call-fixer" of the previous version of
Laserlock (Laserlock version 5, for example, Desperados: Wanted
Dead or Alive)?
Well, we can keep the same one to fix all our Call
Laserlock of this version (there are only very few things to modify).
If you want more explanations about this routine, I
send you back to my previous tutorial :p
Rem: - Compared to the
previous version (version 5), there are no more checksums, applied
on this routine, which calculates redirection address of the
"call Laserlock", nor on the executable file itself , at time of its call. Thus, we can
modify the code if it is necessary (and it is what I did, by
patching address 00BA6F8E with a jmp edi !!! ).
- The exploit, present in the version 5, which consisted in
making the program patch itself and replacing the call Laserlock by call/jmp APIs, from
the 50th API and which made possible to avoid CD authentification, has been corrected…
Call-fixer (Laserlock.asm):
Image Import Descriptor Format or Import Table (read "peering inside the PE" of Matt Pietrek!) :
An entry (a DLL and all its functions) in the Image Import Descriptor consists of 5 Dword.
Dword 1 - Characteristics (hint name array)
This dword is a pointer to the first element
of a pointers table.
Each pointer of this table points to the hint name, followed
with a function name.
Dword 2 - TimeDateStamp
Dword 3 - ForwarderChain
Dword 4 - DLL’s name
This dword is a pointer to the name of the
DLL (null terminated ASCII string)
Dword 5 - Import Address Counts
This dword is a pointer towards the first element
of an addresses table.
This addresses table functions in parallel with the one of
pointers to the hint names (names of functions).
Extracted from Import Function tutorial.doc / Import-Function in section RDATA.doc by El.CaRaCoL. (In French)
Thank you El.CaRaCoL. ;-)
C) "Reversing" Approach :
1. Fixing "variable" addresses :title cca
.386
.model small, stdcall
option casemap :none
.code
_TextStart equ 00BA0000h
_TextEnd equ 00BA7B9Dh
start:
pushad
mov edx, _TextStart
@1: cmp edx, _TextEnd
je @2
check1:
cmp word ptr [edx], 01EBh
jne check2
cmp word ptr [edx+05], 07EBh
jne check2
cmp word ptr [edx+0Ah], 0F9EBh
jne check2
mov ecx, 0Eh
jmp paste
check2:
cmp word ptr [edx], 04EBh
jne try_again
cmp word ptr [edx+03], 04EBh
jne try_again
cmp dword ptr [edx+14h], 03
jne try_again
cmp word ptr [edx+29h], 04EBh
jne try_again
cmp word ptr [edx+2Ch], 0FBEBh
jne try_again
mov ecx, 2Fh
jmp paste
paste:
mov al, 90h
mov edi, edx
rep stosb
try_again:
inc edx
jmp @1
@2: popad
int 03
nop
end start
The Image Base is in SPEEnc since the
beginning…
Image Base, which is initialized (at the beginning of
protection), by this code:
01A7:004013EC 3E8B853E000B10 MOV
EAX, DS:[EBP+100B003E]
01A7:004014F3 89041E MOV
[EBX+ESI], EAX
So, OEP "is just coded" and a simple
subtraction makes it possible to find easily!!!
OEP (VO) = 9B917A32h - 9B6D10DBh = 00246957h
5. Anti-debugging tricks:
At first time, we could say that there were no anti-debugging tricks.
Indeed, game launches without any problem with SoftIce, loaded. We have no warning message, no crashes, exit or anything else...
So, there is no direct debugging detection.
But, when we put bp / bpm (hardware breakpoint), we discover that anti-debugging tricks are present...
First of all, a small log of FrogsIce (Thank you +Frog's Print):
Hook of interruption 3:
Laserlock thus hooks the int 03 to its own routine
(located in 00BA21BC), which take care of erasing Debug Registers (dr0,
dr1 and dr2) and by the same time clearing the Hardware Breakpoints !!!
Moreover, this routine in 00BA21BC is called (in ring 0)
much more than once, by the int 03, disseminated a
little everywhere in the code…
By putting a bpx adresse/API, you go directly on this routine (but not when it was planed :p) and you got
a pretty crash in 00BA21FA !!! (on Ring 0)
Quite simply because the address ds:[ebp+048B5986] in 00BA21FA (1)
is not "valid"…
It is the same for the address ds:[ebp+048BD074] in 00BA231E (2),
where you arrive if you avoided the 1st crash by modifying the eip.
And if you manage to return to windows after these crashes,
you will got a crash of the explorer, each time you want to go anywhere that the Desktop (My documents, any folder, etc…) and even when you want to restart the computer …
Indeed, a crash (or an early exit) of SPEEnc lets the int 03, hooked (it is not very clean), which is not the case for Starforce. The explorer seems to use int 03, when folders are browsed. If you minimize the game between the hook and the unhook by the SPEEnc, after a breakpoint and an infinite loop, you will obtain explorer's crashes in case of browsing folders.
Now, why these crashes in (1) and (2) ?
Because of the "ebp excentric" value. When SPEEnc is normally executed, ebp has a certain value.
When we are in (1), ebp = FC2EA6D0, so ebp+048B5986 take 00BA0056 as value and eax = 9B6D10DB.
When we are in (2), ebp = ECCD9F74, so ebp+048BD074 take 00BA7744 as value (eax has its previous value).
So, when a int 03 is called at any other moment (that the ones specified by the SPEEnc), like a bp, there will be big chance to have an invalid memory access (on read / write), because of the different value of ebp register.
The restoration of IDT, on the int 03, is done only
just before the redirection towards the OEP of the unpacked executable …
Note: The int 03 is
hooked by the instructions in 00BA1F7E and 00BA1FCF… (see my Tutorial
about Starforce for more detail on the IDT).
If we avoid the hook of int 03 (by avoiding the instructions in
00BA1F7E and 00BA1FCF), the program will crash… (this is due to
the int 03, disseminated a little everywhere in the code).
Clearing Drx:
This routine is not very efficient, since
I can break on Laserlock code without problems, using a bpm !!!
Indeed, when we put our 1st bpm, SoftIce uses the dr3 and as
this one is not erased, we can thus break.
Thus, this routine limit only the use of hardware breakpoints to one!!!
And you are by no means prevented from putting several bpm and
breaking without problems in the code separating two consecutive int 03…
Nopping the mov drx, eax makes crash the program,
much further, because of the integrity checks of SPEEnc !!!
It is thus necessary to proceed differently to circumvent
this…
Interruptions (int 03) disseminated a little
everywhere in the code:
Presence of int 03 in 00BA1BD2, 00BA1C93, 00BA205C,
00BA23CA, 00BA2656, 00BA2847, 00BA29CE, 00BA3C48, 00BA3F82, 00BA43A1,
00BA445E, 00BA4A69, 00BA4EBB, 00BA515D, 00BA55FC, 00BA6073 and
00BA66B2. They are thus rather numerous and are as many
possibilities of anti-bpx and anti-hardware breakpoint (by clearing the
drx).
Some examples:
etc…
You have certainly seen this recurring cmp dword ptr ds:[ebp+048B59C0], 00000000 and preceding all the int 03 (except the one in 00BA205C)…
And what does correspond ds:[ebp+048B59C0] to ?
It is there, that is stored the old routine ("the address") of
the int 03 previously hooked …
However, as we saw, if we only try to avoid the hook of int 03, the
program crashes … (because of all these int 03).
Then let's test this :
In 00BA1F26 (storage of the int 03 old routine), we
put edx at 0 (r edx 0), so that it saves this value.
In 00BA1F7E, we avoid the instruction while making point eip
on the following instruction (r eip eip+3).
In 00BA1FCF, we avoid also the instruction by a "r eip
eip+4".
Lastly, we avoid the int 03 in 00BA205C (r eip eip+1).
And now you will be able to put all the bpx/bpx API you
want :)
We solve in the same time the anti-bpx and the drx clearing…
But why this presence of cmp / je?
Because contrary to win 98, XP does not make possible any read/write attempt in IDT in ring 3 (normal execution mode of programs)…
This code ensures thus compatibility with this last system.
You will have noticed that this int 03 hook routine is included in a "SEH structure".
Any attempt to read / write IDT values on XP send us directly to (39)07A6 (SE Handler), 390000 being Image base of the SPEEnc...
Restoration of IDT (on the int 03 vector):
Just before the "jump" towards the OEP of the
unpacked executable, the IDT is restored:
Many exceptions (SEH):
SPEEnc contains many exceptions throughout its code:
Here it is the routine, which determines whether there is
enough available memory for SPEEnc.
If it is not the case, the jump in 00BA32DD is not carried out
and this following error message appears :
The use of all these exceptions, present a little everywhere in the code, is probably used as anti-tracing technique, but it's useless …
6. Integrity checks :
Here's the integrity checks routine of SPEEnc code, which
makes you avoiding code modifications (if not -> risk of a crash) :
This routine is called several times by the call 00BA7248, located
in 00BA722C.
On the 3rd call, the check is done on the SPEEnc, about the block starting in 00BA0190 (esi) and with a size of 7540 (ecx).
The result of the operation is finally stored in eax.
7. Decoding layers :
1st decoding layer:
We saw that it was carried out at 004014D5, in order to
decipher the block starting at 00BA0000 (esi), with a size of 7B9D (ecx)
(see the chapter fixing the variable addresses). But in fact, instructions are valid, only for the block starting in 00BA0190 and
finishing in 00BA04A5, which can be explained by the application of a second decoding layer…
2nd decoding layer:
Then, once our 1st block is deciphered, the
following routine, at 00BA733F (identical to the previous one, but with polymorphic code, this time), called at
00BA0455, is charged to decipher the block starting at 00BA04A5, with a
size of 44F2.
This routine is then called at 00BA1B32, to decipher a block
starting at 00BA9A46 for a size of 3421B (from datas…).
The checking of the disc is then carried out…
The call at 00BA1B32, calls this routine again to
decipher the code at 00BA4997, with a size of 2617 (all the executable
code of SPEEnc is thus deciphered…), then to decipher a block of
datas on SPEEnc, starting at 00BA748C and with a size of 244.
Unpacking of the tms2003.exe is
finally executed, using this routine also (00BA733F). It is called several times by
the call at 00BA5ABC, to proceed by blocks, starting
from the end of executable (relocations) and going up
gradually…
It remains a last important question : is it possible to crack this version of Laserlock without having an original CD ?
The answer is yes :).
8. Faultsin original disc authentification :
To determine where disc checking is done (authentification), we have to put a breakpoint on GetDriveTypeA API (don't forget to avoid anti-debugging tricks). Then, we land in NIL32.dll module.
When re-running the executable file and putting a breakpoint on CreateFileA, we see that Laserlock creates some temporary files in C:\Windows\TEMP :
- nomouse
- nomouse.com
- nomouse.sp
- NIL32.dll
- SPEEnc.Dup
These files are erased, when the SPEEnc has finished its task (when the game starts).
So, it is possible to retrieve NIL32.dll, by stopping in the code before the time, it is created and after the time, it is deleted (for example, by breaking on GetDriveTypeA). We have just to go in the temporay folder to copy it. The hook (interception) of the int 03 by the SPEEnc must be avoided, because the explorer interferes with this hook (use of int 03 by the explorer in folders navigation) and leads to a crash...
We edit the dll PE with LordPE.
OEP is 0A150 (RVA), Image Base is 0x10000000.
We have just to put a bpm 1000A150 X to break at the OEP.
We break on it. We run again (F5) to break a second time.
The NIL32.dll module is then unpacked (deciphered) and 1000A150 seems to be the OEP of the unpacked dll.
And if it is not the case, it does not matter, because we want to dump this dll, only to study it in dead listing.
In the code, we can see some call [00C0xxxx], corresponding to the Laserlock redirected call [API].
We have again variable addresses at this stage.
We launch a call-fixer to solve this problem.
Then, we dump at the OEP, with LordPE :
We create a new Import Table with ImpRec :
To do it, we choose the tms2003.exe process. We click on Pick DLL and we select the nil32.dll module.
Then, we have just to enter the beginning of the IAT : 1E000 (RVA), its size : 1F4 and to click on Get Imports.
Don't forget to solve the GetProcAddress import to obtain the new Import Table (see previously).
By disassembling the dll, we can see a part of code, which is still ciphered (offsets from 0x2E66 to 0x5CED, that is to say, a size of 0x2E87) :
We can put a bpm 10002E66 X to break and dump the deciphered code with LordPE :
Then, we replace the deciphered code in the previous dumped .dll .
We obtain a fully rebuilt dll. By examining the disassembled code, what can we see ?
The same String Data References as the Laserlock v5 dll : "*LASERLOK* Copyright (c) 1992-1996", "Petros Skalkos **", "v5.00.607 Compile:21/3/2002".
Finally, protectionnists re-release always the same protection but in a different way.
They take their old protection dll (previous version) and have just implemented the SPEEnc, as a layer, enabling to hide the dll protection...
How can the CD authentification be bypassed ?
By putting a bp on the GetDriveTypeA API, we land at this code :
We have the classical APIs couple : GetLogicalDriveStingsA (returns the existing drives on the system) / GetDriveTypeA (returns the type of a specified drive).
The GetFileAttributesA API returns the LASERLOK.IN file attribute (hidden attribute). So, the flag can be reversed (or some nops can be placed).
We can also make inconditional, the jump on 10005620 (it has the same effect).
So, it is possible to crack Laserlock SPEEnc without the original disc.
Bypassing the check on LASERLOK.IN file attribute, seems to be enough to avoid the other physical structure checks,
as some SDRs let it assumed : "_*NTCD_Last5 ChkSum error*", "_*NTCD_Prev ChkSum error*", "_*NTCD_SIGN not found*",
"_*NTCDFound*", etc...
However, Laserlock does not reach the security level of some other protections, at this stage .
Indeed, the CD physical structure (defective sectors or something else) is usually used to prevent copy, but is also used by some protections to extract a key, enabling the game executable to be deciphered...
Then, an original CD is needed to crack it, unless the deciphering algorithm implementation is bad (faults, bruteforce, etc...).
D) Conclusions :
Generalization:
What changes from one game to another?
I looked at another game, protected by the same version of SPEEnc. It is Codename : Outbreak…
When they say that Laserlock is not generic, it makes me laugh.
It is exactly the same principle…
The "differences" are :
- the "Image Base" of SPEEnc changes… It is 007A0000
instead of 00BA0000.
- the OEP is always "decoded" by subtraction. This time,
9F9B992D is subtracted instead of 9B6D10DB
- the instructions of "fixed" SPEEnc have slightly
different addresses: the RET, which makes jump towards OEP
is in 6C06 instead of 6D89 from tms2003…
This must be explained by a "pseudo-random"
insertion of polymorphic code blocks into SPEEnc…
- API GetProcAddress is redirected twice in IAT (in
50C244 and 50C3A4) instead of one…
- the IT is more destroyed than in tms2003, since the
pointers towards the name of dlls are also cleared (Dword 1).
In other words, nothing fabulous to deserve the name
of "non generic" protection !!!
Infos (for this game) :
OEP = 8E3AC (VO)
IT begins at 50C000 (size: 1D0)
IAT begins at 50C1F4 (size: 9F0)
Now, you have enough information to make your own
unpacker ;-)
Creating a unpacker in this case is more educational than another thing ;
very few games have been protected with SPEEnc version of Laserlock…
(Codename : Outbreak, Tennis Masters Series 2003, Post Mortem and
Warrior Kings, in France…).
This protection is finally easier than it appeared at first ;) …
It still contains many errors of conception and is very
far from being incrackable, as its authors ensure it…
You can always thank the author for this amusing and
interesting protection ; he kindly left us his email…
As for Microïds, I am disappointed, that they
closed shop and I do not understand why…
This french editor:studio made good games like Syberia 1 & 2,
Tennis Masters Series, War And Peace: 1796-1815, compared to
the garbage that french studios like Davilex or Cyanide make, studios which are still alive!!!
They have already tested all the protections available on
the market: Laserlock with
Tennis Masters Series 2003, Safedisc with Syberia 2, Starforce with War And Peace: 1796-1815, VOB ProtectCD with Tennis Masters
Series (the first)… In vain…
Here it is finished with
Laserlock tutorials :p
Removing the CD-check of Codename :
Outbreak :
Once Laserlock removed from Outbreak.exe, it remains
a CD-check to remove :
The game launches (without movies) and then we
reach the main menu…
But the two options "Play solo" and "Intro" are grayed and
nonaccessible :
Moreover, a click on "Play solo" displays the
following error message (it is not the case for "Intro"):
Lol… Even if you have the original, you
got a limited version if you do not insert the CD!!!
We will destroy this. Disassemble Outbreak.exe, for
example with W32Dasm. We look for
GetDriveTypeA/GetVolumeInformationA APIs and we fall on this code :
This routine of CD checking is very close to that of Tennis
Masters Series 2003, except for the use of
GetLogicalDriveStringsA API…
This API determines the drives configuration of
your computer, making it possible to restrict the tests by GetDriveTypeA API
on drives to the existing ones only.
The GetDriveTypeA API determines for a given drive, if it
is a CD drive.
In a such case, the GetVolumeInformationA API returns the
volume of inserted CD (if there is one).
Lastly, returned volume is compared with "OUTBREAK" string …
This routine is called twice, at 0046369B and at
0048E0D8…
The call in 0046369B is not followed by a
test, contrary to the one in 0048E0D8 :
You will have understood that you just have to nop the
conditional jump in 0048E0DF, to launch the game (with the movies)
and to play without CD!
And for the fans of String Data References :
E) Thanks:
Greetz:
ACiD BuRN, ArthaXerXès, Black Check, cdkiller (ProtectionID), CyberBob Jr, ^DAEMON^, Dark-Angel, DecOde12, diablo2oo2, Duelist, El-Caracol, EliCZ, Elraizer, evlncrn8, Fravia+, +Frog's Print, KeopS, Gádix, GRim@, G-RoM, Iczelion, kilby, Laxity, Lorian, LutiN NoIR, MackT, MrOcean, NeuRaL NoiSE, Neutral AtomX, Ni2, Nody, [NtSC], +ORC, Pedro, Peex, PEiD (snaker, Qwerton, Jibz), Psyché, Pulsar, +Pumqara, Ricardo Narvaja, Skuater, +Spath, +splaj, Stone, TeeJi, The Owl, tHeRaiN, TaMaMBoLo, +Tsehp, Tola, woodmann, +Xoanon, [yAtes], yoda... and all
those which I forgot and who contribute actively to the scene by their
tutorials, tools and others…
all the icedump TEAM, ARTeam, CracksLatinos, DREAD, FRET, ShmeitCorp, UCF2000, UNPACKiNG GODS, TMG, all game groups…
All +HCU Students
All ppl of RCE Messageboard
these great sites:
http://207.218.156.34/krobar/index.html
http://arteam.accessroot.com/
http://tuts4you.com/
http://www.woodmann.net/forum/index.php
http://www.woodmann.net/yates/index.htm
Special Greetz:
Christal: Thank you for all
that you did for the French scene and your so great implication.
My best regards :)
Laserlock: Thank you to the developers of this protection, for the few recreation hours (too few …)
+Frog's Print & +Spath: Thank you for FrogsIce :-)
GRim@: Thank you for your
"Beginner" tutorials, with which I started…
R!SC: Thanks,
Master, for your tuts about CD-ROM commercial protections, like
Safedisc, SecuROM, VOB ProtectCD, etc…: -)
All members of FFF ;-)
Message to TomRipley : Plz, come back !!!
Final words:
I hope that you enjoyed reading this
tutorial.
If you want to study this protection, I can upload these tutorial targets. So, mail me at :
dWx5c3NlMjAwOV9mckB5YWhvby5mcg==
(base64 encoded)
I tried to make an original presentation "cracking"/"reversing"
to show that it was possible to crack commercial protections
with a minimum of knowledge and without be aware of all the various anti-cracking techniques of protection…
A vague idea of these various techniques is largely
enough as you have seen…
It is nevertheless much more interesting to reverse
these techniques and it highly facilitates the attack ;)
But, the boundary between these two concepts tends to be currently
erased.
Reality is always much more complex than a simple dichotomy…
Concerning Tennis Masters Series 2003, I would say
that it is one of the best (more complete) games of tennis, on
PC, with the Top Spin series …
It is very far from the poor/terrible level of the
Roland Garros game on PC!!!
"If you like a game, Buy it !"
uLysse, on 27 / 02 /07
"There is a crack, a crack in everything... That's how the light gets in."
Copyright © uLysse / FFF