No, we are not going to talk about space travelling, or interplanetary missions. No. We are going to talk about Lua. Lua is Portuguese for Moon and it is a very nice scripting language that is usually hidden behind the Python hype.
Anyway, why are we talking about Lua?. Well, I have been planning to write a series of articles about “How does the hacker’s tools work?”, as a response to all those “How does you use those hacker’s tools without having a clue of what you are doing?”. I started talking about ProxyChains some weeks ago and this is the second post of the series.
Again. Why Lua?. Ok, two of the most widely used hacker’s tools are wireshark and nmap… And know what?.. both use Lua as scripting language. You can write wireshark dissectors, or sophisticated recon scripts using NSE (the Nmap Scripting Engine) and for doing both things you will have to write some Lua code.
Not a Language Tutorial
If you were expecting a Lua tutorial, I regret to disappoint you. There are very good tutorials on-line, and , on top of that, the language is pretty simple.
So, we are going to see how to add Lua scripting capabilities to our own tools… the same way that wireshark or nmap does.
Embedding a Scripting Language
When you embedded a scripting language in your applications, there are always two thing you have to do:
- Load and run scripting code from external files
- Allow the scripting code call functions provided by your application
These two things are what we are going to elaborate through this post.
I will be using Lua 5.1 in the examples. I haven’t tried neither 5.0 nor 5.2. Probably any of them will be OK but I cannot assure that.
Embedding a Lua Interpreter
Let’s start embedding a Lua interpreter in a C application and run an external Lua script. As you will shortly find out this is really simple:
#include <lua5.1/lauxlib.h>
static lua_State *l;
int
main(int argc, char *argv[])
{
l = luaL_newstate ();
luaL_openlibs (l);
luaL_dofile (l, argv[1]);
return 0;
}
The luaL_newstate
initiates a new Lua environment. The lua_State
var is, somehow, the handler for our Lua interpreter. Once the interpreter is started we need to load a minimal set of libraries. You have to do this if you want to print something on the console, open a file, do some math or manipulate strings. So, you better call luaL_openlibs
just before you initialise your Lua environment.
Now, it is time to compile it:
gcc -o test1 test1.c `pkg-config --cflags --libs lua5.1`
To test this first program, we need a Lua script. So let’s write the omnipresent Hello World
in Lua:
print ("Hello World")
Let’s save it in a file named hello.lua
Now we can run our application:
$ ./test1 hello.lua
Hello World
So far so good.
A Stack Machine
Before going further in our trip to the moon, we have to introduce the concept of stack machine. A stack machine is a kind of computer that uses a stack for its operations instead of registers as most of the processors you may know. Check the wiki for details Stack machine - Wikipedia.
Lua has been build this way, and all operations and symbols used by a Lua instance have to go in and out of a virtual stack. So, from this point on, we will see how we push data into this stack to communicate with the Lua interpreter and how we pop data from the Lua interpreter to get results.
We will see in a bit all this at work, just be ready to see some push
s and pop
s in the code to interact with the interpreter.
Have you ever heard about Forth?. it is a stack-based language used by the Open Firmware project. So if you want to configure some non-x86 machine it will be handy to know a little bit of Forth
Getting the value of a variable
We have just learned how to run Lua scripts from our apps. Now we are going to see how to execute a specific function in a Lua script and how to get values out of that script. To do this test we need a more sophisticated Lua script. Please, welcome sum.lua
function sum (a,b)
return a+b
end
r = sum (1,2)
This script defines a function that adds the two numbers it receives as a parameter, and then, in the main script body, it calls that function and stores the result in a global variable named r
.
Let’s see how we can run the sum function from our app and how we can get the value of r.
#include <stdio.h>
#include <lua5.1/lauxlib.h>
static lua_State *l;
int
main(int argc, char *argv[])
{
l = luaL_newstate ();
luaL_openlibs (l);
luaL_dofile (l, "sum.lua");
/* Read Global var */
lua_getglobal (l, "r");
if (!lua_isnumber (l, -1)) return -1;
printf ("Script calculation is: %d\n", (int)lua_tonumber(l, -1));
lua_pop (l, 1);
return 0;
}
The beginning of our program initialises the Lua context, as usual, and then it opens and executes the sum.lua
file.
The next thing the program does is to get the value of r
, the variable set in our Lua script. Any global symbol in the Lua environment can be accessed with the lua_getglobal
function. This function will add to the Lua virtual stack the symbol passed as second parameter. In this case the global var r
.
Then it checks if the result is actually a number. The lua_isnumber
does this test. The second parameter is the index in the virtual stack. The stack pointer points to the next available position in the stack, so the value -1 references the last value pushed into the stack.
Now we know that we have a Lua number in the top of the stack. We have to convert it to a C number before being able to print it in our C program. This is common to most scripting languages out there. They manage their own internal types in order to provide all their magic (duck typing for instance) but, when those languages are embedded, a bit of conversion code is always needed. Anyway, lua_tonumber
converts the object in the stack to a number.
Finally we have to clean the stack. We have used our global and we do not need it any more, so we can remove it from the stack using lua_pop
. The second parameter here, indicates how many objects we want to pop from the stack.
Smart Configuration files
What we have discussed so far does not look very impressive, but, as suggested in the official Lua documentation, we had already set up the fundamentals for a smart configuration system for our applications.
Let’s write a very simple Lua script to configure our application
user = os.getenv("USER")
if user == "root" then
home_dir = "/root"
else
home_dir ="/home/"..user
end
So, this script sets two configuration parameters, a user name and a home folder name. User name is obtained from the current environment and the folder directory is dynamically determined based on the user name. This is the power of using a scripting language to write configuration files. you can run code to produce your configuration on the fly based on, for instance, the current environment.
For completeness, this is a small C program, using this configuration file:
#include <stdio.h>
#include <lua5.1/lauxlib.h>
static lua_State *l;
int
main(int argc, char *argv[])
{
l = luaL_newstate ();
luaL_openlibs (l);
luaL_dofile (l, "config.lua");
lua_getglobal (l, "home_dir");
printf ("Configuration folder is:%s\n", (char*)lua_tostring(l,-1));
lua_close (l);
return 0;
}
You can define more complex data structures that may be more suitable for your current application… but that is a bit beyond of this already quite long post :). You should go and read the original Lua documentation for all the details and to get to know the tables
, a powerful Lua data type.
Calling a function
At this point, we have introduce almost everything needed to call a function. Functions are also global objects (at least for our current knowledge of the environment). We already know how to get them in the stack (lua_getglobal
), and we know how to also push data into the stack. This is how we are going to pass parameters.
The last missing part is how to tell Lua that we want it to call a function using all those values in the stack.
Let’s go back to our sum example and let’s do some small changes:
#include <stdio.h>
#include <lua5.1/lauxlib.h>
static lua_State *l;
int
main(int argc, char *argv[])
{
l = luaL_newstate ();
luaL_openlibs (l);
luaL_dofile (l, "sum.lua");
lua_getglobal (l, "sum");
lua_pushnumber (l, 10);
lua_pushnumber (l, 20);
lua_pcall (l, 2, 1, 0);
printf ("Result:%d\n", (int)lua_tonumber(l, -1));
lua_pop (l, 1);
lua_close (l);
return 0;
}
The interface is pretty much the same that the one we used to access the global var, but now, using the lua_pcall
function to actually execute the function. This is a summary of how it works:
- Get the function using
lua_getglobal
- Push the parameters in the stack
- Invoke the function using
pcall
. The second parameter is the number of parameters we are passing to the function. The third parameter is the number of values returned by the function. The forth parameter we will not discuss now. - The return value(s) will be pushed into the virtual stack, so we can get them, and convert to C types as required.
- Finally we clean-up the stack removing the return value
This may look a bit cumbersome, but it can be easily improved using a vararg function. Check this link for a reference implementation: Programming in Lua : 25.3
The last piece
The last piece to complete our Lua interface is to enable our Lua script to call C functions. Adding a C function to the current Lua environment is pretty simple:
lua_pushcfunction (l, c_func);
lua_setglobal (l, "c_func");
The code above will add a function named c_func
(that we will define right away) to the Lua environment, and creates a global object named c_func
that any lua script can actually execute. The C function will look like this:
int
c_func (lua_State *L)
{
int x;
if (lua_gettop(L) >= 0) {
x = (int) lua_tonumber (L, -1);
printf ("Received : %d\n", x);
/* Returning x + 1*/
lua_pushnumber(L, x + 1);
}
return 1;
}
It should look familiar at this point. The function will receive the current Lua environment as unique parameter. When calling the function from the Lua script, the parameters are automatically pushed into the Lua virtual stack before transferring control to the C function. In the same way, any return value (we can return more than one) have to be pushed into the stack before the C function returns.
So, this function, does the following:
- Check that there is at least one value in the stack
- Takes that value and converts it to a number (yes, you are right, we should check that it is actually a number… wonder how?)
- Then we print the value so we can check the parameter made it to our C function
- And finally we push the function return value that, in this case, is the function parameter increased by 1.
Now we can write Lua scripts like this (let’s call it c.lua
):
x = 10
print (c_func(x))
That will output
$ ./test3 c.lua
Received : 10
11
Conclusions
This is the very basics to get a Lua interpreter integrated into your application, in the same way that wireshark or nmap does. Now, you are a step closer to write your own hacking tools… or any other tool that requires a scripting language ( https://en.wikipedia.org/wiki/Category:Lua-scripted_video_games )
Do you have an idea for a hacking tool using an scripting language?.. Let us know!