-
Target game: Sid Meier's Gettysburg
Tools: W32Dasm, Soft-Ice if u want to trace thru the routine
Level: 1, newbies only!
Other: Nuffing this time.. gonna make it quick and then goto sleep ;)
Ok.. the game uses the typical GetDriveTypeA routine thats easy to follow
and even more easy to crack. I got this after disasming lee.w32 (backup!)
Huh?.. *ZZZZZZZZZZZZZZZZZZZzzzzzzzzzzzzzzzzzzzzz*ZZZZZZZZ ZZZZZ*ZZZZZZZZZZZZZ*
.................................................. ...........................
.................................................. ...........................
... erhmm.... g'morning.. :).. seems like I had fallen asleep.. heheh.. oh
well.
NOTE! Cracking isnt this exhausting!.. I just had had a loonng day.. ;)
Okayz.. lets finish this piece of crap. Does this look familiar?
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004666F7(C)
|
:0046669D 8D45E4 lea eax, dword ptr [ebp-1C]
:004666A0 50 push eax
* Reference To: KERNEL32.GetDriveTypeA, Ord:00DEh <-- i wonder..
|
:004666A1 FF1500655A00 Call dword ptr [005A6500]
:004666A7 83F805 cmp eax, 00000005 <-- check for CD-ROM
:004666AA 753F jne 004666EB <-- not found -> jump
:004666AC 68A0055A00 push 005A05A0
:004666B1 E85A020000 call 00466910
:004666B6 83C404 add esp, 00000004
:004666B9 8D45E4 lea eax, dword ptr [ebp-1C]
:004666BC 50 push eax
:004666BD 68A0055A00 push 005A05A0
:004666C2 E859020000 call 00466920
:004666C7 83C408 add esp, 00000008
:004666CA 56 push esi
:004666CB 68A0055A00 push 005A05A0
:004666D0 E84B020000 call 00466920
:004666D5 83C408 add esp, 00000008
:004666D8 8D85A4FDFFFF lea eax, dword ptr [ebp+FFFFFDA4]
:004666DE 50 push eax
:004666DF 68A0055A00 push 005A05A0
:004666E4 FFD7 call edi
:004666E6 83F8FF cmp eax, FFFFFFFF <-- CD found?
:004666E9 757D jne 00466768 <-- Nope, jump *Reverse This*
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004666AA(C)
|
:004666EB 8A45E4 mov al, byte ptr [ebp-1C]
:004666EE 43 inc ebx
:004666EF FEC0 inc al
:004666F1 83FB1A cmp ebx, 0000001A <-- check drive letters
:004666F4 8845E4 mov byte ptr [ebp-1C], al
:004666F7 7CA4 jl 0046669D <-- jump if not all done
:004666F9 8B450C mov eax, dword ptr [ebp+0C]
:004666FC 85C0 test eax, eax <-- check if all done and CD
found
:004666FE 0F859C000000 jne 004667A0 <-- Not found -> Jump, found ->
go on
:00466704 6A00 push 00000000
:00466706 8D8D98E0FFFF lea ecx, dword ptr [ebp+FFFFE098]
:0046670C 6A00 push 00000000
:0046670E 6AFF push FFFFFFFF
Sorry guys.. I could prolly give u more detailed infos if I had traced thru
this in SI..
but since I didnt.. I'll just make a "lucky guess"..haha.. not really a lucky
guess, coz
this protection doesnt differ that much its easy to find the correct patching
spot without
tracing.
Like I already pointed out in the code bit above, u should reverse the jump
over there.
That was my "lucky guess" and it turned out to be a right guess :) Next time
I'll be in
touch with SI again to give u more detailed and more specified info (I just
hope it wont
be getdrivetypea again..).
:04666E9 757D -> 747D
.. and you're done! all scenarios all playable and there wont be "CD not found"
at the
beginning. Congratz!
-
The Cracking Answer
-------------------
Author : Bug Error
-------------------
Target : Starcraft 1.0 US No CD
--------------------------------
Toolz that you'll need
-----------------------
- Soft-Ice 3.23 or higher
- W32dasm 8.93 or higher
- hiew 6 or higher
- Initial Notes
----------------
- Install the game (full)
- Copy "install.exe" from your original cd to your starcraft directory
- Please be sure that you don't have the cd into your drive
First Approach
--------------
- Press CTRL + D to go in Soft-Ice
- Set a breakpoint on GetDriveTypea : BPX GetDriveTypeA
- Press F5
- Run the game, and you're back in Sot-Ice
- Press F11 to get the caller
- You must see this :
0177:15012c40 call [KERNEL32!GetDriveTypeA]
0177:15012c46 mov esi, eax
- You see also that you're into Strom.dll
- So, you know that the cd check is in "storm.dll"
- Note the address 15012c46, you'll need this
Disassembling the target
------------------------
- Run W32dasm, and open "storm.dll"
- Click on goto and goto code location, and enter 15012c46
- You must see this :
* Reference To: KERNEL32.GetDriveTypeA, Ord:00DFh
:15012c40 ff15f0240315 Call dword ptr [150324f0]
:15012c46 8bf0 mov esi, eax
- Scroll down till you see :
:15012c85 eb78 jmp 15012cff
- Click on Jump To's icon
- You must see this :
:15012ce5 6681f9001f cmp cx, 1f00
:15012cea 740b je 15012cf7 => Force this to JUMP...
:15012cec 6681f9001f cmp cx, 0805
:15012cf1 895c2410 mov dword ptr [esp+10], ebx
:15012cf5 7508 jne 15012cff
* Referenced by a (U)nconditional or (C)onditional Jump at address
:15012cea(C)
:15012cf7 c744241001000000 mov [esp+10], 00000001 => ...to go here :))
* Referenced by a (U)nconditional or (C)onditional Jump at address
:15012c85(U), 15012cbe(U), :15012cf5(C)
:15012cff 399c2440020000 cmp dword ptr [esp+00000240], ebx => You're here
- Please be sure that you're on 15012cea and take the @offset in the task, here
it's 00012cea
Let's gonna crack :))
---------------------
- Run Hiew and open "storm.dll"
- Press F4 and choose "Decode"
- Press F5 and enter 12cea
- Press F4 and choose "Hex"
- Press F3 and enter EB
- Press F9 to update the file
Run the game
------------
- Wouaw, Stracraft 1.0 runs without the CD, you've cracked the game :))
-
Star Wars Episode 1 Racer - CD crack by Static Vengeance - May 26th, 1999
REQUIREMENTS:
Full game install
W32Dasm & Hex editor
With all the hype about the new Star Wars movie (episode 1) you just knew there were going to be
games based on it. Star Wars Episode 1 Racer is just such a game. The game requires a 3D accelerator
and makes good use of it as well! With dual voodoo 2 cards the game looks fantasic and with all the
options turned on (or on high) runs quit fast. The cut scenes are very good and the game play is great
so this game is well worth the money to buy. I just have two minor problems with this racer. First, once
you've seen the animations (cut scene movies) you really don't need to seem them every time you play the
game. Second is a little program bug so commonly found in todays games, and that is the copy protection
used. Why do they always make you have the original CD in the drive just to play the darn game? Like any
game you'll be playing alot you don't want to hunt down the original CD to play it. Also if you have kids
you'll want to make sure the CD is protected from harm. The best way to do that is not to have the game
require the CD! With a little effort on your part and a little guidance on my part you'll be able to do
that with this game.
If you install the game and run it you'll notice that you'll need to put the CD in the drive. One
of the reasons this is needed is due to the fact that the music files and all of the animations are kept on
the CD to keep the game install size down. Fair enough, but what if we kill the animations and copy the
music files to the hard drive? Then we can track down the CD check and kill that as well. We'll end up with
a cracked copy of the game we can play anytime without the need for the CD to be in the CD Rom drive. So let's
get started on our quest. Install the game and you'll see two exe files. The first one is basicly a loader,
but it has some very important features. When you first run the game it's the file racer.exe that let's you
choose your 3D card and resolution. Otherwise you're limited the stock 640x480 @ 16 bit color. Hey!, we've
got big monitors and high powered 3D cards and we want to use higher res, right? So we'll need to kill the
CD check in that file. The other file is of course the main game program called swep1rcr.exe and we'll need
to track down the CD check in that file as well. So disassemble racer.exe and do the usual trick:
Go up to the menu bar and select "Refs" and then "String Data Refs" from the drop down menu. When the refs
pop-up box comes up, grab the slider bar and start scrolling down looking for anything that looks interesting.
Eventualy, if you're paying attention, you'll find a ref of "/LNCH099/Please insert the CD " Double click on
that and you'll be put in the middle of some routine. However this string comes up 3 times so you'll have to
look at the surounding code to see which one is the one that is the CD check. So checking around a bit with
the second occurrance you'll see some interesting things:
-- Program Code --
:00404856 8D95F0FEFFFF lea edx, dword ptr [ebp+FFFFFEF0]
:0040485C 52 push edx
:0040485D E8BE7D0000 call 0040C620
:00404862 83C408 add esp, 00000008
* Possible StringData Ref from Data Obj ->"Star Wars: Episode I Racer\"
|
:00404865 68ACCC4200 push 0042CCAC
:0040486A 8D85F0FEFFFF lea eax, dword ptr [ebp+FFFFFEF0]
:00404870 50 push eax
:00404871 E8AA7D0000 call 0040C620
:00404876 83C408 add esp, 00000008
* Possible StringData Ref from Data Obj ->"v1.0"
|
:00404879 68C8CC4200 push 0042CCC8
:0040487E 8D8DF0FEFFFF lea ecx, dword ptr [ebp+FFFFFEF0]
:00404884 51 push ecx
:00404885 E8967D0000 call 0040C620
:0040488A 83C408 add esp, 00000008
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004048D5(U)
|
:0040488D 6A00 push 00000000 <-- Push a 0 on the stack
:0040488F E80F570000 call 00409FA3 <-- First call instruction before the CD request
:00404894 83C404 add esp, 00000004 <-- Fix stack due to push command
:00404897 85C0 test eax, eax <-- Test eax for value
:00404899 753C jne 004048D7 <-- Conditional jump before asking for the CD!!
:0040489B 6A01 push 00000001
* Possible StringData Ref from Data Obj ->"/LNCH073/Error"
|
:0040489D 68D0CC4200 push 0042CCD0
:004048A2 E844090000 call 004051EB
:004048A7 83C404 add esp, 00000004
:004048AA 50 push eax
* Possible StringData Ref from Data Obj ->"/LNCH099/Please insert the CD " <-- What got us here and why
->"into your CD-ROM player and try " <-- we're doing this
->"again."
|
:004048AB 68E0CC4200 push 0042CCE0
:004048B0 E836090000 call 004051EB
:004048B5 83C404 add esp, 00000004
:004048B8 50 push eax
:004048B9 6A00 push 00000000
* Reference To: USER32.MessageBoxA, Ord:01BEh <-- Post a windows pop-up message box
|
:004048BB FF1530344200 Call dword ptr [00423430]
:004048C1 89857CFDFFFF mov dword ptr [ebp+FFFFFD7C], eax
:004048C7 83BD7CFDFFFF02 cmp dword ptr [ebp+FFFFFD7C], 00000002
:004048CE 7505 jne 004048D5
:004048D0 E91E010000 jmp 004049F3 <-- Jump back up to the mystery call!!
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004048CE(C)
|
:004048D5 EBB6 jmp 0040488D
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00404899(C)
|
:004048D7 E831510000 call 00409A0D <-- We want to get at least this far
:004048DC 8985E4FDFFFF mov dword ptr [ebp+FFFFFDE4], eax
:004048E2 83BDE4FDFFFF04 cmp dword ptr [ebp+FFFFFDE4], 00000004
:004048E9 7F40 jg 0040492B
* Possible StringData Ref from Data Obj ->"/LNCH075/Star Wars: Episode I "
->"Racer"
|
:004048EB 6828CD4200 push 0042CD28
:004048F0 E8F6080000 call 004051EB
-- Continuing Program Code --
That's interesting to me, first you have a call then, the code tests eax for a zero value. If
eax is not zero the code jumps over asking for the CD! However, if eax is zero then up comes a windows
message box asking for the CD. Then the code checks to see your response and will either exit to windows
or loop back up to the mystery call! Well, let's take a closer look at that call and see what it's doing:
* Referenced by a CALL at Address:
|:0040488F <-- Only called once!
|
:00409FA3 55 push ebp
:00409FA4 8BEC mov ebp, esp
:00409FA6 81EC10040000 sub esp, 00000410
:00409FAC E82FFFFFFF call 00409EE0
:00409FB1 8885FCFEFFFF mov byte ptr [ebp+FFFFFEFC], al
:00409FB7 C685FDFEFFFF00 mov byte ptr [ebp+FFFFFEFD], 00
* Possible StringData Ref from Data Obj ->":\" <-- Pushes a pointer to ":\" as in "D:\"
|
:00409FBE 6814ED4200 push 0042ED14
:00409FC3 8D85FCFEFFFF lea eax, dword ptr [ebp+FFFFFEFC]
:00409FC9 50 push eax
:00409FCA E851260000 call 0040C620
:00409FCF 83C408 add esp, 00000008
:00409FD2 8D8DF4FCFFFF lea ecx, dword ptr [ebp+FFFFFCF4]
:00409FD8 51 push ecx
:00409FD9 E8CCFCFFFF call 00409CAA
:00409FDE 83C404 add esp, 00000004
:00409FE1 8D95FCFEFFFF lea edx, dword ptr [ebp+FFFFFEFC]
:00409FE7 52 push edx
:00409FE8 8D85F0FBFFFF lea eax, dword ptr [ebp+FFFFFBF0]
:00409FEE 50 push eax
:00409FEF E81C260000 call 0040C610
:00409FF4 83C408 add esp, 00000008
:00409FF7 8D8DF4FCFFFF lea ecx, dword ptr [ebp+FFFFFCF4]
:00409FFD 51 push ecx
:00409FFE 8D95F0FBFFFF lea edx, dword ptr [ebp+FFFFFBF0]
:0040A004 52 push edx
:0040A005 E816260000 call 0040C620
:0040A00A 83C408 add esp, 00000008
:0040A00D 8D85F0FBFFFF lea eax, dword ptr [ebp+FFFFFBF0]
:0040A013 50 push eax
:0040A014 E866FBFFFF call 00409B7F
:0040A019 83C404 add esp, 00000004
:0040A01C 85C0 test eax, eax
:0040A01E 745A je 0040A07A
:0040A020 837D0800 cmp dword ptr [ebp+08], 00000000
:0040A024 744D je 0040A073
:0040A026 6A00 push 00000000
:0040A028 6A00 push 00000000
:0040A02A 6A00 push 00000000
:0040A02C 6A00 push 00000000
:0040A02E 6A00 push 00000000
:0040A030 6804010000 push 00000104
:0040A035 8D8DF8FDFFFF lea ecx, dword ptr [ebp+FFFFFDF8]
:0040A03B 51 push ecx
:0040A03C 8D95FCFEFFFF lea edx, dword ptr [ebp+FFFFFEFC]
:0040A042 52 push edx
* Reference To: KERNEL32.GetVolumeInformationA, Ord:0177h <-- Get the volume name of the drive
|
:0040A043 FF1554324200 Call dword ptr [00423254]
:0040A049 85C0 test eax, eax
:0040A04B 7422 je 0040A06F
:0040A04D 8B4508 mov eax, dword ptr [ebp+08] <-- Pointer from getvolume call
:0040A050 50 push eax <-- Push it on the stack
:0040A051 8D8DF8FDFFFF lea ecx, dword ptr [ebp+FFFFFDF8] <-- Pointer to known volume name
:0040A057 51 push ecx <-- Push it on the stack
:0040A058 E803750000 call 00411560 <-- Compare the two
:0040A05D 83C408 add esp, 00000008
:0040A060 85C0 test eax, eax
:0040A062 7507 jne 0040A06B <-- eax=1 means no match
:0040A064 B801000000 mov eax, 00000001 <-- Set up for passed CD check
:0040A069 EB11 jmp 0040A07C <-- Jump to exit
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040A062(C)
|
:0040A06B 33C0 xor eax, eax <-- Failed volume comparison
:0040A06D EB0D jmp 0040A07C <-- Jump to exit
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040A04B(C)
|
:0040A06F 33C0 xor eax, eax <-- Had an error reading volume name
:0040A071 EB09 jmp 0040A07C <-- Jump to exit
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040A024(C)
|
:0040A073 B801000000 mov eax, 00000001 <-- Set up for a pass
:0040A078 EB02 jmp 0040A07C <-- Jump to exit
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040A01E(C)
|
:0040A07A 33C0 xor eax, eax <-- The CD check failed
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:0040A069(U), :0040A06D(U), :0040A071(U), :0040A078(U)
|
:0040A07C 8BE5 mov esp, ebp
:0040A07E 5D pop ebp
:0040A07F C3 ret <-- Return to the caller
Alright, very simple here, the code get's the volume name of the drive, does a compare if
everything works out, eax is loaded with 00000001 and it returns. If there is an error reading the
information or the volume doesn't match what it should, then eax is loaded with zero which means
the CD check failed. Well, armed with this information we can go back up to the code at 0040488F
and change the call instruction to mov eax, 00000001 this will force the jne at 00404899 to always
be taken. This patch allows racer.exe to function and bypasses the CD check. One down and one to
go, on to the next half of this quest:
To start we must now disassemble swep1rcr.exe and do the same trick as above. This time, when
scrolling down the ref box you'll come across "swep1rcr.exe" This is a good sign (when hunting down
CD checks) so double click it and you'll be in the middle of this routine:
* Referenced by a CALL at Addresses:
|:00423E70 , :00425456
|
:00425500 81EC8C030000 sub esp, 0000038C
:00425506 B93B000000 mov ecx, 0000003B
:0042550B 33C0 xor eax, eax
:0042550D 53 push ebx
:0042550E 55 push ebp
:0042550F 56 push esi
:00425510 57 push edi
:00425511 8DBC24AD010000 lea edi, dword ptr [esp+000001AD]
:00425518 F3 repz
:00425519 AB stosd
:0042551A 66AB stosw
:0042551C AA stosb
:0042551D A1E4794B00 mov eax, dword ptr [004B79E4]
:00425522 85C0 test eax, eax
:00425524 0F8467010000 je 00425691
:0042552A 8D442418 lea eax, dword ptr [esp+18]
:0042552E 50 push eax
* Possible StringData Ref from Data Obj ->"swep1rcr.exe" <-- What got us here
|
:0042552F 680C7F4B00 push 004B7F0C
* Reference To: VERSION.GetFileVersionInfoSizeA, Ord:0001h <-- Get info on this file
|
:00425534 E8DB910700 Call 0049E714
:00425539 8BF0 mov esi, eax
:0042553B 85F6 test esi, esi
:0042553D 0F84AE000000 je 004255F1
:00425543 56 push esi
:00425544 E8F79C0700 call 0049F240
:00425549 83C404 add esp, 00000004
:0042554C 8BD8 mov ebx, eax
:0042554E 53 push ebx
:0042554F 56 push esi
:00425550 6A00 push 00000000
* Possible StringData Ref from Data Obj ->"swep1rcr.exe"
|
:00425552 680C7F4B00 push 004B7F0C
* Reference To: VERSION.GetFileVersionInfoA, Ord:0000h <-- Get more info on this file
|
:00425557 E8B2910700 Call 0049E70E
:0042555C 85C0 test eax, eax
:0042555E 0F8484000000 je 004255E8
:00425564 8D4C2414 lea ecx, dword ptr [esp+14]
:00425568 8D542410 lea edx, dword ptr [esp+10]
:0042556C 51 push ecx
:0042556D 52 push edx
* Possible StringData Ref from Data Obj ->"\VarFileInfo\Translation"
|
:0042556E 68F07E4B00 push 004B7EF0
:00425573 53 push ebx
* Reference To: VERSION.VerQueryValueA, Ord:000Ah
|
:00425574 E88F910700 Call 0049E708
:00425579 85C0 test eax, eax
:0042557B 746B je 004255E8
:0042557D 8B442410 mov eax, dword ptr [esp+10]
:00425581 33C9 xor ecx, ecx
:00425583 33D2 xor edx, edx
:00425585 668B4802 mov cx, word ptr [eax+02]
:00425589 668B10 mov dx, word ptr [eax]
:0042558C 51 push ecx
:0042558D 52 push edx
:0042558E 8D8424A4020000 lea eax, dword ptr [esp+000002A4]
* Possible StringData Ref from Data Obj ->"\StringFileInfo\%04X%04X\FileVersion"
|
:00425595 68C87E4B00 push 004B7EC8
:0042559A 50 push eax
* Reference To: USER32.wsprintfA, Ord:0264h
|
:0042559B FF15D0C14A00 Call dword ptr [004AC1D0]
:004255A1 83C410 add esp, 00000010
:004255A4 8D4C2414 lea ecx, dword ptr [esp+14]
:004255A8 8D542410 lea edx, dword ptr [esp+10]
:004255AC 8D84249C020000 lea eax, dword ptr [esp+0000029C]
:004255B3 51 push ecx
:004255B4 52 push edx
:004255B5 50 push eax
:004255B6 53 push ebx
* Reference To: VERSION.VerQueryValueA, Ord:000Ah
|
:004255B7 E84C910700 Call 0049E708
:004255BC 85C0 test eax, eax
:004255BE 7428 je 004255E8
:004255C0 8B7C2410 mov edi, dword ptr [esp+10]
:004255C4 83C9FF or ecx, FFFFFFFF
:004255C7 33C0 xor eax, eax
:004255C9 8D94249C010000 lea edx, dword ptr [esp+0000019C]
:004255D0 F2 repnz
:004255D1 AE scasb
:004255D2 F7D1 not ecx
:004255D4 2BF9 sub edi, ecx
:004255D6 8BC1 mov eax, ecx
:004255D8 8BF7 mov esi, edi
:004255DA 8BFA mov edi, edx
:004255DC C1E902 shr ecx, 02
:004255DF F3 repz
:004255E0 A5 movsd
:004255E1 8BC8 mov ecx, eax
:004255E3 83E103 and ecx, 00000003
:004255E6 F3 repz
:004255E7 A4 movsb
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:0042555E(C), :0042557B(C), :004255BE(C)
|
:004255E8 53 push ebx
:004255E9 E8E29B0700 call 0049F1D0
:004255EE 83C404 add esp, 00000004
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0042553D(C)
|
:004255F1 689C554D00 push 004D559C
:004255F6 6A50 push 00000050
:004255F8 68C0F2E900 push 00E9F2C0
* Possible StringData Ref from Data Obj ->"CD Path" <-- Hint, hint....
|
:004255FD 68C07E4B00 push 004B7EC0
:00425602 E8A97C0700 call 0049D2B0
:00425607 83C410 add esp, 00000010
:0042560A 85C0 test eax, eax
:0042560C 7551 jne 0042565F
:0042560E 68C0F2E900 push 00E9F2C0
* Reference To: KERNEL32.GetDriveTypeA, Ord:00DFh <-- Commonly used call in CD checks
|
:00425613 FF15C4C04A00 Call dword ptr [004AC0C4]
:00425619 83F805 cmp eax, 00000005 <-- 05 is the value for CD Rom drives
:0042561C 7541 jne 0042565F <-- If not a CD the take this jump (failed)
* Possible StringData Ref from Data Obj ->".\data\config\default\"
|
:0042561E 68843E4B00 push 004B3E84
:00425623 68C0F2E900 push 00E9F2C0
:00425628 8D8C24A4000000 lea ecx, dword ptr [esp+000000A4]
* Possible StringData Ref from Data Obj ->"%s\Gnome\%swheel.map" <-- Check for this file
|
:0042562F 68A87E4B00 push 004B7EA8
:00425634 51 push ecx
:00425635 E816950700 call 0049EB50
:0042563A 83C410 add esp, 00000010
:0042563D 8D94249C000000 lea edx, dword ptr [esp+0000009C]
* Possible StringData Ref from Data Obj ->"w" <-- Write to the CD
|
:00425644 68A47E4B00 push 004B7EA4
:00425649 52 push edx
:0042564A E8619B0700 call 0049F1B0
:0042564F 83C408 add esp, 00000008
:00425652 85C0 test eax, eax
:00425654 745A je 004256B0 <-- Take this to continue with intro
:00425656 50 push eax
:00425657 E8649A0700 call 0049F0C0
:0042565C 83C404 add esp, 00000004
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:0042560C(C), :0042561C(C)
|
:0042565F A16CB55000 mov eax, dword ptr [0050B56C]
:00425664 6A10 push 00000010
* Possible StringData Ref from Data Obj ->"BAD INSTALL"
|
:00425666 68987E4B00 push 004B7E98
* Possible StringData Ref from Data Obj ->"Error: Please reinstall program " <-- Something we don't ever
->"from CD-ROM." <-- want to see!
|
:0042566B 68447E4B00 push 004B7E44
:00425670 50 push eax
* Reference To: USER32.MessageBoxA, Ord:0195h
|
:00425671 FF15E0C14A00 Call dword ptr [004AC1E0]
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004257D0(C)
|
:00425677 E854EAFFFF call 004240D0
:0042567C 6A00 push 00000000
:0042567E E88D930700 call 0049EA10
:00425683 83C404 add esp, 00000004
:00425686 5F pop edi
:00425687 5E pop esi
:00425688 5D pop ebp
:00425689 5B pop ebx
:0042568A 81C48C030000 add esp, 0000038C
:00425690 C3 ret <-- Return to the caller
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00425524(C)
|
:00425691 689C554D00 push 004D559C
:00425696 68C0F2E900 push 00E9F2C0
:0042569B E8B0940700 call 0049EB50
:004256A0 83C408 add esp, 00000008
:004256A3 33C0 xor eax, eax
:004256A5 5F pop edi
:004256A6 5E pop esi
:004256A7 5D pop ebp
:004256A8 5B pop ebx
:004256A9 81C48C030000 add esp, 0000038C
:004256AF C3 ret <-- Return to the caller
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00425654(C) <-- Got via conditional jump from above
|
* Possible StringData Ref from Data Obj ->"100_0" <-- Partial volume name of the CD
|
:004256B0 683C7E4B00 push 004B7E3C
:004256B5 8D442420 lea eax, dword ptr [esp+20]
* Possible StringData Ref from Data Obj ->"racer%s"
|
:004256B9 68347E4B00 push 004B7E34
:004256BE 50 push eax
:004256BF E88C940700 call 0049EB50
* Reference To: KERNEL32.GetVolumeInformationA, Ord:014Fh <-- Get the volume of the disk
|
:004256C4 8B2DC8C04A00 mov ebp, dword ptr [004AC0C8]
* Reference To: USER32.MessageBoxA, Ord:0195h
|
:004256CA 8B1DE0C14A00 mov ebx, dword ptr [004AC1E0]
:004256D0 83C40C add esp, 0000000C
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004257D6(U)
|
:004256D3 6A00 push 00000000
:004256D5 6A00 push 00000000
:004256D7 6A00 push 00000000
:004256D9 6A00 push 00000000
:004256DB 6A00 push 00000000
:004256DD 8D8C2430010000 lea ecx, dword ptr [esp+00000130]
:004256E4 6880000000 push 00000080
:004256E9 51 push ecx
:004256EA 68C0F2E900 push 00E9F2C0
:004256EF FFD5 call ebp
:004256F1 85C0 test eax, eax
:004256F3 0F849C000000 je 00425795
:004256F9 8D7C241C lea edi, dword ptr [esp+1C]
:004256FD 83C9FF or ecx, FFFFFFFF
:00425700 33C0 xor eax, eax
:00425702 8D54241C lea edx, dword ptr [esp+1C]
:00425706 F2 repnz
:00425707 AE scasb
:00425708 F7D1 not ecx
:0042570A 83C1FE add ecx, FFFFFFFE
:0042570D 8D84241C010000 lea eax, dword ptr [esp+0000011C]
:00425714 51 push ecx
:00425715 52 push edx
:00425716 50 push eax
:00425717 E8B4980700 call 0049EFD0
:0042571C 83C40C add esp, 0000000C
:0042571F 85C0 test eax, eax
:00425721 7578 jne 0042579B
* Possible StringData Ref from Data Obj ->".\data\config\default\" <-- Partial path from the CD
|
:00425723 68843E4B00 push 004B3E84
:00425728 68C0F2E900 push 00E9F2C0
:0042572D 8D8C24A4000000 lea ecx, dword ptr [esp+000000A4]
* Possible StringData Ref from Data Obj ->"%s\Gnome\%swheel.map"
|
:00425734 68A87E4B00 push 004B7EA8
:00425739 51 push ecx
:0042573A E811940700 call 0049EB50
:0042573F 83C410 add esp, 00000010
:00425742 8D94249C010000 lea edx, dword ptr [esp+0000019C]
* Possible StringData Ref from Data Obj ->"\Gnome\Data\Anims\PlanetG.znm" <-- The animation file to play
|
:00425749 68147E4B00 push 004B7E14
:0042574E 68C0F2E900 push 00E9F2C0
* Possible StringData Ref from Data Obj ->"%s%s"
|
:00425753 6824254B00 push 004B2524
:00425758 52 push edx
:00425759 E8F2930700 call 0049EB50
:0042575E 83C410 add esp, 00000010
:00425761 8D84249C010000 lea eax, dword ptr [esp+0000019C]
:00425768 6A00 push 00000000
:0042576A 50 push eax
:0042576B E8F0AD0700 call 004A0560
:00425770 8BF0 mov esi, eax
:00425772 83C408 add esp, 00000008
:00425775 83FEFF cmp esi, FFFFFFFF
:00425778 7421 je 0042579B
:0042577A 56 push esi
:0042577B E830AD0700 call 004A04B0
:00425780 83C404 add esp, 00000004
:00425783 3DE7141201 cmp eax, 011214E7
:00425788 56 push esi
:00425789 7450 je 004257DB <-- Need to take this jump to continue on
:0042578B E820AC0700 call 004A03B0
:00425790 83C404 add esp, 00000004
:00425793 EB06 jmp 0042579B
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004256F3(C)
|
* Reference To: KERNEL32.GetLastError, Ord:00F4h
|
:00425795 FF15C0C04A00 Call dword ptr [004AC0C0]
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:00425721(C), :00425778(C), :00425793(U)
|
:0042579B 8D4C241C lea ecx, dword ptr [esp+1C]
:0042579F 8D94249C020000 lea edx, dword ptr [esp+0000029C]
:004257A6 51 push ecx
* Possible StringData Ref from Data Obj ->"Error: Please insert CD-ROM '%s' " <-- Not something we would
->"into drive." <-- ever want to see!
|
:004257A7 68B07D4B00 push 004B7DB0
:004257AC 52 push edx
:004257AD E89E930700 call 0049EB50
:004257B2 8B0D6CB55000 mov ecx, dword ptr [0050B56C]
:004257B8 83C40C add esp, 0000000C
:004257BB 8D84249C020000 lea eax, dword ptr [esp+0000029C]
:004257C2 6A31 push 00000031
* Possible StringData Ref from Data Obj ->"CD ERROR" <-- Says it all right here
|
:004257C4 68A47D4B00 push 004B7DA4
:004257C9 50 push eax
:004257CA 51 push ecx
:004257CB FFD3 call ebx
:004257CD 83F802 cmp eax, 00000002
:004257D0 0F84A1FEFFFF je 00425677
:004257D6 E9F8FEFFFF jmp 004256D3
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00425789(C)
|
:004257DB E8D0AB0700 call 004A03B0
* Possible StringData Ref from Data Obj ->"\Gnome\" <-- Partial path from the CD
|
:004257E0 BF9C7D4B00 mov edi, 004B7D9C
:004257E5 83C9FF or ecx, FFFFFFFF
:004257E8 33C0 xor eax, eax
:004257EA 83C404 add esp, 00000004
:004257ED F2 repnz
:004257EE AE scasb
:004257EF F7D1 not ecx
:004257F1 2BF9 sub edi, ecx
:004257F3 8BF7 mov esi, edi
:004257F5 8BD1 mov edx, ecx
:004257F7 BFC0F2E900 mov edi, 00E9F2C0
:004257FC 83C9FF or ecx, FFFFFFFF
:004257FF F2 repnz
:00425800 AE scasb
:00425801 8BCA mov ecx, edx
:00425803 4F dec edi
:00425804 C1E902 shr ecx, 02
:00425807 F3 repz
:00425808 A5 movsd
:00425809 8BCA mov ecx, edx
:0042580B 83E103 and ecx, 00000003
:0042580E F3 repz
:0042580F A4 movsb
:00425810 5F pop edi
:00425811 5E pop esi
:00425812 5D pop ebp
:00425813 5B pop ebx
:00425814 81C48C030000 add esp, 0000038C
:0042581A C3 ret <-- Return to the caller
This routine, as long as it is, doesn't return any special value in eax so if you replace the
first instruction with a ret (C3) the CD check is effectively bypassed. Now that the CD checks in both
exe files have been disabled or bypassed, it's time to address another problem with the game.
The other problem with this game is: All the music files and all of the animation files are
stored on the CD rom. I can live without the all cut scenes, but I like the music. So I tracked down
the routine that plays the animations and FiX'ed it so the game would skip them. To do this you'll need
to go back to the refs box and look for a string that has something to do with the animation roiutnes
like "\Data\Anims" If you double click on it you'll be in the middle of the routine that plays the
animation files for the game. I will not show this routine as it's simply too long and would provide
little if any knowlegde. However, starting with the ref, search backwards until you find the start of
the routine. You will eventually see that this LONG routine starts at 4252A0 and is called from four
other locations. If you trace it to the end, you'll see like the CD check this routine doesn't return
any special value either. Replacing the first instruction with a ret code (C3) will disable all the
animations. Then if you copy the music directory to your hard drive the game will play just fine and
will no longer require you to have the CD online. That is of course, the whole reason behind our
efforts and this tutorial. The actual steps to crack Star Wars Episode 1 Racer are:
1. Install the game
2. Copy the "\Music" directory
(from "CD":\Gnome\Data\wavs\ to your install directory in Data\wavs\)
3. Copy the "\Anims" directory <-- Skip if you want to kill anims anyways
(from "CD":\Gnome\Data\ to your install directory in Data\)
4. Make the following edits to the following files:
Edit Racer.exe
=============================================
Search for: E8 0F 57 00 00 at offset 18,575
Change to : B8 01 00 00 00
Edit swep1rcr.exe
=============================================
Search for: 81 EC 8C 03 00 at offset 149,760
Change to : C3 -- -- -- --
- Optional: Kill the animation sequences:
Search for: 81 EC 0C 01 00 at offset 149,152
Change to : C3 -- -- -- --
For the French version: Edit Racer.exe
=============================================
Search for: E8 79 57 00 00 at offset 18,725
Change to : B8 01 00 00 00
Edit swep1rcr.exe
=============================================
Search for: 81 EC 8C 03 00 at offset 153,216
Change to : C3 -- -- -- --
- Optional: Kill the animation sequences:
Search for: 81 EC 0C 01 00 at offset 152,608
Change to : C3 -- -- -- --
5. Enjoy the game, graphics and races.
-
How to crack "The Neverhood" CD-Check
Welcome to yet another tutorial by me! I have just recently got this oldie (it was released
in 1996!), because I wanted to play it. The problem was that I had to return this game
to the friend who gave it to me after 1 day, and I don't have a burner. So I figured I will
try and rip it, so it could stay as long as I want it on my computer!
First I installed the game. Installation only requires 5 megs of your Hard disk, because
all the movies are in the CD. After you install the game, remove the CD from the drive,
and click on NHC.exe. You get that message "Error Reading CDROM". Disassemble the file
and look for the string ref's in Win32Dasm. After you found it, you'll notice that that
messagebox is not really helpfull, since you can't get to the real CD-Check. That's
what I figured out when I first tried.
It might sound odd, but the saved games are saved inside the registry. You can figure that
out by looking in the string ref's. Go to the registry and look for the installation path:
HKEY_LOCAL_MACHINE\Software\DreamWorks Interactive\Neverhood
You'll see this kind of data:
Data Drive=D:\
PID=54767-442-5719094-59095
Installed Directory=C:\Program Files\DreamWorks Interactive\Neverhood
Run File"=C:\Program Files\DreamWorks Interactive\Neverhood\NHC
KBPS_CD=00002800
KBPS=00002800
Installed=00000001
After you see this, you ought to understand what to do!
all you have to do, is simply change the "Data Drive" value into ".".
Why? Because the app is looking for 'D:\' which is my CD-Rom drive.
If you change that value to '.' it will simply look for the data in the current directory
where the HNC.exe file is located. But you cannot really play unless you copy the entire
Data directory from within the CD-Rom (over 600 megs).
In order to completely finish this crack, you'll have to create a RegPatch file (a .reg
file). This is how it should look like:
<----- Begin RegSetup.reg ------->
REGEDIT4
[HKEY_LOCAL_MACHINE\Software\DreamWorks Interactive\Neverhood]
"Data Drive"="."
<----- End RegSetup.reg ------->
Pretty simple isn't it?
BTW, Neverhood is one of the most enjoyable games I have ever played!
Have fun... :)
-
I would like to say a few words at the start of this file as I feel that it is necessary to do so
Over the last year or so I have been looking at Fravia+'s site, and thinking that it was good thing that somebody has taken the effort to tutor the new generation.
I started taking other peoples code apart in 1983, yet I have been retired for around five/six years... Why did I decide to return ?
Well I think this will be a bit of a one off to be honest.
There seems to be a shortage of good information on reversing CD based protection systems, I don't know if this counts as good information but it may help somebody.
After checking out Fravia+'s site every once in a while I thought I should add a tutorial, to give something back for the pleasure I have had from reading some of the essays.
During the summer I finally moved on from my old 486 to a decent spec system, and also got myself a CD-R.
Well after playing about with it for a while, I started to look into what the best mastering software was, and found the CD-R discussion forum at , where everybody had been complaining about how they couldn't copy certain games.
Well amongst the usual no brain postings there where a few interesting reports, such as about CDs over 75 minutes, illegal Table of Contents and large files on disk.
Whenever you saw a patch listed it seemed that the inhabitants of the message board, thought of the author as some sort of supernatural creature.
The reality is that our brains are wired a little differently, to everybody else.
Most of the protection schemes have the following simple structure:
Is the drive a CD ?
Does a file exist ?
Can that drive be written to ?
That's about it, a bit lame really, perhaps even hiding this inside a DLL, if they are in an ugly mood.
Well considering I wanted Thief (I collect as much as I can afford by ex Infocom staff), and Eidos used what looked like a "mean" protection system. I bought Thief.
Well... it was quite a disappointment to tell the truth (not the game, I may add it puts a whole new spin on the Doom/Quake genre, but the protection itself).
The protection system used for Thief relies upon :
1: More than 75 mins of data on the CD
2: An invalid TOC, Data, Audio, Audio, Data
3: Four Fake files on the first data track, each of approx. 515 MB, KXEP.AFP, AZXP.AFP, TFJB.AFP & IGYQ.AFP.
4: Mixed case in the CD Volume name.
Anyway the Eidos TOC is only to make a straight copy difficult, as the two audio tracks aren't used at all and the other tracks isn't even checked for.
This is real dumb as all the necessary functions are there in MSCDEX.
Without these three tracks, 74 minutes is more than enough to hold the real data track.
The four fake .AFP files are not used properly within the protection system, although they deter casual copying, there is a 4KB block loaded, and I think they even check it's the correct data, it is not necessary for the program to actually run.
Obviously it would have been easy enough to copy each of the 4096 byte blocks to separate files and simply seek to offset 0 (rather than 696406016, 496444928, 696514560 or 696346624, as actually used), and then read the 4096 bytes each time, but it would have slowed me down.
To be honest it did slow me down because I was convinced that they would not be so stupid and lazy not to use this data (I was wrong).
I don't even think they check for the mixed case in the CD volume label.
Tools used:
Filemon, W32Dasm and hiew
Using filemon, I watched as thief.exe opened each of these hidden .AFP files where opened and a seek was carried out to around 696496016 bytes into the file, 4096 bytes read and then the file closed.
This occurred for each of the .AFP files, with various (but similar seek values).
After that I cut a CD with all the files except the .AFP fakes, and as the software I was using wouldn't allow me to use mixed case volume labels
I used W32Dasm to disassemble thief.exe.
I searched for .AFP and found that one large subroutine was used to open them, this made life easier.
The routine was at 00526100 through to 526274 and was called from 3 addresses, all within a 4KB region of RAM.
Then I searched for GetDriveTypeA which lives between 0050d720 to 0050d735
It called from 0050d773 and 0050da5e
The call to 0050d773 is placed within a routine (between 0050d740 to 0050d78f)
Appeared to be reserved for scanning through drives D: to Z; looking for CD drives.
Not very interesting
The call from 0050da5e looked much more interesting as it seemed to test the return value of GetDriveTypeA.
Six instructions after this call to GetDriveTypeA was a call to 00526100 the .AFP read routine.
A few instructions further on a second call to the .AFP routine took place and some testing of eax the routine did a ret
This routine is called from 0050dadc
The other call to the .AFP read appears to trace back to 0050dad5
This was the region that the tests on the invisible .AFP files are called from
This means that the all AFP reads and protection checks take place from an area separated by 2 bytes.
Just like this
:0050DAD5 E8E6FEFFFF call 0050D9C0 ; First Call
:0050DADA EB05 jmp 0050DAE1
:0050DADC E82FFFFFFF call 0050DA10; Second and third calls
To quote Homer Simpson DOH!
The Subroutine this is in looks just like this
* Referenced by a CALL at Address:00414FCC
:0050DAC0 6A00 push 00000000
:0050DAC2 6A00 push 00000000
* Possible StringData Ref from Data Obj ->"only_check_path"
:0050DAC4 68E0BF6000 push 0060BFE0
:0050DAC9 E862AF0300 call 00548A30
:0050DACE 83C40C add esp, 0000000C
:0050DAD1 84C0 test al, al
:0050DAD3 7507 jne 0050DADC
:0050DAD5 E8E6FEFFFF call 0050D9C0
:0050DADA EB05 jmp 0050DAE1
* Referenced by a Jump at Address:0050DAD3(C)
:0050DADC E82FFFFFFF call 0050DA10
* Referenced by a Jump at Address: 0050DADA(U)
:0050DAE1 85C0 test eax, eax
:0050DAE3 7405 je 0050DAEA
:0050DAE5 E986FBFFFF jmp 0050D670
* Referenced by a Jump at Address: 0050DAE3(C)
:0050DAEA 33C0 xor eax, eax
:0050DAEC C3 ret
Well doesn't :00414FCC look a bit out of place in all this, and just look at this
:0050DAC0 6A00 push 00000000
:0050DAC2 6A00 push 00000000
Looks like some .OBJ code has been linked, and they wanted to make sure of some free space on the stack.
Well if we look at 00414FCC, we could nop the call and see what happens.
But I wont.
Why ?
Well assuming that the protection code called is not written by Looking Glass (the authors of Thief), as all the Eidos stuff on release, has similar (if not the same) protection.
They won't check the internal code of the protection routines.
However they may check their own code, including the call to the disk protection.
So rather than using four NOPs to delete the call 0050DAC0, I chose to add a RET (C3) at 0050DAC0, that way all the code by Looking Glass is totally intact.
So fire up a hex editor and search for
6A,00,6A,00,68,E0,BF,60,00
Change the (first) 6A to C3, it is the only occurrence of these hex values, and write the data back to disk.
The file offset is 10CEC0, (if you are using hiew then it is 50DAC0, in the other offset mode)
-
Thief v1.14 - CD crack by R!SC - 10/01/99
REQUIREMENTS:
Hex editor
W32Dasm 8.93 !
Do a full install, remove the CD, run the game. You get a standard messagebox asking you to
insert the CD. "Missing CD"-"Please insert the CD into the CD Drive"
First off, make a copy of thief.exe, load this into W32Dasm. We begin by looking through the
string references for one of our messages. Heh, I didnt find any ref's! So we take a different
approach. Look through the imported functions for a reference to KERNEL32.GetDriveTypeA
(commonly used in CD checks(as you remember!)). Double click on the reference several times,
looking at the code every time you click it. GetDriveTypeA returns a value in eax between 0 &
6, we are only intrested in the code that checks eax for a '5'. There is only one reference
that does this.
* Referenced by a CALL at Addresses:
|:0050D773 , :0050DA5E <-- Trace the call back by double right clicking these (hit F12 to return)
|
:0050D720 8B442404 mov eax, dword ptr [esp+04]
:0050D724 50 push eax <-- Points to a null-terminated string that specifies
- the root directory of the disk to return information about.
* Reference To: KERNEL32.GetDriveTypeA, Ord:00DFh - this mean 'C:\',0 or whatever drive letter the caller might be on...
|
:0050D725 FF1528315B00 Call dword ptr [005B3128]
:0050D72B 33C9 xor ecx, ecx <-- zero ecx (ecx=32bit reg, cx=16bit reg, cl=low 8bits of cx)
:0050D72D 83F805 cmp eax, 00000005 <-- checking for a CD-ROM
:0050D730 0F94C1 sete cl <-- sets the byte in cl to a '01' if eax=5
:0050D733 8BC1 mov eax, ecx <-- copies ecx into eax (what the last command did or didnt set)
:0050D735 C3 ret <-- Return to caller
Normally, in most cases I have seen, when there's a call to a CD check, there is normally a test
and a conditional jump afterwards, the protection can be bypassed by either forcing the jump, or
not taking the call at all. So I wanted to trace this code back to the original caller. Using
WDasm 8.93! like I stated at the top, double right click the first caller '50D773'. This code is
right beneath the call to GetDriveTypeA.
* Referenced by a CALL at Addresses:
|:0050D7FA , :0050D84D
|
:0050D740 8B442404 mov eax, dword ptr [esp+04]
:0050D744 53 push ebx
:0050D745 85C0 test eax, eax
:0050D747 B341 mov bl, 41 <-- 'A'
:0050D749 7444 je 0050D78F
:0050D74B 8B4C240C mov ecx, dword ptr [esp+0C]
:0050D74F 85C9 test ecx, ecx
:0050D751 7410 je 0050D763
:0050D753 0FBE00 movsx eax, byte ptr [eax]
:0050D756 50 push eax
:0050D757 E8D4EF0800 call 0059C730
:0050D75C 8BD8 mov ebx, eax
:0050D75E 83C404 add esp, 00000004
:0050D761 FEC3 inc bl <-- go onto the next drive letter...
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0050D751(C)
|
:0050D763 80FB5A cmp bl, 5A <-- 'Z'
:0050D766 7F27 jg 0050D78F - simple routine to clear eax and ret
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0050D784(C) <-- referenced to by itself
|
* Possible StringData Ref from Data Obj ->"D:\"
|
:0050D768 6808BF6000 push 0060BF08 <-- pushes the drive letter were on
:0050D76D 881D08BF6000 mov byte ptr [0060BF08], bl <-- stores the next letter to check
:0050D773 E8A8FFFFFF call 0050D720 <-- call to GetDriveTypeA Subroutine that brought us here
:0050D778 83C404 add esp, 00000004 - return a 01 in eax if weve got a CD-ROM
:0050D77B 85C0 test eax, eax
:0050D77D 7509 jne 0050D788 <-- if eax in not equal(to 0) jump!
:0050D77F FEC3 inc bl <-- increase the letter
:0050D781 80FB5A cmp bl, 5A <-- compare it with 'Z'
:0050D784 7EE2 jle 0050D768 <-- loop until we found a CD-ROM
:0050D786 5B pop ebx - or ran out of drive letters
:0050D787 C3 ret
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0050D77D(C)
|
* Possible StringData Ref from Data Obj ->"D:\"
|
:0050D788 B808BF6000 mov eax, 0060BF08 <-- exit with the Drive letter of CD-Drive in eax
:0050D78D 5B pop ebx
:0050D78E C3 ret
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:0050D749(C), :0050D766(C)
|
:0050D78F 33C0 xor eax, eax
:0050D791 5B pop ebx
:0050D792 C3 ret
This code starts with drive letter 'A' and calls our previous subroutine to determine if were
looking at a CD-ROM, if not it increases the letter and checks again. Anyway trace this back to
one of its callers. Double right click '50D7FA'
* Referenced by a CALL at Addresses:
|:0050D9CA , :0050D9E1 <-- the original callers to this routine (trace these back)
|
:0050D7A0 81EC04010000 sub esp, 00000104
:0050D7A6 8D442400 lea eax, dword ptr [esp]
:0050D7AA 53 push ebx
:0050D7AB 56 push esi
:0050D7AC 57 push edi
:0050D7AD 6804010000 push 00000104
:0050D7B2 50 push eax
* Possible StringData Ref from Data Obj ->"cd_path"
|
:0050D7B3 68C0BF6000 push 0060BFC0
:0050D7B8 33DB xor ebx, ebx
:0050D7BA E871B20300 call 00548A30
:0050D7BF 83C40C add esp, 0000000C
:0050D7C2 84C0 test al, al
:0050D7C4 7528 jne 0050D7EE <-- this jne
:0050D7C6 BF18516700 mov edi, 00675118
:0050D7CB 83C9FF or ecx, FFFFFFFF
:0050D7CE 33C0 xor eax, eax
:0050D7D0 8D54240C lea edx, dword ptr [esp+0C]
:0050D7D4 F2 repnz
:0050D7D5 AE scasb
:0050D7D6 F7D1 not ecx
:0050D7D8 2BF9 sub edi, ecx
:0050D7DA 8BC1 mov eax, ecx
:0050D7DC 8BF7 mov esi, edi
:0050D7DE 8BFA mov edi, edx
:0050D7E0 C1E902 shr ecx, 02
:0050D7E3 F3 repz
:0050D7E4 A5 movsd
:0050D7E5 8BC8 mov ecx, eax
:0050D7E7 83E103 and ecx, 00000003
:0050D7EA F3 repz
:0050D7EB A4 movsb
:0050D7EC EB05 jmp 0050D7F3 <-- this jmp
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0050D7C4(C) <-- ref by same routine, the jne up there
|
:0050D7EE BB01000000 mov ebx, 00000001
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0050D7EC(U) <-- ref by same routine, the jmp just up there.
|
:0050D7F3 8D4C240C lea ecx, dword ptr [esp+0C]
:0050D7F7 6A00 push 00000000
:0050D7F9 51 push ecx
:0050D7FA E841FFFFFF call 0050D740 <-- Call that we traced back
:0050D7FF 83C408 add esp, 00000008
:0050D802 A314516700 mov dword ptr [00675114], eax <-- save varible in eax
:0050D807 85C0 test eax, eax <-- check return value of previous call
:0050D809 746B je 0050D876 <-- if it was zero we never found a CD-Drive
Weve not get to the original caller to the CD-Check routine yet, so lets carry on tracing back.
Double right click '50D9CA' at the top of this code.
* Referenced by a CALL at Address:
|:0050DAD5 <-- only one caller this time ;)
|
:0050D9C0 C7051451670000000000 mov dword ptr [00675114], 00000000
:0050D9CA E8D1FDFFFF call 0050D7A0 <-- Call that we just traced back
:0050D9CF 85C0 test eax, eax <-- check return value
:0050D9D1 7517 jne 0050D9EA
Goddamn it. Still not there yet, trace this back.
* Referenced by a CALL at Address:
|:00414FCC <-- YIPPEE! only one caller and the code is located faraway near the start of the executable
|
:0050DAC0 6A00 push 00000000
:0050DAC2 6A00 push 00000000
* Possible StringData Ref from Data Obj ->"only_check_path"
|
:0050DAC4 68E0BF6000 push 0060BFE0
:0050DAC9 E862AF0300 call 00548A30
:0050DACE 83C40C add esp, 0000000C
:0050DAD1 84C0 test al, al
:0050DAD3 7507 jne 0050DADC
:0050DAD5 E8E6FEFFFF call 0050D9C0 <-- call we traced back
:0050DADA EB05 jmp 0050DAE1
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0050DAD3(C)
|
:0050DADC E82FFFFFFF call 0050DA10 <-- see 'ps' at the bottom of the file
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0050DADA(U)
|
:0050DAE1 85C0 test eax, eax
:0050DAE3 7405 je 0050DAEA
:0050DAE5 E986FBFFFF jmp 0050D670
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0050DAE3(C)
|
:0050DAEA 33C0 xor eax, eax
:0050DAEC C3 ret
OK, Trace this back to 414FCC, I think weve found what weve been looking for at last..
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:00414F9B(C), :00414FBF(C)
|
:00414FCC E8EF8A0F00 call 0050DAC0 <-- A CALL
:00414FD1 85C0 test eax, eax <-- A TEST
:00414FD3 750B jne 00414FE0 <-- A CONDITIONAL JUMP
:00414FD5 50 push eax - jump if eax not equal zero
:00414FD6 6A01 push 00000001
:00414FD8 E8337B1100 call 0052CB10 <-- This traces to a call to Terminate Process
:00414FDD 83C408 add esp, 00000008 -- Which is very BAD
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00414FD3(C)
|
:00414FE0 E8EB020000 call 004152D0
:00414FE5 8D542440 lea edx, dword ptr [esp+40]
:00414FE9 C744244003000000 mov [esp+40], 00000003
:00414FF1 52 push edx
:00414FF2 6A01 push 00000001
OK, I(we) traced all those calls back to this one call at the start of the file, theres a
call, a test and a conditional jump. I first decided to force the jne by changing it to a jmp.
Saved my change to the code, and ran the game. Shit, it still asks for the CD, I clicked
cancel, then the bloody thing loaded into the game! OK, the message box is somewhere deep
inside of the CD-check routine. I decided to kill the call to the routine instead, so the CD is
never checked, the message box will never be shown, and the game will work? Highlight the call
to the check ':00414FCC E8EF8A0F00 call 0050DAC0' Write down the offset at the
bottom of the screen, probably 0143CC, hexedit thief.exe goto 143CC and change the E8 to a B8.
Save and run the game, it works fine now without needing the CD.
Another tutorial comes to an end and another game has been FiX'ed!
happy cracking love R!SC --
[ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
PS. If you trace back the second caller to GetDriveTypeA (0050DA5E), scroll up a bit, this is
referenced by a call at 50DADC, trace this back to routine, this one is referenced by 414FCC ;)
three easy steps to get there, you should always follow all the routes possible and check them
out, it pays off!
for v1.14 - edit thief.exe at offset 143CC (hex)
================================================== =========
Search for: E8 EF 8A 0F 00 call 0050DAC0
Change to : B8 -- -- -- -- mov eax, 000F8AEF (which is not 0, so the jne is always taken)
I borrowed these off someone else and included them here. (win32api.txt)
GetDriveType Return Function codes: (Donated by: +-=Riddler=-+)
Value Meaning
0 Drive Cannot Be determined
1 Root Dir Does not exist
2 DriveRemoveable
3 A Fixed Disk (HardDrive)
4 Remote Drive(Network)
5 Cd-Rom Drive <-- Game crackers only intrested if return code is 05!
6 RamDisk
-
Cracking the Mystique Patch for Tombraider.
Target: Matrox Mystique patch for tombraider.
Tools Used:
Softice 3.2 (Get it! The video card support is 100 times better!)
Wdasm 8.9 (Find the registered version on the web!)
FileMonitor
Well, a friend of mine just got Tombraider on warez, but then needed
the Matrox Mystique video patch cracking for his video card.
I thought this would be a perfect opportunity for me to try some
DOS4GW cracking, and to see what a cd-rom protection was like.
First of all, I ran FileMon, whilst I ran Tombraider.
I noticed that it searched all drives(from a to z) for
"\data\title.phd", obviously a CD-file.
It couldn't find it, so I used subst
eg: subst j: d:\games\tomb
Now I ran it again, and it succesfully found title.phd on the faked j drive
Then the target tries creating a file in the root directory of the drive
where it found the file on (in my case j:).
I then tried to use fakecd, but for some reason this program allows
file writes (or atleast it did on my system...) so it did not behave like
a read-only media (a CD-Rom) would have done...
Ok, I now had a theory about what to crack, but no idea about how to
crack it (I have never cracked a DOS4GW program before).
I wasn't sure if Dos files could be disassembled using Wdasm, but I
gave it a try and it seemed to work.
In the dead listing of tomb.exe, there are only 3 interrupt 21's that
have ah=3d (open file)
I wrote down the op codes for these instructions, and then loaded
tombraider once more.
When the initial DOS4GW screen appeared, I pressed ctrl D, and
then did a search for the byte-codes of my three interrupts.
Once found, I then set a bpx on them, and let the program run once
more.
Only one of them ever seems to be executed, and that is the one at
82E1BAAD
Ok, So when it searches for its CD-file "title.phd" , this file must be
found successfully, yet when it searches for the random file, this must
NOT be found, and yet they both use the same code?
What's happening here?
Obviously the code at 82E1BAAD returns a value, and the value is
checked further up the code tree.
So both times (when it expects a "good" open file, and when it
expects a "bad" open file), I repeatedly press F12, to go back up the
call tree, and wrote down the values as I went...
Good. Expects file to be opened successfully.
82E1BAAD, is called by
82E0FFFA, is called by
82E10079, is called by
82E1008E, is called by
82DE35A4
Bad. Expects file to NOT be opened successfully
82E1BAAD, is called by
8EE0FFFA, is called by
82E10079, is called by
82E1008E, is called by
82DE3624
Ahh, we have found some code that differ!
The code at 82DE35A4 and the code at 82DE3624
look like this...
call 82E1008E
test eax,eax
jz ....
Ok, this means that after each call, it checks for eax=FALSE.
Eax will be = 0 when the file could NOT be created or opened
successfully. 5which happens when you write on a CD-Rom,
a very simple way to check if the media is a CD, btw).
We want to fool the program into thinking that the file was not
created, like it would have happened on a "REAL" CD.
Thus we can just change
7410 jz ...
to
EB10 jmp ...
But if we were to do that, every time we ran tombraider, we would
have a new random "checkCD" file added by our target to the tomb
directory, not very elegant...
Why?
Because we don't allow the program to delete the file afterwards!
Here is the code that checks for the valid file:
624: E85DCA0200 CALL 086 //Try to Open file
629: 85C0 TEST EAX,EAX //File Opened successfully?
62B: 7410 JZ 63D
//This is only called when cd-rom is "writable"
//This happens when eax=1
62D: E826CD0200 CALL 358 <Maybe delete file?
632: 89D8 MOV EAX, EBX
634: E8CFD00200 CALL 708 <Maybe close file handle?
639: 31C0 XOR EAX, EAX <Set bad flag
63B: EB05 JMP 642 <Jump to end
//This is jumped to when the file could not be written to
//This happens when eax=0
63D: B801000000 MOV EAX, 1 < Set "good" flag
642: 83C410 ADD ESP, 10
645: 5A POP EDX
646: 5B POP EBX
647: C3 RET
So, what do the calls at 62d and 634 do? Who cares? They are
evidently used to clean up the file, so we may as well use them
ourselves.
The easiest way to change this is to nop out the jmp at 63b, so
that it will fall through to 63D, and always set our good flag.
Therefore change
63B: EB05 JMP 642
to
63B: 31C0 XOR EAX, EAX ;ax is zero! Who cares?
;will be set true in the
;next instruction!
And it works!
Is this all? I wasn't sure, but it anyway no longer said "please
insert tomb raider cd" at the start of the program, and there
wasn't any files left in the tomb directory either... clean
crack!
-
Today , we will speak about CD check on Tomb3 !!! (editor said : good protected ..)
This game is protected against copy because there is 4 files of 600 Mo !
4*600= 2400Mo !
A CD-R isn't greater then 650 Mo so , it is impossible but there is a problem !
the original CD of Tom3 contains 3Go !!!
like nothing is impossible , i will explain u how to copy it and how to crack it !!!
[ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
About the protection...
A Stupid Cd check with check of files ....
[ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
The Essay...
So , let's go !!
the 4 files are : Awcs.afp ; Neir.afp ; Oket.afp et Vfaw.afp.
For duplicate tomb 3 , we have to copy on you hard drive all the files of the cd except the four !!!
then create 4 files with the same name , and put them in the directory where you copy the CD
before !
open this files and put 1 caracter in it !! just 1 octet !
now we can record tomb 3!!
but the game won't work because it is protected yet !!
Now , it is Time to crack !!!
We are playing with a cd check !!! and the game tell us : " Tomb Raider III CD ?"
We will kick this shit !!!
if you have already cracked with wdasm , you will think : "i will search this phrase in String
data references and crack it !!" but we can't found it !!! :(
So we are in crap !!
lets think a few ?
we have got 4 files , and we kicked them why not looking at this files ?
and in String data reference we see : d:\Awcs.afp , d:\Neir.afp , d:\Oket.afp et d:\Vfaw.afp.
Yeah !!!! i think it is a good thing !
we will try on the first!
Double click on it and we are in Wdasm ! we press up with the scrol bar and we found :
the jne (Jump if not equal) do the jump if it can't find the file with 600 Mo we change it
in je (jump if equal) and now , the prog jump when it found the file !! it can always search !!
it will never find it because , now it is equal to 1 octet !
Ok ! now just edit in hex the tomb3 file and search for 85FF756568D4 and replace it by
85FF746568D4 . now , save the files !
the jne 0048D2CE is now Je 0048D2CE.!!!
Now , we have to do the same on other files (d:\Neir.afp , d:\Oket.afp et d:\Vfaw.afp)
the 2 first will be like the first , but the last (D:\Vfaw.afp) isn't the same !
we don't care of the last , there is nothing to change !
so, if you do the same thing on the 2 others files , you have done this :
- for "Neir.afp":
0F85F9000000 by 0F84F9000000 ===> 85 (jne) becomes 84 (je)
- for "Oket.afp":
0F85AD000000 by 0F84AD000000 ===> 85 (jne) becomes 84 (je)
- nothing for "Vfaw.afp"
now , you have to save the change with an hexeditor!!
when it is finish , you just have to run the game !!!
the Game work good !!! with a CD-R !!!
ToMB RAiDER III is Now Cracked !!!
notes :
if you want to save the change with the hexeditor , you must save the file with another name
because it is used by Wdasm and it is write protected !!
ex: save it with Tomb.exe then close Wdasm and rename it with Tomb3.exe !
voila ! it is finish for this tutor ! I hope you learn something in this !!!
if there is one problem you can mail ma at
[ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
.
Happy Cracking and have FuN ! :)
-
TOMB RAIDER III
"Understanding CD Protections Systems"
Written by +Sandman
Introduction
Greetings Reversers',
At the time of this essay their are currently around half-a-dozen or so commercial protection systems for PC CD games/utilities, they being:-
SecuROM
SafeDisc
SafeCast
LaserLock
ProtectCD
CD-Cops
DiscGuard
The Copy-Protected CD & The Bongle
In addition, there are a number of methods which can also be used to protect a CD, they being:-
OverSize/OverBurn the CD
Illegal TOC
Dummy Files
Physical Errors.
Of course, some CD's have a combination of the above which then complicates matters even worse when you try and backup your CD's as I do.
Tomb Raider III is considered as having a 'weak' protection system even though it uses a number of distinct protections systems/methods to prevent the non reverser from making a backup of their game CD.
About this protection system
Tomb Raider III employs the following CD Protection systems:-
Dummy Files
Illegal TOC
CD Checks
You may have come across references to 'Dummy Files' but may still be unsure to what they mean and how they work, therefore allow me to explain what they are.
Dummy Files are, in basic terms, simply a number of files (usually there are five of these on a CD) that, when you check their sizes in File Manager show that they are around 600+ megabytes in size!!. In fact, you will usually see four of these files with this huge file size while the other is around 116 bytes and is unreadable.
Currently, these Dummy Files are very easy to spot, they ALL have the file extension of .AFP, and will use different file names on different CD games but all end with the .AFP file extension.
In general, these large dummy files are checked in the following manner.
The program will often 'read' a number of bytes into these dummy files and look for a specific byte to make sure they are intact. Often the program will 'read' thousands or even millions of bytes into these files just to read a single number from them. Defeating this kind of check is -fairly- easy, all you would have to do is to delete these dummy files and replace them with a 1 byte text file using the original names of the dummy files. Then, you would locate where in the program it 'read's these dummy files and where it pushes the offset value for the number of bytes to -read- you would replace this value with '0', so that it reads the first byte in our dummy text files. You would also need to check what value it's going to look for and put this value into your 1 byte text file. This would have to be repeated within the program for each of the dummy files that it checks for.
On the Tomb Raider III CD the following files are the dummy ones:-
File Name Comments
Awcs.afp
Config.afp
Neir.afp
Oket.afp
Vfaw.afp File size reported as 680 megabytes
File size reported as 116 bytes
File size reported as 681 megabytes
File size reported as 680 megabytes
File size reported as 681 megabytes
Of course standard CD's cannot hold more than 650 megabytes of data so these reported file sizes are there only to confuse any program you use to copy them. In reality, these over-large files have been deliberately corrupted and it's data will be pointing to other parts of the CD. CD Writers, when they come across these types of files will often refuse to copy these files because they are not recognized as being part of the CD ISO standards that defines how files are to be stored on CD's.
In cases such as this, these files are know to use Illegal Table Of Contents (T.O.C) which only a few CD Copiers can handle. The two most talked about CD Copiers around are Nero and CDR-WIN which are able to ignore illegal TOC's. Under the CD ISO standards, all CD's are suppose to use a recognized format or structure that defines how files are to be stored on the CD. The Table Of Contents on CD's is very much like the FAT16 / FAT32 format used on our hard disks, which, if changed or damaged, will in most cases, prevent our hard disk from being recoqnised by our software programs that are not programed to accept any other type of directory system.
Have you noticed yet that the protection system Dummy Files are also related to Illegal (TOC's). This is often the case, one protection method is usually directly or indirectly related to other protection systems/methods. Solving them will often require you to go about backing up your software in some interesting ways, which, may at first look rather complicated for the newbie reverser to master.
For many newbies, the common question they all ask is "What is the thought process that goes into reversing a protection system?".
Well, lets take this question a little higher, here's how I reversed this CD Protection right from scratch. From knowing absolutely nothing about it to solving it so that I can back it up.
Yes, I'm aware that by writing this tutorial I'm in effect showing you how to pirate this and other games and if that's your intention then your a lamer. Backing up our legal software for our personal use is considered paramount because of the expense of the original software.
The Essay
After purchasing Tomb Raider III I had no idea what kind of protection system it used that would prevent me from backing it up. First thing I did was to open up the File Manager and have a look at the files and folders stored on the CD.
Because I have read a number of references on the web related to CD Protections systems I know that many of these can be recoqnised in a number of ways..
First, I looked at the CD itself to see if I could see a picture on the inside ring that would identify that this CD was protected by SecuROM. No picture was found. SecuROM protected CD's have an electronic marking printed on the CD surface which assigns a unique ID-Code to each CD. There are currently 4 versions of SecureRom, known as: SecuROM R1, SecuROM R2, SecuROM R3, SecuROM R4.
Next, I looked for a hidden directory on the CD called "LaserLock", which, if existed would tell me that it was protected by LaserLock. In this case no such directory existed. LaserLock uses a combination of encryption software and unique laser marking on the CD surface made during the special LaserLock mastering procedure, in order to make copying practically impossible. Every CD-ROM application has a unique locking parameter that provides a complete protection against illegal re-mastering and reproduction. LaserLock offers excellent protection for every application as each application package is characterized by a unique encryption parameter that is specified during LaserLocking procedure.
Next, while still looking at the files and directories of the CD I looked for the following files: 00000001.TMP, CLCD16.DLL, CLCD32.DLL and most important CLOKSPL.EXE.. If any or all of these files were found then I would know that this CD was protected by SafeDisc.None were not found.
Next, I checked the CD for any of the following files: CMS16.DLL, CMS_95.DLL or CMS_NT.DLL. None were found. However, had I found any of these files then I would know that this CD was protected by SecuROM.SecuROM is a patented CD-ROM copy protection technology that identifies a ‘genuine’ CD-ROM by a special authentication mechanism. During Sony DADC’s mastering process an electronic fingerprint is applied onto the glass master which assigns a unique number to each CD-ROM title.
SafeCast and CD-Copswere not checked for because little is known about them and or have no visible means to identify them or, as in the case of ProtectCDthey are not know to be used in any commercial program at this time.
This now leaves Illegal TOC's and Dummy Files..
Well what do you know, under the File Manager I see five files all ending with .AFP. Checking their reported file sizes I see four of them are well over 680 megabytes. Now if you check the properties for this CD while still in the File Manager you will see that the total size of this CD is 690 megabytes. Too big to backup on a standard CD. If, like me you have a CD Writer that doesn't have the Overburn option or, is not able to use 80 minute CD's then we may have a problem..
Okay, now if you have Nero installed then if you select your CD Drive under File Manager and right click on it you will see the menu option Properties. Select this and then click on the Volumes menu tab. You won't see the Volumes tab unless you have Nero installed. Right, can you see that we have:-
I. An ISO /Juliet track that is 534 megabytes in size.
II. Two Audio tracks
III A Second ISO / Juliet track that is ALSO 534 megabytes in size. Its this extra data track that fools many CD Copiers into giving up trying to copy this CD.
If your CD Writer is unable to 'OverBurn' CD's then trying to do a straight copy of this CD will result in an error message from Nero stating that this CD is too big to fit onto a standard CD. CDRWIN may also state the same although I didn't test this.
Now the fun begins...
Audio tracks on game CD's are 9 times out of ten optional. By optional I mean they are not always checked for when the game runs and that the game can run happily without them. At this point in my quest to backup this game I cannot be sure of this and will only know this for certain once I've done a test backup.
TIP. Everyone making backups should already know this. When making a test backup ALWAYS use a CD-RW first. That way, if you make a mistake somewhere and the game still does not work as you expect it to then you don't end up with a coaster, since your CD-RW disk can be re-written again, unlike a CD-R.
Okay, I've decided to leave out the two audio tracks and now left with two data tracks. Which one do I choose?. The answer is the First data track, since it's this first track that gets read by all CD Drives. The second data track is there to fool your copier software.
Right, we are now left with one data track, but how do we copy it?.. We could copy the whole CD but as already mentioned, my CD Writer can't handle CD's with more than 650 megabytes. The answer is we use Nero's ability to copy Selected Tracks.
This is how to do this under Nero..
Start up Nero and go into the CD-Recorder menu option. Select 'Choose Recorder' and make sure that Nero is told to use the 'Image Recorder'. This is important as this tells Nero to save the resulting track image onto your hard disk.
Next, go back into the menu option CD-Recorder and this time select the option Save Tracks. Nero should now bring up a new screen showing you all the tracks on our Tomb Raider III CD. You need to select the first track, leave all the others alone. Now fill in the data boxes telling Nero what filename to use and where to store this track image. Make sure the directory you choose already exists, else Nero won't accept this. Once you have done this, click on the Save button. Nero should now begin copying the first data track on our CD. Time for a cuppa I believe..:)
Once copying has been completed, there should have been no errors at this copying stage. Go back into the menu option CD-Recorder and again select 'Choose Recorder' and this time select your CD-Writer, which ever it is.
We should now have a 534 megabyte image file on our hard disk and now it's time to burn it on our CD-RW disk. Don't use a standard CD-R at this point, if we make a mistake at any point then we won't end up with an expensive coaster or two.
From Nero's File menu select 'Burn Image' and locate where you have stored your first Game Track image. Now follow the prompts and burn this image file onto our CD-RW disk.
Once completed, close down Nero and try and run Tomb Raider III. (You should have already installed the game before all this copying took place).
Opps, the game as expected has thrown up a message box telling us it needs the original game CD. Lets fix this bug..:)
Before we go any further it's time now to think like a reverser and analyse what we've done to our backup and what differences there might be that could trigger the game into not accepting our backup copy.. Right, we know we have all the dummy .AFP files intact so no problem there. We've left out two audio tracks that -might- be checked for but I doubt this. We have also left out a second, data track that is -not- used, it's there to help prevent the disk being copied, but it -could- still be checked?. They are the obvious things we notice, however, there are others, such as. Our backup CD is now 534 megabytes in size compared to the original of 690 megabytes, the program perhaps checks to see if there is 690 megabytes of data?, might use a CRC checksum?.
If you checked the game's directory you will see that Tomb Raider III installs about a two megabytes of files onto your hard disk, they being the 1MB executable file and the rest are made up of a few windows support .DLL files.
At this point some reversers may fire up Softice and begin tracking down where the program checks the CD and where it decides to reject or accept it but for me, I like to see where I'm going and what I'm up against first!.
Fire up W32Dasm and select the file:C:\ Program Files\Core Design\Tomb Raider III\tomb3.exe
If you checked the properties for your shortcut to Tomb Raider III then you will know that this is the file that gets executed, besides, it's the only executed file in this directory..:)
Now what do we look for?.
Lets take a look at the String Data Resources for this file.. Who know's, we might see something of interest to us?.
If we look for the message that the game gives us when it detected that our backup copy was not the original then we find that there are no references to this error message. Hardly surprising, that would have been too easy.. OK, what else can we see..
Well, there are four references to our dummy .AFP files..
"d:\VFAW.AFP"
"d:\NEIR.AFP"
"d:\OKET.AFP"
"d:\AWCS.AFP"
While we're in W32Dasm lets take a look at the four checks to our dummy files, and while we're there lets also make some notes for when we use Softice.
Okay, using the four reference strings (shown above) we can quickly locate where in the program's code they handled our four dummy files. Okay, now click on the String Reference to "d:\VFAW.AFP" and W32Dasm will take us to where in this program this string is referenced from. From here we must scroll up the window until we see where the beginning of this routine starts.
* Referenced by a CALL at Address: :004B2827
;Here's the beginning of four dummy file check routine, which is being called from memory
;address 004B2827. We should now note the following two memory address for when we use Softice.
;1. bpx 004B2827 --> Location of where the Call to the Dummy File checking routine
;2. bpx 0048D140 --> Start of the Dummy File checking routine.
:0048D140 56 push esi
:0048D141 57 push edi
:0048D142 E8F952FFFF call 00482440
:0048D147 85C0 test eax, eax
:0048D149 7521 jne 0048D16C
........
........
........ ;I will skip the rest of this routine for now to bring to your attention
........ ;the last few lines of this routine. While we may not know much about Assembly
........ ;we can at least make some educated (ZEN) guesses just by looking..:)
........
........
The Dummy File checking routine has two possible routes it can take when it has finished checking our four dummy files. We know this because there are two RET instructions that are referenced from within our file checking routine.
Two choices suggest a 'good cracker' and 'bad cracker' decision to me. The 'common' thing with both of these possible exits is it's setting of the AL register with a predetermined value.
The instruction XOR al,al will set the AL register to '0'
The instruction mov al,01 will set the AL register to '1'
The AL register is commonly used as a 'flag' to signal to the rest of the program wether or not a task was completed or not. Think of it as a True or False.
* Referenced by a (C)onditional Jump at Address: 0048D15D(C)
:0048D2C9 32C0 xor al, al ---> Register AL set to '0'
:0048D2CB 5F pop edi
:0048D2CC 5E pop esi
:0048D2CD C3 ret
* Referenced by a (C)onditional Jump at Addresses:
:0048D1CF(C), :0048D21B(C), :0048D267(C), :0048D2AF(C)
:0048D2CE 5F pop edi
:0048D2CF B001 mov al, 01 ---> Register AL set to '1'
:0048D2D1 5E pop esi
:0048D2D2 C3 ret
Okay, now save off your W32Dasm project, this will save us from having to disassemble the executable file again.
It's time to fire up Softice and do some work, this theory stuff is ok but we now need to verify our work and shed some more light on the way this program performs it's CD checks.
Press Ctrl + D to fire up Softice and lets try breaking in on that error message "Tomb Raider III CD?"
Type: bpx messageboxa
Type: X to exit softice.
Now try and run Tomb Raider III.
As you can see, we saw our CD being accessed but Softice failed to break on our error message.. Click the Cancel button to close this error message.
As we learn more and more about CD protection systems we learn that there are a number of API calls the protectionist can use to access the CD Disk.
Here's a few API functions we can use:-
GetDriveType
GetFileAttributesA **
GetFileSize
GetLogicalDrives
GetlogicalDriveStrings
GetLastError **
ReadFile
One of the most commonly used is the GetDriveTypeA api call. This function will return a value that corresponds to what drive types you currently have installed on your computer.
Here are the return values from the GetDriveTypeA API call.
Return Values Comments
0
1
2
3
4
5
6 Drive Cannot Be Determined
Root Directory Does Not Exist
Drive Is Removable (Zip drives etc)
A Fixed Disk (HardDrive)
Remote Drive(Network)
CD-Rom Drive
RamDisk
Right, lets use GetDriveTypeA as our Softice breakpoint. Fire up Softice ( Ctrl & D )
Type: bpx GetDriveTypeA
Type: bd 0 to disable our original messageboxa breakpoint which we now don't need anymore.
Type: x to exit softice
Run Tomb Raider III again.
Softice now breaks at system function: WritePrivateProfileStringA which was triggered by our
Press F11 once. This will tell Softice to continue executing our GetdriveTypeA function and break again once execution returns back to where it was originally called from, which we're hoping is within the Tomb Raider's code.
We're now back in the Tomb Raider III program code.
Okay, now remember those notes we made earlier in W32Dasm?. No?, well ok, I will remind you again. We found in W32Dasm where the four dummy files are handled and we also found where this routine was called from:-
;1. bpx 004B2827 --> Location of where the Call to the Dummy File checking routine
;2. bpx 0048D140 --> Start of the Dummy File checking routine.
So, while still in Softice type: bc * to clear all our previous breakpoints so that they won't interfere with our next set of breakpoints.
Next, lets take a look where the Call to our dummy file routine is located.
Type: u 004b2827
Then type: bpx 004b2827 to set a new breakpoint on this memory location.
Here's what our code section looks like:-
:004B2827 E814A9FDFF call 0048D140 ; Call CD Protection (Dummy File checks)
:004B282C 84C0 test al, al ; Does AL=0 (0=CD is not the original)
:004B282E 0F846A020000 jz 004B2A9E ; Display Error Message "Tomb Raider III CD?"
:004B2834 8B1594ED6C00 mov edx, dword ptr [006CED94]
:004B283A A190ED6C00 mov eax, dword ptr [006CED90]
:004B283F 52 push edx
:004B2840 50 push eax
:004B2841 6898ED6C00 push 006CED98
:004B2846 E8C5C1FDFF call 0048EA10
:004B284B 83C40C add esp, 0000000C
:004B284E C705E8ED6C00B0ED6C00 mov dword ptr [006CEDE8], 006CEDB0
:004B2858 C705E4ED6C0098ED6C00 mov dword ptr [006CEDE4], 006CED98
:004B2862 E8E9A1FDFF call 0048CA50
:004B2867 84C0 test al, al
:004B2869 7411 je 004B287C
Now type: x to exit softice.
Okay, run Tomb Raider III again. Softice now breaks at: 004b2827
If you we're to press F10 twice you will see that the register EAX = FFFFFF00 and that the Zero flag has been 'set' and that if we we're to press the F10 key again once more that Softice will jump to to memory location 004b2a9e where our error message will be displayed.. Since the test al,al instruction is testing the low byte of the EAX register we can type: al? to see the low value of the EAX register. Notice that the AL register has been given the value of 0?.
By all means test this out for yourself, it's the only way you will be able to slowly build up a picture of what is going off around. When you've done, simply re-run the game and you will once again break at memory location 004b2827.
Right press the T key once while softice is waiting on the call 0048D140 instruction. The T command simply tells Softice to (T)race into this function rather than skip over it. This will take Softice to the beginning of our four Dummy Files checking routine. We should now see this code section:-
I recommend that you study this code and try and visualize it's simplicity in it's execution. If I were to convert this routine into plain -English- then it would go something like this:-
Check in turn for the presence of each of our four dummy files. For each check, push onto the stack two numbers, a file offset number and another number that should exist at this file offset.
Use this file offset value to read through the dummy file and read what number is found at this file offset. Is the -read- value the same as the number on the stack?. If so then continue with checking the next dummy file. If not, then CD is NOT an original so zero the AL register using xor al,al. If however, everything checks out ok then set the AL register to 1 using the instruction: mov al, 01
* Referenced by a CALL at Address: :004B2827
:0048D140 56 push esi
:0048D141 57 push edi
:0048D142 E8F952FFFF call 00482440
:0048D147 85C0 test eax, eax
:0048D149 7521 jne 0048D16C ;1st check ok? then jump
:0048D14B A190ED6C00 mov eax, dword ptr [006CED90]
:0048D150 50 push eax
:0048D151 6A66 push 00000066
:0048D153 E838120000 call 0048E390
:0048D158 83C408 add esp, 00000008
:0048D15B 84C0 test al, al
:0048D15D 0F8466010000 je 0048D2C9 ;Bad Cracker jump, so set AL = 0
:0048D163 E8D852FFFF call 00482440
:0048D168 85C0 test eax, eax
:0048D16A 74DF je 0048D14B
:0048D16C A0203F6300 mov al, byte ptr [00633F20] ;-> AL = CD Drive Letter
:0048D171 A2A8EF4C00 mov byte ptr [004CEFA8], al ; Save CD Drive Letter
:0048D176 A2B8EF4C00 mov byte ptr [004CEFB8], al ; " " " "
:0048D17B A2C8EF4C00 mov byte ptr [004CEFC8], al ; " " " "
:0048D180 A2D8EF4C00 mov byte ptr [004CEFD8], al ; " " " "
:0048D185 68D47A4C00 push 004C7AD4 ;->"rb"
:0048D18A 68A8EF4C00 push 004CEFA8 ;->"d:\VFAW.AFP" ;Save Filename on the STACK
:0048D18F E88C8D0200 call 004B5F20 ;Check if file d:\VFAW.AFP exist?
:0048D194 8BF0 mov esi, eax
:0048D196 83C408 add esp, 00000008
:0048D199 85F6 test esi, esi
:0048D19B 7504 jne 0048D1A1 ;File exist? then proceed onto the next check.
:0048D19D 33FF xor edi, edi ;Else, set edi to 0
:0048D19F EB2C jmp 0048D1CD
:0048D1A1 6A00 push 00000000
:0048D1A3 6800508429 push 29845000 ;Save the file offset value 298545000h
:0048D1A8 56 push esi
:0048D1A9 E8F2970200 call 004B69A0 ;Goto the dummy file's offset value
:0048D1AE 83C40C add esp, 0000000C
:0048D1B1 56 push esi
:0048D1B2 E8B9970200 call 004B6970 ;Now read value found at this offset location
:0048D1B7 83C404 add esp, 00000004
:0048D1BA 33C9 xor ecx, ecx
:0048D1BC 83F87B cmp eax, 0000007B ;Does value in file = 7Bh?
:0048D1BF 0F94C1 sete cl
:0048D1C2 56 push esi
:0048D1C3 8BF9 mov edi, ecx
:0048D1C5 E8C6960200 call 004B6890
:0048D1CA 83C404 add esp, 00000004
:0048D1CD 85FF test edi, edi
:0048D1CF 0F85F9000000 jne 0048D2CE
:0048D1D5 68D47A4C00 push 004C7AD4 ;->"rb"
:0048D1DA 68B8EF4C00 push 004CEFB8 ;->"d:\NEIR.AFP" ;Save Filename on the STACK
:0048D1DF E83C8D0200 call 004B5F20 ;Check if file d:\VFAW.AFP exist?
:0048D1E4 8BF0 mov esi, eax
:0048D1E6 83C408 add esp, 00000008
:0048D1E9 85F6 test esi, esi
:0048D1EB 742C je 0048D219 ;File exist? then proceed onto the next check.
:0048D1ED 6A00 push 00000000
:0048D1EF 6800588229 push 29825800 ;Save the file offset value 29825800h
:0048D1F4 56 push esi
:0048D1F5 E8A6970200 call 004B69A0 ;Goto the dummy file's offset value
:0048D1FA 83C40C add esp, 0000000C
:0048D1FD 56 push esi
:0048D1FE E86D970200 call 004B6970 ;Now read value found at this offset location
:0048D203 83C404 add esp, 00000004
:0048D206 33D2 xor edx, edx
:0048D208 83F833 cmp eax, 00000033 ;Does value in file = 33h?
:0048D20B 0F94C2 sete dl
:0048D20E 56 push esi
:0048D20F 8BFA mov edi, edx
:0048D211 E87A960200 call 004B6890
:0048D216 83C404 add esp, 00000004
:0048D219 85FF test edi, edi
:0048D21B 0F85AD000000 jne 0048D2CE
:0048D221 68D47A4C00 push 004C7AD4 ;->"rb"
:0048D226 68C8EF4C00 push 004CEFC8 ;->"d:\OKET.AFP" ;Save Filename on the STACK
:0048D22B E8F08C0200 call 004B5F20 ;Check if file d:\VFAW.AFP exist?
:0048D230 8BF0 mov esi, eax
:0048D232 83C408 add esp, 00000008
:0048D235 85F6 test esi, esi
:0048D237 742C je 0048D265 ;File exist? then proceed onto the next check.
:0048D239 6A00 push 00000000
:0048D23B 6800288429 push 29842800 ;Save the file offset value 29842800h
:0048D240 56 push esi
:0048D241 E85A970200 call 004B69A0 ;Goto the dummy file's offset value
:0048D246 83C40C add esp, 0000000C
:0048D249 56 push esi
:0048D24A E821970200 call 004B6970 ;Now read value found at this offset location
:0048D24F 83C404 add esp, 00000004
:0048D252 33C9 xor ecx, ecx
:0048D254 83F875 cmp eax, 00000075 ;Does value in file = 75h?
:0048D257 0F94C1 sete cl
:0048D25A 56 push esi
:0048D25B 8BF9 mov edi, ecx
:0048D25D E82E960200 call 004B6890
:0048D262 83C404 add esp, 00000004
:0048D265 85FF test edi, edi
:0048D267 7565 jne 0048D2CE
:0048D269 68D47A4C00 push 004C7AD4 ;->"rb"
:0048D26E 68D8EF4C00 push 004CEFD8 ;->"d:\AWCS.AFP" ;Save Filename on the STACK
:0048D273 E8A88C0200 call 004B5F20 ;Check if file d:\VFAW.AFP exist?
:0048D278 8BF0 mov esi, eax
:0048D27A 83C408 add esp, 00000008
:0048D27D 85F6 test esi, esi
:0048D27F 742C je 0048D2AD ;File exist? then proceed onto the next check.
:0048D281 6A00 push 00000000
:0048D283 6800E08129 push 2981E000 ;Save the file offset value 2981E000h
:0048D288 56 push esi
:0048D289 E812970200 call 004B69A0 ;Goto the dummy file's offset value
:0048D28E 83C40C add esp, 0000000C
:0048D291 56 push esi
:0048D292 E8D9960200 call 004B6970 ;Now read value found at this offset location
:0048D297 83C404 add esp, 00000004
:0048D29A 33D2 xor edx, edx
:0048D29C 83F87B cmp eax, 0000007B ;Does value in file = 7Bh?
:0048D29F 0F94C2 sete dl
:0048D2A2 56 push esi
:0048D2A3 8BFA mov edi, edx
:0048D2A5 E8E6950200 call 004B6890
:0048D2AA 83C404 add esp, 00000004
:0048D2AD 85FF test edi, edi
:0048D2AF 751D jne 0048D2CE ;If all checks complete, then jump to
;Good Cracker Exit Point.
:0048D2B1 A190ED6C00 mov eax, dword ptr [006CED90]
:0048D2B6 50 push eax
:0048D2B7 6A66 push 00000066
:0048D2B9 E8D2100000 call 0048E390
:0048D2BE 83C408 add esp, 00000008
:0048D2C1 84C0 test al, al
:0048D2C3 0F85BCFEFFFF jne 0048D185 ;CD Verified so jump and set AL = 1
* Referenced by a (C)onditional Jump at Address: :0048D15D(C) ( Bad Cracker Exit )
:0048D2C9 32C0 xor al, al
:0048D2CB 5F pop edi
:0048D2CC 5E pop esi
:0048D2CD C3 ret
* Referenced by a Jump at Addresses: :0048D1CF(C), :0048D21B(C), :0048D267(C), :0048D2AF(C)
:0048D2CE 5F pop edi
:0048D2CF B001 mov al, 01
:0048D2D1 5E pop esi
:0048D2D2 C3 ret
If you study the above code fragment you will no doubt notice that we -could- nop or change just two conditional jumps at memory location(s):-
1. :0048D15D 0F8466010000 je 0048D2C9 ;Bad Cracker jump, so set AL = 0
2. :0048D2C3 0F85BCFEFFFF jne 0048D185 ;CD Verified so jump and set AL = 1
However, these are pretty obvious locations to change if you are thinking to distribute this game in a pirate form since in which case you would not include the four dummy files, which in any case are not required for the game to run and therefore would be considered as excess baggage. Remember, our backup of this game DOES contain these dummy files so therefore any checks made by the program on our four dummy files WILL prove true and will be accepted by the checking routine. However, in creating a backup of the original game there are other changes to it that we couldn't help but make that, in turn, the protection routine does detect. Okay, enough rambling...
If you follow through the above routine using Softice you will see that we are sent to the 'Bad Cracker' exit point here:-
:0048D2AF 751D jne 0048D2CE ; If all checks complete, then jump to
;Good Cracker Exit Point.
Therefore, all we need to do is to change the conditional jump into an unconditional jump, one that will ALWAYS jump to the Good Cracker Exit point and which will set our AL register to 1.
Our line therefore should read:-
:0048D2AF EB1D jp 0048D2CE ; Always jump to Good Cracker Exit Point.
Notice that all we have done is to change one byte which has changed a conditional jump into an unconditional jump.
Job Done.
Final Notes
A common mistake people -still- keep making when they go about reversing CD Protection systems is to try and crack a heavily protected CD rather than starting from scratch and learning the basic principles of CD Protection systems first. Look kid, unless you are already a highly talented programmer then you just ain't gonna make it and will find the going extremely tough.
To a newbie, no protection system is -easy- to understand, however, looking at this tutorial you will - i hope- see some of the kind of thinking you will need to make in order to progress any further. If you can understand the general outline of this tutorial then you will be able to use it's guidelines on a great many other similar protected CD's. Eidos, the maker of Tomb Raider III uses this CD Protection system on many of their games in one form or another, and while they will use variations of what has been explained in this tutorial you -should- still be able to backup -most- of them simply by following the guidelines I have already explained here.
-
Title : TOMB RAIDER 4 (GAME)
Version : 1.0
Protection : Cd Check
Producer :
کد:
http://www.eidosinteractive.com
Cracker : Zaks (zakssim@geocities.com)
Tools : W32Dasm, Hiew
Difficulty : Easy
Tutorial No. : 3
================================================== ===============
1) Install Tomb 4. Copy the whole Cd to your install dir. Run the game. Cd out. Messagebox appears "Tomb Raider - the last reveletion cd". Backup tomb4.exe. Open W32dasm and dissasemble your tomb4 backup. Look for our message at string data references. We have nearly the same message twice - "Tomb Raider -The Last Reveletion". Double click on the first one. We are just at the right place.
:0048D89F 881DA5287500 mov byte ptr [007528A5], bl
:0048D8A5 891DBC287500 mov dword ptr [007528BC], ebx
:0048D8AB E8A00B0000 call 0048E450
:0048D8B0 83C40C add esp, 0000000C
:0048D8B3 84C0 test al, al
:0048D8B5 0F8500040000 jne 0048DCBB
:0048D8BB E8F060FEFF call 004739B0
:0048D8C0 84C0 test al, al
:0048D8C2 7525 jne 0048D8E9 -> Good Boy
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0048D8E7(C) -> Here we see who call the error message
|
:0048D8C4 6A25 push 00000025
* Possible StringData Ref from Data Obj ->"Tomb Raider"
|
:0048D8C6 6838354B00 push 004B3538
* Possible StringData Ref from Data Obj ->"Tomb Raider - The Last Revelation "
->"CD"
|
:0048D8CB 6810354B00 push 004B3510 -> Here we are at first
:0048D8D0 53 push ebx
* Reference To: USER32.MessageBoxA, Ord:01BEh
|
:0048D8D1 FF15CC814A00 Call dword ptr [004A81CC]
:0048D8D7 83F802 cmp eax, 00000002
:0048D8DA 0F84DB030000 je 0048DCBB
:0048D8E0 E8CB60FEFF call 004739B0
:0048D8E5 84C0 test al, al
:0048D8E7 74DB je 0048D8C4 -> Bad Boy. If the Cd is not found we have a never ending loop. And if it is found we go to the next line where is Good Boy.
2) Lets observe the code precisely. So lets see who call the cd error message. It is 0048D8E7. Go there. But who call this messagebox. Noone ... we see it is just never ending loop (until the cd is found of course). The easiest way to crack the game here is simply change Bad Boy at 0048D8E7 from je (74) to jne (75). I did not try this but it have to work.
3) The hardest way is to look for good boy and with an inteligent jump to bypass whole cd check routine. So look carefuly before the *Referenced by ..... : 0048D8E7 . Lets think for a second. The error message is called by 0048D8E7, but not only from there. We remember that in assembler the processor go line by line. So the message is also called by previous line 0048D8C2. Look at and above it:
:0048D8BB E8F060FEFF call 004739B0
:0048D8C0 84C0 test al, al
:0048D8C2 7525 jne 0048D8E9 -> Good Boy
4) Hmm .. does not we have a perfect check routine here and if the cd is found the processor will jump directly to 0048D8E9. Lets try this. Write the offset of jne 0048D8E9. For me it was 8d8c2. Open hiew and open tomb4.exe. F4 - decode. F5 - Go to the offset 8d8c2 (for me). First change jne (75) to jmps (EB). ! Remember ! It is not enough (in most cases) to only change jne to jmps - you also have to destroy the previous call and test by simply nop(ing) (90) them. So nop the call and test. You do this in this way:
5) First place cursor at the begining of the call function (call 004739B0) then count how many simbols are there. We count EBCB60FEFF - 10 simbols. Now you must remember that every two simbols are 1 byte so we have 5 bytes long line (10 : 2 = 5). You see that nop (90) is just 1 byte (90 - 2 symbols : 2 = 1 byte). So to comletely nop whole call (5 bytes long) we have to overwrite it with 5 times 90. We press F3 and start writing 90 (five times). Do not worry if you go on the next line. F9 - to update. Now lets nop also test al,al. I suppose now you can handle this alone but for those of you who did not understand me clearly I will explain it once again briefly. Go to begining of test al,al. Count simbols 84C0 (we have 4 simbols, so we have 2 bytes). And to nop 2 bytes we have to write 90 (nop) 2 times. Press F3 end write 9090. F9 - update. You are supposed to have something like this :
:0048D8BB 90 nop
:0048D8BC 90 nop
:0048D8BD 90 nop
:0048D8BE 90 nop
:0048D8BF 90 nop
:0048D8C0 90 nop
:0048D8C1 90 nop
:0048D8C2 EB25 jmp 0048D8E9
ESC - quit.
6) Try the game now. It runs just fine.
================================================== ===============================================
Second way to crack the game. Good for a game where we cannot find the error message.
1) Open W32dasm and dissasemble your tomb4 backup. Click on search/find text and look for getdrivetypea. GetDriveTypeA is a inbuilt (in kernel32) function for checking if the cd is in your drive (it really does more then this but it is of no interest for us). First we find this:
Addr:000AA992 hint(0104) Name: GetDriveTypeA // just declaration of the function we do not need
The second search is something more valuable :
* Reference To: KERNEL32.GetDriveTypeA, Ord:0104h
|
:00473A01 8B3DEC804A00 mov edi, dword ptr [004A80EC]
Lets see what call this we scroll up a bit and see :
* Referenced by a CALL at Addresses:
|:0048D8BB , :0048D8E0 -> we need to go to this adresses and see what is there
|
:004739B0 83EC18 sub esp, 00000018
:004739B3 A1AC174B00 mov eax, dword ptr [004B17AC]
:004739B8 8B0DB0174B00 mov ecx, dword ptr [004B17B0]
:004739BE 8B15B4174B00 mov edx, dword ptr [004B17B4]
:004739C4 53 push ebx
:004739C5 8944240C mov dword ptr [esp+0C], eax
:004739C9 66A1B8174B00 mov ax, word ptr [004B17B8]
:004739CF 56 push esi
:004739D0 57 push edi
:004739D1 894C2418 mov dword ptr [esp+18], ecx
:004739D5 8954241C mov dword ptr [esp+1C], edx
:004739D9 6689442420 mov word ptr [esp+20], ax
So we go to first address. Double click with right mouse button on 0048D8BB. Surprise. We are just at the right place (on the right time :))). You know what to do from here. If not just read again the first method desribed above.
2) This metod is good because many games have inner build error messages and they are not displayed at string data references.