首页
论坛
课程
招聘
[原创]用 Lua 简单还原 OpCode 顺序
2019-4-4 14:44 15815

[原创]用 Lua 简单还原 OpCode 顺序

2019-4-4 14:44
15815

前段时间外出游荡,遇上个大兄弟说能不能跑个 Lua 脚本把 Lua 里被修改的 OpCode 顺序弄出来,最近有空自己尝试一下

 

首先准备材料

  • 被修改 OpCode 顺序的 Lua 虚拟机程序一个,不限 SO/DLL/EXE;
  • 同版本的正常 Lua 虚拟机程序一个,不知道版本的同学可以从字符串里找,这里是 Lua 5.1.5;
  • 随便写一个能正常编译的 Lua 函数。

思路

  1. dump 出 Lua 虚拟机中的脚本字节码文件;
  2. 用正常的字节码去校对 OpCode 乱序的字节码。

一般情况下 *.luac 文件由 luac 程序生成,其中的数据是由 luaU_dump 函数产生,在 luac.c 文件中被调用,而 luaU_dump 的另一个入口在 lapi.clua_dump,被绑定到 Lua 的 string.dump 函数。
通过在 Lua 脚本中对需要 dump 的函数用 string.dump,可以得到对应的字节码。

 

分别在目标 Lua 和正常 Lua 虚拟机中运行以下这段代码,获得 OpCode 乱序后的 luac 文件和正常的 luac 文件:

-- lua script
function test()
    -- ...略
end
local data = string.dump(test)
local fp = io.open("test.luac","wb")
fp:write(data)
fp:close()

拿得到的两份 luac 文件比较下,提取出差异内容,差异的部分应该是 Instruction 中的 OpCode。

 

从 Lua 源码中的 lvm.c 文件的 luaV_execute 函数中得知,是通过 GET_OPCODE 宏获取到 OpCode,再执行对应的操作

// lvm.c
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;
      }
    //......
}

GET_OPCODE 宏的定义在 lopcodes.h 文件中,相关代码如下:

// lopcodes.h
#define cast(t, exp)    ((t)(exp))
#define SIZE_OP        6
#define POS_OP        0
#define MASK1(n, p)    ((~((~(Instruction)0)<<n))<<p)
#define GET_OPCODE(i)    (cast(OpCode, ((i)>>POS_OP) & MASK1(SIZE_OP,0)))

简单来说,指令 & 0x3F 就可以得到 OpCode 的数值

 

依旧在目标 Lua 中执行,让它自己输出 OpCode 顺序,完整代码资源在附件

-- lua sciprt
-- ...
local data = string.dump(test)    -- dump
local new_op = {}
-- 用目标 lua 和正常 lua 的 dump 数据对比
for i = 1, #data do
    local by_ori = string.byte(ori_data,i)
    local by_new = string.byte(data,i)
    if by_ori ~= by_new then
        local op_name = ori_op_name[bit:_and(0x3F,by_ori) + 1]
        local op_idx = bit:_and(0x3F,by_new)
        new_op[op_name] = op_idx
    end
end

print("old \t new \t name")
for idx, op_name in pairs(ori_op_name) do
    local tmp = ''
    if new_op[op_name] ~= nil then
        tmp = new_op[op_name]
    end
    print((idx - 1) .. "\t" .. tmp .. "\t" .. op_name )
end

输出结果

 

对于手游中使用的 xlua/ulua/tolua,操作方法类似

 

下面是技术总结

  1. Lua 版本一定要相同
  2. 用于 dump 的函数,尽量覆盖所有的指令操作,否则只能提取出已有的指令

附件为用到的相关资源


[培训] 优秀毕业生寄语:恭喜id:一颗金柚子获得阿里offer《安卓高级研修班》火热招生!!!

最后于 2019-4-4 17:29 被Amun编辑 ,原因: 话题修正
上传的附件:
收藏
点赞8
打赏
分享
打赏 + 50.00
打赏次数 1 金额 + 50.00
 
赞赏  wx小白   +50.00 2020/07/20
最新回复 (33)
雪    币: 594
活跃值: 活跃值 (421)
能力值: ( LV5,RANK:73 )
在线值:
发帖
回帖
粉丝
bambooqj 活跃值 2019-4-4 15:49
2
0
这帖子不错..很强.
雪    币: 102
活跃值: 活跃值 (220)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lhb天羽 活跃值 2019-4-4 16:39
3
0
mark
雪    币: 1100
活跃值: 活跃值 (408)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Tatsuy 活跃值 2019-4-4 17:38
4
0
哇这个思路……
坚固的堡垒从内部被攻破
这样子获取对照很棒哦
雪    币: 15535
活跃值: 活跃值 (17963)
能力值: (RANK:75 )
在线值:
发帖
回帖
粉丝
Editor 活跃值 2019-4-4 18:12
5
0
感谢分享~
雪    币: 36
活跃值: 活跃值 (257)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
芃杉 活跃值 2019-4-4 18:56
6
0
mark 感谢分享
雪    币: 101
活跃值: 活跃值 (304)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xxRea 活跃值 2019-4-11 11:38
7
0
哇,厉害啊,大佬
雪    币: 53
活跃值: 活跃值 (89)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Zkeleven 活跃值 2019-4-11 20:04
8
0
学习了
雪    币: 167
活跃值: 活跃值 (458)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
落叶似秋 活跃值 2 2019-4-15 09:55
9
0
前来支持师兄
雪    币: 198
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
天道xxxx 活跃值 2019-4-16 03:54
10
0
厉害 但是不管用
雪    币: 198
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
天道xxxx 活跃值 2019-4-16 05:01
11
0
读取不了。。
雪    币: 138
活跃值: 活跃值 (26)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
着迷留香 活跃值 2019-4-17 10:43
12
0
落叶似秋 前来支持师兄
朋友,读了你的文章 ,有些小疑问,加个QQ,可以吗?3133916
雪    币: 30
活跃值: 活跃值 (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
keeslient 活跃值 2019-4-21 15:02
13
0
感谢分享啊
雪    币: 55
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Jmdebugger 活跃值 2019-4-23 10:17
14
0
很棒
雪    币: 17
活跃值: 活跃值 (177)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
guotouck 活跃值 2019-5-14 14:59
15
1
感觉没意义啊.. 前提哪里来的明文lua ?
看起来这是 拿 明文lua和解密lua 对比计算的  前提哪里来的明文lua?
最后于 2019-5-14 15:21 被guotouck编辑 ,原因:
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_nxzuumgu 活跃值 2019-11-8 00:03
16
0
看了您的文章,有一个点,没有想通,如何获得目标lua虚拟机执行程序?比如我现在只有打包完成的so文件。期待您的回复
雪    币: 5847
活跃值: 活跃值 (983)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
黑洛 活跃值 1 2019-11-8 00:43
17
0
guotouck 感觉没意义啊.. 前提哪里来的明文lua ?看起来这是&nbsp;拿&nbsp;明文lua和解密lua&nbsp;对比计算的&nbsp;&nbsp; ...
一看就没认真读文章,人家说是对比opcode顺序,你自己写一个文件包含所有操作就行了。
雪    币: 1358
活跃值: 活跃值 (590)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
Amun 活跃值 2019-11-8 11:11
18
0
动态库需要导出函数,才能被外部调用。在 Lua 的动态库中一般存在 `luaL_dofile` `luaL_loadbuffer`  等等,可以直接拿来用。如果是以静态库形式集成的 Lua,要自己找函数偏移。
雪    币: 17
活跃值: 活跃值 (177)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
guotouck 活跃值 2019-11-8 12:15
19
0
Amun 动态库需要导出函数,才能被外部调用。在 Lua 的动态库中一般存在 `luaL_dofile` `luaL_loadbuffer` 等等,可以直接拿来用。如果是以静态库形式集成的 Lua,要自己找函 ...

需要满足以下条件吧.
1.找到对方的 `luaL_loadbuffer` pcall接口  
2.对方支持明文lua运行,国产很多厂商都把明文lua接口删除了的 只支持二进制编码格式运行

然后你这demo我运行了下 根本不行啊 是不是上传有错误. 
 

 dofile("C:\\Users\\hello\\Desktop\\Check_OpCode\\check_opcode.lua")
C:\Users\hello\Desktop\Check_OpCode\check_opcode.lua:64: table index is nil
stack traceback:
        C:\Users\hello\Desktop\Check_OpCode\check_opcode.lua:64: in main chunk
        [C]: in function 'dofile'
        stdin:1: in main chunk
        [C]: ?
最后于 2019-11-8 12:16 被guotouck编辑 ,原因:
雪    币: 1358
活跃值: 活跃值 (590)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
Amun 活跃值 2019-11-8 15:01
20
0
  1. 删除加载明文脚本相关的代码可能会导致大量使用 require,dofile,loadfile,dostring,loadstring,loadlib,load相关功能的 Lua 库发生故障,一般只会隐藏导出接口。
  2. 无故障
雪    币: 17
活跃值: 活跃值 (177)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
guotouck 活跃值 2019-11-9 23:48
21
0
Amun 1. 删除加载明文脚本相关的代码可能会导致大量使用 `require`,`dofile`,`loadfile`,`dostring`,`loadstring`,`loadlib`,`load`相关功能 ...
终于代码可以跑了 win10出错..... win7可以 . ,不支持是不是系统不同 编码不同 反正WIN10不可以  难怪我下了N份这种一键找op的..都是这坑

网易的游戏 都不支持明文lua加载 只可以二进制编译加载 
最后于 2019-11-9 23:49 被guotouck编辑 ,原因:
雪    币: 483
活跃值: 活跃值 (223)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wx小白 活跃值 2020-7-20 09:43
22
0
我想问一下,如何拿到目标lua虚拟机  如果指的是so文件  我如何用so文件加载我的lua文件为字节码文件  请大佬指点
雪    币: 1358
活跃值: 活跃值 (590)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
Amun 活跃值 2020-7-20 12:15
23
0
wx小白 我想问一下,如何拿到目标lua虚拟机 如果指的是so文件 我如何用so文件加载我的lua文件为字节码文件 请大佬指点
最简单的方法是自己写一个 APP,调用 liblua.so 的 API 函数进行加载执行。
雪    币: 483
活跃值: 活跃值 (223)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wx小白 活跃值 2020-7-20 15:10
24
0
能具体点吗   我对lua虚拟机不熟悉  调用那些函数   可以把lua源码编译成字节码文件
雪    币: 3476
活跃值: 活跃值 (229)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
不知世事 活跃值 1 2020-9-9 15:26
25
0
通过目标虚拟机加载lua文件跟正常虚拟机编译的luac进行对比“吐出”映射表
游客
登录 | 注册 方可回帖
返回