首页
论坛
课程
招聘
[调试逆向] [原创]Lua脚本反编译入门之一
2014-4-12 23:20 78954

[调试逆向] [原创]Lua脚本反编译入门之一

2014-4-12 23:20
78954
随着越来越多的游戏,软件采用Lua来实现业务逻辑,
想搞黑产的同学,时常便会遇见lua脚本,可惜大部分都是编译过的lua脚本,而且还是自定义的。
便难倒了很多菜鸟,lua 的实现机制,那可是虚拟机技术,非常难于调试。
本教程,便来普及lua 的虚拟机指令及其反编译lua脚本,成为文本形式的脚本

1.Lua的虚拟机指令,5.2 的有40条

Lua的指令使用一个32bit的unsigned integer表示。所有指令的定义都在lopcodes.h文件中(可以从Lua 官方网站下载),使用一个enum OpCode代表指令类型。在lua5.2中,总共有40种指令(id从0到39)。根据指令参数的不同,可以将所有指令分为4类:



typedef enum {
/*----------------------------------------------------------------------
name                args        description

------------------------------------------------------------------------*/
OP_MOVE,/*        A B        R(A) := R(B)                                        */
OP_LOADK,/*        A Bx        R(A) := Kst(Bx)                                        */
OP_LOADKX,/*        A         R(A) := Kst(extra arg)                                */
OP_LOADBOOL,/*        A B C        R(A) := (Bool)B; if (C) pc++                        */
OP_LOADNIL,/*        A B        R(A), R(A+1), ..., R(A+B) := nil                */
OP_GETUPVAL,/*        A B        R(A) := UpValue                                */

OP_GETTABUP,/*        A B C        R(A) := UpValue[RK(C)]                        */
OP_GETTABLE,/*        A B C        R(A) := R(B)[RK(C)]                                */

OP_SETTABUP,/*        A B C        UpValue[A][RK(B)] := RK(C)                        */
OP_SETUPVAL,/*        A B        UpValue := R(A)                                */
OP_SETTABLE,/*        A B C        R(A)[RK(B)] := RK(C)                                */

OP_NEWTABLE,/*        A B C        R(A) := {} (size = B,C)                                */

OP_SELF,/*        A B C        R(A+1) := R(B); R(A) := R(B)[RK(C)]                */

OP_ADD,/*        A B C        R(A) := RK(B) + RK(C)                                */
OP_SUB,/*        A B C        R(A) := RK(B) - RK(C)                                */
OP_MUL,/*        A B C        R(A) := RK(B) * RK(C)                                */
OP_DIV,/*        A B C        R(A) := RK(B) / RK(C)                                */
OP_MOD,/*        A B C        R(A) := RK(B) % RK(C)                                */
OP_POW,/*        A B C        R(A) := RK(B) ^ RK(C)                                */
OP_UNM,/*        A B        R(A) := -R(B)                                        */
OP_NOT,/*        A B        R(A) := not R(B)                                */
OP_LEN,/*        A B        R(A) := length of R(B)                                */

OP_CONCAT,/*        A B C        R(A) := R(B).. ... ..R(C)                        */

OP_JMP,/*        A sBx        pc+=sBx; if (A) close all upvalues >= R(A) + 1        */
OP_EQ,/*        A B C        if ((RK(B) == RK(C)) ~= A) then pc++                */
OP_LT,/*        A B C        if ((RK(B) <  RK(C)) ~= A) then pc++                */
OP_LE,/*        A B C        if ((RK(B) <= RK(C)) ~= A) then pc++                */

OP_TEST,/*        A C        if not (R(A) <=> C) then pc++                        */
OP_TESTSET,/*        A B C        if (R(B) <=> C) then R(A) := R(B) else pc++        */

OP_CALL,/*        A B C        R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */
OP_TAILCALL,/*        A B C        return R(A)(R(A+1), ... ,R(A+B-1))                */
OP_RETURN,/*        A B        return R(A), ... ,R(A+B-2)        (see note)        */

OP_FORLOOP,/*        A sBx        R(A)+=R(A+2);
                        if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/
OP_FORPREP,/*        A sBx        R(A)-=R(A+2); pc+=sBx                                */

OP_TFORCALL,/*        A C        R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2));        */
OP_TFORLOOP,/*        A sBx        if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx }*/

OP_SETLIST,/*        A B C        R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B        */

OP_CLOSURE,/*        A Bx        R(A) := closure(KPROTO[Bx])                        */

OP_VARARG,/*        A B        R(A), R(A+1), ..., R(A+B-2) = vararg                */

OP_EXTRAARG/*        Ax        extra (larger) argument for previous opcode        */
} OpCode;

**********************************************************
                                  虚拟机指令(2) MOVE & LOAD

OP_MOVE  A  B
OP_MOVE用来将寄存器B中的值拷贝到寄存器A中,由于Lua是基于寄存器虚拟机,大部分的指令都是直接对寄存器进行操作,而不需要对数据进行压栈和弹栈。OP_MOVE 指令的作用 是将一个Local变量复制给另一个local变量.
例子:
local a = 10;  
local b = a;  
编译出来的结果
1   [1] LOAD        0 1;1代表的是常量表的项,这里代表的是10  
2   [2] MOVE        1 0
所代表的二进制为
                     B                 A        OP_Code
Load    0  1  =  100000000 000000000 00000000   000001   =  0x80000001 ,也就是说, 0x80000001 的二进制所代表的指令为  Load  0  1,这里B中的最高位为1,表示的B为常量表的序号,而不是寄存器

MOVE   1  0 =   000000000 000000000 00000001  000000   =  0x40

*****************华丽分割线***********************************************
1.lua 的二进制格式,官方的luac.exe 编译出来的格式


原始的lua 脚本为
local a = 10
local b = a
print(b)

下面介绍格式文件,介绍每个字段的意思.当然啦,这种格式是官方的,各个游戏公司可能会做一些改动,但是万变不离其宗。个个字段已经用颜色标明了
在lua 的源文件中,前面四个字节  1b 4c 75 61  也就是 \033Lua , 标识的是lua文件的特有的标示符数据格式,代表是lua
#define LUA_SIGNATURE        "\033Lua"  033时八进制  = 0x1b ,很多那些反编译工具判断这四个字节的值,来判断是否能反编译,很多公司都会偷偷的去掉或者用其他的值来替换,以迷惑菜鸟。呵呵

52  第五个字节,表示的是,当前lua 的目标版本,这里指的是5.2 版本。
感觉编辑的好痛苦,我还是直接贴我的比较图算了,看起来比较舒服



函数的头描述
linedefined   =    00 00 00 00   ;函数定义开始处的行号
linedefined   =    00 00 00 00     ; 函数定义结束处的行号 ;顶级函数开始和结束行号都是为00
numparams  =    00          ;固定参数的数目 number of fixed parameters
is_vararg      =    01            ;可变参数标识符
                                            • 1=VARARG_HASARG
                                            • 2=VARARG_ISVARARG
                                             • 4=VARARG_NEEDSARG
maxstacksize  =  03         ;调用函数所需要的堆栈空间指令段
sizecode         =   06 00 00 00  ; 函数中 指令的数目,缓存区的大小 = sizecode * sizeof(Instruction),每四个字节为一条指令
code               =  02 00 00 00 41 00 00 00 87 40 40 00 c1 00 80 00 a0 40 00 01 1e 00 80 00
                    
常量列表 保存着函数中引用的常量的列表 (常量池)
Constant.sizek    =  02 00 00 00    ;常量列表的大小 ,缓存区的大小  = Constant.sizek * sizeof(TValue) = 2 * 8 = 16,每项为8个字节,
TValue *               =                                                                             03 00 00 .
                                           00 00 00 00 24 40 04 06 00 00 00 70 72 69 6e 74  ....$@.....print
Constant list 数据结构   保存着函数中引用的常量的列表 (常量池)
Integer 常量列表的大小 (sizek)
[
    1 byte 常量类型 (value in parentheses):  • 0=LUA_TNIL, 1=LUA_TBOOLEAN,• 3=LUA_TNUMBER, 4=LUA_TSTRING
     Const 常量本身: 如果常量类型是0这个域不存在;如果类型是1,这个是0或1;如果类型是3这个域是 Number;如果类型是4 这个域是String。
]
这里的String 是包含"0"为结束的字符串


为什么上传图片以后,图片都变小了,而且不清晰呢?

***********************给大家发一点福利,矫正虚拟机指令的函数**************************************
//矫正虚拟机指令
DWORD Rectify(DWORD Source);
{
    DWORD Instruction = Source;
    BYTE  Source_OpCode =  Instruction & 0x3F;
    switch(Source_OpCode)
    {
        case OP_MOVE:
                Source_OpCode  = Target_OpCode;
             break;
         ...
    }
   Instruction = ((Instruction & 0xFFFFFFC0) | Source_OpCode);
   return Instruction
}

[注意] 招人!base上海,课程运营、市场多个坑位等你投递!

上传的附件:
收藏
点赞0
打赏
分享
最新回复 (53)
雪    币: 110
活跃值: 活跃值 (18)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
sysercn 活跃值 2014-4-12 23:59
2
0
持续关注~
雪    币: 339
活跃值: 活跃值 (47)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
毁灭 活跃值 2 2014-4-13 00:00
3
0
嗯 值得关注一下 现在用LUA的越来越多了
雪    币: 248
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
紫夜星纱 活跃值 2014-4-13 08:44
4
0
提取资源文件或者用LUA反编译软件 反成伪代码,不是更快
雪    币: 199
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
dgann 活跃值 2014-4-13 08:49
5
0
楼主继续啊
雪    币: 37
活跃值: 活跃值 (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
枫叶飘 活跃值 2014-4-13 12:44
6
0
这个需要好好关注
雪    币: 58
活跃值: 活跃值 (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
天缺 活跃值 2014-4-13 16:01
7
0
如何你这样想你就错了,LUA反编译软件是不能反过来的,别人改了指令表。
雪    币: 58
活跃值: 活跃值 (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
天缺 活跃值 2014-4-13 16:03
8
0
另求楼主快更新,支持楼主
雪    币: 114
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
西班牙 活跃值 2014-4-14 17:52
9
0
期待下一集
雪    币: 2542
活跃值: 活跃值 (131)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
davidfoxhu 活跃值 1 2014-4-16 07:53
10
0
期待下一集
雪    币: 943
活跃值: 活跃值 (5587)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
kanxue 活跃值 8 2014-4-16 08:20
11
0
先设优秀,等系列完成再设精华
雪    币: 43
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xujinmysh 活跃值 2014-4-16 10:31
12
0
Lua需要深入研究了,越来越多的程序使用lua脚本编译了,趋势很明显
雪    币: 342
活跃值: 活跃值 (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
技术生命 活跃值 2014-4-16 11:50
13
0
mark留名,等更新
雪    币: 60
活跃值: 活跃值 (74)
能力值: ( LV12,RANK:220 )
在线值:
发帖
回帖
粉丝
cater 活跃值 5 2014-4-16 11:56
14
0
http://lua-users.org/wiki/LuaTools

5.0
http://luadec.luaforge.net/

5.1
https://code.google.com/p/luadec/
http://sourceforge.net/projects/unluac/
https://github.com/sztupy/luadec51/wiki

==========
https://github.com/mlnlover11/LuaAssemblyTools

好似 版本差异蛮大的,撸主辛苦了。
雪    币: 35
活跃值: 活跃值 (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
vvLinker 活跃值 2014-4-16 22:12
15
0
这块越来越受关注了
雪    币: 245
活跃值: 活跃值 (12)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
INightElf 活跃值 2 2014-4-17 01:41
16
0
对不起各位,最近实在是太忙了,回到家都12点左右,周末一定更新!
雪    币: 24
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
高级小白 活跃值 2014-4-17 06:51
17
0
留名................等更新
雪    币: 100
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
晓月残星 活跃值 2014-4-17 18:52
18
0
做记号,等待楼主更新
雪    币: 0
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
heshilove 活跃值 2014-4-17 20:44
19
0
关注,,,,。
雪    币: 4
活跃值: 活跃值 (17)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
heavenbase 活跃值 2014-4-17 21:47
20
0
收藏,持续关注
雪    币: 182
活跃值: 活跃值 (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
justlovemm 活跃值 2014-4-18 11:04
21
0
期待楼主的下一篇,另外这种编码格式是跨平台的吗,比如大端小端之类的问题?
雪    币: 245
活跃值: 活跃值 (12)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
INightElf 活跃值 2 2014-4-18 16:22
22
0
文件格式中有说明大小端的标识
雪    币: 5
活跃值: 活跃值 (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
pooiy 活跃值 2014-4-20 13:36
23
0
其实楼主可以用一个实例加以说明会更容易看懂,期待你的下一篇
雪    币: 211
活跃值: 活跃值 (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
binlanone 活跃值 2014-4-21 14:25
24
0
en ,虽然还看不懂,但是也看得很激动
雪    币: 38
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
tbyp 活跃值 2014-4-21 15:12
25
0
留名学习了,楼主继续
游客
登录 | 注册 方可回帖
返回