Game Name: MDK 2
Game Vendor: GOG
Game Process: mdk2Main.exe
Game Version: 1.003
Game File Size: 768 KB
[ Context ]
Hello, folks. I've recently started looking at old games from my childhood, simply because at the time I was just enjoying playing them rather than checking out what's "under the hood". So I've had a nice time digging up/out whatever the internet apparently either doesn't have anymore or it never had. Doing searches for cheats, trainers, etc. for these games will return very little to no results, I guess mostly because no one gives a rat's ass about them anymore. Well, not everyone That being said, let's proceed.
[ Cheats ]
Scouring the Internet for some references I found several cheats being listed out [Link].
Then I wanted to learn a bit where these came from, how they're stored in the game's data, are they strings [?], are they some functions [?] Then I noticed in the actual game disclaimer there's mentioning of the word "Lua"
The cheats mentioned 2 paragraphs above are to be typed into a console which you can open via the Tilde (`~) key:
Several considerations:
- If the key doesn't work for you and you're on some non-QWERTY keyboard, then please follow this and add EN ad you secondary keyboard language: [Link]. You can then use Alt + Shift key combination to switch between keyboard languages back and forth.
- You will notice YOU CANNOT PASTE text in the console. Which is very annoying. This led to what follows.
- I believe the console can only process 1-liner commands. Since you cannot paste more text, I doubt anyone would want to write a Lua function from start to end with no 'new line' rows. I have not tried this, as it wouldn't make sense. Why am I mentioning Lua functions you will discover a bit later
[ Background ]
That being said.. and learning that the game's Engine is called Omen and it's a LUA Engine, I was curious to know WHICH Lua version were they using. The game was developed in 2000, so Lua wasn't that very far ahead. I then looked up the referenced strings in the binary and found out there's a "Lua 3.1" reference So boom, there we go.
Then I said to myself: "I wanna find the source code for Lua 3.1 and/or DLL binaries built with the SAME Visual Studio C++ version the game uses (VC++ 8)". Old shit again, right? Chances of me finding stuff like that were very slim. Well.. I did find the source code for Lua 3.1 at [Link]. Note that it's a .tar.gz containing a .tar. So you'll have to double-extract it (I will also attach it to this page at the bottom, so we keep back-ups). From that I was only interested in the src folder, seeing there's nothing to be used in the bin folder. You'll learn in a bit why the source code was SUPER useful
Then.. "alright, I have the source code.. but I also want to find a binary.. if possible, one built with same VC++ 8 as the game's". I couldn't find a 3.1, but I did find a 3.2 at [Link], built with VC++ 7 though. Useful, in absence of anything else. Also linking it at the bottom.
Lastly, "cool, I have these, but since we're talking about Lua, isn't the game supposed to be running some Lua scripts? where are these?". I then saw there are a bunch of ZIP files in the game's folder, then \MDK 2\data\ path:
So I tried to extract them, only to learn BioWare used some proprietary compression (PKImploding). But hey, at least there's a tool that can extract them - PKZIP - which I could download from [Link]. More information on the subject can be read at this location: [Link] (you will notice I will be referencing this forum several times more).
PKZIP helped me unpack what I was interested in and found quite a bunch of nice .lua scripts in those ZIPs (you can see the folders extracted in the screenshot above). The scripts helped me understand a bit how the game's Engine works, as well as this topic: [Link]. So I want to take a quick stop and thank that dude there -- Egor305 -- for all the nice and juicy information he's pulled out from the game back in 2014.
With all of the above in mind I was able to map 80% of the Lua functions in the game's binary (using both the source code and the 3.2 DLL to guide myself by; how: by searching for string references from the mdk2Main.exe into the source code and the 3.2 DLL's referenced strings; nothing magic about it, just plain logic). So this is how my executable looks like now:
Like in the MDK topic on this forum, you will find the .dd32 database at the bottom, so you can inspect and use it to your heart's content.
[ Running Lua Scripts ]
As per the topic I mentioned above - [Link] - there is mentioning of a Lua function which, if ran in the game's Lua context, could allow the user to SPAWN various objects. The code, transcribed, looks like this:
Code: Select all
function make(type)
b=mdkGetPlayerGob()
g=mdkCreateObjectLua("",type,scene)
QuatYDir(g.position,b.orientation)
VectorMul(g.position,6)
VectorAdd(g.position,b.position)
end
So.. how the hell do we run this, considering we can't PASTE an entire block of text in the existing console? The answer came through studying a bit how the game loads up its .lua files and executes them. And that happens here:
The function is called "dofile" internally, but you can see it's a C wrapper calls-in Lua functions. Reading through [Link], I understand that it's good practice to wrap the Lua calls with a lua_beginblock/lua_endblock pair:
Then we have the main exec, so to speak, in the form of lua_dobuffer, doing this:
Hey, a lot of information in the documentation that helps connect the dots. Don't you think?
[ Cheat Table ]
With that in mind and with some guidance/tips from my good ol' pal Zanzer -- thanks, by the way! -- I was able to design this CE UDF:
Download:
Open CE, target mdk2Main.exe, then open the table. When asked if you want to run the Lua code, click YES. To open the UDF head to Table menu in main CE GUI, then UDF1, then Restore and show. Make sure to drag it outside CE's main window - left or right - as it will get placed behind the main CE GUI when you alt-tab to another process.
The code behind it does the following:
Code: Select all
COMMAND_COUNT = 0
function UDF1_InputKeyUp(sender, key)
if isKeyPressed(VK_SHIFT) then
if key == VK_RETURN then
local text = sender.Lines.Text
if text and #text > 0 then
text = trim(text)
UDF1.Log.Append('* ' .. string.format( "%03X", COMMAND_COUNT ) .. ' *\r\n')
UDF1.Log.Append(text .. '\r\n')
--text = text:gsub( "\r\n", "\n" )
writeString( getAddressSafe( "_buff" ), text )
writeBytes( getAddressSafe( "_buff" ) + #text, 0 )
writeInteger( getAddressSafe( "_size" ), #text )
executeCodeEx( 0, nil, getAddressSafe( "_exec" ) )
sender.Lines.Text = nil
COMMAND_COUNT = COMMAND_COUNT + 1
end
end
end
return key
end
function UDF1_ClearClick(sender)
strings_clear(memo_getLines(UDF1_Log))
COMMAND_COUNT = 0
end
function trim(s)
return s:find'^%s*$' and '' or s:match'^%s*(.*%S)'
end
local gameModule = getAddressSafe( process )
local offset = 0x500
local _name = gameModule + offset + 0x00
unregisterSymbol( "_name" )
registerSymbol( "_name", _name, true )
writeString( _name, 'script' )
writeBytes( _name + 0x6, 0, 0 )
local _size = gameModule + offset + 0x08
unregisterSymbol( "_size" )
registerSymbol( "_size", _size, true )
local _exec = gameModule + offset + 0x10
fullAccess( _exec, 0x1000 - offset )
unregisterSymbol( "_exec" )
registerSymbol( "_exec", _exec, true )
local _buff = gameModule + offset + 0x40
unregisterSymbol( "_buff" )
registerSymbol( "_buff", _buff, true )
local lua_beginblock = gameModule + 0x43F50
unregisterSymbol( "_lua_beginblock" )
registerSymbol( "_lua_beginblock", lua_beginblock, true )
local lua_dobuffer = gameModule + 0x46100
unregisterSymbol( "_lua_dobuffer" )
registerSymbol( "_lua_dobuffer", lua_dobuffer, true )
local lua_endblock = gameModule + 0x43FA0
unregisterSymbol( "_lua_endblock" )
registerSymbol( "_lua_endblock", lua_endblock, true )
local _wrapper = [[
_exec:
push ebp
mov ebp,esp
call _lua_beginblock
push _name
push [_size]
push _buff
call _lua_dobuffer
add esp,C
call _lua_endblock
mov esp,ebp
pop ebp
ret
]]
result, disableinfo = autoAssemble( _wrapper )
- There are 2 memo boxes and a button
- Your text goes into the bottom memo, the white one, called Input. It accepts multi-line, hence why we're doing it like this and not through the game's console (where you would have to type everything in 1 line/row).
- Once you type your stuff and are ready to send it to the game's Lua, you will press Shift+Enter key combination.
- The function UDF1_InputKeyUp OnKeyUp event handles input coming from the form and when it detects Shift+Enter have been pressed, it does 2 things: outputs the text to the top memo, the purplish one called Log -- AND -- executes your text in the game Lua's context.
- the Clear button will clean the Log memo and reset an internal variable to 0 (COMMAND_COUNT). This variable is used to keep track of how many commands/functions/scripts you've type in (just a quirk, not that important). The clean-up is done via function UDF1_ClearClick OnClick event.
- What's being executed in the game's Lua context is done through local _wrapper, which is an assembled piece of code in the PE header of mdk2Main.exe. How it's executed: through executeCodeEx( 0, nil, getAddressSafe( "_exec" ) ) in UDF1_InputKeyUp function.
So.. with that in mind, you can now copy this..
Code: Select all
function make(type)
b=mdkGetPlayerGob()
g=mdkCreateObjectLua("",type,scene)
QuatYDir(g.position,b.orientation)
VectorMul(g.position,6)
VectorAdd(g.position,b.position)
end
Code: Select all
make(num OR string)
The num OR string in the above code wrapper has to be changed to the values listed in this topic: [Link].
For example, if I am playing as Kurt and I want to spawn a Super Chain Gun object, I would hit Tilde (`~) key and type in:
Code: Select all
make(356)
Code: Select all
make(OBJ_SUPERCHAINGUN)
And here's an example of a spawned SUPERCHAINGUNs:
To close the console once hitting Enter, press ESC key. Yes, it will bring up the game menu, but you can hit ESC again to resume the game.
[ Others ]
I've mapped a few things in my executable and below you can download the .dd32 file to be used with x32dbg (it's the x86 debugger that's part of the [Link]). Inside this file you will find a shit ton of comments and labels to assist in your craving to study the game's executable
Download:
What to do with it:
- get x64dbg downloaded and unzip it to a folder of your choice (e.g.: C:\x64dbg\)
- head to \x32\db folder (e.g.: C:\x64dbg\x32\db\) and place the .dd32 file in the ZIP there
- open mdk2Main.exe in x32dbg and check the comments/labels
Also attached the mdk2Main.exe for reference/backup/archiving purposes, just in case the GOG.com version updates (doubt it would):
As usual, enjoy!
BR,
Sun
P.S.: Next-up -- Giants: Citizen Kabuto.
How to use this cheat table?
- Install Cheat Engine
- Double-click the .CT file in order to open it.
- Click the PC icon in Cheat Engine in order to select the game process.
- Keep the list.
- Activate the trainer options by checking boxes or setting values from 0 to 1