LuaHook-NG is a library designed to facilitate hooking into applications which utilise Lua.
The project is CMake based. a JSON file is included for the benefit of Visual Studio's CMake support; it can also be used as a guideline for the appropriate compiler, assembler and linker arguments that should be used when invoking CMake if you don't have Visual Studio 2019.
The primary responsibilities are separated into two parts:
The hook is responsible for getting into the process space of the target app. Currently only one such hook exists which acts as a shim for the Windows OS DLL IPHLPAPI.dll
The injector takes care of loading LuaHook-NG which then takes care of hooking.
The hook consists of a generic set of interfaces and some generic code code.
These interfaces are designed to be used to bring together implementation code that handles a specific platform, application and, if needed, runtime-patching.
When adding a new OS, you will need to provide an entry point for it. Currently there is a dllmain provided for Windows only. You should also implement a loader that will load client libraries (code that will use the Lua API and interact with the targeted application)
There is currently an implementation for PAYDAY2 on x86 Windows, PAYDAY1 will also be supported shortly. In order to use the hook, both IPHLPAPI.dll and LuaHook-NG.dll need to reside in the same directory as PAYDAY2. Your client libraries should live in a subfolder called LuaHook-NG.
LuaHook-NG does not interfere with target applications beyond establishing the necessary hook points (if any). It is intended that you build separate library files which then reside in the LuaHook-NG folder. These will then be dynamically loaded at runtime by LuaHook-NG.
When building a client library, it is advisable to look at the source code of the ones bundled with this code repository. In any case though, here is a guide to the general procedure:
#include <LuaHookNG.h>
- this provides all necessary types and functions inside theLuaHookNG
namespace;- Decide which points you need to hook and create a class or classes that
implement one or more of the interfaces defined in
LuaHook-NG/include/interface
. - a. Create an instance of
LuaHookNG::LuaAppLink
passing a reference to your class as a constructor argument. For convenience, you can useLuaAppLink::RegisterMultiple
if you have a single class that implements multiple interfaces. You are required to ensure that your class instance is valid for the duration ofLuaAppLink
's lifetime. b. When theLuaAppLink
instance goes out of scope, the client registered to it will no longer be registered.
Please note that you must not construct or destruct a LuaAppLink
from
within your handler client. This will result in a double-acquire of a protective
mutex within LuaHook-NG which results in Undefined Behaviour. You should create
a signalling mechanism between your handler client and the rest of your app which
can then safely unregister your handler.
The Lua API is designed to be usable in the same way you would expect to use a normal Lua API. However, this may not be possible for all applications.
See the README.md in the folder of the application you are interested in for
info on any limitations or unimplemented Lua functions - for example,
src/windows/x86/PAYDAY2/README.md
. Please note that unimplemented Lua
functions will always throw std::runtime_error
- they may also present a
visible dialog, depending on platform.
Please do note that the sizes of lua_Number
and lua_Integer
will always be
double
and ptrdiff_t
respectively. However, you need to be aware of your
target application if you intend to rely on these values. For target apps which
use smaller size types (such as PAYDAY1 using float
) values you pass in will
be narrowed, values you receive will have been extended.
Similarly, Lua implementations may vary - if you attempt to load in standard Lua bytecode into a LuaJIT app, it will fail and vice versa.
LuaHookNG implements a Version()
function which you can call to determine the
hook's release.
The project uses semantic versioning and you can consequently expect that a change in the major version may break compatibility, including the ability to successfully load your client library.
A change in the minor version will not break any correctly used functionality, but new features have been added.
A change in the patch version will also not break any correctly use functionality and only denotes bug fixes.