Reversing Lua’s C API
For the rest of this writeup I’m going to be using IDA Pro. This tutorial assumes a basic knowledge of both IDA(or another disassembler) and the Lua programming language.
If you click on the link above in the Lua section, you’ll see a list of Lua’s C API Functions. They are basically just functions you can call to interact/manipulate Lua through C. The easiest way that I’ve found to locate specific C API function’s is to just download the Lua source code and look for string references. You can find the Lua version that the program uses’s by searching for the string $Lua
Once you’ve figured out what Lua version the program uses, download the source code and open it up in a text editor. At this point you can just use strings to locate any C API function. I’m using Lua version 5.1.1, but the process doesn’t change much throughout versions.
Executing custom lua scripts
In order to execute custom lua scripts, you need to find two functions: luaL_loadbuffer and lua_pcall.
If you open up the lua source code and look at the Lua method “db_debug”, you’ll see that it calls both luaL_loadbuffer and lua_pcall. 
Open up a disassembler and cross reference “=(debug command)”. You should get 1 result, which will bring you inside of db_debug. 
If you look at line 22, you’ll see luaL_loadbuffer and lua_pcall being called. With those two functions alone you can execute any custom Lua script(see here)
I’m not going to cover finding any more lua API functions because the process is mostly the same for every lua method.
Interacting with Lua scripts
Dumping Lua Scripts
I’m not entirely sure if there are other ways to load Lua scripts, but in every program I’ve seen, Lua scripts are loaded through luaL_loadbuffer. You can dump Lua scripts by hooking luaL_loadbuffer and writing scripts to a file.
The typedef for luaL_loadbuffer is
Here is an example of dumping lua scripts from a hooked luaL_loadbuffer method(note that I use int* in place of lua_State* because I personally have no need to reverse lua_State):
Adding this code to your luaL_loadbuffer hook allows you to dump Lua scripts. However, this code might not work in every situation. luaL_loadbufffer supports passing a file buffer OR plain Lua text in the buff parameter. You could end up crashing if you try to create a file with plain text passed in the buff parameter. I haven’t ran into this issue yet, so I can’t provide a definitive solution.
One solution could be to check the size of the buffer with strlen. If the buffer stores the bytes of a lua file, then it should have a length of 5 and the text “LuaQ” when the buffer is converted to a string.
Adding that check to your hook should work, but it might not work in every case.
Another thing to note is that some programs pass the files name(if applicable) in the description parameter, so you might be able to assign files their real name.
If you successfully dump a program’s Lua files and notice they look like garbage in a text editor, then it usually means the lua scripts are compiled. You can use a tool called unluac to decompile those scripts and retrieve the source code if that is the case.
Modifying/Replacing Lua scripts in memory
If you a script gets loaded from a file in luaL_loadbuffer, then you can just swap the buffer and size in your hook.
The code above is an example of how you could replace a script in memory. The only issue is that it assumes the script name is passed in the description parameter, and that the script is being loaded from a file. If thats not the case then you’ll have to find some way to identify the script you’re looking to modify(possibly use the size parameter)
If the script is not being loaded from a file, then one option would be to do some string processing on the buffer parameter to modify/parse its contents.
Using the Lua C API
Assuming you’ve found whatever API function’s you want to use, the biggest issue to tackle is dealing with multithreading/Lua states. If you’re not familiar with what a Lua state is then see here
When I first started reversing apps that use Lua, I always had an issue with random crashes when trying to execute API functions. In my case, the issue was that the program I was reversing had multiple Lua states, and was multi-threaded.
Multi-threading is relevant to Lua because it is a stack based language. Here’s an example issue you might run into if threading is a problem:
Imagine you’re trying to call a method, so you push a parameter on the stack. If the program is multithreaded and you’re not making the API calls in the Lua thread, then there’s a chance that another thread could push something else onto the stack before you can call the method that uses the parameter. This would corrupt the stack causing the program to crash.
When I ran into this problem, I remember reading some post saying that I had to “find the program’s internal Lua locking mechanisms”. In my experience, I’ve never actually had to do that.
The solution is simple: hook any Lua API function that gets executed often, and execute whatever API function’s you want in your hook. Generally I hook lua_pcall. Some programs don’t use lua_pcall though, so you may have to hook a different method(such as lua_gettop).
The only other issue is figuring out which Lua state to use. If a program uses multiple Lua states then you have to figure out which one you want to use. If there is a specific Lua state you need to use, then you just have to find a global value specific to that state. Here is an example of executing your own Lua code in a hooked function.
Things to note
- The variable bExecuteCustomLuaCode gives you control of when you want to execute code. The variable can be removed so long as you have proper control flow to determine when you want to execute custom lua code.
- Because sleep() cannot be used in your hook(unless you want to block the entire thread that lua is executing in), I recommend using the clock_t class. The clock_t class allows you to easily keep track of time between function calls, and can be used for some very hacky solutions.
- If you aren’t targetting a specific Lua State, then you can just remove the code in relation to setting the target lua state. However, you have to make sure you’re executing all the API functions on the same Lua State. Assuming it doesn’t matter which Lua State you use, I reccomend creating a global variable to store whichever lua state you use(which you can just choose randomly in your hook) and executing all API function’s in that lua state.
- Additionally, if the program you’re reversing only has one lua state, then you can just remove all the code relating to using a specific lua state. Sadly that’s not the case in all programs, so its just a matter of luck.
Closing Thoughts
The Lua API is generally pretty easy to reverse. Alot of programs that embed Lua implement a large portion of their functionality in Lua(even going as far as making C functions callable through lua). Whether or not reversing the lua API is worth it depends on what functionality they implement in lua, and what functionality you are looking for.
Here are my signatures for some of lua’s C API functions(version 5.1.1):
The signatures should work for other versions of lua, but they could break in older/newer versions of lua.
Как выгрузить код из контекста Lua
Я использовал функцию luaL_loadbuffer() в течение длительного времени, и она отлично работает.
Однако теперь мне нужно разгрузить. Почему я хочу это сделать?
У меня есть внутренние карты C++, которые я хочу инициализировать с помощью сценариев Lua, но затем отбросьте каждый сценарий Lua, как только карта C++ была инициализирована. В таблице Lua используется гораздо больше памяти (7 мегабайт против 200 тыс. Для C++) и не может выполнять такие функции, как lower_bound() и upper_bound() которые мне нужны.
Элементами карты являются std::pair<uint32_t, uint32_t> , по существу IP-адреса, хранящиеся в двоичном формате.
Любой способ выгрузить код Lua, который был загружен в контекст Lua после его выполнения один раз?
Как выгрузить/уничтожить lua-скрипт?
Я пытаюсь сделать очень простую оболочку lua, которую можно использовать для загрузки и запуска нескольких сценариев Lua. Меня это беспокоит, потому что я не вижу никакой документации о том, как правильно уничтожить/удалить загруженные скрипты без полного уничтожения самого lua_State.
Можно ли удалить/выгрузить загруженные lua-скрипты? Это не нужно или постоянный вызов luaL_dofile приведет к утечке памяти?
Упрощенный вопрос. Если я вызову luaL_dofile для того же объекта lua_State, приведет ли это к утечке памяти или проблемам, или lua обрабатывает это в серверной части, когда загружает новый скрипт?
2 ответа
Если под выгрузить вы подразумеваете отмену эффектов запуска некоторого кода Lua, то это невозможно сделать, если вы не сохраните состояние того, что ценно, перед запуском кода. Это можно сделать, поместив код в песочницу.
Если вы просто хотите удалить таблицу Lua, обнулите все ссылки на нее и разрешите сборке мусора таблицы автоматически или вручную.
Когда вы загружаете файл lua, вы действительно выполняете его код. Это не похоже на dll или что-то в других языках:
int luaL_dofile (lua_State *L, const char *filename);
Загружает и запускает данный файл. Он определяется следующим макросом:
Если ваш файл выглядит примерно так:
Затем загрузка файла создаст функцию «sayHello» для глобального объекта. Если вы снова загрузите файл, он заменит существующую функцию новой, и не должно быть утечки памяти. Любой, кто вызывает «sayHello», вызовет новую функцию для глобального объекта, если только он не сохранил ссылку на исходную функцию. Код обычно делает это, потому что вызов локальной переменной немного быстрее, чем глобальная функция. Например, если в другом файле есть local sayhi = sayHello вверху, то любые вызовы ‘sayhi’ будут вызывать исходную функцию.
Если вы создаете классы и ожидаете, что данные останутся, любые объекты (таблицы lua), созданные до перезагрузки, по-прежнему будут ссылаться на метатаблицы для старых классов. Код для ваших новых классов не будет автоматически применяться к классам, созданным до перезагрузки.
How do I unload/destroy a lua script?
I’m trying to make a very simple lua wrapper that can be used to load & run multiple Lua scripts. I’m concerned because I don’t see any documentation on how to properly destroy/delete loaded scripts without completely destroying the lua_State itself.
Is it possible to delete/unload loaded lua scripts? Is this unnecessary or will continuously calling luaL_dofile lead to a memory leak?
Simplified question. If I call luaL_dofile on the same lua_State object, will this lead to a memory leak or issues or does lua handle this in the back end as it loads a new script?
2 Answers 2
If by unload you mean undo the effects of running some Lua code, then it cannot be done unless you save the state of what is precious before running the code. This can be done by sandboxing the code.
If you just want to remove a Lua table, set to nil all references to it and let the table be garbage collected automatically or manually.
When you load a lua file you are really executing it’s code. It’s not like a dll or something in other languages:
int luaL_dofile (lua_State *L, const char *filename);
Loads and runs the given file. It is defined as the following macro:
If your file is something like this:
Then loading the file will create a function ‘sayHello’ on the global object. If you load the file again it will replace the existing function with the new one and there should be no memory leak. Anyone calling ‘sayHello’ will call the new function on the global object, unless they saved a reference to the original function. Code commonly does this because it is slightly faster to call a local variable instead of a global function. If another file has local sayhi = sayHello at the top for instance then any calls to ‘sayhi’ will call the original function.
If you are creating classes and expect the data to remain, any objects (lua tables) created before the reload will still reference the metatables for the old classes. The code for your new classes will not automatically apply to classes created before the reload.