首页
社区
课程
招聘
[分享] 效果最好的Lua反编译器
2023-4-16 11:27 10746

[分享] 效果最好的Lua反编译器

2023-4-16 11:27
10746

有点标题党了,不过确实是我已知的lua反编译器里效果最好的了

 

在线使用 http://luadec.metaworm.site/
图片描述

 

现有的反编译工具多多少少有些不完美

  • luadec:缺少块分析,稍微复杂的脚本会反编译失败
  • unluac:缺少中间变量的消除,存在大量的冗余语句影响分析速度

然后我自己尝试实现了一个lua反编译器,开源了字节码parser部分的代码https://github.com/metaworm/luac-parser-rs

 

功能/特色

  • 基于块分割以及支配树分析,可以消除大部分中间变量
  • 绘制流程图,可对照参考原始的lua指令
  • 自定义parser,可编写定制的parser来反编译非官方的lua字节码
  • 多行字符串的识别优化
  • 现已支持所有主流lua版本:lua5.1/lua5.2/lua5.3/lua5.4/luajit

还有一些不足之处,是由于反编译导致很多原始信息丢失,对某些if条件的合并还有and/or语句的还原可能会和原始逻辑不一致,这种情况下可以查看流程图来辅助确认

 

关于隐私

  1. 字节码的解析在前端实现,解析成中间形式交由后端反编译,不会上传原文件
  2. 自定义parser保存在浏览器本地存储中,不会上传后端

最后看一下反编译效果的对比,以这段脚本为例 luac5.1 -s ralloc_regression_9.lua

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
Common.StandardResourceSpawn = function(r0_pr31, r1_pr31, r2_pr31, r3_pr31, r4_pr31, r5_pr31, r6_pr31) -- proto 31
   local r7_pr31 = Universe:GetPlayerGameObject()
   if r7_pr31 == nil or not r7_pr31.isValid then
      return
   end
   if r3_pr31 == nil or not r3_pr31.isValid or r3_pr31.containingWorld ~= r7_pr31.containingWorld then
      return
   end
   if r1_pr31 ~= nil then
      if not r4_pr31 then
         r4_pr31 = 180
      end
      if not r5_pr31 then
         r5_pr31 = {
            x = 0,
            y = 0.699999988079071,
            z = 0,
            rotY = 0
         }
      end
      for r11_pr31, r12_pr31 in pairs(r1_pr31) do
         -- backwards jump barrier
         if Classes.ResourceBase:ResourceIsValidToSpawn(r12_pr31[1][1], r12_pr31[1][2]) then
            r13_pr31 = Luattrib:ReadAttribute(r12_pr31[1][1], r12_pr31[1][2], "ResourceType")
            local r14_pr31 = r12_pr31[2]
            if r13_pr31 == Constants.ResourceTypes.WandPower then
               r14_pr31 = r7_rt(r12_pr31[1][1], r12_pr31[1][2], r14_pr31)
            end
            if r13_pr31 == Constants.ResourceTypes.Unlockable then
            end
            local r15_pr31 = Classes.Job_PropellResource:Spawn(r2_pr31, r3_pr31, r12_pr31[1][1], r12_pr31[1][2], r14_pr31, r4_pr31, r5_pr31, nil, nil, {
               r2_pr31,
               r3_pr31
            })
            r15_pr31:ExecuteAsIs()
         end
      end
   end
end

luadec的反编译结果 luadec luac.out

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
--cannot find blockend > 3 , pc = 2, f->sizecode = 4
--cannot find blockend > 4 , pc = 3, f->sizecode = 4
--cannot find blockend > 98 , pc = 97, f->sizecode = 99
--cannot find blockend > 99 , pc = 98, f->sizecode = 99
-- Decompiled using luadec 2.2 rev: 895d923 for Lua 5.1 from https://github.com/viruscamp/luadec
-- Command line: luac.out
 
-- params : ...
-- function num : 0
-- DECOMPILER ERROR at PC2: Confused about usage of register: R0 in 'UnsetPending'
 
Common.StandardResourceSpawn = function(l_1_0, l_1_1, l_1_2, l_1_3, l_1_4, l_1_5, l_1_6)
  -- function num : 0_0
  local l_1_7 = Universe:GetPlayerGameObject()
  if l_1_7 == nil or not l_1_7.isValid then
    return
  end
  if l_1_3 == nil or not l_1_3.isValid or l_1_3.containingWorld ~= l_1_7.containingWorld then
    return
  end
  if l_1_1 ~= nil then
    if not l_1_4 then
      l_1_4 = 180
    end
    do
      do
        if not l_1_5 then
          local l_1_8 = {}
          l_1_8.x = 0
          l_1_8.y = 0.69999998807907
          l_1_8.z = 0
          l_1_8.rotY = 0
          l_1_5 = l_1_8
        end
        for l_1_12,l_1_13 in pairs(l_1_1) do
          if (Classes.ResourceBase):ResourceIsValidToSpawn((l_1_13[1])[1], (l_1_13[1])[2]) then
            r13_pr31 = Luattrib:ReadAttribute((l_1_13[1])[1], (l_1_13[1])[2], "ResourceType")
            local l_1_14 = l_1_13[2]
            if r13_pr31 == (Constants.ResourceTypes).WandPower then
              l_1_14 = r7_rt((l_1_13[1])[1], (l_1_13[1])[2], l_1_14)
            end
            if r13_pr31 == (Constants.ResourceTypes).Unlockable then
              local l_1_15, l_1_16 = (Classes.Job_PropellResource):Spawn, Classes.Job_PropellResource
              local l_1_17 = l_1_2
              local l_1_18 = l_1_3
              local l_1_19 = (l_1_13[1])[1]
              local l_1_20 = (l_1_13[1])[2]
              local l_1_21 = l_1_14
              local l_1_22 = l_1_4
              local l_1_23 = l_1_5
              local l_1_24, l_1_25 = nil, nil
              do
                local l_1_26 = {}
                -- DECOMPILER ERROR at PC92: No list found for R25 , SetList fails
 
                l_1_16(l_1_17)
                -- DECOMPILER ERROR at PC96: LeaveBlock: unexpected jumping out IF_THEN_STMT
 
                -- DECOMPILER ERROR at PC96: LeaveBlock: unexpected jumping out IF_STMT
 
                -- DECOMPILER ERROR at PC96: LeaveBlock: unexpected jumping out IF_THEN_STMT
 
                -- DECOMPILER ERROR at PC96: LeaveBlock: unexpected jumping out IF_STMT
 
              end
            end
          end
        end
        -- WARNING: undefined locals caused missing assignments!
      end
    end
  end
end

unluac的反编译结果 unluac luac.out

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
--Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true -Dswing.defaultlaf=com.sun.java.swing.plaf.gtk.GTKLookAndFeel -Dswing.crossplatformlaf=com.sun.java.swing.plaf.gtk.GTKLookAndFeel
local L0_1, L1_1
L0_1 = Common
function L1_1(A0_2, A1_2, A2_2, A3_2, A4_2, A5_2, A6_2)
  local L7_2, L8_2, L9_2, L10_2, L11_2, L12_2, L13_2, L14_2, L15_2, L16_2, L17_2, L18_2, L19_2, L20_2, L21_2, L22_2, L23_2, L24_2, L25_2, L26_2, L27_2
  L7_2 = Universe
  L8_2 = L7_2
  L7_2 = L7_2.GetPlayerGameObject
  L7_2 = (L7_2(L8_2))
  if L7_2 ~= nil then
    L8_2 = L7_2.isValid
    if L8_2 then
      goto lbl_10
    end
  end
  do return end
  ::lbl_10::
  if A3_2 ~= nil then
    L8_2 = A3_2.isValid
    if L8_2 then
      L8_2 = A3_2.containingWorld
      L9_2 = L7_2.containingWorld
      if L8_2 == L9_2 then
        goto lbl_20
      end
    end
  end
  do return end
  ::lbl_20::
  if A1_2 ~= nil then
    if not A4_2 then
      A4_2 = 180
    end
    if not A5_2 then
      L8_2 = {}
      L8_2.x = 0
      L8_2.y = 0.699999988079071
      L8_2.z = 0
      L8_2.rotY = 0
      A5_2 = L8_2
    end
    L8_2 = pairs
    L9_2 = A1_2
    L8_2, L9_2, L10_2 = L8_2(L9_2)
    for L11_2, L12_2 in L8_2, L9_2, L10_2 do
      L13_2 = Classes
      L13_2 = L13_2.ResourceBase
      L14_2 = L13_2
      L13_2 = L13_2.ResourceIsValidToSpawn
      L15_2 = L12_2[1]
      L15_2 = L15_2[1]
      L16_2 = L12_2[1]
      L16_2 = L16_2[2]
      L13_2 = (L13_2(L14_2, L15_2, L16_2))
      if L13_2 then
        L13_2 = Luattrib
        L14_2 = L13_2
        L13_2 = L13_2.ReadAttribute
        L15_2 = L12_2[1]
        L15_2 = L15_2[1]
        L16_2 = L12_2[1]
        L16_2 = L16_2[2]
        L17_2 = "ResourceType"
        L13_2 = (L13_2(L14_2, L15_2, L16_2, L17_2))
        r13_pr31 = L13_2
        L13_2 = L12_2[2]
        L14_2 = r13_pr31
        L15_2 = Constants
        L15_2 = L15_2.ResourceTypes
        L15_2 = L15_2.WandPower
        if L14_2 == L15_2 then
          L14_2 = r7_rt
          L15_2 = L12_2[1]
          L15_2 = L15_2[1]
          L16_2 = L12_2[1]
          L16_2 = L16_2[2]
          L17_2 = L13_2
          L14_2 = (L14_2(L15_2, L16_2, L17_2))
          L13_2 = L14_2
        end
        L14_2 = r13_pr31
        L15_2 = Constants
        L15_2 = L15_2.ResourceTypes
        L15_2 = L15_2.Unlockable
        if L14_2 == L15_2 then
        end
        L14_2 = Classes
        L14_2 = L14_2.Job_PropellResource
        L15_2 = L14_2
        L14_2 = L14_2.Spawn
        L16_2 = A2_2
        L17_2 = A3_2
        L18_2 = L12_2[1]
        L18_2 = L18_2[1]
        L19_2 = L12_2[1]
        L19_2 = L19_2[2]
        L20_2 = L13_2
        L21_2 = A4_2
        L22_2 = A5_2
        L23_2 = nil
        L24_2 = nil
        L25_2 = {}
        L26_2 = A2_2
        L27_2 = A3_2
        L25_2[1] = L26_2
        L25_2[2] = L27_2
        L14_2 = (L14_2(L15_2, L16_2, L17_2, L18_2, L19_2, L20_2, L21_2, L22_2, L23_2, L24_2, L25_2))
        L16_2 = L14_2
        L15_2 = L14_2.ExecuteAsIs
        L15_2(L16_2)
      end
    end
  end
end
L0_1.StandardResourceSpawn = L1_1

metaworm's luadec的反编译结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
-- filename: ""
-- line: [0, 0] id: 0
function Common.StandardResourceSpawn(r0, r1, r2, r3, r4, r5, r6)
  -- line: [1, 39] id: 1
  local r7 = Universe:GetPlayerGameObject()
  if r7 == nil or not r7.isValid then
    return
  end
  if r3 == nil or not r3.isValid or r3.containingWorld ~= r7.containingWorld then
    return
  end
  if r1 ~= nil then
    if not r4 then
      r4 = 180
    end
    if not r5 then
      r5 = {
        x = 0,
        y = 0.699999988079071,
        z = 0,
        rotY = 0,
      }
    end
    for r11, r12 in pairs(r1) do
      if Classes.ResourceBase:ResourceIsValidToSpawn(r12[1][1], r12[1][2]) then
        r13_pr31 = Luattrib:ReadAttribute(r12[1][1], r12[1][2], "ResourceType")
        local r13 = r12[2]
        if r13_pr31 == Constants.ResourceTypes.WandPower then
          r13 = r7_rt(r12[1][1], r12[1][2], r13)
        end
        if r13_pr31 ~= Constants.ResourceTypes.Unlockable then
        end
        Classes.Job_PropellResource:Spawn(r2, r3, r12[1][1], r12[1][2], r13, r4, r5, nil, nil, {
          r2,
          r3
        }):ExecuteAsIs()
      end
    end
  end
end

[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

最后于 2023-4-16 13:17 被metaworm编辑 ,原因:
收藏
点赞8
打赏
分享
最新回复 (12)
雪    币: 37
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_aicyioze 2023-4-17 23:37
2
0
然而并不能用呀.
雪    币: 19410
活跃值: (29069)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
秋狝 2023-4-18 09:14
3
1
感谢分享
雪    币: 4235
活跃值: (8395)
能力值: ( LV9,RANK:181 )
在线值:
发帖
回帖
粉丝
nevinhappy 2 2023-4-18 09:18
4
0

So this is your toy ?

雪    币: 434
活跃值: (1670)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
metaworm 2023-4-19 21:35
5
0
mb_aicyioze 然而并不能用呀.
报什么错了吗;忘了说,需要浏览器支持webassembly
雪    币: 434
活跃值: (1670)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
metaworm 2023-4-19 21:37
6
0
nevinhappy So this is your toy ?
可能服务器开小差了,再试试吧,我这一直是正常的
雪    币: 37
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_aicyioze 2023-4-20 20:55
7
0
建议把jar换成最新的 有些匿名参数可以解出来
雪    币: 434
活跃值: (1670)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
metaworm 2023-4-21 00:47
8
0
mb_aicyioze 建议把jar换成最新的 有些匿名参数可以解出来
?你说unluac? 
雪    币: 107
活跃值: (3560)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Imxz 2023-4-21 09:40
9
0
对于Luajit的支持非常好, 期待开源
雪    币: 267
活跃值: (3209)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
EX呵呵 2023-5-1 21:46
10
0
mark
雪    币: 223
活跃值: (783)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
果冻大砍刀 2023-5-13 23:56
11
0
踏遍铁鞋无觅处,感谢大佬无私分享
雪    币: 3671
活跃值: (3848)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
caolinkai 2023-5-14 12:59
12
0
厉害
雪    币: 37
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_aicyioze 2023-7-19 17:49
13
0
这个改过opcode的要怎么反编译呢,不能搞个简单修改op顺序调用的吗
游客
登录 | 注册 方可回帖
返回