精华内容
下载资源
问答
  • luac反编译工具

    2018-03-30 21:19:05
    luac反编译工具!luac反编译工具!luac反编译工具!luac反编译工具!luac反编译工具!
  • LUAC反编译

    热门讨论 2016-01-26 21:26:51
    在测试过程中,发现海岛大亨解包出来的某些lua文件在反编译过程中会比较慢(cmd下执行unluac同样的情况) 导致程序看起来似乎假死,但是实际还在运行中,请耐心等待其执行完成。 CMD反编译命令: java -jar unluac...
  • luac 反编译

    千次阅读 2017-12-17 21:06:19
    首先下载unluac.jar, 然后运行命令. java -jar unluac.jar testin.luac>testout.luac 然后就好了, 厉害吧,  ...印象中是.lua 都是源码, 根本 不需要反编译啊, 只有luac 是经过一次 编译后的, 已经看不懂了, 需要修改

    首先下载unluac.jar, 然后运行命令. java -jar unluac.jar testin.luac>testout.luac  然后就好了, 厉害吧, 


    印象中是.lua 都是源码, 根本 不需要反编译啊, 只有luac 是经过一次 编译后的, 已经看不懂了, 需要修改

    展开全文
  • LUAC反编译.rar

    2020-03-18 12:50:26
    真正可用的,LUAC反编译工具 1.首先安装jdk,不会的请百度“jdk安装与环境变量配置”,安装好软件就可以为所欲为了 2.将源文件(要解密的文件)的文件后缀命名为.luac,然后选择源文件,选择解密后文件的目标目录 ...
  • LUAC反编译程序.zip

    2020-07-08 14:03:08
    运行环境:GUI界面:.net framework 2.0 unluac :java环境,反编译过程中,会在程序目录生成执行文件,反编译结束后会自动删除。
  • 资源包含lua5.1、lua5.2、lua5.3编译工具和反编译工具,chunkspy5.1、chunkspy5.2反汇编工具,以及unluac.jar反编译luac工具。
  • 两种.luac反编译过程

    万次阅读 2018-11-30 11:49:09
    Luac反编译 ​ 针对Cocos2dx-lua提供的轻量级加密方案的反编译。该博客参考自原文章 一般使用该轻量级加密方案的命令如下: cocos luacompile -s 未加密源码目录 -d 加密后源码目录 -e -k 加密key -b 加密sign...

    解密Cocos2dx-lua XXTEA加密后.luac文件

    ​ 针对Cocos2dx-lua提供的轻量级加密方案的反编译。该博客参考自原文章

    加密命令以及参数

    一般使用该轻量级加密方案的命令如下:

    cocos luacompile -s 未加密源码目录 -d 加密后源码目录 -e -k 加密key -b 加密sign --disable-compile

    要解密,那么需要知道的是加密key加密sign

    一、加密解密思路

    ​ 我们将后缀为.lua的文件加密成.luac文件,然后放入apk中,那么在程序运行时,势必需要对.luac的文件进行解密,然后再加载运行文件。那程序是如何知道我们在加密key呢?有两个猜想:

    ​ 1,加密key写入文件,程序在解密时先读取文件中的加密key,再解密。

    ​ 2,加密key与程序内部约定某个值。

    显然,第一种做法很不明智,key值直接存入文件很容易破解,那么就验证第二种做法,既然加密key是约定的,那么肯定可以在程序中找到该值。通过搜索发现验证了该想法。

    在工程的frameworks\runtime-src\Classes\AppDelegate.cpp文件applicationDifFinishLauching方法中
    AppDelegate.cpp

    能够看到设置了加密key和sign

    二、反编译luac

    ​ 要反编译.luac文件,需要知道加密key和sign。上面提供了一个思路,sign在.luac中寻找,key在打包后的libcocos2dlua.so中寻找。

    1,寻找加密sign

    ​ 用记事本打开某个.luc文件,文件开头的前几个字符即加密sign
    记事本打开.luac文件

    2、寻找加密key

    ​ 下载IDA(交互式反汇编器),将libcocos2dlua.so拖到该IDA快捷图标上,此时会弹出
    so打开选择框

    选择 OK,等待加载function name,避免操作应用是卡住。等会后选择view/open subviews/strings
    strings窗口

    Ctrl + F 搜索 刚刚获取的sign(XXTEA),得到如下结果
    搜索sign

    点击该结果,在该结果的附近则能够发现加密key(2dxLua)
    加密key

    3、加密key,加密sign已经获取,如何反编译

    cocos使用的XXTEA进行加密,其在external目录下,在xxtea.h可以看到,提供了加密解密方法

    #ifndef XXTEA_H
    #define XXTEA_H
    
    #include <stddef.h> /* for size_t & NULL declarations */
    
    #if defined(_MSC_VER)
    
    typedef unsigned __int32 xxtea_long;
    
    #else
    
    #if defined(__FreeBSD__) && __FreeBSD__ < 5
    /* FreeBSD 4 doesn't have stdint.h file */
    #include <inttypes.h>
    #else
    #include <stdint.h>
    #endif
    
    typedef uint32_t xxtea_long;
    
    #endif /* end of if defined(_MSC_VER) */
    
    #define XXTEA_MX (z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z)
    #define XXTEA_DELTA 0x9e3779b9
    
    unsigned char *xxtea_encrypt(unsigned char *data, xxtea_long data_len, unsigned char *key, xxtea_long key_len, xxtea_long *ret_length);
    unsigned char *xxtea_decrypt(unsigned char *data, xxtea_long data_len, unsigned char *key, xxtea_long key_len, xxtea_long *ret_length);
    
    #endif
    

    4、运行cpp文件,调用解密方法,解密.luac文件

    win上运行cpp文件,可以按照MinGW MinGW,选择mingw-get-setup.exe。选中里面的mingw32-gcc-g+±bin进行安装。安装完成后配置下环境变量,安装目录下的bin,例如D:\MinGW\bin

    在cocos引擎external目录下复制一份xxtea.cpp和xxtea.h,修改xxtea.cpp的后缀名为xxtea.c,不知为啥,用.cpp后缀就是生成不了exe文件。然后编写一个入口文件,main.c

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include"xxtea.h"
    int main(int argc,char*argv[]){
    	FILE*fp;
    	char*key;
    	char*sign;
    	char*infile;
    	char*outfile;
    	char*buf,*data;
    	unsigned long size;
    	int keylen,signlen,retlen;
    	if(argc<5){
    		printf("usage:lua_decrypt infile outfile sign key\n");
    		return -1;
    	}
    	else{
    		infile=argv[1];
    		outfile=argv[2];
    		sign=argv[3];
    		key=argv[4];
    		keylen=strlen(key);
    		signlen=strlen(sign);
    	}
    
    	if((fp=fopen(infile,"rb"))==NULL){
    			perror("can't open the input file");
    			return -1;
    	}
    	fseek(fp, 0L, SEEK_END);
    	size=ftell(fp);
    	rewind(fp);
    	buf=(char*)malloc(size);
    	fread(buf,size,1,fp);
    	fclose(fp);
    	data=xxtea_decrypt(buf+signlen,size-signlen,key,keylen,&retlen);
    	if(data==NULL){
    		printf("%s decrypt fail\n",infile);
    		return -1;
    	}
    	if((fp=fopen(outfile,"wb+"))==NULL){
    		    perror("can't open the output file");
    			return -1;
    	}
    	fwrite(data,retlen,1,fp);
    	fclose(fp);
    	free(data);
    	printf("%s decrypt successful\n",infile);
    	return 0;
    
    }
    
    
    

    将这三个xxtea.c xxtea.h main.c这三个文件放在同一个目录下,进入cmd,进入该目录下,键入

    gcc xxteac main.c -o luac_decrypt生成luac_decrypt.exe,然后将要解密的.luac文件放在该目录下,键入

    luac_decrypt xx.luac xx.lua sign key即可反编译.luac文件。

    例如放置了version.luac文件在该目录,sign是XXTEA,key是2dxLua,即命令如下:

    luac_decrypt version.luac version.lua XXTEA 2dxLua即可以反编译后输出文件version.lua

    三、扩展,批处理

    ​ 每次都是命令行反编译一个文件,显示效率低效。可以编写批处理,设置luac文件夹,输出文件夹,反编译exe路径,sign,key,然后循环反编译luac文件夹下所有的.luac文件

    rem "decompile Luac script"
    echo off
    rem set your luac direction
    set sourcePath=C:\Users\86181\Desktop\luac
    rem set your luac_decrypt.exe path
    set decryptPath=C:\Users\86181\Desktop\luac_decrypt.exe
    rem outfile direction
    set outfilePath=C:\Users\86181\Desktop\lua\
    set suffix=.lua
    set sign=XXTEA
    set key=2dxLua
    
    md %outfilePath%
    
    for /r %sourcePath% %%i in (*.luac) do ( 
    	%decryptPath% %%i %outfilePath%%%~ni%suffix% %sign% %key%
    )
    
    pause
    
    

    反编译Luac加密的.luac文件

    一、.lua文件编译为字节码文件.luac

    ​ lua中自带将.lua文件编译为字节码文件,命令行luac -o 输出文件 源文件

    在桌面新建文件夹aaa,放入源文件helper.lua命令行中执行

    luac -o helper_luac.luac helper.lua会在aaa文件夹下生成helper_luac.luac文件,用记事本打开该文件。
    记事本打开helper_luac.luac

    二、.luac文件反编译为.lua文件

    ​ 下载unluac.jar包,官网地址

    将下载后的包重命名为unluac.jar,并拖动到aaa文件夹下,执行命令java -jar unluac.jar helper_luac.luac>helper_decrypt.lua(需要支持java命令),这时会在aaa文件夹下生成helper_decrpyt.lua,将原本的helper.lua与反编译后的helper_decrpyt.lua进行对比,发现除了某些格式,代码基本一致,反编译成功。
    编译前后对比

    展开全文
  • luac 格式分析与反编译

    万次阅读 2018-10-09 10:31:00
    前言 测试某游戏时,游戏加载的是luac脚本: 文件格式 - 010editor官方bt只能识别luac52版本 ...文章目录前言luac51格式分析Luac文件格式文件头格式函数体luac.exe存储luac过程分析luac反编译获取lua51 vmlu...

    前言

    测试某游戏时,游戏加载的是luac脚本:

    • 文件格式 - 010editor官方bt只能识别luac52版本
    • opcode对照表 - 这个游戏luac的opcode对照表也被重新排序,unluac需要找到lua vm的opcode对照表,才能反编译。

    luac51格式分析

    Luac文件格式

    一个Luac文件包含两部分:文件头与函数体。

    文件头格式

    typedef struct {
        char signature[4];   //".lua"
        uchar version;
        uchar format;
        uchar endian;
        uchar size_int;
        uchar size_size_t;
        uchar size_Instruction;
        uchar size_lua_Number;
        uchar lua_num_valid;
        uchar luac_tail[0x6];
    } GlobalHeader;
    

    第一个字段**signature**在lua.h头文件中有定义,它是LUA_SIGNATURE,取值为“\033Lua",其中,\033表示按键。LUA_SIGNATURE作为Luac文件开头的4字节,它是Luac的Magic Number,用来标识它为Luac字节码文件。Magic Number在各种二进制文件格式中比较常见,通过是特定文件的前几个字节,用来表示一种特定的文件格式。

    version 字段表示Luac文件的格式版本,它的值对应于Lua编译的版本,对于5.2版本的Lua生成的Luac文件,它的值为0x52。

    **format**字段是文件的格式标识,取值0代表official,表示它是官方定义的文件格式。这个字段的值不为0,表示这是一份经过修改的Luac文件格式,可能无法被官方的Lua虚拟机正常加载。

    **endian**表示Luac使用的字节序。现在主流的计算机的字节序主要有小端序LittleEndian与大端序BigEndian。这个字段的取值为1的话表示为LittleEndian,为0则表示使用BigEndian。

    **size_int**字段表示int类型所占的字节大小。size_size_t字段表示size_t类型所占的字节大小。这两个字段的存在,是为了兼容各种PC机与移动设备的处理器,以及它们的32位与64位版本,因为在特定的处理器上,这两个数据类型所占的字节大小是不同的。

    **size_Instruction**字段表示Luac字节码的代码块中,一条指令的大小。目前,指令Instruction所占用的大小为固定的4字节,也就表示Luac使用等长的指令格式,这显然为存储与反编译Luac指令带来了便利。

    **size_lua_Number**字段标识lua_Number类型的数据大小。lua_Number表示Lua中的Number类型,它可以存放整型与浮点型。在Lua代码中,它使用LUA_NUMBER表示,它的大小取值大小取决于Lua中使用的浮点数据类型与大小,对于单精度浮点来说,LUA_NUMBER被定义为float,即32位大小,对于双精度浮点来说,它被定义为double,表示64位长度。目前,在macOS系统上编译的Lua,它的大小为64位长度。

    **lua_num_valid**字段通常为0,用来确定lua_Number类型能否正常的工作。

    **luac_tail**字段用来捕捉转换错误的数据。在Lua中它使用LUAC_TAIL表示,这是一段固定的字符串内容:"\x19\x93\r\n\x1a\n"。

    在文件头后面,紧接着的是函数体部分。一个Luac文件中,位于最上面的是一个顶层的函数体,函数体中可以包含多个子函数,子函数可以是嵌套函数、也可以是闭包,它们由常量、代码指令、Upvalue、行号、局部变量等信息组成。

    函数体

    typedef struct {
        //header
        ProtoHeader header;
    
        //code
        Code code;
    
        // constants
        Constants constants;
    
        // functions
        Protos protos;
    
        // upvalues
      //Upvaldescs upvaldescs;
    
        // string
        //SourceName src_name;
    
        // lines
        Lines lines;
        
        // locals
        LocVars loc_vars;
        
        // upvalue names
        UpValueNames names;
    } Proto;
    

    **ProtoHeader**是Proto的头部分。它的定义如下:

    typedef struct {
        uint32 linedefined;
        uint32 lastlinedefined;
        uchar numparams;
        uchar is_vararg;
        uchar maxstacksize;
    } ProtoHeader;
    

    **code**lua vm操作码
    constants lua语句其实只是将标志符合关键字给去掉了

    printf("Hello %s from %s on %s\n",os.getenv"USER" or "there",_VERSION,os.date())
    

    这是一条lua语句,那么在luac文件中可见,可以推测出大概的lua语句

    ���printf����Hello %s from %s on %s
    ����os����getenv����USER����there�  ���_VERSION����date
    

    **protos**下一个函数体,函数体是链式存储的
    **lines**该函数存在多少行lua语句
    **loc_vars**函数内部局部变量个数
    **names**函数内部局部变量名

    luac.exe存储luac过程分析

    luac的函数体在luac.exe中分main函数和一般函数,存储过程如下:
    1、存储main函数头、代码、lua语句字符串进行存储
    2、存储普通函数
    2.1、存储普通函数体
    2.2、遍历普通函数链表,直至结束
    3、存储main函数行数、参数、参数名

    #### 具体过程
    分析luac.exe存储过程,很容易分析出luac的文件格式。
    ```cpp
    int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip)
    {
     DumpState D;
     D.L=L;
     D.writer=w;
     D.data=data;
     D.strip=strip;
     D.status=0;
     DumpHeader(&D);
     DumpFunction(f,NULL,&D);
     return D.status;
    }
    
    

    lua源码luac.c中,DumpHeader 存储了luac头格式,而在**DumpFunction**则对函数体进行了存储。

    static void DumpHeader(DumpState* D)
    {
     char h[LUAC_HEADERSIZE];
     luaU_header(h);
     DumpBlock(h,LUAC_HEADERSIZE,D);
    }
    

    **DumpHeader**存储了LUAC_HEADERSIZE(12)byte的头格式。

    static void DumpConstants(const Proto* f, DumpState* D)
    {
     int i,n=f->sizek;
     DumpInt(n,D);
     for (i=0; i<n; i++)
     {
      const TValue* o=&f->k[i];
      DumpChar(ttype(o),D);
      switch (ttype(o))
      {
       case LUA_TNIL:
      break;
       case LUA_TBOOLEAN:
      DumpChar(bvalue(o),D);
      break;
       case LUA_TNUMBER:
      DumpNumber(nvalue(o),D);
      break;
       case LUA_TSTRING:
      DumpString(rawtsvalue(o),D);
      break;
       default:
      lua_assert(0);      /* cannot happen */
      break;
      }
     }
     n=f->sizep;
     DumpInt(n,D);
     for (i=0; i<n; i++) DumpFunction(f->p[i],f->source,D);
    }
    
    static void DumpDebug(const Proto* f, DumpState* D)
    {
     int i,n;
     n= (D->strip) ? 0 : f->sizelineinfo;
     DumpVector(f->lineinfo,n,sizeof(int),D);
     n= (D->strip) ? 0 : f->sizelocvars;
     DumpInt(n,D);
     for (i=0; i<n; i++)
     {
      DumpString(f->locvars[i].varname,D);
      DumpInt(f->locvars[i].startpc,D);
      DumpInt(f->locvars[i].endpc,D);
     }
     n= (D->strip) ? 0 : f->sizeupvalues;
     DumpInt(n,D);
     for (i=0; i<n; i++) DumpString(f->upvalues[i],D);
    }
    
    static void DumpFunction(const Proto* f, const TString* p, DumpState* D)
    {
     DumpString((f->source==p || D->strip) ? NULL : f->source,D);
     DumpInt(f->linedefined,D);
     DumpInt(f->lastlinedefined,D);
     DumpChar(f->nups,D);
     DumpChar(f->numparams,D);
     DumpChar(f->is_vararg,D);
     DumpChar(f->maxstacksize,D);
     DumpCode(f,D);
     DumpConstants(f,D);
     DumpDebug(f,D);
    }
    

    递归遍历存储函数体过程。


    luac反编译

    获取lua51 vm

      $ git clone https://github.com/mkottman/AndroLua
      $ ndk-build
    

    lua_execute函数

    在lua vm中luac解释执行luac opcode的函数是luaV_execute,但是有些so会将lua_execute函数名隐藏,以下是通过lua_resume找到execute函数。

      LUA_API int lua_resume (lua_State *L, int nargs) {
        int status;
        lua_lock(L);
        if (L->status != LUA_YIELD && (L->status != 0 || L->ci != L->base_ci))
            return resume_error(L, "cannot resume non-suspended coroutine");
        if (L->nCcalls >= LUAI_MAXCCALLS)
          return resume_error(L, "C stack overflow");
        luai_userstateresume(L, nargs);
        lua_assert(L->errfunc == 0);
        L->baseCcalls = ++L->nCcalls;
        status = luaD_rawrunprotected(L, resume, L->top - nargs);
        if (status != 0) {  /* error? */
          L->status = cast_byte(status);  /* mark thread as `dead' */
          luaD_seterrorobj(L, status, L->top);
          L->ci->top = L->top;
        }
        else {
          lua_assert(L->nCcalls == L->baseCcalls);
          status = L->status;
        }
        --L->nCcalls;
        lua_unlock(L);
        return status;
      }
    

    lua_resume中调用luaD_rawrunprotected函数,将resum函数指针作为参数传入

      static void resume (lua_State *L, void *ud) {
        StkId firstArg = cast(StkId, ud);
        CallInfo *ci = L->ci;
        if (L->status == 0) {  /* start coroutine? */
          lua_assert(ci == L->base_ci && firstArg > L->base);
          if (luaD_precall(L, firstArg - 1, LUA_MULTRET) != PCRLUA)
            return;
        }
        else {  /* resuming from previous yield */
          lua_assert(L->status == LUA_YIELD);
          L->status = 0;
          if (!f_isLua(ci)) {  /* `common' yield? */
            /* finish interrupted execution of `OP_CALL' */
            lua_assert(GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_CALL ||
                       GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_TAILCALL);
            if (luaD_poscall(L, firstArg))  /* complete it... */
              L->top = L->ci->top;  /* and correct top if not multiple results */
          }
          else  /* yielded inside a hook: just continue its execution */
            L->base = L->ci->base;
        }
        luaV_execute(L, cast_int(L->ci - L->base_ci));
      }
    
    

    resum函数中调用luaV_execute

    void luaV_execute (lua_State *L, int nexeccalls) {
    
        ...
    
        switch (GET_OPCODE(i)) {
          case OP_MOVE: {
            setobjs2s(L, ra, RB(i));
            continue;
          }
          case OP_LOADK: {
            setobj2s(L, ra, KBx(i));
            continue;
          }
          case OP_LOADBOOL: {
            setbvalue(ra, GETARG_B(i));
            if (GETARG_C(i)) pc++;  /* skip next instruction (if C) */
            continue;
          }
    
        ...
    
        }
      }
    }
    

    luaV_execute中存在38个switch case,然后再该游戏的lua vm中找到execute函数同样也是38个switch case,分析得到opcode对照表:

    game orgin
      0 0
      1 24
      2 c
      3 d
      4 1
      5 2 
      6 3 
      7 4 
      8 5
      9 7 
      a 8
      b 6
      c a
      d b
      e 9
      f e
      10 f
      11 10
      12 11
      13 12 
      14 13
      15 14
      16 15
      17 16
      18 17
      19 18
      1a 19
      1b 1a
      1c 1b
      1d 1c
      1e 1d
      1f 1e
      20 1f
      21 20
      22 21
      23 22
      24 23
      25 25
    

    编译unluac

    将分析出来的对照表覆盖到unluac的OpcodeMap.java中进行编译,生成unluac.jar

        } else if(version == 0x51) {
        map = new Op[38];
        map[0] = Op.MOVE;
        map[36] = Op.LOADK;
        map[12] = Op.LOADBOOL;
        map[13] = Op.LOADNIL;
        map[1] = Op.GETUPVAL;
        map[2] = Op.GETGLOBAL;
        map[3] = Op.GETTABLE;
        map[4] = Op.SETGLOBAL;
        map[7] = Op.SETUPVAL;
        map[5] = Op.SETTABLE;
        map[8] = Op.NEWTABLE;
        map[9] = Op.SELF;
        map[10] = Op.ADD;
        map[11] = Op.SUB;
        map[6] = Op.MUL;
        map[14] = Op.DIV;
        map[15] = Op.MOD;
        map[16] = Op.POW;
        map[17] = Op.UNM;
        map[18] = Op.NOT;
        map[19] = Op.LEN;
        map[20] = Op.CONCAT;
        map[21] = Op.JMP;
        map[22] = Op.EQ;
        map[23] = Op.LT;
        map[24] = Op.LE;
        map[25] = Op.TEST;
        map[26] = Op.TESTSET;
        map[27] = Op.CALL;
        map[28] = Op.TAILCALL;
        map[29] = Op.RETURN;
        map[30] = Op.FORLOOP;
        map[31] = Op.FORPREP;
        map[32] = Op.TFORLOOP;
        map[33] = Op.SETLIST;
        map[34] = Op.CLOSE;
        map[35] = Op.CLOSURE;
        map[37] = Op.VARARG; 
      } else if(version == 0x52) {
    

    最后尝试反编译luac文件,成功!!!~~~

    java -jar unluac.jar test.lua
    

    010 editor模版:https://github.com/saidyou/unluc.git

    luac

    Note: 资料参考:

    展开全文
  • lua反编译工具

    2018-05-10 16:24:46
    lua反编译工具包括lua 5.1 与 lua 5.2 包括lua.exe luac.exe luadec.exe 等 可以用此工具加密lua为luac 也可以解密luac为lua
  • 本文所指luajit,皆指luajit2.1.0-beta2版本。...本文主要分析ljd反编译工具源码(https://github.com/NightNord/ljd),并参照feicong的luajit字节码分析一文(https://github.com/feicong/lua_re/blob/master/lu...

    本文所指luajit,皆指luajit2.1.0-beta2版本。

    一、背景

    逆向apk时,得到luajit字节码文件,将反编译luajit的过程记录如下。

    本文主要分析ljd反编译工具源码(https://github.com/NightNord/ljd),并参照feicong的luajit字节码分析一文(https://github.com/feicong/lua_re/blob/master/lua/lua_re3.md),制作Luajit字节码文件格式结构图以直观反映luajit字节码文件格式,并对ljd中存在的bug进行修正,说明使用过程中遇到的问题。

    二、反编译luajit字节码前期准备

    搜集资料,找到两种解决方案。

    方案一

    将luajit字节码文件用luajit.exe(luajit -bl luajit-byte-path)反编成操作码文件,然后再将操作码文件解析成可读文件。

    用autoit编写,下载下来的有打包好的exe文件,简单测试的话可以按如下操作:

    1.下载编译字节码文件对应版本的luajit,可以自己编译,编译好后,将luajit.exe及对应的dll、lib等文件及源码目录下的jit文件夹一同拷贝进luajit-decomp目录。

    2.将需要测试的luajit字节码文件拷贝至luajit-decomp目录,并重命名为test.lua

    3.双击运行,会生成out.lua文件。

    反编译效果如下图:

    6ea1e981bd2320f5cc99f8773a323802.png效果不如人意,对此不做具体分析。

    方案二

    分析luajit字节码文件,及对应版本的luajit源码,写反编译工具将字节码直接反编译成luajit源码。我们主要分析这种。

    过程中主要参照这三篇文章:

    三、Ljd源码分析

    (1)ljd目录结构说明

    9e5d8e7f7572b334941038bac2c56385.png(2)ljd函数调用流程分析

    画了一张解析时调用流程图:

    3bf7d4b1548b7600584f325440194489.png

    详细分析如下:

    Main函数调用ljd.rawdump.parser.parse函数,如下:

    8ca2ad055e59280052ae6d6893753f42.png

    parse会生成state对象实例parser和header对象实例header,然后调用_reader_header方法,并将parser和header传进去,如下图:

    f9527055eb4bdc92e19aba83b0067279.png

    _reader_header调用read函数,如下图:

    00cb69d6754ddb85783eb546f0a22eb1.png

    进入_check_magic、_read_vesion、_read_flags、_read_name函数查看的话,能得到magic为3个字节,version为1个字节,flags大小为1个uleb128,而接下来的源码文件名取决于flags里的is_stripped标志位,如果这个标志位是0,代表有字节码包含调试信息,文件中接下来的字节存放的是源码名称,否则不包含调试信息,接下来的字节内容就是prototypes。

    _reader_header方法调用完成之后,会调用_read_prototypes函数,如下图:

    cb567874ce962a9b91f8c1e6602e9a67.png

    这个函数会循环读取文件字节到prototype对象,我们来看prototype结构:

    8a1be0ba5583b937a54f418a90132871.png

    可以看到里面包含标志、参数数量及操作指令及大小数量、常量、调试信息,但是没看到整个prototype的大小信息及各个字段的字节大小信息。我们接着往下看ljd.rawdump.prototype.read函数:

    74b0e86d88cbc8e39f14e7487324a41b.png这里我们可以看到在解析prototype之前会先读取size,大小为1uleb128,接着会解析prototype内容,同样进入_read_flags、_read_counts_and_sizes、_read_instructions、_read_constants、_read_debuginfo函数内,可以看到,flag为1字节,arguments_count为1字节,Framesize为1字节,upvalues_counts为1字节,complex_constants_count大小为1uleb128,numeric_constants_count大小为1uleb128,instructions_count大小为1uleb128,接下来的字节还是取决于文件头header的flag中的is_stripped标志位,如果is_stripped标志位是0,则接下来的字节存储的是debuginfo_size大小1uleb128,first_line_numb大小1uleb128,lines_count大小1uleb128,如果是1,则没有debuginfo信息。再然后存储的是操作指令instructions,大小取决于解析出来的instructions_count,然后是常量信息constants,大小取决于解析出来的upvalues_count、complex_constants_count、numeric_constants_count,最后,如果解析出来的debuginfo_size大小不为0,则接下来的字节存储的的debuginfo信息,如果debuginfo_size是0,则此prototype结束,然后循环读取下一个prototype。

    根据上面的分析,制作下图,以直观反映luajit字节码文件结构:

    3ed6776cf85d890e36bc2c1e0c3ff764.png

    (3)ljd的bug所在

    还是需要看一下解析时的调用流程:

    d89275d68a825d2d3dcdd1056a38f8bd.png

    从图中可以很明显的看到,在ljd.rawdump.parser.py中的parser函数中,构造了parser和header对象,然后调用_read_header函数,读取luajit字节码文件的文件头到header对象,接下来调用_read_protoypes函数,并传递parser对象,由ljd.rawdump.prototype中的read负责解析。这是解析luajit字节码的一个宏观过程,我贴一张调试过程中的图,就能明显看到问题所在了,调试1:

    6f1ae743006396eefa6eb427aaba0a2b.png

    调试二:

    d68ea83ce305e074829b6228dbdd3eeb.png

    可以明显看出来_read_header函数解析过的header中的flag值没有被带进_read_protoypes函数,而后面读取debuginfo信息时,是需要根据header中的flag值去判断,这里就出现了bug。因为程序默认是读取的带有调试信息的luajit字节码文件,所以当读取带有调试信息的luajit字节码文件,bug不显,但是当读取不带调试信息的luajit字节码文件时,程序就会解析错误。如下:

    错误一:

    c785ede9f4bfa441210ca9fd6f162d7e.png

    如果此时认为是编码问题的话,你可能会将编码都调成”Unicode-escape”,但是依然会出错。错误二:

    8756b7c2940114721891c94fb138da7a.png(4)修正ljd的bug

    知道bug原因了,就可以直接动手改了。如图:

    805fa49a8251c4d8afc86f1d01f5ea39.png

    bb78d1e4bc1b995b061025c23dceb95b.png

    四、结果

    (1)当用LuaJit编译Lua源码时,编译字节码时如果加-g选项,即字节码包含调试信息,反编译时几乎可以完全还原的,还原效果如下图:

    5fe8b543c3b130d8a50704e9db63af3c.png(2)编译时不加-g选项,即不带调试信息,反编译时,是解析不出函数体内的本地变量名称的,因为字节码文件中就没有变量名称信息,只知道有变量占位符,所以在反编译解析时,只能按照规则重命名命名本地变量,还原效果如下图:

    5ec95ff3167cc53a0bf360e15afcf477.png

    (3)修正后源码

    注意事项:工具使用环境python3+,用法:pythonmani.py “path”

    Luajit 源码下载地址:http://luajit.org/download.html  windows下需要用vs控制台编译。

    展开全文
  • 本文阐述针对Cocos2dx-lua提供的轻量级加密方案的反编译。本文demo对象:lua文件大概分3种。lua是明文代码,直接用ide能打开,luac是lua编译后的字节码,文件头特征为0x1B 0x4C 0x75 0x61 0x51。lua虚拟机直接解析...
  • JSC -luac文件反编译破解-DecApkTools-master,国内全,非常好用!各种破解
  • lua编译与反编译

    千次阅读 2013-02-18 19:09:10
    lua的编译需要工具luac.exe cmd: luac xxx.lua -o xxx.lua 编译后的文件为二进制文件,未加密,可用luadec.exe进行反编译: cmd: luadec xxx.lua -d xxx.lua 反编译后几乎与源码没什么区别
  • 最近开始学习对于lua代码的保护,先对基本的概念加以理解并进行记录; 一、编译lua 1.1 lua源码编译 这些在Linux下的支持比较好,直接make就可以; ...lualib工程:1)添加除了lua.c 和 luac...
  • 众所周知,Lua是一种强大的脚本语言,并且这种语言是用C语言实现的。为什么要学习这门语言?因为它可以增强我看C语言代码的功底。我下的Lua版本是Lua5.3...下好了,该怎么编译?打开Makefile,于是看到关键的一行:P...
  • luadec lua反编译工具

    千次阅读 2013-01-10 10:30:20
    在cmd中执行,跟上参数就可以了,假设我们的luadec放在c:\lua下,想要看到c:\test\test.lua文件的源码,那么我们可以使用如下操作1.打开CMD 命令行窗口2.在窗口中输入如下命令 c:\lua\luadec.exe -d c:\test\test....
  • cocos2d-x lua反编译(1)

    千次阅读 2016-08-13 15:55:23
    luac的解密
  • Lua反编译工具

    热门讨论 2012-12-29 17:31:44
    luadec **.luac > **.lua
  • Lua反编译流程

    万次阅读 2015-03-31 21:28:51
    lua源文件--obfuscate-->lua源文件(混淆后)--compile-->luac文件(带调试用的变量名和行号)--strip-->luac文件(不带调试信息) lua/luac--加密/打包-->数据文件 数据文件--解包/解密-->lua/luac-->lua虚拟机 1....
  • Lua语言凭借其高效、简洁与跨平台等多种特性,一直稳立于游戏、移动APP等特定的开发领域中。目前Lua主要有5.1、5.2、5.3共三个版本。5.1版本的Lua之所以目前仍然被广泛使用的原因之一,是由于另一个流行的项目LuaJit...
  • 原标题:非虫 | Lua程序逆向之Luac文件格式分析 简介Lua语言对于游戏开发与相关逆向分析的人来说并不陌生。Lua语言凭借其高效、简洁与跨平台等多种特性,一直稳立于游戏、移动APP等特定的开发领域中。目前Lua主要有...
  • 上一篇讲解了如何加载一个Luac文件到IDA Pro当中,加载进入idb数据库的内容犹如切好洗净的食材,并不能粗暴的直接展示给用户,还需要IDA Pro中的处理器模块对内容进行下一步的汇编渲染与指令功能注释,才能最终装...
  • 这一篇的主要目的是,讲解如何为IDA Pro编写Luac的文件加载器,一方面强化对二进制文件格式的理解;另一方面,通过对IDA Pro进行扩展的插件式开发,更深入的领会IDA Pro的设计思想,以及掌握更多的高级使用方法...
  • Lua脚本 解密加密工具喜欢的拿走吧!android编的有福了!
  • lua字节码混淆与反编译

    千次阅读 2019-05-20 17:21:27
    title: luadec相关的一些总结 背景 在做openwrt相关的路由器时,为了更好的保护lua脚本的代码,通常...混淆、解析和反编译的前提是对文件格式的定义是一致的,因而一般需要把格式定义在lua解释器的源码中,并在适当...

空空如也

空空如也

1 2 3 4 5
收藏数 91
精华内容 36
关键字:

luac反编译