Free Information Xchange '98 presents:
Get Medieval - CD crack by Static Vengeance - Sep 12, 1998
Requirementes:
Hex editor and full game install
W32Dasm if you wish to follow along
Get Medieval is a new 1998 version of Gauntlet produced by Monolith. The game is great if you
like Gaunlet and is done well. I, of course, want to be able to play the game without the CD so I looked
into cracking this game. The CD check is much like that found in Captain Claw (or just "Claw") which is
also produced by Monolith. Also, once again this provides me with the oppertunity to write up another
tutorial for you to read and learn from. So follow along with me as we go on our own adventure with Get
Medieval's copy protection, and find out how to slay this evil beast.
To get started you'll need some tools. The two tools I used the most are W32Dasm from RUSOft and
a Hex editor. The Hex editor I use is HEdit, only becuase this is the first one I used. However any hex
editor will work fine. Next you'll need to disassemble the exe file and then we can get started. After
you have W32Dasm up and running and have disassembled Medieval.exe, go up the menu bar and select "Refs"
and then down to String Data References from the drop down menu. Now you get the Refs pop up box. From
here grab the slider bar and start looking for interesting things. Right away you'll see a a ref like
"%c:\GAME\MEDIEVAL.EXE" I've seen this in many copy protection routines, so I double clicked on this one
first. This put me in the middle of the following routine:
* Referenced by a CALL at Addresses:
|:00410790 , :0042C075 <-- Called by two locations
|
:004107F0 64A100000000 mov eax, dword ptr fs:[00000000]
:004107F6 6AFF push FFFFFFFF
:004107F8 683B484D00 push 004D483B
:004107FD 50 push eax
:004107FE A0C86A5000 mov al, byte ptr [00506AC8]
:00410803 64892500000000 mov dword ptr fs:[00000000], esp
:0041080A 81EC60040000 sub esp, 00000460
:00410810 53 push ebx
:00410811 33DB xor ebx, ebx
:00410813 56 push esi
:00410814 3AC3 cmp al, bl
:00410816 57 push edi
:00410817 0F852C010000 jne 00410949
:0041081D 899C2450010000 mov dword ptr [esp+00000150], ebx
:00410824 53 push ebx
:00410825 6802000080 push 80000002
:0041082A 53 push ebx
* Possible StringData Ref from Data Obj ->"1.0"
|
:0041082B 6860574F00 push 004F5760
* Possible StringData Ref from Data Obj ->"Get Medieval"
|
:00410830 6850574F00 push 004F5750
* Possible StringData Ref from Data Obj ->"Monolith Productions"
|
:00410835 6838574F00 push 004F5738
:0041083A 8D8C2468010000 lea ecx, dword ptr [esp+00000168]
:00410841 899C248C040000 mov dword ptr [esp+0000048C], ebx
:00410848 E853100700 call 004818A0
* Reference To: KERNEL32.GetDriveTypeA, Ord:00DFh <-- Commonly used in CD checks
|
:0041084D 8B3DD0D04D00 mov edi, dword ptr [004DD0D0]
:00410853 85C0 test eax, eax
:00410855 0F8480000000 je 004108DB <-- 00 means "Drive Cannot Be determined"
:0041085B 8D44240C lea eax, dword ptr [esp+0C]
:0041085F 53 push ebx
:00410860 8D4C2414 lea ecx, dword ptr [esp+14]
:00410864 50 push eax
:00410865 51 push ecx
* Possible StringData Ref from Data Obj ->"CdRom Drive"
|
:00410866 68C8664F00 push 004F66C8
:0041086B 8D8C2460010000 lea ecx, dword ptr [esp+00000160]
:00410872 C744241C1E000000 mov [esp+1C], 0000001E
:0041087A 885C2420 mov byte ptr [esp+20], bl
:0041087E E85D120700 call 00481AE0 <-- Check against CD Rom drive
:00410883 85C0 test eax, eax
:00410885 7454 je 004108DB
:00410887 8A442410 mov al, byte ptr [esp+10]
:0041088B 3C14 cmp al, 14
:0041088D 7E4C jle 004108DB
:0041088F 0FBEF0 movsx esi, al
:00410892 56 push esi
:00410893 8D542434 lea edx, dword ptr [esp+34]
* Possible StringData Ref from Data Obj ->"%c:\" <-- Start with C:\ and work through all drives
| <-- Again, "%c:\" is commonly used in CD checks
:00410897 68C0664F00 push 004F66C0
:0041089C 52 push edx
:0041089D 8AD8 mov bl, al
:0041089F E83CB90500 call 0046C1E0
:004108A4 83C40C add esp, 0000000C
:004108A7 8D442430 lea eax, dword ptr [esp+30]
:004108AB 50 push eax
:004108AC FFD7 call edi
:004108AE 83F805 cmp eax, 00000005
:004108B1 7528 jne 004108DB
:004108B3 56 push esi
:004108B4 8D4C2454 lea ecx, dword ptr [esp+54]
* Possible StringData Ref from Data Obj ->"%c:\GAME\MEDIEVAL.EXE" <-- Path name on CD for the EXE
| <-- The "c" will get updated to CD rom letter
:004108B8 68D4664F00 push 004F66D4
:004108BD 51 push ecx
:004108BE E81DB90500 call 0046C1E0
:004108C3 83C40C add esp, 0000000C
:004108C6 8D542450 lea edx, dword ptr [esp+50]
:004108CA 52 push edx
:004108CB E8D0FEFFFF call 004107A0
:004108D0 83C404 add esp, 00000004
:004108D3 85C0 test eax, eax
:004108D5 0F8586000000 jne 00410961 <-- Jump down to exit section of routine
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:00410855(C), :00410885(C), :0041088D(C), :004108B1(C)
|
:004108DB B341 mov bl, 41
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0041092E(C)
|
:004108DD 0FBEF3 movsx esi, bl
:004108E0 56 push esi
:004108E1 8D842470030000 lea eax, dword ptr [esp+00000370]
* Possible StringData Ref from Data Obj ->"%c:\" <-- Starting over with checks
|
:004108E8 68C0664F00 push 004F66C0
:004108ED 50 push eax
:004108EE E8EDB80500 call 0046C1E0
:004108F3 83C40C add esp, 0000000C
:004108F6 8D8C246C030000 lea ecx, dword ptr [esp+0000036C]
:004108FD 51 push ecx
:004108FE FFD7 call edi
:00410900 83F805 cmp eax, 00000005
:00410903 7524 jne 00410929
:00410905 56 push esi
:00410906 8D542454 lea edx, dword ptr [esp+54]
* Possible StringData Ref from Data Obj ->"%c:\GAME\MEDIEVAL.EXE" <-- File we're looking for
|
:0041090A 68D4664F00 push 004F66D4
:0041090F 52 push edx
:00410910 E8CBB80500 call 0046C1E0
:00410915 83C40C add esp, 0000000C
:00410918 8D442450 lea eax, dword ptr [esp+50]
:0041091C 50 push eax
:0041091D E87EFEFFFF call 004107A0
:00410922 83C404 add esp, 00000004
:00410925 85C0 test eax, eax
:00410927 7538 jne 00410961 <-- Take this jump for successful CD check
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00410903(C)
|
:00410929 FEC3 inc bl <-- Increase the total number of tries
:0041092B 80FB5A cmp bl, 5A <-- Max number of atempts for CD check
:0041092E 7EAD jle 004108DD <-- If less the max #, keep trying
:00410930 8D8C2450010000 lea ecx, dword ptr [esp+00000150]
:00410937 C7842474040000FFFFFFFF mov dword ptr [esp+00000474], FFFFFFFF
:00410942 E879100700 call 004819C0
:00410947 32C0 xor al, al <-- Zero out al for failed CD check
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:00410817(C), :00410980(U)
|
:00410949 8B8C246C040000 mov ecx, dword ptr [esp+0000046C]
:00410950 5F pop edi
:00410951 5E pop esi
:00410952 64890D00000000 mov dword ptr fs:[00000000], ecx
:00410959 5B pop ebx
:0041095A 81C46C040000 add esp, 0000046C
:00410960 C3 ret
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses: <-- Need to get here for passed CD check
|:004108D5(C), :00410927(C)
|
:00410961 8D8C2450010000 lea ecx, dword ptr [esp+00000150]
:00410968 881DC86A5000 mov byte ptr [00506AC8], bl
:0041096E C7842474040000FFFFFFFF mov dword ptr [esp+00000474], FFFFFFFF
:00410979 E842100700 call 004819C0
:0041097E 8AC3 mov al, bl <-- Move a non-zero value to al, bl=number of tries
:00410980 EBC7 jmp 00410949 <-- Jump back up to the exit section
:00410982 90 nop
:00410983 90 nop
:00410984 90 nop
That's the basics of what the CD check is doing. Now we'll look at the two callers to find
the place we will want to place our patch. So let's first check out the code around 410790:
* Referenced by a CALL at Addresses:
|:0041064F , :00410719 , :0041072D <-- Called three times
|
:00410790 E85B000000 call 004107F0 <-- Read the exe off the CD
:00410795 33C9 xor ecx, ecx <-- Zero out the ecx
:00410797 84C0 test al, al <-- Test for the result of the CD check
:00410799 0F95C1 setne cl <-- Non-zero in al will result in cl = 01
:0041079C 8BC1 mov eax, ecx <-- Move the the "new" value into eax
:0041079E C3 ret <-- Return to the caller
Alright, that's pretty short. So lets go back one step and check out the three calls from
above. We'll check out the code surounding the three calls to see what needs to be done to kill
this call to the CD check. What we're looking for is a good spot to put a simple patch, idealy it's
place where we could make a single edit. So let's keep going with this one.
* Referenced by a CALL at Address:
|:0046A729 <-- Called from one spot!
|
:00410630 64A100000000 mov eax, dword ptr fs:[00000000]
:00410636 6AFF push FFFFFFFF
:00410638 681B484D00 push 004D481B
:0041063D 50 push eax
:0041063E 64892500000000 mov dword ptr fs:[00000000], esp
:00410645 81ECC0000000 sub esp, 000000C0
:0041064B 53 push ebx
:0041064C 55 push ebp
:0041064D 56 push esi
:0041064E 57 push edi
:0041064F E83C010000 call 00410790 <-- The first call to the above routine
:00410654 85C0 test eax, eax
:00410656 740A je 00410662 <-- Zero in eax means the CD check failed
:00410658 B801000000 mov eax, 00000001 <-- Setup for a sucessful CD check
:0041065D E912010000 jmp 00410774 <-- Jump down to the exit section
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00410656(C)
|
:00410662 8BAC24E0000000 mov ebp, dword ptr [esp+000000E0]
* Reference To: USER32.LoadStringA, Ord:0183h
|
:00410669 8B1D78D44D00 mov ebx, dword ptr [004DD478]
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0041074E(U)
|
:0041066F 8B0DD8005200 mov ecx, dword ptr [005200D8]
:00410675 8D442450 lea eax, dword ptr [esp+50]
:00410679 6A7C push 0000007C
:0041067B 50 push eax
* Possible Ref to Menu: MEDIEVAL, Item: "Single 1"
|
* Possible Reference to String Resource ID=32804: "Please insert the Get Medieval CD-ROM into the drive."
|
:0041067C 6824800000 push 00008024
:00410681 51 push ecx
:00410682 FFD3 call ebx
:00410684 85C0 test eax, eax
:00410686 7524 jne 004106AC
* Possible StringData Ref from Data Obj ->"Please insert the game CD-ROM " <-- This says it all, and is
->"into the drive." <-- what we never want to see
|
:00410688 BF90664F00 mov edi, 004F6690
:0041068D 83C9FF or ecx, FFFFFFFF
:00410690 F2 repnz
:00410691 AE scasb
:00410692 F7D1 not ecx
:00410694 2BF9 sub edi, ecx
:00410696 8D542450 lea edx, dword ptr [esp+50]
:0041069A 8BC1 mov eax, ecx
:0041069C 8BF7 mov esi, edi
:0041069E 8BFA mov edi, edx
:004106A0 C1E902 shr ecx, 02
:004106A3 F3 repz
:004106A4 A5 movsd
:004106A5 8BC8 mov ecx, eax
:004106A7 83E103 and ecx, 00000003
:004106AA F3 repz
:004106AB A4 movsb
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00410686(C)
|
:004106AC 8B15D8005200 mov edx, dword ptr [005200D8]
:004106B2 8D4C2410 lea ecx, dword ptr [esp+10]
:004106B6 6A3E push 0000003E
:004106B8 51 push ecx
* Possible Reference to String Resource ID=32771: "Get Medieval"
|
:004106B9 6803800000 push 00008003
:004106BE 52 push edx
:004106BF FFD3 call ebx
:004106C1 85C0 test eax, eax
:004106C3 7524 jne 004106E9
* Possible StringData Ref from Data Obj ->"Get Medieval"
|
:004106C5 BF50574F00 mov edi, 004F5750
:004106CA 83C9FF or ecx, FFFFFFFF
:004106CD F2 repnz
:004106CE AE scasb
:004106CF F7D1 not ecx
:004106D1 2BF9 sub edi, ecx
:004106D3 8D542410 lea edx, dword ptr [esp+10]
:004106D7 8BC1 mov eax, ecx
:004106D9 8BF7 mov esi, edi
:004106DB 8BFA mov edi, edx
:004106DD C1E902 shr ecx, 02
:004106E0 F3 repz
:004106E1 A5 movsd
:004106E2 8BC8 mov ecx, eax
:004106E4 83E103 and ecx, 00000003
:004106E7 F3 repz
:004106E8 A4 movsb
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004106C3(C)
|
:004106E9 8D4C2410 lea ecx, dword ptr [esp+10]
:004106ED 6A31 push 00000031
:004106EF 8D542454 lea edx, dword ptr [esp+54]
:004106F3 51 push ecx
:004106F4 52 push edx
:004106F5 55 push ebp
* Reference To: USER32.MessageBoxA, Ord:0195h
|
:004106F6 FF1574D44D00 Call dword ptr [004DD474]
:004106FC 83F801 cmp eax, 00000001
:004106FF 7571 jne 00410772
:00410701 E8331E0C00 call 004D2539
:00410706 8B4804 mov ecx, dword ptr [eax+04]
:00410709 E82E890B00 call 004C903C
:0041070E C78424D800000000000000 mov dword ptr [esp+000000D8], 00000000
:00410719 E872000000 call 00410790 <-- Second call to 410790
:0041071E 85C0 test eax, eax
:00410720 7531 jne 00410753
:00410722 68E8030000 push 000003E8
* Reference To: KERNEL32.Sleep, Ord:023Fh
|
:00410727 FF1560D24D00 Call dword ptr [004DD260]
:0041072D E85E000000 call 00410790 <-- The last call to 410790
:00410732 85C0 test eax, eax
:00410734 C78424D8000000FFFFFFFF mov dword ptr [esp+000000D8], FFFFFFFF
:0041073F 751D jne 0041075E
:00410741 E8F31D0C00 call 004D2539
:00410746 8B4804 mov ecx, dword ptr [eax+04]
:00410749 E803890B00 call 004C9051
:0041074E E91CFFFFFF jmp 0041066F
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00410720(C)
|
:00410753 C78424D8000000FFFFFFFF mov dword ptr [esp+000000D8], FFFFFFFF
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0041073F(C)
|
:0041075E E8D61D0C00 call 004D2539
:00410763 8B4804 mov ecx, dword ptr [eax+04]
:00410766 E8E6880B00 call 004C9051
:0041076B B801000000 mov eax, 00000001 <-- Set up for a passed CD check
:00410770 EB02 jmp 00410774 <-- Jump over "set for fail"
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004106FF(C)
|
:00410772 33C0 xor eax, eax <-- Set for a failed CD check
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:0041065D(U), :00410770(U)
|
:00410774 8B8C24D0000000 mov ecx, dword ptr [esp+000000D0] <-- This the exit section
:0041077B 5F pop edi
:0041077C 5E pop esi
:0041077D 5D pop ebp
:0041077E 64890D00000000 mov dword ptr fs:[00000000], ecx
:00410785 5B pop ebx
:00410786 81C4CC000000 add esp, 000000CC
:0041078C C3 ret
Well we have gone through a lot of code, but it's down to just one call now, so let's check
out the call 410630 and see if we can make our patch here:
-- Program code --
:0046A728 55 push ebp
:0046A729 E8025FFAFF call 00410630 <-- Do the CD check
:0046A72E 83C404 add esp, 00000004 <-- Adjust stack point for "ebp"
:0046A731 85C0 test eax, eax <-- Test the pass/fail value in eax
:0046A733 0F84CC020000 je 0046AA05 <-- Take this jump for failed check
:0046A739 6854020000 push 00000254
:0046A73E E86DDF0500 call 004C86B0
:0046A743 83C404 add esp, 00000004
:0046A746 89442414 mov dword ptr [esp+14], eax
:0046A74A 3BC5 cmp eax, ebp
-- Continuing programming code --
Finally, we have a place to put a simple patch and we have sucessfully kill the FIRST
call the CD check routine. My method to cracking programs is kill the call to the CD check
and let the program code be able to continue normaly as though the CD check had passed. The
"best" way to do that here, is to change the call 00410630 to mov eax, 00000001. This allows
the program to "fall" through the je and let the game continue so we can play it. Now, lets
go back and track down the second call and find a good location to place our other patch.
Then we'll have a cracked game that can be played any time without the CD present.
* Referenced by a CALL at Addresses:
|:00426D21 , :00427391 , :0042C551 , :0042D461 <-- Called by four seperate places
|
:0042C060 56 push esi
:0042C061 8BF1 mov esi, ecx
:0042C063 8B86E0000000 mov eax, dword ptr [esi+000000E0] <-- Flag used for "CD check done"
:0042C069 85C0 test eax, eax
:0042C06B 7408 je 0042C075 <-- Jump down to the CD check below
:0042C06D 8A86DC000000 mov al, byte ptr [esi+000000DC] <-- Else load the pass/fail flag
:0042C073 5E pop esi
:0042C074 C3 ret <-- Return to the caller
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0042C06B(C)
|
:0042C075 E87647FEFF call 004107F0 <-- Call the CD check
:0042C07A 8886DC000000 mov byte ptr [esi+000000DC], al <-- Store the result in new flag
:0042C080 C786E000000001000000 mov dword ptr [esi+000000E0], 00000001 <-- Show we have done the check
:0042C08A 5E pop esi
:0042C08B C3 ret <-- Return to the caller
As you can see, a good place to put the second patch is right here at 42C075. Again changing
the call to mov eax, 00000001 will overwrite the CD check and allow the program to continue running.
After appling this patch along with the first one, you will have successfully cracked Get Medieval.
Which is why started this little adventure. The steps need to crack this one are as follows:
1. Do a full game install
2. Make the following edits:
Edit Medieval.exe
=============================================
Search for: E8 76 47 FE FF at offset 177,269
Change to : B8 01 00 00 00
Search for: E8 02 5F FA FF at offset 432,937
Change to : B8 01 00 00 00
Get Medieval is now FiX'ed and can be run from your hard drive without the CD being online.
The last thing you can do is to copy Medieval.fec, which is the movie file. Just copy this file to
the main Medieval game directory and the program will find it and use it. This is one of the most
funny intro movies I have ever seen. I just love the comments made by the four game characters, it
made me bust out laughing. This is of course optional and not needed to play the game, but I think
it's worth the 42 megs it takes up on the hard drive.
Well that concludes this tutorial, now go Get Medieval on someone!
Static Vengeance
Get Medieval Cheat Codes (same as Claw)
---------------------------------------
mpkfa God mode
mppos Global position
mpfps Show frames per second