LuaJit分析(二)luajit反编译工具

目前网上的luajit反编译工具主要存在两款:

总的来说,luajit-decomp比较稳定,但是反编译出来的代码可读性差,之所以稳定,是因为它先使用 luajit -bl 命令将字节码转换成汇编代码,再通过线性扫描汇编代码,转换成lua脚本代码。
Ljd是使用Python写的反编译工具,定义了luajit2.0完整的指令信息,并实现了所有的luajit字节码解析函数,解析出来的lua脚本可读性高

luajit-decomp

  1. 使用方式
    1)下载后,将luajit字节码对应版本的luajit.exe、lua库的dll文件以及jit文件夹拷贝到luajit-decmp目录。
    2)将待反编译的luajit字节码拷贝到当前目录,命名为test.lua
    3)运行decoder_new.exe,生成test.asm、out.lua、out2.lua
    4)test.asm是luajit使用-bl命令生成的汇编代码,out.lua是生成的反编译代码,out2.lua是优化后的反编译代码
  1. 实际测试

测试的lua代码如下,这是table.remove函数

function remove(t, pos)
    CHECK_tab(t)
    local len = #t
    if pos == nil then
      if len ~= 0 then
         local old = t[len]
         t[len] = nil
         return old
      end
    else
      CHECK_int(pos)
      if pos >= 1 and pos <= len then
         local old = t[pos]
         for i=pos+1,len do
        t[i-1]= t[i]
      end
      t[len] = nil
      return old
   end
  end
end

2、反编译效果

1)生成的test.asm文件

– BYTECODE – test.lua:0-0
0001 GGET 2 0 ; "CHECK_tab"
0002 MOV 3 0
0003 CALL 2 1 2
0004 LEN 2 0
0005 ISNEP 1 0
0006 JMP 3 => 0014
0007 ISEQN 2 0 ; 0
0008 JMP 3 => 0034
0009 TGETV 3 0 2
0010 KPRI 4 0
0011 TSETV 4 0 2
0012 RET1 3 2
0013 JMP 3 => 0034
0014 => GGET 3 1 ; "CHECK_int"
0015 MOV 4 1
0016 CALL 3 1 2
0017 KSHORT 3 1
0018 ISGT 3 1
0019 JMP 3 => 0034
0020 ISGT 1 2
0021 JMP 3 => 0034
0022 TGETV 3 0 1
0023 ADDVN 4 1 1 ; 1
0024 MOV 5 2
0025 KSHORT 6 1
0026 FORI 4 => 0031
0027 => SUBVN 8 7 1 ; 1
0028 TGETV 9 0 7
0029 TSETV 9 0 8
0030 FORL 4 => 0027
0031 => KPRI 4 0
0032 TSETV 4 0 2
0033 RET1 3 2
0034 => RET0 0 1

 2)生成的out.lua文件

function someFunc0()
var_0_3 = INPUT_VAR_0_
CHECK_tab(var_0_3)
LEN unhandled at 0004
if INPUT_VAR_1_ == nil then
for var_0_3, var_0_4 in (INPUT_VAR_0_ calling function) do --INPUT_VAR_0_ FORTEST-FORTEST
--jump to 0014 (if previous if statement is false) --0014 JMP-JMP
if CHECK_tab ~= 0 then
for var_0_3, var_0_4 in (INPUT_VAR_0_ calling function) do --INPUT_VAR_0_ FORTEST-FORTEST
--jump to 0034 (if previous if statement is false) --0034 JMP-JMP
var_0_4 = nil --var_0_4 PRIMITIVE-PRIMITIVE
INPUT_VAR_0_[CHECK_tab] = var_0_4
return unknown0
for var_0_3, var_0_4 in (INPUT_VAR_0_ calling function) do --INPUT_VAR_0_ FORTEST-FORTEST
--jump to 0034 (if previous if statement is false) --0034 JMP-JMP
--location 0014--0014 LOCATION-LOCATION
var_0_4 = INPUT_VAR_1_
CHECK_int(var_0_4)
var_0_3 = 1 --var_0_3 NUMBER-NUMBER
if var_0_3 <= INPUT_VAR_1_ then
for var_0_3, var_0_4 in (INPUT_VAR_0_ calling function) do --INPUT_VAR_0_ FORTEST-FORTEST
--jump to 0034 (if previous if statement is false) --0034 JMP-JMP
if INPUT_VAR_1_ <= CHECK_tab then
for var_0_3, var_0_4 in (INPUT_VAR_0_ calling function) do --INPUT_VAR_0_ FORTEST-FORTEST
--jump to 0034 (if previous if statement is false) --0034 JMP-JMP
var_0_4 = INPUT_VAR_1_ +  1 --var_0_4 NUMBER-NUMBER
var_0_5 = CHECK_tab
var_0_6 = 1 --var_0_6 NUMBER-NUMBER
for var_0_7 = var_0_4,var_0_5,var_0_6 do --location 0026, loop ends at 0031-1
var_0_8 = var_0_7 -  1 --var_0_8 NUMBER-NUMBER
INPUT_VAR_0_[var_0_8] = unknown2
end --location 0030, loops back to 0027-1
var_0_4 = nil --var_0_4 PRIMITIVE-PRIMITIVE
INPUT_VAR_0_[CHECK_tab] = var_0_4
return unknown1
--location 0034--0034 LOCATION-LOCATION
return
end

3)生成的out2.lua文件

function randomFunctiona (INPUT_VAR_0_,INPUT_VAR_1_)
 var_0_3 = INPUT_VAR_0_
 CHECK_tab(var_0_3)
 LEN unhandled at 0004
 if INPUT_VAR_1_ == nil then
  --jump to 0014 (if previous if statement is false) --0014 JMP-JMP
  if CHECK_tab ~= 0 then
   --jump to 0034 (if previous if statement is false) --0034 JMP-JMP
   var_0_4 = nil --var_0_4 PRIMITIVE-PRIMITIVE
   INPUT_VAR_0_[CHECK_tab] = var_0_4
   return unknown0
  end
 else
  --location 0014--0014 LOCATION-LOCATION_
  var_0_4 = INPUT_VAR_1_
  CHECK_int(var_0_4)
  var_0_3 = 1 --var_0_3 NUMBER-NUMBER
  if var_0_3 <= INPUT_VAR_1_ then
   --jump to 0034 (if previous if statement is false) --0034 JMP-JMP
   if INPUT_VAR_1_ <= CHECK_tab then
    --jump to 0034 (if previous if statement is false) --0034 JMP-JMP
    var_0_4 = INPUT_VAR_1_ +  1 --var_0_4 NUMBER-NUMBER
    var_0_5 = CHECK_tab
    var_0_6 = 1 --var_0_6 NUMBER-NUMBER
    for var_0_7 = var_0_4,var_0_5,var_0_6 do --location 0026, loop ends at 0031-1
     var_0_8 = var_0_7 -  1 --var_0_8 NUMBER-NUMBER
     INPUT_VAR_0_[var_0_8] = unknown2
    end --location 0030, loops back to 0027-1
    var_0_4 = nil --var_0_4 PRIMITIVE-PRIMITIVE
    INPUT_VAR_0_[CHECK_tab] = var_0_4
    return unknown1
   end
  end
 end
 return
end

可以看到luajit-decomp不能还原函数名,并且代码的可读性极差,并且实质上luajit-decomp只是将汇编代码转换成lua代码,所以依赖luajit解释器,并且解释器与字节码的版本要对应,否则反汇编的结果会不正确

Ljd

  1. 使用方法

           下载后执行 Python main.py 字节码文件 

      2、反编译效果

function remove(slot0, slot1)
        CHECK_tab(slot0)
        slot2 = #slot0
        if slot1 == nil then
                if slot2 ~= 0 then
                        slot0[slot2] = nil
                        return slot0[slot2]
                end
        else
                CHECK_int(slot1)
                if 1 <= slot1 and slot1 <= slot2 then
                        slot3 = slot0[slot1]
                        for slot7 = slot1 + 1, slot2, 1 do
                                slot0[slot7 - 1] = slot0[slot7]
                        end
                        slot0[slot2] = nil
                        return slot3
                end
        end
        return
end

可以看到,ljd可以恢复字节码文件中的函数名,库函数等符号信息,可读性高

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值