diff options
Diffstat (limited to 'bruiser')
| -rw-r--r-- | bruiser/README.md | 3 | ||||
| -rw-r--r-- | bruiser/asmrewriter.c | 149 | ||||
| -rw-r--r-- | bruiser/asmrewriter.h | 89 | ||||
| -rw-r--r-- | bruiser/bruiser-extra.h | 3 | ||||
| -rw-r--r-- | bruiser/bruiser.cpp | 175 | ||||
| -rw-r--r-- | bruiser/bruiser.h | 5 | ||||
| -rw-r--r-- | bruiser/bruisercapstone.c | 188 | ||||
| -rw-r--r-- | bruiser/bruisercapstone.h | 31 | ||||
| -rw-r--r-- | bruiser/bruiserffi.c | 3 | ||||
| -rw-r--r-- | bruiser/lua-scripts/demo2.lua | 30 | ||||
| -rw-r--r-- | bruiser/lua-scripts/xobj.lua | 8 | ||||
| -rw-r--r-- | bruiser/makefile | 4 | 
12 files changed, 672 insertions, 16 deletions
| diff --git a/bruiser/README.md b/bruiser/README.md index 72b44d8..29c66c5 100644 --- a/bruiser/README.md +++ b/bruiser/README.md @@ -94,4 +94,5 @@ package.path = package.path .. ";LUA_PATH"  packege.cpath = package.cpath .. ";LUA_CPATH"  ``` -The following lines make the rocks in `LUA_PATH` and `LUA_CPATH` available on bruiser. You can get `LUA_PATH` and `LUA_CPATH` by runnin `luarocks path --bin`. You can also look at the `default.lua` that is shipped with bruiser.<br/> +The following lines make the rocks in `LUA_PATH` and `LUA_CPATH` available on bruiser. You can get `LUA_PATH` and `LUA_CPATH` by runnin `luarocks path --bin`. You can also look at the `defaults.lua` that is shipped with bruiser.<br/> +Also since there is a cli option that tells bruiser which lua script to load before handing control over to user code, you can have more than one such script to suit your needs.<br/> diff --git a/bruiser/asmrewriter.c b/bruiser/asmrewriter.c new file mode 100644 index 0000000..2bfdcf1 --- /dev/null +++ b/bruiser/asmrewriter.c @@ -0,0 +1,149 @@ + + +/***************************************************Project Mutator****************************************************/ +/*first line intentionally left blank.*/ +/*bruiser's lua asmrewriter implementation for jump tables*/ +/*Copyright (C) 2018 Farzad Sadeghi + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.*/ +/**********************************************************************************************************************/ +#include "./lua-5.3.4/src/lua.hpp" +#include "./bruisercapstone.h" +#include "./asmrewriter.h" + +#include <inttypes.h> +/**********************************************************************************************************************/ +static JMP_S_T* convert_jmpt(lua_State* __ls, int index) { +  JMP_S_T* dummy = (JMP_S_T*)lua_touserdata(__ls, index); +  if (dummy == NULL) luaL_typerror(__ls, index, dummy); +  return dummy; +} + +static JMP_S_T* check_jmpt(lua_State* __ls, int index) { +  JMP_S_T* dummy; +  luaL_checktype(__ls, index, LUA_TUSERDATA); +  dummy = (JMP_S_T*)luaL_checkudata(__ls, index, JMP_S_T); +  if (dummy == NULL) luaL_typerror(__ls, index, dummy); +  return dummy; +} + +static JMP_S_T* push_jmpt(lua_State* __ls) { +  JMP_S_T* dummy = (JMP_S_T*)lua_newuserdata(__ls, sizeof(JMP_S_T)); +  luaL_getmetatable(__ls, JMP_S_T); +  lua_setmetatable(__ls, -2); +  return dummy; +} + +static int new_jmpt(lua_State* __ls) { +  JMP_T jmp_t = luaL_optint(__ls, 1, 0); +  uint64_t location = luaL_optint(__ls, 2, 0); +  uint8_t size = luaL_optint(__ls, 3, 0); +  // +  // +  // +  uint64_t address = luaL_optint(__ls, 7, 0); +  uint64_t address_y = luaL_optint(__ls, 8, 0); +  uint64_t address_n = luaL_optint(__ls, 9, 0); +  unsigned char y = luaL_optint(__ls, 10, 0); +  unsigned char n = luaL_optint(__ls, 11, 0); +  unsigned char z = luaL_optint(__ls, 12, 0); +  JMP_S_T* dummy = push_jmpt(__ls); +  dummy->type = jmp_t; +  dummy->location = location; +  dummy->size = size; +  //dummy->next =; +  //dummy->next_y =; +  //dummy->next_n =; +  dummy->address = address; +  dummy->address_y = address_y; +  dummy->address_n = address_n; +  dummy->y = y; +  dummy->n = n; +  dummy->z = z; +  return 1; +} + +static int jmpt_custom(lua_State* __ls) { +  JMP_S_T* dummy = check_jmpt(__ls, 1); +  printf("this is the jump table custom function.\n"); +  lua_pushnumber(__ls, dummy->type); +  lua_pushnumber(__ls, dummy->location); +  lua_pushnumber(__ls, dummy->size); +  lua_pushlightuserdata(__ls, dummy->next); +  lua_pushlightuserdata(__ls, dummy->next_y); +  lua_pushlightuserdata(__ls, dummy->next_n); +  lua_pushnumber(__ls, dummy->address); +  lua_pushnumber(__ls, dummy->address_y); +  lua_pushnumber(__ls, dummy->address_n); +  lua_pushnumber(__ls, dummy->y); +  lua_pushnumber(__ls, dummy->n); +  lua_pushnumber(__ls, dummy->z); +  return 12; +} + +#define SET_GENERATOR(X) \ +  static int jmpt_set_##X(lua_State* __ls) {\ +  JMP_S_T* dummy = check_jmpt(__ls,1);\ +  dummy->type = luaL_checkint(__ls, 2);\ +  lua_settop(__ls, 1);\ +  return 1;\ +} + +#define X_LIST_GEN \ +  X(type, "setter method for type")\ +  X(location, "setter method for location")\ +  X(size, "setter method for size")\ +  X(address, "setter method for address")\ +  X(address_y, "setter method for address_y")\ +  X(address_n, "setter method for address_n")\ +  X(y, "setter method for y")\ +  X(n, "setter method for n")\ +  X(z, "setter method for z") + +#define X(X1,X2) SET_GENERATOR(X1) +X_LIST_GEN +#undef X +#undef X_LIST_GEN +#undef SET_GENERATOR + +static int jmpt_set_next(lua_State* __ls) {} +static int jmpt_set_next_y(lua_State* __ls) {} +static int jmpt_set_next_n(lua_State* __ls) {} + +static int jmpt_gc(lua_State* __ls) {} + +int jmpt_register(lua_State* __ls) { +  luaL_openlib(__ls, JMP_S_T, jmpt_methods, 0); +  luaL_newmetatable(__ls, JMP_S_T); +  luaL_openlib(__ls, 0, jmpt_meta, 0); +  lua_pushliteral(__ls, "__index"); +  lua_pushvalue(__ls, -3); +  lua_rawset(__ls, -3); +  lua_pushliteral(__ls, "__metatable"); +  lua_pushvalue(__ls, -3); +  lua_rawset(__ls, -3); +  lua_pop(__ls, 1); +  return 1; +} +//@DEVI-after jmpt_register, the methods are still on the stack. remove them by lua_pop(__ls, 1) +/**********************************************************************************************************************/ +//@DEVI-the main is only meant for testing +#pragma weak main +int main(int argc, char** argv) { +  return 0; +} +/**********************************************************************************************************************/ +/*last line intentionally left blank.*/ + diff --git a/bruiser/asmrewriter.h b/bruiser/asmrewriter.h new file mode 100644 index 0000000..ce28dcd --- /dev/null +++ b/bruiser/asmrewriter.h @@ -0,0 +1,89 @@ + + +/***************************************************Project Mutator****************************************************/ +/*first line intentionally left blank.*/ +/*bruiser's lua asmrewriter implementation for jump tables*/ +/*Copyright (C) 2018 Farzad Sadeghi + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.*/ +/**********************************************************************************************************************/ +#include "./lua-5.3.4/src/lua.hpp" +#include "./bruisercapstone.h" + +#include <inttypes.h> +/**********************************************************************************************************************/ +#ifndef ASM_REWRITER_H +#define ASM_REWRITER_H + +static JMP_S_T* convert_jmpt(lua_State* __ls, int index); +static JMP_S_T* check_jmpt(lua_State* __ls, int index); +static JMP_S_T* push_jmpt(lua_State* __ls); +static int new_jmpt(lua_State* __ls); +static int jmpt_custom(lua_State* __ls); + +#define SET_GENERATOR(X) \ +  static int jmpt_set_##X(lua_State* __ls); + +#define X_LIST_GEN \ +  X(type, "setter method for type")\ +  X(location, "setter method for location")\ +  X(size, "setter method for size")\ +  X(address, "setter method for address")\ +  X(address_y, "setter method for address_y")\ +  X(address_n, "setter method for address_n")\ +  X(y, "setter method for y")\ +  X(n, "setter method for n")\ +  X(z, "setter method for z") + +#define X(X1,X2) SET_GENERATOR(X1) +X_LIST_GEN +#undef X +#undef X_LIST_GEN +#undef SET_GENERATOR + +static int jmpt_set_next(lua_State* __ls) {} +static int jmpt_set_next_y(lua_State* __ls) {} +static int jmpt_set_next_n(lua_State* __ls) {} + +static const luaL_reg jmpt_methods[] = { +  {"new", new_jmpt}, +  {"set_type", jmpt_set_type}, +  {"set_location", jmpt_set_location}, +  {"set_size", jmpt_set_size}, +  {"set_address", jmpt_set_address}, +  {"set_address_y", jmpt_set_address_y}, +  {"set_address_n", jmpt_set_address_n}, +  {"set_next", jmpt_set_next}, +  {"set_next_y", jmpt_set_next_y}, +  {"set_next_n", jmpt_set_next_n}, +  {"set_y", jmpt_set_y}, +  {"set_n", jmpt_set_n}, +  {"set_z", jmpt_set_z}, +  {0,0} +}; + +static int jmpt_gc(lua_State* __ls) {} + +static const luaL_reg jmpt_meta[] = { +  {"__gc", jmpt_gc}, +  {0, 0} +} + +int jmpt_register(lua_State* __ls) { + +#endif +/**********************************************************************************************************************/ +/*last line intentionally left blank.*/ + diff --git a/bruiser/bruiser-extra.h b/bruiser/bruiser-extra.h index b834345..94392e2 100644 --- a/bruiser/bruiser-extra.h +++ b/bruiser/bruiser-extra.h @@ -131,6 +131,9 @@ std::vector<std::string> LUA_FUNCS =    "xobjlist()",    "xallocglobal(",    "xallocallglobals()", +  "getjmptable(", +  "freejmptable(", +  "dumpjmptable(",    "_G",    "_VERSION",    "assert", diff --git a/bruiser/bruiser.cpp b/bruiser/bruiser.cpp index 50c01cc..e6a3520 100644 --- a/bruiser/bruiser.cpp +++ b/bruiser/bruiser.cpp @@ -28,6 +28,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.*  #include "ORCmutation.h"  #include "executioner.h"  #include "bruiserffi.h" +#include "bruisercapstone.h"  /*standard headers*/  #include <fstream>  #include <string> @@ -105,9 +106,96 @@ cl::opt<bool> MainFileOnly("MainOnly", cl::desc("bruiser will only report the re  cl::opt<std::string> M0XMLPath("xmlpath", cl::desc("tells bruiser where to find the XML file containing the Mutator-LVL0 report."), cl::init(bruiser::M0REP), cl::cat(BruiserCategory), cl::ZeroOrMore);  cl::opt<bool> LuaJIT("jit", cl::desc("should bruiser use luajit or not."), cl::init(true), cl::cat(BruiserCategory), cl::ZeroOrMore);  cl::opt<bool> Verbose("verbose", cl::desc("verbosity"), cl::init(false), cl::cat(BruiserCategory), cl::ZeroOrMore); +// @DEVI-FIXME-we need something like python's code module. lua's -i is not it. +cl::opt<bool> LuaInteractive("interactive", cl::desc("run in interactive mode"), cl::init(false), cl::cat(BruiserCategory), cl::ZeroOrMore);  cl::opt<std::string> NonCLILuaScript("lua", cl::desc("specifies a lua script for bruiser to run in non-interactive mode"), cl::init(""), cl::cat(BruiserCategory), cl::Optional);  cl::opt<std::string> LuaDefault("luadefault", cl::desc("the path to the luadefault file. the default option is where the bruiser executable is."), cl::init("./defaults.lua"), cl::cat(BruiserCategory), cl::ZeroOrMore);  /**********************************************************************************************************************/ +template <typename T> +int pushLuaTableInt(lua_State* __ls, std::vector<T> vec) { +  int tableindex = 1; +  lua_newtable(__ls); +  if (!lua_checkstack(__ls, vec.size())) { +    PRINT_WITH_COLOR_LB(RED, "cant grow lua stack. current size is too small."); +    return -1; +  } +  for (auto& iter : vec) { +    lua_pushinteger(__ls, tableindex); +    tableindex++; +    lua_pushinteger(__ls, iter); +    lua_settable(__ls, -3); +  } +  return 0; +} + +int pushLuaTableString(lua_State* __ls, std::vector<std::string> vec) { +  int tableindex = 1; +  lua_newtable(__ls); +  if (!lua_checkstack(__ls, vec.size())) { +    PRINT_WITH_COLOR_LB(RED, "cant grow lua stack. current size is too small."); +    return -1; +  } +  for (auto& iter : vec) { +    lua_pushinteger(__ls, tableindex); +    tableindex++; +    lua_pushstring(__ls, iter.c_str()); +    lua_settable(__ls, -3); +  } +  return 0; +} + +template <typename T> +int pushLuaTableNumber(lua_State* __ls, std::vector<T> vec) { +  int tableindex = 1; +  lua_newtable(__ls); +  if (!lua_checkstack(__ls, vec.size())) { +    PRINT_WITH_COLOR_LB(RED, "cant grow lua stack. current size is too small."); +    return -1; +  } +  for (auto& iter : vec) { +    lua_pushinteger(__ls, tableindex); +    tableindex++; +    lua_pushnumber(__ls, iter); +    lua_settable(__ls, -3); +  } +  return 0; +} + +template <typename T> +std::vector<T> getLuaTableInt(lua_State* __ls, int numargs, int argnum) { +  std::vector<T> ret; +  int table_length = lua_rawlen(__ls, argnum); +  lua_checkstack(__ls, table_length); +  for (int i = 1; i <= table_length; ++i) { +    lua_rawgeti(__ls, argnum, i); +    ret.push_back(lua_tointeger(__ls, i + numargs)); +  } +  return ret; +} + +std::vector<std::string> getLuaTableString(lua_State* __ls, int numargs, int argnum) { +  std::vector<std::string> ret; +  int table_length = lua_rawlen(__ls, argnum); +  lua_checkstack(__ls, table_length); +  for (int i = 1; i <= table_length; ++i) { +    lua_rawgeti(__ls, argnum, i); +    ret.push_back(lua_tostring(__ls, i + numargs)); +  } +  return ret; +} + +template <typename T> +std::vector<T> getLuaTableNumber(lua_State* __ls, int numargs, int argnum) { +  std::vector<T> ret; +  int table_length = lua_rawlen(__ls, argnum); +  lua_checkstack(__ls, table_length); +  for (int i = 1; i <= table_length; ++i) { +    lua_rawgeti(__ls, argnum, i); +    ret.push_back(lua_tonumber(__ls, i + numargs)); +  } +  return ret; +} +/**********************************************************************************************************************/  class LuaEngine  {    public: @@ -252,8 +340,59 @@ class PyExec {      return 0;      } -    //std::vector<std::string> actionParser(std::string action) {} -    //void convertPush(PyObject* pyobject) {} +    std::vector<std::string> actionParser(std::string action) {} +    void convertNPush(PyObject* pyobject) {} + +    int64_t pyInt(PyObject* po) {return PyLong_AsLong(po);} + +    double pyFloat(PyObject* po) {return PyFloat_AsDouble(po);} + +    std::vector<PyObject*> pyList_unpack(PyObject* po) { +      std::vector<PyObject*> dummy; +      if (PyList_Check(po)) { +        int size = PyList_Size(po); +        for (int i = 0; i < size; ++i) { +          dummy.push_back(PyList_GetItem(po, i)); +        } +      } else { +        PRINT_WITH_COLOR_LB(RED, "Not a PyList object."); +      } +      return dummy; +    } + +    std::string pyString(PyObject* po) { +      return PyBytes_AsString(PyUnicode_AsEncodedString(PyObject_Repr(po), "utf-8", "surrogateescape")); +    } + +    std::pair<std::vector<PyObject*>, std::vector<PyObject*>> pyDict_unpack(PyObject* po) { +      std::vector<PyObject*> Keys, Values; +      if (PyDict_Check(po)) { +        Keys = pyList_unpack(PyDict_Keys(po)); +        Values = pyList_unpack(PyDict_Values(po)); +      } else { +        PRINT_WITH_COLOR_LB(RED, "Not a PyDict object."); +      } +      return std::make_pair(Keys, Values); +    } + +    char* pyBytes(PyObject* po) { +      char* dummy; +      if (PyBytes_Check(po)) { +        dummy = PyBytes_AsString(po); +      } else { +        PRINT_WITH_COLOR_LB(RED, "Not a PyBytes object."); +      } +      return dummy; +    } + +    char* pyByteArray(PyObject* po) { +      char* dummy; +      if (PyByteArray_Check(po)) { +        dummy = PyByteArray_AsString(po); +      } else { +        PRINT_WITH_COLOR_LB(RED, "Not a PyByteArray object."); +      } +    }      int getAsCppStringVec(void) {        if (Verbose) PRINT_WITH_COLOR_LB(BLUE, "processing return result..."); @@ -1443,7 +1582,7 @@ class LuaWrapper      int BruiserLuaXObjAllocGlobal(lua_State* __ls) {        int numargs = lua_gettop(__ls); -      if (numargs != 2) {PRINT_WITH_COLOR_LB(RED, "expected exactly two args. did not get that.");} +      if (numargs != 2) {PRINT_WITH_COLOR_LB(RED, "expected exactly two args. did not get that.");return 0;}        std::string glob_name = lua_tostring(__ls , 1);        size_t size = lua_tointeger(__ls, 2);        xglobals.reserve(size); @@ -1452,6 +1591,33 @@ class LuaWrapper      int BruiserLuaXObjAllocAllGlobals(lua_State* __ls) {} +    int BruiserGetJumpTable(lua_State* __ls) { +      int numargs = lua_gettop(__ls); +      if (numargs != 2) {PRINT_WITH_COLOR_LB(RED, "expected exactly two args. did not get that.");return 0;} +      uint64_t size = lua_tointeger(__ls, 1); +      std::vector<uint8_t> code_v = getLuaTableInt<uint8_t>(__ls, 2, 2); +      auto ptr = makejmptable(size, code_v.data()); +      std::cout << RED << &ptr << NORMAL << "\n"; +      lua_pushlightuserdata(__ls, ptr); +      return 1; +    } + +    int BruiserFreeJumpTable(lua_State* __ls) { +      int numargs = lua_gettop(__ls); +      if (numargs != 1) {PRINT_WITH_COLOR_LB(RED, "expected exactly one argument.");} +      uint64_t head = lua_tointeger(__ls, 1); +      freejmptable((JMP_S_T*)head); +      return 0; +    } + +    int BruiserDumpJumpTable(lua_State* __ls) { +      int numargs = lua_gettop(__ls); +      if (numargs != 1) {PRINT_WITH_COLOR_LB(RED, "expected exactly one argument of type lightuserdata.");} +      uint64_t ptr = lua_tointeger(__ls, 1); +      dumpjmptable((JMP_S_T*)ptr); +      return 0; +    } +      /*read the m0 report*/      int BruiserLuaM0(lua_State* __ls)      { @@ -2064,6 +2230,9 @@ int main(int argc, const char **argv) {      lua_register(LE.GetLuaState(), "xobjlist", &LuaDispatch<&LuaWrapper::BruiserLuaXObjGetList>);      lua_register(LE.GetLuaState(), "xallocglobal", &LuaDispatch<&LuaWrapper::BruiserLuaXObjAllocGlobal>);      lua_register(LE.GetLuaState(), "xallocallglobals", &LuaDispatch<&LuaWrapper::BruiserLuaXObjAllocAllGlobals>); +    lua_register(LE.GetLuaState(), "getjmptable", &LuaDispatch<&LuaWrapper::BruiserGetJumpTable>); +    lua_register(LE.GetLuaState(), "freejmptable", &LuaDispatch<&LuaWrapper::BruiserFreeJumpTable>); +    lua_register(LE.GetLuaState(), "dumpjmptable", &LuaDispatch<&LuaWrapper::BruiserDumpJumpTable>);      /*its just regisering the List function from LuaWrapper with X-macros.*/  #define X(__x1, __x2) lua_register(LE.GetLuaState(), #__x1, &LuaDispatch<&LuaWrapper::List##__x1>); diff --git a/bruiser/bruiser.h b/bruiser/bruiser.h index 616f2c8..584d652 100644 --- a/bruiser/bruiser.h +++ b/bruiser/bruiser.h @@ -157,7 +157,10 @@ help CMDHelp[] = {    {"xcall", "xcall(index, num_args)", "call xobj with the given index in to the xobj vector with the given number of args", "", "returns the xobj call result"},    {"xobjlist", "xobjlist()", "return a table containing xobj pointers and names. names are keys, values are the pointers.", "", "table of pairs"},    {"xallocglobal", "xallocglobal(index)", "allocate a global value with index index", "", ""}, -  {"xallocallglobals", "xallocallglobals()", "allocate all globals", "", ""} +  {"xallocallglobals", "xallocallglobals()", "allocate all globals", "", ""}, +  {"getjmptable", "getjmptable(size, code)", "get a table of all jumps", "", "returns a pointer to the head of the jump table linked-list as lightuserdata"}, +  {"freejmptable", "freejmptable(head)", "free the jmp table linked-list", "", "nothing"}, +  {"dumpjmptable", "dumpjmptable(head)", "dumps the jmp table linked-list", "", "nothing"}  };  /**********************************************************************************************************************/  /** diff --git a/bruiser/bruisercapstone.c b/bruiser/bruisercapstone.c index aea791d..8e190c5 100644 --- a/bruiser/bruisercapstone.c +++ b/bruiser/bruisercapstone.c @@ -31,17 +31,28 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.*  #include <string.h>  /**********************************************************************************************************************/  /**********************************************************************************************************************/ +JMP_S_T* head = NULL; +JMP_S_T* tail = NULL;  extern char etext, edata, end;  // quad  #define CODE_1 "\x55\x48\x89\xe5\x48\x83\xec\x20\x89\x7d\xfc\x89\x75\xf8\x89\x55\xf4\x89\x4d\xf0\x8b\x7d\xfc\x8b\x75\xf8\xe8\xd1\xfd\xff\xff\x8b\x7d\xf4\x8b\x75\xf0\x89\x45\xec\xe8\xc3\xfd\xff\xff\x8b\x4d\xec\x1\xc1\x89\xc8\x48\x83\xc4\x20\x5d\xc3"  // glob  #define CODE_2 "\x55\x48\x89\xe5\x48\x8b\x05\x0d\x15\x20\x00\x48\x8b\x0d\xee\x14\x20\x00\x48\x8b\x15\xf7\x14\x20\x00\x48\x8b\x35\xd8\x14\x20\x00\x8b\x3e\x03\x3a\x03\x39\x03\x38\x89\xf8\x5d\xc3" +// main +# define CODE_3 "\x31\xed\x49\x89\xd1\x5e\x48\x89\xe2\x48\x83\xe4\xf0\x50\x54\x49\xc7\xc0\x60\x07\x40\x00\x48\xc7\xc1\xf0\x06\x40\x00\x48\xc7\xc7\x90\x06\x40\x00\xff\x15\xa6\x0b\x20\x00\xf4\x0f\x1f\x44\x00\x00\x55\xb8\x38\x10\x60\x00\x48\x3d\x38\x10\x60\x00\x48\x89\xe5\x74\x17\xb8\x00\x00\x00\x00\x48\x85\xc0\x74\x0d\x5d\xbf\x38\x10\x60\x00\xff\xe0\x0f\x1f\x44\x00\x00\x5d\xc3\x66\x0f\x1f\x44\x00\x00\xbe\x38\x10\x60\x00\x55\x48\x81\xee\x38\x10\x60\x00\x48\x89\xe5\x48\xc1\xfe\x03\x48\x89\xf0\x48\xc1\xe8\x3f\x48\x01\xc6\x48\xd1\xfe\x74\x15\xb8\x00\x00\x00\x00\x48\x85\xc0\x74\x0b\x5d\xbf\x38\x10\x60\x00\xff\xe0\x0f\x1f\x00\x5d\xc3\x66\x0f\x1f\x44\x00\x00\x80\x3d\x6d\x0b\x20\x00\x00\x75\x17\x55\x48\x89\xe5\xe8\x7e\xff\xff\xff\xc6\x05\x5b\x0b\x20\x00\x01\x5d\xc3\x0f\x1f\x44\x00\x00\xf3\xc3\x0f\x1f\x40\x00\x66\x2e\x0f\x1f\x84\x00\x00\x00\x00\x00\x55\x48\x89\xe5\x5d\xeb\x89\x66\x0f\x1f\x84\x00\x00\x00\x00\x00\x55\x48\x89\xe5\xb8\x01\x00\x00\x00\x5d\xc3\x0f\x1f\x44\x00\x00\x55\x48\x89\xe5\xb8\x02\x00\x00\x00\x5d\xc3\x0f\x1f\x44\x00\x00\x55\x48\x89\xe5\xb8\x03\x00\x00\x00\x5d\xc3\x0f\x1f\x44\x00\x00\x55\x48\x89\xe5\xb8\x04\x00\x00\x00\x5d\xc3\x0f\x1f\x44\x00\x00\x55\x48\x89\xe5\xb8\x05\x00\x00\x00\x5d\xc3\x0f\x1f\x44\x00\x00\x55\x48\x89\xe5\xb8\x06\x00\x00\x00\x5d\xc3\x0f\x1f\x44\x00\x00\x55\x48\x89\xe5\x89\x7d\xfc\x89\x75\xf8\x8b\x75\xfc\x03\x75\xf8\x89\xf0\x5d\xc3\x66\x66\x66\x2e\x0f\x1f\x84\x00\x00\x00\x00\x00\x55\x48\x89\xe5\x89\x7d\xfc\x89\x75\xf8\x8b\x75\xfc\x2b\x75\xf8\x89\xf0\x5d\xc3\x66\x66\x66\x2e\x0f\x1f\x84\x00\x00\x00\x00\x00\x55\x48\x89\xe5\xf2\x0f\x11\x45\xf8\xf2\x0f\x11\x4d\xf0\xf2\x0f\x10\x45\xf8\xf2\x0f\x58\x45\xf0\x5d\xc3\x66\x0f\x1f\x44\x00\x00\x55\x48\x89\xe5\xf2\x0f\x11\x45\xf8\xf2\x0f\x11\x4d\xf0\xf2\x0f\x10\x45\xf8\xf2\x0f\x5c\x45\xf0\x5d\xc3\x66\x0f\x1f\x44\x00\x00\x55\x48\x89\xe5\xf2\x0f\x11\x45\xf8\xf2\x0f\x11\x4d\xf0\xf2\x0f\x11\x55\xe8\xf2\x0f\x10\x45\xf8\xf2\x0f\x58\x45\xf0\xf2\x0f\x58\x45\xe8\x5d\xc3\x66\x66\x66\x2e\x0f\x1f\x84\x00\x00\x00\x00\x00\x55\x48\x89\xe5\x48\x83\xec\x20\x89\x7d\xfc\x89\x75\xf8\x89\x55\xf4\x89\x4d\xf0\x8b\x7d\xfc\x8b\x75\xf8\xe8\x31\xff\xff\xff\x8b\x7d\xf4\x8b\x75\xf0\x89\x45\xec\xe8\x23\xff\xff\xff\x8b\x4d\xec\x01\xc1\x89\xc8\x48\x83\xc4\x20\x5d\xc3\x66\x0f\x1f\x44\x00\x00\x55\x48\x89\xe5\x48\x89\x7d\xf8\x48\x8b\x45\xf8\x5d\xc3\x66\x90\x55\x48\x89\xe5\x48\x8d\x05\xc5\x09\x20\x00\x48\x8d\x0d\xba\x09\x20\x00\x48\x8d\x15\xaf\x09\x20\x00\x48\x8d\x35\xa4\x09\x20\x00\x8b\x3e\x03\x3a\x03\x39\x03\x38\x89\xf8\x5d\xc3\x0f\x1f\x40\x00\x55\x48\x89\xe5\x48\x83\xec\x20\xb8\x0a\x00\x00\x00\xb9\x14\x00\x00\x00\xc7\x45\xfc\x00\x00\x00\x00\x89\x7d\xf8\x48\x89\x75\xf0\x89\xc7\x89\xce\xe8\xa7\xfe\xff\xff\x48\x8d\x3d\xc0\x00\x00\x00\x89\x45\xec\xb0\x00\xe8\x46\xfd\xff\xff\xbf\x14\x00\x00\x00\xbe\x0a\x00\x00\x00\x89\x45\xe8\xe8\xa4\xfe\xff\xff\x48\x83\xc4\x20\x5d\xc3\x66\x2e\x0f\x1f\x84\x00\x00\x00\x00\x00\x0f\x1f\x40\x00\x41\x57\x41\x56\x49\x89\xd7\x41\x55\x41\x54\x4c\x8d\x25\xee\x06\x20\x00\x55\x48\x8d\x2d\xee\x06\x20\x00\x53\x41\x89\xfd\x49\x89\xf6\x4c\x29\xe5\x48\x83\xec\x08\x48\xc1\xfd\x03\xe8\xc7\xfc\xff\xff\x48\x85\xed\x74\x20\x31\xdb\x0f\x1f\x84\x00\x00\x00\x00\x00\x4c\x89\xfa\x4c\x89\xf6\x44\x89\xef\x41\xff\x14\xdc\x48\x83\xc3\x01\x48\x39\xdd\x75\xea\x48\x83\xc4\x08\x5b\x5d\x41\x5c\x41\x5d\x41\x5e\x41\x5f\xc3\x90\x66\x2e\x0f\x1f\x84\x00\x00\x00\x00\x00\xf3\xc3" +/**********************************************************************************************************************/ +/**********************************************************************************************************************/ +JMP_S_T* iter_next(JMP_S_T* arg) {return arg->next;} +JMP_S_T* iter_next_y(JMP_S_T* arg) {return arg->next_y;} +JMP_S_T* iter_next_n(JMP_S_T* arg) {return arg->next_n;} +/**********************************************************************************************************************/ +/**********************************************************************************************************************/  /**********************************************************************************************************************/  /**********************************************************************************************************************/  uint32_t get_textsection_length(void) {return &edata-&etext;}  /**********************************************************************************************************************/  /**********************************************************************************************************************/ -uintptr_t get_symbol_rt_address(const char* symbol_name) {} +uintptr_t get_symbol_rt_address(const char* symbol_name) {return NULL;}  /**********************************************************************************************************************/  /**********************************************************************************************************************/  void int2byte(int value, uint8_t* ret_value, size_t size) { @@ -95,7 +106,7 @@ int ks_write(ks_arch arch, int mode, const char* assembly, int syntax, unsigned    if (syntax) ks_option(ks, KS_OPT_SYNTAX, syntax);    if (ks_asm(ks, assembly, 0, &encode, &size, &count)) {printf("errored out\n"); return -1;} -#if 0 +#if 1    else {      printf("%s =", assembly);      for (size_t i = 0; i < size; ++i) { @@ -119,14 +130,17 @@ int global_rewriter(int offset, size_t size, uint8_t* asm_code, const char* obj)    unsigned char *encode;    if (cs_open(CS_ARCH_X86, CS_MODE_64, &handle) != CS_ERR_OK) return -1; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpointer-sign"    count = cs_disasm(handle, obj, size, 0x0, 0, &insn); -  printf("number of instructions: %d.\n\n", count); +#pragma GCC diagnostic pop +  printf("number of instructions: %zu.\n\n", count);    cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON);    if (count > 0) {      size_t j;      for (j = 0; j < count; ++j) { -      printf(CYAN"%d.\t"NORMAL, j); +      printf(CYAN"%zu.\t"NORMAL, j);        printf(GREEN"0x%"PRIx64":\t%s\t\t%s\t"NORMAL, insn[j].address, insn[j].mnemonic, insn[j].op_str);        printf(BLUE"insn size: %d\n"NORMAL, insn[j].size);        //for (int i = 0; i < 16; ++i) {code[i] = insn[j].bytes[i]; printf("%02x ", code[i]);} @@ -159,14 +173,17 @@ int call_rewriter(int offset, size_t size, uint8_t* asm_code, const char* obj) {    size_t size_counter = 0;    if (cs_open(CS_ARCH_X86, CS_MODE_64, &handle) != CS_ERR_OK) return -1; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpointer-sign"    count = cs_disasm(handle, obj, size, 0x0, 0, &insn); -  printf("number of instructions: %d.\n\n", count); +#pragma GCC diagnostic pop +  printf("number of instructions: %zu.\n\n", count);    cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON);    if (count > 0) {      size_t j;      for (j = 0; j < count; ++j) { -      printf(CYAN"%d.\t"NORMAL, j); +      printf(CYAN"%zu.\t"NORMAL, j);        printf(GREEN"0x%"PRIx64":\t%s""\t\t%s\t"NORMAL, insn[j].address, insn[j].mnemonic, insn[j].op_str);        for (int i = 0; i < 16; ++i) {code[i] = insn[j].bytes[i]; printf(BLUE"%02x "NORMAL, code[i]);}        printf("\n"); @@ -198,6 +215,141 @@ int call_rewriter(int offset, size_t size, uint8_t* asm_code, const char* obj) {  }  /**********************************************************************************************************************/  /**********************************************************************************************************************/ +JMP_S_T* makejmptable(size_t size, uint8_t* obj) { +  csh handle; +  cs_insn* insn; +  size_t count; +  uint8_t rewritten[16]; +  uint8_t code[16]; +  size_t size_counter = 0; + +  head = malloc(sizeof(JMP_S_T)); +  tail = malloc(sizeof(JMP_S_T)); +  head->type = NONE; +  head->next = NULL; +  tail = head; + +  if (cs_open(CS_ARCH_X86, CS_MODE_64, &handle) != CS_ERR_OK) return NULL; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpointer-sign" +  count = cs_disasm(handle, obj, size, 0x0, 0, &insn); +#pragma GCC diagnostic pop +  printf("number of instructions: %zu.\n\n", count); +  cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); + +  intmax_t address; +  if (count > 0) { +    size_t j; +    for (j = 0; j < count; ++j) { +      printf(CYAN"%zu.\t"NORMAL, j); +      printf(GREEN"0x%"PRIx64":\t%s""\t\t%s\t"NORMAL, insn[j].address, insn[j].mnemonic, insn[j].op_str); +      for (int i = 0; i < 16; ++i) {code[i] = insn[j].bytes[i]; printf(BLUE"%02x "NORMAL, code[i]);} +      printf("\n"); + +      if (strcmp(insn[j].mnemonic, "jmp") == 0) { +        char* endptr; +        address = strtoumax(insn[j].op_str, &endptr, 0); +#if 1 +        printf(RED"found a jmp\n"); +        for (int i = 0; i < 16; ++i) {code[i] = insn[j].bytes[i]; printf(RED"%02x "NORMAL, code[i]);} +        printf("\n"); +        printf(RED"%jx\n", address); +        printf(RED"%d\n", insn[j].size); +#endif +        JMP_S_T* dummy = malloc(sizeof(JMP_S_T)); +        dummy->location = insn[j].address; +        dummy->type = JMP; +        dummy->address = address; +        dummy->size = insn[j].size; +        dummy->next = NULL; +        tail->next = dummy; +        tail = dummy; +      } + +      if (strcmp(insn[j].mnemonic, "je") == 0) { +        char* endptr; +        address = strtoimax(insn[j].op_str, &endptr, 0); +#if 1 +        printf(RED"found a je\n"); +        for (int i = 0; i < 16; ++i) {code[i] = insn[j].bytes[i]; printf(RED"%02x "NORMAL, code[i]);} +        printf("\n"); +        printf(RED"%jx\n", address); +        printf(RED"%d\n", insn[j].size); +#endif +        JMP_S_T* dummy = malloc(sizeof(JMP_S_T)); +        dummy->location = insn[j].address; +        dummy->type = JE; +        dummy->address_y = address; +        dummy->size = insn[j].size; +        dummy->next = NULL; +        tail->next = dummy; +        tail = dummy; +      } + +      if (strcmp(insn[j].mnemonic, "jne") == 0) { +        char* endptr; +        address = strtoimax(insn[j].op_str, &endptr, 0); +#if 1 +        printf(RED"found a jne\n"); +        for (int i = 0; i < 16; ++i) {code[i] = insn[j].bytes[i]; printf(RED"%02x "NORMAL, code[i]);} +        printf("\n"); +        printf(RED"%lx\n", address); +        printf(RED"%d\n", insn[j].size); +#endif +        JMP_S_T* dummy = malloc(sizeof(JMP_S_T)); +        dummy->location = insn[j].address; +        dummy->type = JNE; +        dummy->address_y = address; +        dummy->size = insn[j].size; +        dummy->next = NULL; +        tail->next = dummy; +        tail = dummy; +      } + +#if 0 +      for (int i = 0; i < insn[j].size; ++i) { +        asm_code[size_counter] = insn[j].bytes[i]; +        size_counter++; +      } +#endif +    } + +    cs_free(insn, count); +  } else { +    printf("ERROR!!!\n"); +  } +  cs_close(&handle); +  return head; +} +/**********************************************************************************************************************/ +int freejmptable(JMP_S_T* _head) { +  JMP_S_T* previous = _head; +  JMP_S_T* current = _head; +  while (current != NULL) { +    previous = current; +    current = current->next; +    free(previous); +  } +  return 0; +} +/**********************************************************************************************************************/ +int dumpjmptable(JMP_S_T* current) { +  while (current != NULL) { +    printf("jump location: %lx", current->location); +    printf("\tjump address: %lu", current->address); +    printf("\tjump type: %d", current->type); +    printf("\tinstruction size: %d\n", current->size); +    current = current->next; +  } +} +/**********************************************************************************************************************/ +void jmprewriter_j(JMP_S_T* jmp, uint8_t* code, JMP_T type, uint8_t* rewritten) { +   +} +void jmprewriter_jne(JMP_S_T* jmp, uint8_t* code, JMP_T type, uint8_t* rewritten) {}; +void jmprewriter_je(JMP_S_T* jmp, uint8_t* code, JMP_T type, uint8_t* rewritten) {} +/**********************************************************************************************************************/ +/**********************************************************************************************************************/  // @DEVI-the following lines are only meant for testing.  #pragma weak main  int main(int argc, char** argv) { @@ -223,6 +375,7 @@ int main(int argc, char** argv) {    printf("end: %10p\n", &end);    printf("text section length: %d\n", get_textsection_length()); +#if 1    printf("----------------------------------------------------------\n");    uint8_t value[4];    int2byte(-528, value, 4); @@ -235,11 +388,34 @@ int main(int argc, char** argv) {    for (int i = 0; i < 4; ++i) {printf("%02x ", value[i]);}    printf("\n");    printf("----------------------------------------------------------\n"); +#endif    unsigned char* encode;    ks_write(KS_ARCH_X86, KS_MODE_64, "add rax, rcx", 0, encode);    ks_free(encode); +#if 0 +  head = malloc(sizeof(JMP_S_T)); +  tail = malloc(sizeof(JMP_S_T)); +  head->type = NONE; +  head->next = NULL; +  tail = head; +#endif +  uint8_t asm_code3[834]; +  JMP_S_T* current = makejmptable(834, CODE_3); + +#if 0 +  while (current != NULL) { +    printf("jump location: %lx", current->location); +    printf("\tjump address: %lu", current->address); +    printf("\tjump type: %d", current->type); +    printf("\tinstruction size: %d\n", current->size); +    current = current->next; +  } +#endif +  dumpjmptable(current); +  freejmptable(current); +    return 0;  }  /**********************************************************************************************************************/ diff --git a/bruiser/bruisercapstone.h b/bruiser/bruisercapstone.h index 054eb19..d10db70 100644 --- a/bruiser/bruisercapstone.h +++ b/bruiser/bruisercapstone.h @@ -21,6 +21,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.*  #include <capstone/capstone.h>  #include <keystone/keystone.h>  #include <stdint.h> +#include <inttypes.h>  /**********************************************************************************************************************/  #ifndef BRUISER_CAPSTONE_H  #define BRUISER_CAPSTONE_H @@ -29,6 +30,30 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.*  extern "C" {  #endif +enum jmp_type {NONE=0, JMP=1, JNE=2, JE=3}; +#define JMP_T enum jmp_type + +struct jmp_s_t { +  JMP_T type; +  uint64_t location; +  uint8_t size; +  struct jmp_s_t* next; +  struct jmp_s_t* next_y; +  struct jmp_s_t* next_n; +  uint64_t address; +  uint64_t address_y; +  uint64_t address_n; +  bool y; +  bool n; +  bool z; +}; +#define JMP_S_T struct jmp_s_t +JMP_S_T* iter_next(JMP_S_T* arg); +JMP_S_T* iter_next_y(JMP_S_T* arg); +JMP_S_T* iter_next_n(JMP_S_T* arg); +extern JMP_S_T* head; +extern JMP_S_T* tail; +  uint32_t get_textsection_length(void);  uintptr_t get_symbol_rt_address(const char* symbol_name);  void int2byte(int value, uint8_t* ret_value, size_t size); @@ -39,6 +64,12 @@ void leb128_decode_u(uint32_t value, uint8_t* ret_value, size_t size);  int ks_write(ks_arch arch, int mode, const char* assembly, int syntax, unsigned char* encode);  int global_rewriter(int offset, size_t size, uint8_t* asm_code, const char* obj);  int call_rewriter(int offset, size_t size, uint8_t* asm_code, const char* obj); +JMP_S_T* makejmptable(size_t size, uint8_t* obj); +int freejmptable(JMP_S_T* _head); +int dumpjmptable(JMP_S_T* head); +void jmprewriter_j(JMP_S_T* jmp, uint8_t* code, JMP_T type, uint8_t* rewritten); +void jmprewriter_jne(JMP_S_T* jmp, uint8_t* code, JMP_T type, uint8_t* rewritten); +void jmprewriter_je(JMP_S_T* jmp, uint8_t* code, JMP_T type, uint8_t* rewritten);  #ifdef __cplusplus  } diff --git a/bruiser/bruiserffi.c b/bruiser/bruiserffi.c index fee9dfe..24ebe0d 100644 --- a/bruiser/bruiserffi.c +++ b/bruiser/bruiserffi.c @@ -32,8 +32,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.*  /**********************************************************************************************************************/  #define VOIDIFY(X) (void*)X  /**********************************************************************************************************************/ -#pragma GCC diagnostic ignored "-Wpointer-to-int-cast"  #pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpointer-to-int-cast"  #define REINTERPRET_GENERATOR(X) \    X ffi_reinterpret_##X(void* result) {return (X)result;} @@ -53,6 +53,7 @@ X_LIST_GEN  #undef X  #undef X_LIST_GEN  #undef REINTERPRET_GENERATOR +#pragma GCC diagnostic pop  float ffi_reinterpret_float(void* result) {return *(float*)&result;}  double ffi_reinterpret_double(void* result) {return *(double*)&result;}  char* ffi_reinterpret_string(void* result) {return (char*)result;} diff --git a/bruiser/lua-scripts/demo2.lua b/bruiser/lua-scripts/demo2.lua index 3b6007a..c8de8aa 100644 --- a/bruiser/lua-scripts/demo2.lua +++ b/bruiser/lua-scripts/demo2.lua @@ -25,11 +25,37 @@ function main()    xobjregister(passthrough_code, "passthrough")  end +function pretty_dump() +  count = 0 +  local text_section = xobj.getTextSection() +  io.write(colors("%{blue}".."    ".."\t".."00 ".."01 ".."02 ".."03 ".."04 ".."05 ".."06 ".."07 ".."08 ".."09 ".."0A ".."0B ".."0C ".."0D ".."0E ".."0F")) +  for k,v in pairs(text_section) do +    if count % 16 == 0 then +      print() +      io.write(colors("%{blue}".."0x"..string.format("%03x",count)), "\t") +    end +    io.write(colors("%{green}"..string.format("%02x", v)), " ") +    count = count + 1 +  end +  count = 0 +  print() +end + +function test() +  local text_section = xobj.getTextSection() +  dummy = xobj.CSDump(text_section) +  print(dummy) +end +  function asm_rewriter()    local text_section = xobj.getTextSection() -  for k,v in pairs(text_section) do io.write(colors("%{blue}"..string.format("%02x",k)),":",colors("%{green}"..string.format("%02x",v)),"\t") end -  io.write("\n") +  local head = getjmptable(#text_section, text_section) +  print("head value is",head) +  dumpjmptable(head) +  freejmptable(haed)  end  --main() +--pretty_dump() +--test()  asm_rewriter() diff --git a/bruiser/lua-scripts/xobj.lua b/bruiser/lua-scripts/xobj.lua index 880730a..81d0bc0 100644 --- a/bruiser/lua-scripts/xobj.lua +++ b/bruiser/lua-scripts/xobj.lua @@ -133,6 +133,14 @@ function xobj.getTextSection()    return objload("elf_get_text_section", elf_exe, "bytes")  end +function xobj.CSDump(code) +  ret = "" +  for k,v in pairs(code) do +    ret = ret.."\\x"..string.format("%02x",v) +  end +  return ret +end +  --end of xobj module  return xobj  -------------------------------------------------------------------------------------------------------------- diff --git a/bruiser/makefile b/bruiser/makefile index d306a4b..a50faf4 100644 --- a/bruiser/makefile +++ b/bruiser/makefile @@ -13,7 +13,7 @@ SRCS=$(wildcard *.cpp)  C_SRCS=$(wildcard *.c)  #for some reason without ld the build fails on ubuntu trusty on travis  #EXTRA_LD_FLAGS+=-lpthread -ldl -lutil -lm -Xlinker -lpython3 -EXTRA_LD_FLAGS+=$(shell $(PY_CONF) --ldflags) -lffi #-lcapstone +EXTRA_LD_FLAGS+=$(shell $(PY_CONF) --ldflags) -lffi -lcapstone -lkeystone  ######################################RULES####################################  .DEFAULT: all @@ -50,7 +50,7 @@ $(LIB_LUA_JIT):  	$(MAKE) -C LuaJIT  	@echo "building with jit" -$(BRUISER): $(BRUISER).o ../mutator_aux.o ../tinyxml2/tinyxml2.o linenoise.o CompletionHints.o mutagen.o ORCmutation.o bruiserffi.o $(LIB_LUA) +$(BRUISER): $(BRUISER).o ../mutator_aux.o ../tinyxml2/tinyxml2.o linenoise.o CompletionHints.o mutagen.o ORCmutation.o bruiserffi.o bruisercapstone.o $(LIB_LUA)  	$(CXX) $^ $(LD_FLAGS) -o $@  clean: | 
