Lua & You - and the game, I guess

Today is going to be a quick demonstration on exploiting games that use Lua. For simplicity I’ll be using Civ 5 as my example.

Introduction

If you are unaware of what Lua is, it’s an open source scripting language developed to be lightweight and portable. Along with that it is quite simple to pick up the syntax, making it a pretty popular choice in many of today’s online games, including Civ 5.

Generally, software that contain an embedded scripting language make it incredibly easy to inject your own scripts. Lua even more so due to the fact that it is open source.

https://www.lua.org/source/

What we’re going to do is create a Dynamic Link Library (DLL) that we can inject into the process which will execute our custom Lua script. Access to the game’s Lua API will make cheat development easy.

Doing some recon

First of all, we have to make sure our game actually uses Lua. In our case it’s trivial to check. The main folder contains ‘lua51_Win32.dll’

found it

Of course it is not always this easy. Often developers will statically link Lua to the main executable rather than put it in the open. Usually removing the symbols as well. This can easily be remedied by scanning for the function signatures, however.

If all else fails a quick Google search should tell you if the game uses any scripting languages.

Another thing I found was the Lua API implementation in the game. This will be useful to us shortly.

http://modiki.civfanatics.com/index.php?title=Lua_and_UI_Reference_(Civ5)

Since our goal is to force the game to run our custom scripts, we must understand how Lua works and how to use it properly. This is where the source code comes in handy.

Based on a couple of forum posts and briefly looking at the source code, executing a script is quite simple. All we need to do is get a lua_State pointer and call two functions. luaL_loadstring and lua_pcall.

Setting up

Create a new DLL project in Visual Studio. Make it so it will spawn a new thread for your main function when it gets attached. (see below)

void MyEntry();

BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved)
{
	if(dwReason == DLL_PROCESS_ATTACH)
	{
		// Disable the DLL_THREAD_ATTACH and DLL_THREAD_DETACH notification calls.
		DisableThreadLibraryCalls(hModule);

		// Run our code in a seperate thread
		CreateThread(0, 0, (LPTHREAD_START_ROUTINE)MyEntry, 0, 0, 0);
	}
}

void MyEntry()
{
	// our main code will be here
	// ..
}

As mentioned earlier, we need to call those 2 functions. Before we can call them they need to be defined in our code. Check out Lua’s source code again and look for the function definitions.

// In lua.h
LUA_API int   (lua_pcall) (lua_State *L, int nargs, int nresults, int errfunc);

// In lauxlib.h
LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s);

Cool. How can we define and call these in our code?


// We typedef the functions based on the definitions we found above from the lua source.
typedef int (__stdcall* _lua_pcall)(void* L, int nargs, int nresults, int errfunc);
typedef int (__stdcall* _luaL_loadstring)(void* L, const char* s);

// This is a handle to the Lua DLL, needed for GetProcAddress
HMODULE hLua = GetModuleHandle("lua51_Win32.dll");

// This tells our code where the functions are actually implemented
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms683212(v=vs.85).aspx
_lua_pcall lua_pcall = (_lua_pcall)GetProcAddress(hLua, "lua_pcall");
_luaL_loadstring luaL_loadstring = (_luaL_loadstring)GetProcAddress(hLua, "luaL_loadstring");

...

// Calling the functions

// Loadstring pushes our script onto the luaState's stack
luaL_loadstring(L, "script will be here");

// And pcall (protected call) executes the string
luaL_pcall(L, 0, 0, 0);

sidenote: you can do this with any exported function in any process, as long as your code is running in the same process.

Awesome. That leaves us with only one more problem. How do we get the lua_State parameter?

Really there are probably a dozen different ways to retrieve it. Some being more reliable than others. For simplicity we’ll find it with an easier method.

Writing a script

With the ability to run whatever we want now, let’s get back to that API we found earlier and take a closer look.

http://modiki.civfanatics.com/index.php?title=Lua_and_UI_Reference_(Civ5)


Player::AddFreeUnit(UnitType arg0, UnitAIType UNITAI_DEFENSE);

Bingo. That was easy, let’s see if we can use it.

local localPlayer = Players[Game.GetActivePlayer()];
localPlayer:AddFreeUnit(GameInfo.Units["UNIT_PIKEMAN"].ID, UNITAI_DEFENSE);

Testing our application

So we have our C++ application setup which will load our script. VS builds it O.K. and we have our DLL file ready to go. Boot up Civ5 and start a match. To load our file into the game, open up Cheat Engine and the memory viewer. Under tools you may choose the ‘Inject DLL’ option to select your fresh hax.

Voila, you should see a nice little pikeman awaiting your orders. That’s all there is to it. Congrats!

Points to improve on

  • The DLL may occassionally crash the game when executing a script. This is because we are not running in the main process thread. The calls we are making are not thread-safe. Because of that, the game may still access & modify the lua_State while we are in the middle of running our own code. This is easily fixed by hooking and running our code in a subroutine that is called from the main thread, such as lua_gettop, making sure nothing else screws with the state.

  • Alternatively to lua_loadstring, you may use lua_loadfile instead to execute scripts directly from a lua file.

  • Another benefit of hooking lua_gettop is that we’ll have direct access to the lua_State pointer directly from the ecx register.

  • Can you create a console window that allows users to input their own scripts?

  • Try to create more scripts to push the game in your favor. I mentioned unit spawning, but there are many more possibilities. Can you give yourself gold? Remove the fog? Hint: the answer is yes.

Conclusion

This was a quick write up sharing some information on how to get a Lua script running with loadstring. If you found this easy, look to improve on it in as many ways as you can. See how many exploits you can find in the game’s API. From there work towards more challenging games. Don’t stop at Lua. There are many game specific languages out there that can be exploited. You just have to explore.

Written on September 14, 2018