This commit is contained in:
Redo
2025-10-06 23:04:30 -05:00
commit 7bee616b8e
12 changed files with 1739 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
.*
!.gitignore

161
inc/lua/lauxlib.h Normal file
View File

@@ -0,0 +1,161 @@
/*
** $Id: lauxlib.h,v 1.88.1.1 2007/12/27 13:02:25 roberto Exp $
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
#ifndef lauxlib_h
#define lauxlib_h
#include <stddef.h>
#include <stdio.h>
#include "lua.h"
/* extra error code for `luaL_load' */
#define LUA_ERRFILE (LUA_ERRERR+1)
typedef struct luaL_Reg {
const char *name;
lua_CFunction func;
} luaL_Reg;
LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname,
const luaL_Reg *l, int nup);
LUALIB_API void (luaL_register) (lua_State *L, const char *libname,
const luaL_Reg *l);
LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e);
LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e);
LUALIB_API int (luaL_typerror) (lua_State *L, int narg, const char *tname);
LUALIB_API int (luaL_argerror) (lua_State *L, int numarg, const char *extramsg);
LUALIB_API const char *(luaL_checklstring) (lua_State *L, int numArg,
size_t *l);
LUALIB_API const char *(luaL_optlstring) (lua_State *L, int numArg,
const char *def, size_t *l);
LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int numArg);
LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int nArg, lua_Number def);
LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int numArg);
LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int nArg,
lua_Integer def);
LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg);
LUALIB_API void (luaL_checktype) (lua_State *L, int narg, int t);
LUALIB_API void (luaL_checkany) (lua_State *L, int narg);
LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname);
LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname);
LUALIB_API void (luaL_where) (lua_State *L, int lvl);
LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...);
LUALIB_API int (luaL_checkoption) (lua_State *L, int narg, const char *def,
const char *const lst[]);
/* pre-defined references */
#define LUA_NOREF (-2)
#define LUA_REFNIL (-1)
LUALIB_API int (luaL_ref) (lua_State *L, int t);
LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref);
LUALIB_API int (luaL_loadfile) (lua_State *L, const char *filename);
LUALIB_API int (luaL_loadbuffer) (lua_State *L, const char *buff, size_t sz,
const char *name);
LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s);
LUALIB_API lua_State *(luaL_newstate) (void);
LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p,
const char *r);
LUALIB_API const char *(luaL_findtable) (lua_State *L, int idx,
const char *fname, int szhint);
/* From Lua 5.2. */
LUALIB_API int luaL_fileresult(lua_State *L, int stat, const char *fname);
LUALIB_API int luaL_execresult(lua_State *L, int stat);
LUALIB_API int (luaL_loadfilex) (lua_State *L, const char *filename,
const char *mode);
LUALIB_API int (luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz,
const char *name, const char *mode);
LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, const char *msg,
int level);
LUALIB_API void (luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup);
LUALIB_API void (luaL_pushmodule) (lua_State *L, const char *modname,
int sizehint);
LUALIB_API void *(luaL_testudata) (lua_State *L, int ud, const char *tname);
LUALIB_API void (luaL_setmetatable) (lua_State *L, const char *tname);
/*
** ===============================================================
** some useful macros
** ===============================================================
*/
#define luaL_argcheck(L, cond,numarg,extramsg) \
((void)((cond) || luaL_argerror(L, (numarg), (extramsg))))
#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL))
#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL))
#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n)))
#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d)))
#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n)))
#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d)))
#define luaL_typename(L,i) lua_typename(L, lua_type(L,(i)))
#define luaL_dofile(L, fn) \
(luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0))
#define luaL_dostring(L, s) \
(luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0))
#define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n)))
#define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n)))
/* From Lua 5.2. */
#define luaL_newlibtable(L, l) \
lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1)
#define luaL_newlib(L, l) (luaL_newlibtable(L, l), luaL_setfuncs(L, l, 0))
/*
** {======================================================
** Generic Buffer manipulation
** =======================================================
*/
typedef struct luaL_Buffer {
char *p; /* current position in buffer */
int lvl; /* number of strings in the stack (level) */
lua_State *L;
char buffer[LUAL_BUFFERSIZE];
} luaL_Buffer;
#define luaL_addchar(B,c) \
((void)((B)->p < ((B)->buffer+LUAL_BUFFERSIZE) || luaL_prepbuffer(B)), \
(*(B)->p++ = (char)(c)))
/* compatibility only */
#define luaL_putchar(B,c) luaL_addchar(B,c)
#define luaL_addsize(B,n) ((B)->p += (n))
LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B);
LUALIB_API char *(luaL_prepbuffer) (luaL_Buffer *B);
LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l);
LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s);
LUALIB_API void (luaL_addvalue) (luaL_Buffer *B);
LUALIB_API void (luaL_pushresult) (luaL_Buffer *B);
/* }====================================================== */
#endif

402
inc/lua/lua.h Normal file
View File

@@ -0,0 +1,402 @@
/*
** $Id: lua.h,v 1.218.1.5 2008/08/06 13:30:12 roberto Exp $
** Lua - An Extensible Extension Language
** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
** See Copyright Notice at the end of this file
*/
#ifndef lua_h
#define lua_h
#include <stdarg.h>
#include <stddef.h>
#include "luaconf.h"
#define LUA_VERSION "Lua 5.1"
#define LUA_RELEASE "Lua 5.1.4"
#define LUA_VERSION_NUM 501
#define LUA_COPYRIGHT "Copyright (C) 1994-2008 Lua.org, PUC-Rio"
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes"
/* mark for precompiled code (`<esc>Lua') */
#define LUA_SIGNATURE "\033Lua"
/* option for multiple returns in `lua_pcall' and `lua_call' */
#define LUA_MULTRET (-1)
/*
** pseudo-indices
*/
#define LUA_REGISTRYINDEX (-10000)
#define LUA_ENVIRONINDEX (-10001)
#define LUA_GLOBALSINDEX (-10002)
#define lua_upvalueindex(i) (LUA_GLOBALSINDEX-(i))
/* thread status */
#define LUA_OK 0
#define LUA_YIELD 1
#define LUA_ERRRUN 2
#define LUA_ERRSYNTAX 3
#define LUA_ERRMEM 4
#define LUA_ERRERR 5
typedef struct lua_State lua_State;
typedef int (*lua_CFunction) (lua_State *L);
/*
** functions that read/write blocks when loading/dumping Lua chunks
*/
typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz);
typedef int (*lua_Writer) (lua_State *L, const void* p, size_t sz, void* ud);
/*
** prototype for memory-allocation functions
*/
typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
/*
** basic types
*/
#define LUA_TNONE (-1)
#define LUA_TNIL 0
#define LUA_TBOOLEAN 1
#define LUA_TLIGHTUSERDATA 2
#define LUA_TNUMBER 3
#define LUA_TSTRING 4
#define LUA_TTABLE 5
#define LUA_TFUNCTION 6
#define LUA_TUSERDATA 7
#define LUA_TTHREAD 8
/* minimum Lua stack available to a C function */
#define LUA_MINSTACK 20
/*
** generic extra include file
*/
#if defined(LUA_USER_H)
#include LUA_USER_H
#endif
/* type of numbers in Lua */
typedef LUA_NUMBER lua_Number;
/* type for integer functions */
typedef LUA_INTEGER lua_Integer;
/*
** state manipulation
*/
LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud);
LUA_API void (lua_close) (lua_State *L);
LUA_API lua_State *(lua_newthread) (lua_State *L);
LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
/*
** basic stack manipulation
*/
LUA_API int (lua_gettop) (lua_State *L);
LUA_API void (lua_settop) (lua_State *L, int idx);
LUA_API void (lua_pushvalue) (lua_State *L, int idx);
LUA_API void (lua_remove) (lua_State *L, int idx);
LUA_API void (lua_insert) (lua_State *L, int idx);
LUA_API void (lua_replace) (lua_State *L, int idx);
LUA_API int (lua_checkstack) (lua_State *L, int sz);
LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n);
/*
** access functions (stack -> C)
*/
LUA_API int (lua_isnumber) (lua_State *L, int idx);
LUA_API int (lua_isstring) (lua_State *L, int idx);
LUA_API int (lua_iscfunction) (lua_State *L, int idx);
LUA_API int (lua_isuserdata) (lua_State *L, int idx);
LUA_API int (lua_type) (lua_State *L, int idx);
LUA_API const char *(lua_typename) (lua_State *L, int tp);
LUA_API int (lua_equal) (lua_State *L, int idx1, int idx2);
LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2);
LUA_API int (lua_lessthan) (lua_State *L, int idx1, int idx2);
LUA_API lua_Number (lua_tonumber) (lua_State *L, int idx);
LUA_API lua_Integer (lua_tointeger) (lua_State *L, int idx);
LUA_API int (lua_toboolean) (lua_State *L, int idx);
LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len);
LUA_API size_t (lua_objlen) (lua_State *L, int idx);
LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx);
LUA_API void *(lua_touserdata) (lua_State *L, int idx);
LUA_API lua_State *(lua_tothread) (lua_State *L, int idx);
LUA_API const void *(lua_topointer) (lua_State *L, int idx);
/*
** push functions (C -> stack)
*/
LUA_API void (lua_pushnil) (lua_State *L);
LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n);
LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n);
LUA_API void (lua_pushlstring) (lua_State *L, const char *s, size_t l);
LUA_API void (lua_pushstring) (lua_State *L, const char *s);
LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt,
va_list argp);
LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...);
LUA_API void (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n);
LUA_API void (lua_pushboolean) (lua_State *L, int b);
LUA_API void (lua_pushlightuserdata) (lua_State *L, void *p);
LUA_API int (lua_pushthread) (lua_State *L);
/*
** get functions (Lua -> stack)
*/
LUA_API void (lua_gettable) (lua_State *L, int idx);
LUA_API void (lua_getfield) (lua_State *L, int idx, const char *k);
LUA_API void (lua_rawget) (lua_State *L, int idx);
LUA_API void (lua_rawgeti) (lua_State *L, int idx, int n);
LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec);
LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz);
LUA_API int (lua_getmetatable) (lua_State *L, int objindex);
LUA_API void (lua_getfenv) (lua_State *L, int idx);
/*
** set functions (stack -> Lua)
*/
LUA_API void (lua_settable) (lua_State *L, int idx);
LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k);
LUA_API void (lua_rawset) (lua_State *L, int idx);
LUA_API void (lua_rawseti) (lua_State *L, int idx, int n);
LUA_API int (lua_setmetatable) (lua_State *L, int objindex);
LUA_API int (lua_setfenv) (lua_State *L, int idx);
/*
** `load' and `call' functions (load and run Lua code)
*/
LUA_API void (lua_call) (lua_State *L, int nargs, int nresults);
LUA_API int (lua_pcall) (lua_State *L, int nargs, int nresults, int errfunc);
LUA_API int (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud);
LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt,
const char *chunkname);
LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data);
/*
** coroutine functions
*/
LUA_API int (lua_yield) (lua_State *L, int nresults);
LUA_API int (lua_resume) (lua_State *L, int narg);
LUA_API int (lua_status) (lua_State *L);
/*
** garbage-collection function and options
*/
#define LUA_GCSTOP 0
#define LUA_GCRESTART 1
#define LUA_GCCOLLECT 2
#define LUA_GCCOUNT 3
#define LUA_GCCOUNTB 4
#define LUA_GCSTEP 5
#define LUA_GCSETPAUSE 6
#define LUA_GCSETSTEPMUL 7
#define LUA_GCISRUNNING 9
LUA_API int (lua_gc) (lua_State *L, int what, int data);
/*
** miscellaneous functions
*/
LUA_API int (lua_error) (lua_State *L);
LUA_API int (lua_next) (lua_State *L, int idx);
LUA_API void (lua_concat) (lua_State *L, int n);
LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud);
LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);
/*
** ===============================================================
** some useful macros
** ===============================================================
*/
#define lua_pop(L,n) lua_settop(L, -(n)-1)
#define lua_newtable(L) lua_createtable(L, 0, 0)
#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n)))
#define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0)
#define lua_strlen(L,i) lua_objlen(L, (i))
#define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION)
#define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE)
#define lua_islightuserdata(L,n) (lua_type(L, (n)) == LUA_TLIGHTUSERDATA)
#define lua_isnil(L,n) (lua_type(L, (n)) == LUA_TNIL)
#define lua_isboolean(L,n) (lua_type(L, (n)) == LUA_TBOOLEAN)
#define lua_isthread(L,n) (lua_type(L, (n)) == LUA_TTHREAD)
#define lua_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE)
#define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0)
#define lua_pushliteral(L, s) \
lua_pushlstring(L, "" s, (sizeof(s)/sizeof(char))-1)
#define lua_setglobal(L,s) lua_setfield(L, LUA_GLOBALSINDEX, (s))
#define lua_getglobal(L,s) lua_getfield(L, LUA_GLOBALSINDEX, (s))
#define lua_tostring(L,i) lua_tolstring(L, (i), NULL)
/*
** compatibility macros and functions
*/
#define lua_open() luaL_newstate()
#define lua_getregistry(L) lua_pushvalue(L, LUA_REGISTRYINDEX)
#define lua_getgccount(L) lua_gc(L, LUA_GCCOUNT, 0)
#define lua_Chunkreader lua_Reader
#define lua_Chunkwriter lua_Writer
/* hack */
LUA_API void lua_setlevel (lua_State *from, lua_State *to);
/*
** {======================================================================
** Debug API
** =======================================================================
*/
/*
** Event codes
*/
#define LUA_HOOKCALL 0
#define LUA_HOOKRET 1
#define LUA_HOOKLINE 2
#define LUA_HOOKCOUNT 3
#define LUA_HOOKTAILRET 4
/*
** Event masks
*/
#define LUA_MASKCALL (1 << LUA_HOOKCALL)
#define LUA_MASKRET (1 << LUA_HOOKRET)
#define LUA_MASKLINE (1 << LUA_HOOKLINE)
#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT)
typedef struct lua_Debug lua_Debug; /* activation record */
/* Functions to be called by the debuger in specific events */
typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar);
LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);
LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n);
LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n);
LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n);
LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n);
LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count);
LUA_API lua_Hook lua_gethook (lua_State *L);
LUA_API int lua_gethookmask (lua_State *L);
LUA_API int lua_gethookcount (lua_State *L);
/* From Lua 5.2. */
LUA_API void *lua_upvalueid (lua_State *L, int idx, int n);
LUA_API void lua_upvaluejoin (lua_State *L, int idx1, int n1, int idx2, int n2);
LUA_API int lua_loadx (lua_State *L, lua_Reader reader, void *dt,
const char *chunkname, const char *mode);
LUA_API const lua_Number *lua_version (lua_State *L);
LUA_API void lua_copy (lua_State *L, int fromidx, int toidx);
LUA_API lua_Number lua_tonumberx (lua_State *L, int idx, int *isnum);
LUA_API lua_Integer lua_tointegerx (lua_State *L, int idx, int *isnum);
/* From Lua 5.3. */
LUA_API int lua_isyieldable (lua_State *L);
struct lua_Debug {
int event;
const char *name; /* (n) */
const char *namewhat; /* (n) `global', `local', `field', `method' */
const char *what; /* (S) `Lua', `C', `main', `tail' */
const char *source; /* (S) */
int currentline; /* (l) */
int nups; /* (u) number of upvalues */
int linedefined; /* (S) */
int lastlinedefined; /* (S) */
char short_src[LUA_IDSIZE]; /* (S) */
/* private part */
int i_ci; /* active function */
};
/* }====================================================================== */
/******************************************************************************
* Copyright (C) 1994-2008 Lua.org, PUC-Rio. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************************************************************/
#endif

9
inc/lua/lua.hpp Normal file
View File

@@ -0,0 +1,9 @@
// C++ wrapper for LuaJIT header files.
extern "C" {
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "luajit.h"
}

BIN
inc/lua/lua5.1.dll Normal file

Binary file not shown.

152
inc/lua/luaconf.h Normal file
View File

@@ -0,0 +1,152 @@
/*
** Configuration header.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef luaconf_h
#define luaconf_h
#ifndef WINVER
#define WINVER 0x0501
#endif
#include <limits.h>
#include <stddef.h>
/* Default path for loading Lua and C modules with require(). */
#if defined(_WIN32)
/*
** In Windows, any exclamation mark ('!') in the path is replaced by the
** path of the directory of the executable file of the current process.
*/
#define LUA_LDIR "!\\lua\\"
#define LUA_CDIR "!\\"
#define LUA_PATH_DEFAULT \
".\\?.lua;" LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;"
#define LUA_CPATH_DEFAULT \
".\\?.dll;" LUA_CDIR"?.dll;" LUA_CDIR"loadall.dll"
#else
/*
** Note to distribution maintainers: do NOT patch the following lines!
** Please read ../doc/install.html#distro and pass PREFIX=/usr instead.
*/
#ifndef LUA_MULTILIB
#define LUA_MULTILIB "lib"
#endif
#ifndef LUA_LMULTILIB
#define LUA_LMULTILIB "lib"
#endif
#define LUA_LROOT "/usr/local"
#define LUA_LUADIR "/lua/5.1/"
#define LUA_LJDIR "/luajit-2.1.0-beta3/"
#ifdef LUA_ROOT
#define LUA_JROOT LUA_ROOT
#define LUA_RLDIR LUA_ROOT "/share" LUA_LUADIR
#define LUA_RCDIR LUA_ROOT "/" LUA_MULTILIB LUA_LUADIR
#define LUA_RLPATH ";" LUA_RLDIR "?.lua;" LUA_RLDIR "?/init.lua"
#define LUA_RCPATH ";" LUA_RCDIR "?.so"
#else
#define LUA_JROOT LUA_LROOT
#define LUA_RLPATH
#define LUA_RCPATH
#endif
#define LUA_JPATH ";" LUA_JROOT "/share" LUA_LJDIR "?.lua"
#define LUA_LLDIR LUA_LROOT "/share" LUA_LUADIR
#define LUA_LCDIR LUA_LROOT "/" LUA_LMULTILIB LUA_LUADIR
#define LUA_LLPATH ";" LUA_LLDIR "?.lua;" LUA_LLDIR "?/init.lua"
#define LUA_LCPATH1 ";" LUA_LCDIR "?.so"
#define LUA_LCPATH2 ";" LUA_LCDIR "loadall.so"
#define LUA_PATH_DEFAULT "./?.lua" LUA_JPATH LUA_LLPATH LUA_RLPATH
#define LUA_CPATH_DEFAULT "./?.so" LUA_LCPATH1 LUA_RCPATH LUA_LCPATH2
#endif
/* Environment variable names for path overrides and initialization code. */
#define LUA_PATH "LUA_PATH"
#define LUA_CPATH "LUA_CPATH"
#define LUA_INIT "LUA_INIT"
/* Special file system characters. */
#if defined(_WIN32)
#define LUA_DIRSEP "\\"
#else
#define LUA_DIRSEP "/"
#endif
#define LUA_PATHSEP ";"
#define LUA_PATH_MARK "?"
#define LUA_EXECDIR "!"
#define LUA_IGMARK "-"
#define LUA_PATH_CONFIG \
LUA_DIRSEP "\n" LUA_PATHSEP "\n" LUA_PATH_MARK "\n" \
LUA_EXECDIR "\n" LUA_IGMARK "\n"
/* Quoting in error messages. */
#define LUA_QL(x) "'" x "'"
#define LUA_QS LUA_QL("%s")
/* Various tunables. */
#define LUAI_MAXSTACK 65500 /* Max. # of stack slots for a thread (<64K). */
#define LUAI_MAXCSTACK 8000 /* Max. # of stack slots for a C func (<10K). */
#define LUAI_GCPAUSE 200 /* Pause GC until memory is at 200%. */
#define LUAI_GCMUL 200 /* Run GC at 200% of allocation speed. */
#define LUA_MAXCAPTURES 32 /* Max. pattern captures. */
/* Configuration for the frontend (the luajit executable). */
#if defined(luajit_c)
#define LUA_PROGNAME "luajit" /* Fallback frontend name. */
#define LUA_PROMPT "> " /* Interactive prompt. */
#define LUA_PROMPT2 ">> " /* Continuation prompt. */
#define LUA_MAXINPUT 512 /* Max. input line length. */
#endif
/* Note: changing the following defines breaks the Lua 5.1 ABI. */
#define LUA_INTEGER ptrdiff_t
#define LUA_IDSIZE 60 /* Size of lua_Debug.short_src. */
/*
** Size of lauxlib and io.* on-stack buffers. Weird workaround to avoid using
** unreasonable amounts of stack space, but still retain ABI compatibility.
** Blame Lua for depending on BUFSIZ in the ABI, blame **** for wrecking it.
*/
#define LUAL_BUFFERSIZE (BUFSIZ > 16384 ? 8192 : BUFSIZ)
/* The following defines are here only for compatibility with luaconf.h
** from the standard Lua distribution. They must not be changed for LuaJIT.
*/
#define LUA_NUMBER_DOUBLE
#define LUA_NUMBER double
#define LUAI_UACNUMBER double
#define LUA_NUMBER_SCAN "%lf"
#define LUA_NUMBER_FMT "%.14g"
#define lua_number2str(s, n) sprintf((s), LUA_NUMBER_FMT, (n))
#define LUAI_MAXNUMBER2STR 32
#define LUA_INTFRMLEN "l"
#define LUA_INTFRM_T long
/* Linkage of public API functions. */
#if defined(LUA_BUILD_AS_DLL)
#if defined(LUA_CORE) || defined(LUA_LIB)
#define LUA_API __declspec(dllexport)
#else
#define LUA_API __declspec(dllimport)
#endif
#else
#define LUA_API extern
#endif
#define LUALIB_API LUA_API
/* Support for internal assertions. */
#if defined(LUA_USE_ASSERT) || defined(LUA_USE_APICHECK)
#include <assert.h>
#endif
#ifdef LUA_USE_ASSERT
#define lua_assert(x) assert(x)
#endif
#ifdef LUA_USE_APICHECK
#define luai_apicheck(L, o) { (void)L; assert(o); }
#else
#define luai_apicheck(L, o) { (void)L; }
#endif
#endif

79
inc/lua/luajit.h Normal file
View File

@@ -0,0 +1,79 @@
/*
** LuaJIT -- a Just-In-Time Compiler for Lua. http://luajit.org/
**
** Copyright (C) 2005-2017 Mike Pall. All rights reserved.
**
** Permission is hereby granted, free of charge, to any person obtaining
** a copy of this software and associated documentation files (the
** "Software"), to deal in the Software without restriction, including
** without limitation the rights to use, copy, modify, merge, publish,
** distribute, sublicense, and/or sell copies of the Software, and to
** permit persons to whom the Software is furnished to do so, subject to
** the following conditions:
**
** The above copyright notice and this permission notice shall be
** included in all copies or substantial portions of the Software.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**
** [ MIT license: http://www.opensource.org/licenses/mit-license.php ]
*/
#ifndef _LUAJIT_H
#define _LUAJIT_H
#include "lua.h"
#define LUAJIT_VERSION "LuaJIT 2.1.0-beta3"
#define LUAJIT_VERSION_NUM 20100 /* Version 2.1.0 = 02.01.00. */
#define LUAJIT_VERSION_SYM luaJIT_version_2_1_0_beta3
#define LUAJIT_COPYRIGHT "Copyright (C) 2005-2017 Mike Pall"
#define LUAJIT_URL "http://luajit.org/"
/* Modes for luaJIT_setmode. */
#define LUAJIT_MODE_MASK 0x00ff
enum {
LUAJIT_MODE_ENGINE, /* Set mode for whole JIT engine. */
LUAJIT_MODE_DEBUG, /* Set debug mode (idx = level). */
LUAJIT_MODE_FUNC, /* Change mode for a function. */
LUAJIT_MODE_ALLFUNC, /* Recurse into subroutine protos. */
LUAJIT_MODE_ALLSUBFUNC, /* Change only the subroutines. */
LUAJIT_MODE_TRACE, /* Flush a compiled trace. */
LUAJIT_MODE_WRAPCFUNC = 0x10, /* Set wrapper mode for C function calls. */
LUAJIT_MODE_MAX
};
/* Flags or'ed in to the mode. */
#define LUAJIT_MODE_OFF 0x0000 /* Turn feature off. */
#define LUAJIT_MODE_ON 0x0100 /* Turn feature on. */
#define LUAJIT_MODE_FLUSH 0x0200 /* Flush JIT-compiled code. */
/* LuaJIT public C API. */
/* Control the JIT engine. */
LUA_API int luaJIT_setmode(lua_State *L, int idx, int mode);
/* Low-overhead profiling API. */
typedef void (*luaJIT_profile_callback)(void *data, lua_State *L,
int samples, int vmstate);
LUA_API void luaJIT_profile_start(lua_State *L, const char *mode,
luaJIT_profile_callback cb, void *data);
LUA_API void luaJIT_profile_stop(lua_State *L);
LUA_API const char *luaJIT_profile_dumpstack(lua_State *L, const char *fmt,
int depth, size_t *len);
/* Enforce (dynamic) linker error for version mismatches. Call from main. */
LUA_API void LUAJIT_VERSION_SYM(void);
#endif

43
inc/lua/lualib.h Normal file
View File

@@ -0,0 +1,43 @@
/*
** Standard library header.
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _LUALIB_H
#define _LUALIB_H
#include "lua.h"
#define LUA_FILEHANDLE "FILE*"
#define LUA_COLIBNAME "coroutine"
#define LUA_MATHLIBNAME "math"
#define LUA_STRLIBNAME "string"
#define LUA_TABLIBNAME "table"
#define LUA_IOLIBNAME "io"
#define LUA_OSLIBNAME "os"
#define LUA_LOADLIBNAME "package"
#define LUA_DBLIBNAME "debug"
#define LUA_BITLIBNAME "bit"
#define LUA_JITLIBNAME "jit"
#define LUA_FFILIBNAME "ffi"
LUALIB_API int luaopen_base(lua_State *L);
LUALIB_API int luaopen_math(lua_State *L);
LUALIB_API int luaopen_string(lua_State *L);
LUALIB_API int luaopen_table(lua_State *L);
LUALIB_API int luaopen_io(lua_State *L);
LUALIB_API int luaopen_os(lua_State *L);
LUALIB_API int luaopen_package(lua_State *L);
LUALIB_API int luaopen_debug(lua_State *L);
LUALIB_API int luaopen_bit(lua_State *L);
LUALIB_API int luaopen_jit(lua_State *L);
LUALIB_API int luaopen_ffi(lua_State *L);
LUALIB_API void luaL_openlibs(lua_State *L);
#ifndef lua_assert
#define lua_assert(x) ((void)0)
#endif
#endif

524
luahooks32.lua Normal file
View File

@@ -0,0 +1,524 @@
hk = require('luahooks32core')
-- Memory protection
-- Allow writing to code areas
local PAGE_EXECUTE_READWRITE = 0x40
function hk.protectRWX(addr, len)
return hk.protect(addr, len, PAGE_EXECUTE_READWRITE)
end
hk._openImages = hk._openImages or {}
-- open library memoization
function hk.open(name)
if name==nil then name = '_baseImage' end
local img = hk._openImages[name]
if img then return img end
img = hk._openRaw(name~='_baseImage' and name or nil)
hk._openImages[name] = img
return img
end
-- Scanning
-- Convert text-style scan pattern into code-style pattern
-- Input: '11 22 33 ? 44'
-- Output: '\x11\x22\x33\x00\x44', 'xxx?x'
local function patToCode(p)
if p:find('^str:') then -- raw string
local pat = p:sub(4, #p)
local mask = ('x'):rep(#pat)
return pat, mask
else -- hex pattern
if p:find('[^a-fA-F0-9 \r\n\t%?]') then
error('hk pattern: pattern contains invalid character', 3) end
local patT, maskT = {}, {}
for word in p:gmatch('[^ \r\n\t]+') do
if word:find('%?') then
table.insert(patT, string.char(0))
table.insert(maskT, '?')
else
local val = tonumber(word, 16)
assert(val and val>=0 and val<=255, 'invalid word in scan pattern: '..word, 3)
table.insert(patT, string.char(val))
table.insert(maskT, 'x')
end
end
return table.concat(patT), table.concat(maskT)
end
end
-- Scan
-- hk.scan('15 1 ? 1f') - return first match (or nil)
-- hk.scan('15 1 ? 1f', 1) - return nth match (or nil) (starting from 1)
-- hk.scan('15 1 ? 1f', true) - return list of all matches (or {})
local unhookAll, rehookAll
hk._scanResultCache = hk._scanResultCache or {}
function hk.scan(pat, opt, img)
if type(pat)~='string' then
error('hk.scan: argument #1: expected string', 2) end
local code, mask = patToCode(pat)
img = img or hk.open()
opt = opt or 1
local _
local cacheEntry = tostring(img)..':'..pat..':'..tostring(opt)
local res = hk._scanResultCache[cacheEntry]
if res then return res end
if opt==true then -- find all matches
res = {}
unhookAll()
while true do
local suc,a = pcall(hk._scanRaw, img, code, mask, #res)
if not a then break end
table.insert(res, a)
end
rehookAll()
elseif type(opt)=='number' and opt%1==0 and opt>0 then -- find nth match
unhookAll()
suc,res = pcall(hk._scanRaw, img, code, mask, opt-1)
rehookAll()
else
error('hk.scan: argument #2: expected true, positive integer, or nil', 2)
end
hk._scanResultCache[cacheEntry] = res
return res
end
-- Writing
local function hexToStr(h)
local t = {}
if h:find('[^a-zA-Z0-9 \r\n\t]') then
error('hk.write: invalid character in hex string', 3) end
for w in h:gmatch('[^ \r\n\t]+') do
local v = tonumber(w, 16)
if not (v and v>=0 and v<=255) then
error('hk.write: invalid hex number: '..w, 3) end
table.insert(t, string.char(v))
end
return table.concat(t)
end
local customWriters = {
hex = function(addr, str, len)
local data = hexToStr(str)
if len then return addr+#data end
return hk.writeStr(addr, data)
end,
str = function(addr, data, len)
if len then return addr+#data end
return hk.writeStr(addr, data)
end,
char = function(addr, val, len)
if len then return addr+1 end
return hk.writeChar(addr, val)
end,
short = function(addr, val, len)
if len then return addr+2 end
return hk.writeShort(addr, val)
end,
int = function(addr, val, len)
if len then return addr+4 end
return hk.writeInt(addr, val)
end,
rel = function(addr, val, len)
if len then return addr+4 end
return hk.writeInt(addr, val - (addr+4))
end,
float = function(addr, val, len)
if len then return addr+4 end
return hk.writeFloat(addr, val)
end,
double = function(addr, val, len)
if len then return addr+8 end
return hk.writeFloat(addr, val)
end,
}
local customWriterDefaults = {
number = 'int',
string = 'hex',
}
local function writeData(addr, data, typ, len)
if type(data)=='table' then
if typ then
error('hk.write: argument #3: expected nil when argument #2 is table', 2) end
if not table.islist(data) then
error('hk.write: argument #2: table must be a list', 2) end
local ntyp = nil
for i,v in ipairs(data) do
if type(v)=='string' and v:sub(#v,#v)==':' then
ntyp = v:sub(1,#v-1)
if not customWriters[ntyp] then
error('hk.write: argument #2: expected writer type at index '
..i..', got \''..ntyp..'\'', 2) end
else
addr = hk.write(addr, data[i], ntyp, len)
ntyp = nil
end
end
return addr
else
if not typ then
typ = customWriterDefaults[type(data)]
if not typ then
error('hk.write: argument #2: expected string, number, or table') end
end
if not customWriters[typ] then
error('hk.write: argument #3: expected writer type, got \''..typ..'\'') end
return customWriters[typ](addr, data, len)
end
end
function hk.write(addr, data, typ)
return writeData(addr, data, typ, false)
end
-- write to a write-protected area by turning off write protection first,
-- then re-enable write protection afterward
function hk.patch(addr, data, typ)
local len = writeData(addr, data, typ, true) - addr
local oldProt = hk.protectRWX(addr, len)
local addrW = writeData(addr, data, typ, false)
hk.protect(addr, len, oldProt)
return addrW
end
-- Hooking
local function writeTrampoline(trAddr, hkAddr, regsPtr)
return hk.write(trAddr, {
-- save registers and flags
'a3',regsPtr, -- mov [regsPtr],eax
'b8',regsPtr, -- mov eax,regsPtr
'89 58 04', -- mov [eax+0x04],ebx
'89 48 08', -- mov [eax+0x08],ecx
'89 50 0c', -- mov [eax+0x0c],edx
'89 70 10', -- mov [eax+0x10],esi
'89 78 14', -- mov [eax+0x14],edi
'89 60 18', -- mov [eax+0x18],esp
'89 68 1c', -- mov [eax+0x1c],ebp
'c7 40 20',hkAddr, -- mov [eax+0x20],hkAddr (res->eip)
'9c', -- pushfd
'5a', -- pop edx
'89 50 24', -- mov [eax+0x24],edx (regs->flags)
'c7 40 28',0, -- mov [eax+0x28],0 (regs->brk = 0)
-- load arguments into ecx+edx and call
'89 c1', -- mov ecx,eax
'ba',hk._getLuaStatePtr(), -- mov edx,L
'e8','rel:',hk._getCallbackPtr(), -- call hook function
-- restore registers
'b8',regsPtr, -- mov eax,regsPtr
'8b 58 04', -- mov ebx,[eax+0x04]
'8b 48 08', -- mov ecx,[eax+0x08]
'8b 50 0c', -- mov edx,[eax+0x0c]
'8b 70 10', -- mov esi,[eax+0x10]
'8b 78 14', -- mov edi,[eax+0x14]
'8b 60 18', -- mov esp,[eax+0x18]
'8b 68 1c', -- mov ebp,[eax+0x1c]
-- if regs.brk, restore eax and retn; otherwise continue
'83 78 28 00', -- cmp dword ptr [eax+0x28],0
'74 06', -- je (past eax restore and retn)
'a1',regsPtr, -- mov eax,[regsPtr]
'c3', -- retn
-- restore flags and eax
'8b 50 24', -- mov edx,[eax+0x24] (regs->flags)
'52', -- push edx
'9d', -- popfd
'a1',regsPtr, -- mov eax,[regsPtr]
-- after this, moved code will be written, followed by a jump back
})
end
local function writeTrampolineReturn(trAddr, retAddr)
return hk.write(trAddr, {
'e9','rel:',retAddr, -- jmp retAddr
})
end
local regsStructSize = 4*11
local regsStruct = {
eax= 0, ebx= 4, ecx= 8, edx=12,
esi=16, edi=20, esp=24, ebp=28,
eip=32, flags=36, brk=40,
}
local regsList = {'eax','ebx','ecx','edx','esi','edi','esp','ebp','eip','flags','brk'}
local function newRegs()
return hk.malloc(regsStructSize)
end
local function readRegsStruct(regsPtr)
local regs = {}
for _,regname in ipairs(regsList) do
regs[regname] = hk.readInt(regsPtr + regsStruct[regname])
end
return regs
end
-- Basic instruction length determination for automatic trampoline construction
-- Add to this table as needed to define instructions
-- a value of true indicates a position-dependent instruction that cannot be moved
local instrLen = {
['1b'] = {
['c9'] = 2, -- sbb ecx,ecx
},
['23'] = {
['c8'] = 2, -- and ecx,eax
},
['33'] = {
['c4'] = 2, -- xor eax,esp
},
['3b'] = {
['15'] = 6, -- cmp edx,i32
},
['50'] = 1, -- push eax
['51'] = 1, -- push ecx
['53'] = 1, -- push ebx
['55'] = 1, -- push ebp
['56'] = 1, -- push esi
['57'] = 1, -- push edi
['5d'] = 1, -- pop ebp
['5e'] = 1, -- pop esi
['5f'] = 1, -- pop edi
['68'] = 5, -- push i32
['6a'] = 2, -- push i8
['72'] = true, -- jb rel8
['74'] = true, -- jz rel8
['75'] = true, -- jnz rel8
['81'] = {
['ec'] = 6, -- sub esp,i32
['c2'] = 6, -- add edx,i32
},
['83'] = {
['c4'] = 3, -- add esp,i8
['e4'] = 3, -- and esp,i8
['ec'] = 3, -- sub esp,i8
},
['85'] = {
['c0'] = 2, -- test eax,eax
},
['89'] = {
['0d'] = 6, -- mov [i32],ecx
['15'] = 6, -- mov [i32],edx
},
['8b'] = {
['0d'] = 6, -- mov ecx,i32
['40'] = 3, -- mov eax,[eax+i8]
['44'] = {
['24'] = 4, -- mov eax,[esp+i8]
},
['45'] = 3, -- mov eax,[ebp+i8]
['6b'] = 3, -- mov ebp,[ebx+i8]
['c8'] = 2, -- mov ecx,eax
['dc'] = 2, -- mov ebx,esp
['e5'] = 2, -- mov esp,ebp
['ec'] = 2, -- mov ebp,esp
['f1'] = 2, -- mov esi,ecx
},
['8d'] = {
['34'] = {
['01'] = 3, -- lea esi,[ecx+eax]
},
['90'] = 6, -- lea edx,[eax+i32]
},
['a1'] = 5, -- mov eax,i32
['b8'] = 5, -- mov eax,i32
['c3'] = 1, -- retn
['d9'] = {
['47'] = 3, -- fld:32 [edi+i8]
['87'] = 6, -- fld:32 [edi+i32]
},
['dd'] = {
['5c'] = {
['24'] = 4, -- fstp:64 [esp+i8]
},
},
['e8'] = true, -- call rel32
['f7'] = {
['d9'] = 2, -- neg ecx
},
}
local function readByteHex(addr)
return ('%02x'):format(hk.readChar(addr)%256)
end
local jmpoutLen = 5 -- Length of the long jump instruction to be inserted as a hook
-- Determine the minimum code length >= jmpoutLen that can be
-- copied out into the trampoline.
-- Returns false if unrecognized instructions
-- Returns true if instructions are position-dependent and cannot be moved
local function determineOverwriteLen(addr)
local len = 0
while len < jmpoutLen do
local val = readByteHex(addr)
local il = instrLen[val]
local ofs = 0
while type(il)=='table' do
ofs = ofs+1
val = readByteHex(addr+ofs)
il = il[val]
end
if not il then return false end
if il==true then return true end
addr = addr + il
len = len + il
end
return len
end
-- Write into existing function to jump to trampoline
local function writeJumpout(rh)
local oldProt = hk.protectRWX(rh.hkAddr, rh.hkLen)
local hkAddrW = hk.write(rh.hkAddr, {
'e9','rel:',rh.trAddr, -- jmp trAddr
})
for i = 1, rh.hkLen-jmpoutLen do -- fill extra space with nops
hkAddrW = hk.write(hkAddrW, '90')
end
hk.protect(rh.hkAddr, rh.hkLen, oldProt) -- restore write protection on jumpout
return hkAddrW
end
-- Write code copied from hooked function into trampoline
local function writeOldCode(rh)
local oldProt = hk.protectRWX(rh.hkAddr, rh.hkLen)
hk.writeStr(rh.hkAddr, rh.movedCode)
hk.protect(rh.hkAddr, rh.hkLen, oldProt)
end
hk._registeredHooks = hk._registeredHooks or {} -- map of addr -> list of callbacks
-- Remove/replace all hooks, used when scanning
unhookAll = function()
for _,rh in pairs(hk._registeredHooks) do
writeOldCode(rh)
end
end
rehookAll = function()
for _,rh in pairs(hk._registeredHooks) do
writeJumpout(rh)
end
end
-- Called from C in trampoline
function _bllua_hk_callback(regsPtr)
local regs = readRegsStruct(regsPtr)
local rh = hk._registeredHooks[regs.eip]
if not rh then
error('_bllua_hk_callback: no callback registered at address') end
rh.callback(regs)
end
-- Main raw hooking function
function hk.hook(hkAddr, callback, hkLen)
if type(hkAddr)~='number' or hkAddr<0 or hkAddr%1~=0 then
error('hk.hook: argument #1: expected number >0 integer', 2) end
if type(callback)~='function' then
error('hk.hook: argument #2: expected function', 2) end
if hkLen~=nil and (type(hkLen)~='number' or hkLen<0 or hkLen%1~=0) then
error('hk.hook: argument #3: expected nil or number', 2) end
-- if a hook is already registered, overwrite it
-- todo: multiple hooks? package names?
if hk._registeredHooks[hkAddr] then
print('hk.hook: warning: a hook is already registered at address '..
('%08x'):format(hkAddr)..', will overwrite.')
hk._registeredHooks[hkAddr].callback = callback
return
end
if hkLen then
if hkLen<jmpoutLen then
error('hk.hook: argument #3: overwrite length must be >= '
..jmpoutLen, 2) end
else
hkLen = determineOverwriteLen(hkAddr)
if hkLen==false then
error('hk.hook: could not automatically determine instruction length. '
..'please specify a length >= '..jmpoutLen..' in argument #3', 2)
elseif hkLen==true then
error('hk.hook: the hook location contains position-dependent code! '
..'please move the hook or use a different hooking method', 2)
end
end
-- create register save struct
local regsPtr = newRegs()
-- create trampoline code
local movedCode = hk.readStr(hkAddr, hkLen)
local trLen = 256 + #movedCode -- eh, good enough
local trAddr = hk.malloc(trLen)
local trOldProt = hk.protectRWX(trAddr, trLen) -- allow execution
local trAddrW = trAddr
trAddrW = writeTrampoline(trAddrW, hkAddr, regsPtr)
trAddrW = hk.writeStr(trAddrW, movedCode)
trAddrW = writeTrampolineReturn(trAddrW, hkAddr + hkLen)
-- create info struct
local rh = {
hkAddr = hkAddr,
hkLen = hkLen,
regsPtr = regsPtr,
trAddr = trAddr,
trLen = trLen,
trOldProt = trOldProt,
movedCode = movedCode,
callback = callback,
}
-- save to hook registry
hk._registeredHooks[hkAddr] = rh
-- write jump out
writeJumpout(rh)
end
-- Remove a hook made by hk.hookRaw
function hk.unhook(hkAddr)
if type(hkAddr)~='number' or hkAddr<0 or hkAddr%1~=0 then
error('hk.unhook: argument #1: expected number >0 integer', 2) end
local rh = hk._registeredHooks[hkAddr]
assert(rh, 'hk.unhook: no hook registered at address '..
('%08x'):format(hkAddr))
-- remove jumpout
writeOldCode(rh)
-- delete allocated data
hk.protect(rh.trAddr, rh.trLen, rh.trOldProt)
hk.free(rh.trAddr)
hk.free(rh.regsPtr)
-- remove from hook registry
hk._registeredHooks[hkAddr] = nil
end
function hex(v) return v and ('%08x'):format(v):sub(1,8) end
-- called when blocklua unloads
function hk.unhookAll()
unhookAll()
for _,rh in pairs(hk._registeredHooks) do
hk.protect(rh.trAddr, rh.trLen, rh.trOldProt)
hk.free(rh.trAddr)
hk.free(rh.regsPtr)
end
hk._registeredHooks = {}
end
-- Utility to display addresses as hex
function hk.hex(v)
return ('%08x'):format(v)
end
-- todo: stack manipulation
_bllua_on_unload['libhooks'] = hk.unhookAll
return hk
-- testing
--[[
'dofile('modules/lualib/luahooks32.lua')
'f = hk.scan('55 8B EC 83 E4 C0 83 EC 38 56 57 8B 7D 08 8B 47 44 D1 E8 A8 01 74 5C 8B 47 28', 2)
'hk.hook(f, function(regs) print(regs) end)
not documented:
hk.open
hk.write / hk.patch formats other than hex
hk.protect
hk.protectRWX
]]

312
luahooks32core.cpp Normal file
View File

@@ -0,0 +1,312 @@
// Uses BlHooks for some things
// Todo: Make independent
#include <Windows.h>
#include <Psapi.h>
#include "lua.hpp"
// Custom types
void bll_hk_newMetatable(lua_State* L, const char* name, struct luaL_Reg* methods) {
if(luaL_newmetatable(L, name)) {
if(methods!=NULL)
luaL_setfuncs(L, methods, 0);
//lua_pushliteral(L, "__index");
//lua_settable(L, -3);
//lua_pushliteral(L, "__metatable");
//lua_pushliteral(L, "access to this metatable is disabled");
//lua_settable(L, -3);
}
lua_pop(L, 1);
}
// Image - Reference to a loaded binary, contains the base pointer and size
typedef struct {
void* base;
size_t size;
} bll_hk_image;
bll_hk_image* bll_hk_newImage(lua_State* L, void* base, size_t size) {
bll_hk_image* img = (bll_hk_image*)lua_newuserdata(L, sizeof(bll_hk_image));
luaL_setmetatable(L, "_bllua_hk.image");
img->base = base;
img->size = size;
return img;
}
int bll_hk_image_tostring(lua_State* L) {
bll_hk_image* img = (bll_hk_image*)luaL_checkudata(L, 1, "_bllua_hk.image");
char buf[100];
sprintf(buf, "image:{addr=%08X,size=%08X}",
(unsigned int)img->base,
(unsigned int)img->size);
lua_pushstring(L, buf);
return 1;
}
struct luaL_Reg bll_hk_image_methods[] = {
{"__tostring", bll_hk_image_tostring},
NULL,
};
void bll_hk_initTypeImage(lua_State* L) {
bll_hk_newMetatable(L, "_bllua_hk.image", bll_hk_image_methods);
}
// Addr - Just a pointer, can be added/subtracted
// Just using numbers for now
//typedef struct {
// void* a;
//} bll_hk_addr;
//int bll_hk_newAddr(lua_State* L, void* a) {
// bll_hk_addr* addr = (bll_hk_addr*)lua_newuserdata(L, sizeof(bll_hk_addr));
// luaL_setmetatable(L, "_bllua_hk.addr");
// addr->a = a;
// return 1;
//}
//int bll_hk_addr_tostring(lua_State* L) {
// bll_hk_addr* addr = (bll_hk_addr*)luaL_checkudata(L, 1, "_bllua_hk.addr");
//
// char buf[100];
// sprintf(buf, "addr:%08X", (unsigned int)addr->a);
// lua_pushstring(L, buf);
// return 1;
//}
//int bll_hk_addr_add(lua_State* L) {
// bll_hk_addr* addr = (bll_hk_addr*)luaL_checkudata(L, 1, "_bllua_hk.addr");
// size_t ofs = luaL_checkinteger(L, 2);
//
// bll_hk_newAddr(L, (char*)addr->a + ofs);
// return 1;
//}
//int bll_hk_addr_sub(lua_State* L) {
// bll_hk_addr* addr = (bll_hk_addr*)luaL_checkudata(L, 1, "_bllua_hk.addr");
// size_t ofs = luaL_checkinteger(L, 2);
//
// bll_hk_newAddr(L, (char*)addr->a - ofs);
// return 1;
//}
//struct luaL_Reg bll_hk_addr_methods[] = {
// {"__tostring", bll_hk_addr_tostring},
// {"__add", bll_hk_addr_add},
// {"__sub", bll_hk_addr_sub},
// NULL,
//};
//void bll_hk_initTypeAddr(lua_State* L) {
// bll_hk_newMetatable(L, "_bllua_hk.addr", bll_hk_addr_methods);
//}
// Scanning
bool bll_hk_patternMatch(char* addr, const char* pat, const char* mask) {
for(; *mask; ++addr, ++pat, ++mask) {
if(*mask=='x' && *addr!=*pat)
return false;
}
return !*mask;
}
void* bll_hk_scan(void* imgBase, size_t imgSize, const char* pat, const char* mask,
int skip) {
char* scanStart = (char*)imgBase;
char* scanEnd = scanStart + imgSize;
for(char* addr=scanStart; addr<scanEnd; addr++) {
if(bll_hk_patternMatch(addr, pat, mask)) {
if(skip==0)
return addr;
else
skip--;
}
}
return NULL;
}
// Lua lib functions
#define BLL_HK_PUSHADDR(_l, _a) lua_pushnumber((_l), (lua_Number)(unsigned int)(_a))
#define BLL_HK_CHECKADDR(_l, _i) (void*)luaL_checkinteger((_l), (_i))
#define BLL_HK_CHECKSIZET(_l, _i) (size_t)luaL_checkinteger((_l), (_i))
int bll_libhk_open(lua_State* L) {
HMODULE mod;
if(lua_isnoneornil(L, 1)) {
mod = GetModuleHandle(NULL);
} else {
const char* modName = luaL_checkstring(L, 1);
mod = GetModuleHandle(modName);
}
if(mod) {
MODULEINFO info;
GetModuleInformation(GetCurrentProcess(), mod, &info, sizeof(MODULEINFO));
bll_hk_newImage(L, info.lpBaseOfDll, info.SizeOfImage);
} else {
lua_pushnil(L);
}
return 1;
}
int bll_libhk_scan(lua_State* L) {
bll_hk_image* img = (bll_hk_image*)luaL_checkudata(L, 1, "_bllua_hk.image");
const char* pat = luaL_checklstring(L, 2, NULL);
const char* mask = luaL_checklstring(L, 3, NULL);
int skip = luaL_checkinteger(L, 4);
void* addr = bll_hk_scan(img->base, img->size, pat, mask, skip);
if(addr==NULL)
lua_pushnil(L);
else
BLL_HK_PUSHADDR(L, addr);
return 1;
}
int bll_libhk_readStr(lua_State* L) {
void* addr = BLL_HK_CHECKADDR(L, 1);
size_t len = BLL_HK_CHECKSIZET(L, 2);
lua_pushlstring(L, (const char*)addr, len); // based lua handling memory for us
return 1;
}
int bll_libhk_writeStr(lua_State* L) {
void* addr = BLL_HK_CHECKADDR(L, 1);
size_t len = 0;
const char* data = luaL_checklstring(L, 2, &len);
memcpy(addr, data, len);
BLL_HK_PUSHADDR(L, (char*)addr+len);
return 1;
}
int bll_libhk_readChar(lua_State* L) {
void* addr = BLL_HK_CHECKADDR(L, 1);
char data = *(char*)addr;
lua_pushinteger(L, data);
return 1;
}
int bll_libhk_writeChar(lua_State* L) {
void* addr = BLL_HK_CHECKADDR(L, 1);
char data = (char)luaL_checkinteger(L, 2);
*(char*)addr = data;
BLL_HK_PUSHADDR(L, (char*)addr + 1);
return 1;
}
int bll_libhk_readShort(lua_State* L) {
void* addr = BLL_HK_CHECKADDR(L, 1);
short data = *(short*)addr;
lua_pushinteger(L, data);
return 1;
}
int bll_libhk_writeShort(lua_State* L) {
void* addr = BLL_HK_CHECKADDR(L, 1);
short data = (short)luaL_checkinteger(L, 2);
*(short*)addr = data;
BLL_HK_PUSHADDR(L, (char*)addr + 2);
return 1;
}
int bll_libhk_readInt(lua_State* L) {
void* addr = BLL_HK_CHECKADDR(L, 1);
int data = *(int*)addr;
lua_pushinteger(L, data);
return 1;
}
int bll_libhk_writeInt(lua_State* L) {
void* addr = BLL_HK_CHECKADDR(L, 1);
int data = (int)luaL_checkinteger(L, 2);
*(int*)addr = data;
BLL_HK_PUSHADDR(L, (char*)addr + 4);
return 1;
}
int bll_libhk_readFloat(lua_State* L) {
void* addr = BLL_HK_CHECKADDR(L, 1);
float data = *(float*)addr;
lua_pushnumber(L, data);
return 1;
}
int bll_libhk_writeFloat(lua_State* L) {
void* addr = BLL_HK_CHECKADDR(L, 1);
float data = luaL_checknumber(L, 2);
*(float*)addr = data;
BLL_HK_PUSHADDR(L, (char*)addr + 4);
return 1;
}
int bll_libhk_readDouble(lua_State* L) {
void* addr = BLL_HK_CHECKADDR(L, 1);
double data = *(double*)addr;
lua_pushnumber(L, data);
return 1;
}
int bll_libhk_writeDouble(lua_State* L) {
void* addr = BLL_HK_CHECKADDR(L, 1);
double data = luaL_checknumber(L, 2);
*(double *)addr = data;
BLL_HK_PUSHADDR(L, (char*)addr + 8);
return 1;
}
int bll_libhk_protect(lua_State* L) {
void* addr = BLL_HK_CHECKADDR(L, 1);
size_t len = BLL_HK_CHECKSIZET(L, 2);
DWORD newProt = (DWORD)luaL_checkinteger(L, 3);
DWORD oldProt = 0;
VirtualProtect(addr, len, newProt, &oldProt);
lua_pushinteger(L, (lua_Integer)oldProt);
return 1;
}
int bll_libhk_malloc(lua_State* L) {
size_t size = (size_t)luaL_checkinteger(L, 1);
void* data = malloc(size);
BLL_HK_PUSHADDR(L, data);
return 1;
}
int bll_libhk_free(lua_State* L) {
void* data = BLL_HK_CHECKADDR(L, 1);
free(data);
return 0;
}
//typedef void(*bll_func_ptr)(void);
//int bll_libhk_call(lua_State* L) {
// void* jdest = BLL_HK_CHECKADDR(L, 1);
// ((bll_func_ptr)jdest)();
// return 0;
//}
// Hooks lib
// regsPtr in ecx, L in edx
__declspec(fastcall) void bll_hk_callback(void* regsPtr, lua_State* L) {
lua_getglobal(L, "_bllua_hk_callback");
BLL_HK_PUSHADDR(L, regsPtr);
lua_pcall(L, 1, 0, 0);
}
int bll_libhk_getLuaStatePtr(lua_State* L) {
BLL_HK_PUSHADDR(L, (void*)L);
return 1;
}
int bll_libhk_getCallbackPtr(lua_State* L) {
BLL_HK_PUSHADDR(L, (void*)bll_hk_callback);
return 1;
}
int bll_libhk_getStrPtr(lua_State* L) {
const char* str = luaL_checkstring(L, 1);
BLL_HK_PUSHADDR(L, (void*)str);
return 1;
}
const luaL_Reg bll_hk_reg[] = {
{"_openRaw" , bll_libhk_open },
{"_scanRaw" , bll_libhk_scan },
{"readStr" , bll_libhk_readStr },
{"writeStr" , bll_libhk_writeStr },
{"protect" , bll_libhk_protect },
{"readChar" , bll_libhk_readChar },
{"writeChar" , bll_libhk_writeChar },
{"readShort" , bll_libhk_readShort },
{"writeShort" , bll_libhk_writeShort },
{"readInt" , bll_libhk_readInt },
{"writeInt" , bll_libhk_writeInt },
{"readFloat" , bll_libhk_readFloat },
{"writeFloat" , bll_libhk_writeFloat },
{"readDouble" , bll_libhk_readDouble },
{"writeDouble", bll_libhk_writeDouble},
{"malloc" , bll_libhk_malloc },
{"free" , bll_libhk_free },
//{"call" , bll_libhk_call },
{"getStrPtr" , bll_libhk_getStrPtr },
{"_getLuaStatePtr", bll_libhk_getLuaStatePtr},
{"_getCallbackPtr", bll_libhk_getCallbackPtr},
NULL,
};
extern "C" int __declspec(dllexport) luaopen_luahooks32core(lua_State* L) {
luaL_register(L, "luahooks32core", bll_hk_reg);
bll_hk_initTypeImage(L);
//bll_hk_initTypeAddr(L);
return 1;
}

BIN
luahooks32core.dll Normal file

Binary file not shown.

55
readme.md Normal file
View File

@@ -0,0 +1,55 @@
# LuaHooks32
Basic x86-32 hooks library for Lua
## How to Install for Blockland+BlockLua
- Install RedBlocklandLoader and BlockLua
- Copy `luahooks32.lua` and `luahooks32core.dll` into the `modules/lualib` folder inside your Blockland install folder (you may have to create it)
## Quick Reference
`hk = require('luahooks32')` - Load the library
### Basic Scanning and Patching
`addr = hk.scan('01 02 ? ff FF')` - Scan the application binary for a pattern
`hk.patch(addr, '01 02 03')` - Patch executable code with a series of bytes
### Hooking
`hk.hook(addr, function(regs) ... end)` - Insert hook into binary code. Registers can be modified inside the hook. Registers are:
`regs.eax` `regs.ebx` `regs.ecx` `regs.edx` `regs.esi` `regs.edi` `regs.esp` `regs.ebp` `regs.eip` `regs.flags`
There is also `regs.brk`, which if set to 1 inside the hook, will cause the hook to execute a `retn` immediately after completing, returning out of whatever function the hook is inside.
Hooks can be inserted anywhere, provided there are at least 5 bytes of position-independent instructions that can be overwritten with a trampoline. Overwritten instructions are then copied into the hook routine.
If the basic builtin disassembler fails to detect the length of instructions to overwrite, a third argument to `bl.hook` can be used to manually specify the trampoline length.
`hk.unhook(addr)` - Remove a previously inserted hook.
`hk.unhookAll()` - Remove all hooks.
### Memory Access
`hk.write(addr, '01 02 03')` - Write a series of bytes
`str = hk.readStr(addr)` - Read a null-terminated C-style string from a memory address, and return its contents as a Lua string
`hk.writeStr(addr, 'hello\0')` - Write a Lua string to memory. Does NOT null-terminate, so you'll have to append `\0` yourself if you want that.
`val = hk.readInt(addr)` - Read a 32-bit signed integer from a memory address (little-endian)
`hk.writeInt(addr, val)`
`val = hk.readFloat(addr)`
`hk.writeFloat(addr, val)`
`val = hk.readChar(addr)`
`hk.writeChar(addr, val)`
`val = hk.readShort(addr)`
`hk.writeShort(addr, val)`
`val = hk.readDouble(addr)`
`hk.writeDouble(addr, val)`
Note that these functions can only write into writeable memory (i.e. stack/heap, not code). Use `hk.patch` to write into protected/executable memory.
`ptr = hk.getStrPtr('str')` - Convert a Lua string into null-terminated C-style and return a pointer to it
`print(hk.hex(val))` - Simple utility to convert a number (usually an address) into 32-bit hexadecimal
`ptr = hk.malloc(numBytes)` - Allocate memory and return a pointer to it
`hk.free(ptr)` - Free previously allocated memory
## Compiling
With any *32-bit* variant of GCC installed (such as MinGW or MSYS2), run the following command in the repo directory:
`g++ luahooks32core.cpp -o luahooks32core.dll -m32 -shared -static-libgcc -Iinc/lua -lpsapi -Linc/lua -llua5.1`
LuaJIT (lua5.1.dll) can be obtained from https://luajit.org/