博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
lua 代码加密方案
阅读量:5761 次
发布时间:2019-06-18

本文共 3764 字,大约阅读时间需要 12 分钟。

require 实现

  • require函数在实现上是依次调用package.searchers(lua51中是package.loaders)中的载入函数,成功后返回。在loadlib.c文件里有四个载入函数的实现,分别为searcher_preload, searcher_Lua, searcher_C, searcher_Croot。
  • searcher_preload是从读取LUA_REGISTRYINDEX的_PRELOAD字段。已经require过的文件会写入到该表中
  • searcher_Lua是依据文件名称查找package.path中的全部路径的lua文件。存在文件则返回
  • searcher_C是搜索package.cpath中的全部路径下的库文件
  • searcher_Croot是对require(“a.b.c”)的情况,读取a库。然后查找函数名为lua_a_b_c的lua_CFunction函数
static void findloader (lua_State *L, const char *name) {  int i;  luaL_Buffer msg;  /* to build error message */  luaL_buffinit(L, &msg);  lua_getfield(L, lua_upvalueindex(1), "searchers");  /* will be at index 3 */  if (!lua_istable(L, 3))    luaL_error(L, LUA_QL("package.searchers") " must be a table");  /*  iterate over available searchers to find a loader */  for (i = 1; ; i++) {    lua_rawgeti(L, 3, i);  /* get a searcher */    if (lua_isnil(L, -1)) {  /* no more searchers? */      lua_pop(L, 1);  /* remove nil */      luaL_pushresult(&msg);  /* create error message */      luaL_error(L, "module " LUA_QS " not found:%s",                    name, lua_tostring(L, -1));    }    lua_pushstring(L, name);    lua_call(L, 1, 2);  /* call it */    if (lua_isfunction(L, -2))  /* did it find a loader? */      return;  /* module loader found */    else if (lua_isstring(L, -2)) {  /* searcher returned error message? */      lua_pop(L, 1);  /* remove extra return */      luaL_addvalue(&msg);  /* concatenate error message */    }    else      lua_pop(L, 2);  /* remove both returns */  }}
  • 如今要实如今require时能读取加密文件,有两种办法,一种是直接改动源码。即改动第二个载入函数,又一次实现当中读取文件内容的函数,另外一种办法是在lua中改动package.searchers表。在载入器的第一和另外一种之间加入一个载入器函数,该载入器模拟searcher_Lua函数。搜索path路径,然后逐个匹配文件。然后读取文件内容,解密。然后调用load载入并返回(c中为luaL_loadbufferx),这里在载入时最好传入文件名称作为来源參数。方便在调试信息中定位.
  • 加密方案可使用相似xxtea轻量级的加密算法
  • 在对lua文件进行加密打包时。能够在文件头写入指定的签名内容。以方便在解密前预先推断是否为有效的加密文件

改动lua源码方案

  • 在searcher_Lua中终于是调用lua_load(L, getF, &lf, lua_tostring(L, -1), mode)载入源文件,该函数的第二个參数getF是一个lua_Reader函数,所以这里能够重写该函数以实现解密,也能够向外部暴露一个接口用来将自己定义的文件读取函数作为參数传给lua_load。以下是原版的getF实现
static const char *getF (lua_State *L, void *ud, size_t *size) {  LoadF *lf = (LoadF *)ud;  (void)L;  /* not used */  if (lf->n > 0) {  /* are there pre-read characters to be read? */    *size = lf->n;  /* return them (chars already in buffer) */    lf->n = 0;  /* no more pre-read characters */  }  else {  /* read a block from file */    /* 'fread' can return > 0 *and* set the EOF flag. If next call to       'getF' called 'fread', it might still wait for user input.       The next check avoids this problem. */    if (feof(lf->f)) return NULL;    *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f);  /* read block */  }  return lf->buff;}

外部改动载入器方案

  • 直接改动package.searchers表,向当中加入载入器,c版实现例如以下
void addLuaSearcher(lua_CFunction func){    if (!func) return;    // stack content after the invoking of the function    // get loader table    lua_getglobal(m_state, "package");          /* L: package */    lua_getfield(m_state, -1, "loaders");       /* L: package, loaders */    // insert loader into index 2    lua_pushcfunction(m_state, func);           /* L: package, loaders, func */    for (int i = lua_objlen(m_state, -2) + 1; i > 2; --i)    {        lua_rawgeti(m_state, -2, i - 1);        /* L: package, loaders, func, function */        // we call lua_rawgeti, so the loader table now is at -3        lua_rawseti(m_state, -3, i);            /* L: package, loaders, func */    }    lua_rawseti(m_state, -2, 2);                /* L: package, loaders */    // set loaders into package    lua_setfield(m_state, -2, "loaders");       /* L: package */    lua_pop(m_state, 1);}
  • 载入器函数实现依据传入的文件名称。逐个匹配的package.path中的内容,存在文件后,然后读取文件内容,解密,最后再将解出的内容调用load载入并返回(c中为luaL_loadbufferx),实现能够參照lua源码中的searcher_Lua实现

转载于:https://www.cnblogs.com/gavanwanggw/p/7344769.html

你可能感兴趣的文章
[CareerCup] 1.6 Rotate Image 翻转图像
查看>>
Python中的画图初体验
查看>>
Java程序员的日常 —— 响应式导航Demo
查看>>
objective-c内存管理基础
查看>>
sap关于价值串的说法(转载)
查看>>
Migration to S/4HANA
查看>>
sed 对目录进行操作
查看>>
什么是代码
查看>>
移动端开发单位——rem,动态使用
查看>>
系列文章目录
查看>>
手把手教你如何提高神经网络的性能
查看>>
前端布局原理涉及到的相关概念总结
查看>>
递归调用 VS 循环调用
查看>>
使用sstream读取字符串中的数字(c++)
查看>>
树莓派下实现ngrok自启动
查看>>
javascript静态类型检测工具—Flow
查看>>
MachineLearning-Sklearn——环境搭建
查看>>
node学习之路(二)—— Node.js 连接 MongoDB
查看>>
Goroutine是如何工作的?
查看>>
《深入理解java虚拟机》学习笔记系列——垃圾收集器&内存分配策略
查看>>