Dump Lua

为了获取程序中的lua代码,我们往往选择Hook dofile函数进行dump
然而很多有一定保护的程序里面lua没有dostring,dofile这样的函数,甚至也没有luaL_loadbuffer,
而且这些函数也不太好定位。
这里有一款方便定位的函数,也可以方便的dump代码: luaD_protectedparser

lua(源码/字节码)的解析过程会经过函数luaD_protectedparser

int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
                                        const char *mode) {
  struct SParser p;
  int status;
  incnny(L);  /* cannot yield during parsing */
  p.z = z; p.name = name; p.mode = mode;
  p.dyd.actvar.arr = NULL; p.dyd.actvar.size = 0;
  p.dyd.gt.arr = NULL; p.dyd.gt.size = 0;
  p.dyd.label.arr = NULL; p.dyd.label.size = 0;
  luaZ_initbuffer(L, &p.buff);
  status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc);
  luaZ_freebuffer(L, &p.buff);
  luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size);
  luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size);
  luaM_freearray(L, p.dyd.label.arr, p.dyd.label.size);
  decnny(L);
  return status;
}

函数如上所示,Hook此函数,可以从其参数ZIO* z中取得lua代码,从char *name中取得代码名。

struct Zio {
  size_t n;            /* bytes still unread */
  const char *p;        /* current position in buffer */
  lua_Reader reader;        /* reader function */
  void *data;            /* additional data */
  lua_State *L;            /* Lua state (for reader) */
};

Zio结构中void* data为

typedef struct LoadS {
  const char *s;
  size_t size;
} LoadS;

((LoadS*)z->data)->s) 就为我们想要的lua代码

这个函数可以通过f_parser函数定位,这个函数往往内联了checkmode函数

static void checkmode (lua_State *L, const char *mode, const char *x) {
  if (mode && strchr(mode, x[0]) == NULL) {
    luaO_pushfstring(L,
       "attempt to load a %s chunk (mode is '%s')", x, mode);
    luaD_throw(L, LUA_ERRSYNTAX);
  }
}


static void f_parser (lua_State *L, void *ud) {
  LClosure *cl;
  struct SParser *p = cast(struct SParser *, ud);
  int c = zgetc(p->z);  /* read first character */
  if (c == LUA_SIGNATURE[0]) {
    checkmode(L, p->mode, "binary");
    cl = luaU_undump(L, p->z, p->name);
  }
  else {
    checkmode(L, p->mode, "text");
    cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c);
  }
  lua_assert(cl->nupvalues == cl->p->sizeupvalues);
  luaF_initupvals(L, cl);
}

搜索字符串attempt to load a即可定位到f_parser或checkmode函数,再向上寻找一层交叉引用即是luaD_protectedparser


如果是Unity的il2cpp模式,甚至是引用了其他开源库封装lua,只要在外部dll中寻找对应的函数就可以了,它们一般都会有一堆带符号的导出函数。

发表评论

电子邮件地址不会被公开。

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据