Have you ever heard of Kajko and Kokosz? They are comic characters created by a Polish comic creator named Janusz Christa. Two Slavic warriors travel the world, tackling all sorts of problems with their village along the way. Over the years, various media related to them have been released - comics, computer games, and recently, they even got their own TV series on Netflix! Some people also suggest that they are the Slavic version of Asterix & Obelix, as the characters’ visual appearance and archetypes are similar in both series. Those suggestions were, however, never confirmed.

Speaking of computer games, in this blog post we will investigate one of them: Knights: Learn to Fly published by Play Publishing in 2005. In this game you can play as either Kajko or Kokosz. Your task is to collect coins, defeat enemies, and in some levels, even fly on a broom! When I was a child, with new games I liked to press every possible key on a keyboard one by one and observing their effects on the game. This game was no different. After I pressed ~ on my keyboard, a console popped up. Back then, I didn’t understand the purpose of such consoles, I tried writing random messages, thinking that maybe this was some kind of chat, and someone would reply. Unfortunately, no one did, so I gave up and closed this mysterious window, focusing instead on playing the game. Today, armed with knowledge about game reverse engineering, we will solve this riddle!

Getting started

Empty console

After we open the console, we are greeted with the message: Argon engine featuring Kajko i Kokosz. Mirage Interactive 2005.. We can type commands and execute them by pressing Enter on the keyboard, just like in normal command prompt. The question is, what commands are accepted and what can we achieve by using them?

Linux commands

To answer this, we will need to take a look inside the game binary. Our task is to find a function that is handling the user commands. To do so, we will use the following property: after you execute a command, the command itself is printed out to the console, so if you type ls and press Enter, ls will be printed to the console. It seems that before the command handler is executed, the print function is called. We could simply put a breakpoint on the print function and then inspect the call stack. Sounds good, but how do we find the print function? This should actually be easy. Do you remember the greeting message that is shown at the top of the console? It looks like a hardcoded string that should be easy to locate, and that string is probably directly passed to the printing function.

Analyzing

To analyze the game executable we will use Ghidra. To perform live debugging - x32dbg, both of them are open source and free to use. After throwing the binary into Ghidra, we can go to Window -> Defined Strings menu, and look for the string located at the top of the console

Defined strings

We see that Ghidra found one reference to that string. Let’s go there

xref

Xref in decompilation window

It looks like the FUN_00431d40 is that one that prints text to the console. We will rename it to print_to_console. Now we can look up all the places from which the function is called:

References to print to console

As we can see, there are a lot of references to this function. We could analyze them one by one, however it would take a lot of time. A much smarter approach is to attach a debugger now. Basically, we will:

  1. Run the game
  2. Attach debugger
  3. Put a breakpoint at FUN_00431d40
  4. Write something to the game console
  5. Inspect call stack on breakpoint trigger, so we can see from where the print was called.

After performing all the steps we see this: x64dbg callstack

So our assumption was correct; indeed after we execute any command (letsreverse in this case), the print function is called, and then the game will jump back to 00434FD0 address. Let’s analyze this function in Ghidra.

function in Ghidra quit fck exec

Interestingly, it looks like some commands are processed prior to printing: quit, exec and… fuck. quit closes the game, exec executes all the commands that are stored in ar.cfg file in game directory, while fuck responds with Don't make me e-mail your mom!. If any of these commands are executed, the command itself won’t be printed to the console. If the entered command is different from those already mentioned, the command itself is printed. Additionally, if the command contains a parameter, such as letsreverse 1, then another handler at address 00433ed0 is called. This can be seen in the screenshots above.

Getting the commands

Next handler

The second handler contains a lot of commands. I parsed the decompiler output to list all of them:

DropDebug
credits
screenwidth
screenheight
bitdepth
runworld
mirmil
loadmodels
DrawModels
DrawToonEffect
drawfps
DrawPolygonCount
drawsnow
SnowPhysics
SnowNumFlakes
drawsky
invisible
drawshadowmesh
raportsubsets
raporttextures
sound
DrawStencilShadows
DrawDepthShadows
drawlightrays
drawgrass
detailedgrass
draweffects
lightsemitsmoke
numconsolelines
consolelog
eraselog
extractusedtextures
grasswidth
meshtospritecoef
shadowdistcoef
qualitytextures
dupadupa
raporttechs
numlights
ForceSmallerTextures
farz
fogfar
fognear
fogr
fogg
fogb
ambientr
ambientg
ambientb
skylightr
skylightg
skylightb
SkyLightRotation
SkyLightPitch
SkyShadowsRotation
SkyShadowsPitch
DrawCharacterPaths
DrawPaths
Dither
PlayerBreathe
ProjectedShadowDist
DrawSnowClouds
MeshUpdateCoef
DrawSprites
DrawScreenFilter
FontSizeCoef
MeshMaterialAmbient
MeshMaterialDiffuse
StartMenu
NoClipSpeed
DrawCameraCoordinates
DrawTreeShadows
DrawTransparent
DrawTranslucent
DrawCompass
michael
UpdateMainGame
Gamma
GammaR
GammaG
GammaB
Debug
SystemDebug
AutoScreenshotTime
EnableAntialiasing
TrilinearFiltering
DisableLensFlares
DisableInsects
TreesAlwaysFullDetail
CameraDeg
CameraDist
CameraUp

A lot of these commands are self-descriptive. The most interesting and intriguing ones, in my opinion, include:

  • credits - Prints out credits that are normally nowhere to be seen in the game(?)
  • runworld- Allows to load arbitrary game levels
  • mirmil - Modifies the game save file to appear as if you have completed the entire game, unlocking all levels. By the way, Mirmił is the name of the gord’s leader. The gord in which some of the game levels take place is named Mirmiłowo
  • invisible - Makes the game character invisible, so enemies don’t target you
  • michael - Sets some values in the memory. However, it seems these values are never read (as evidenced by both static analysis and setting a hardware breakpoint), so the behavior remains unknown
  • dupadupa - Enables speedhack and possibility to pass walls and obstacles without colliding with them. Intriguing name, especially considering that dupa means ass in Polish. You can see the command effect on the video below

Future

The reason why those commands were left in the official game release remains unknown. It is unclear whether the authors left them by mistake or intentionally. However, we can make use of them when it comes to modding. In future posts, I will show you how to print your own text to the console, and how to add your own commands.