当前位置: 首页 > article >正文

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

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

  • Luajit-decomp: GitHub - bobsayshilol/luajit-decomp: LuaJIT decompiler
  • Ljd: https://github.com/NightNord/ljd

总的来说,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可以恢复字节码文件中的函数名,库函数等符号信息,可读性高


http://www.kler.cn/news/283019.html

相关文章:

  • Linux——驱动——自动设备
  • Nginx: 缓存, 不缓存特定内容和缓存失效降低上游压力策略及其配置示例
  • 基于python文案转语音并输出-自媒体等职业副业均可使用,不受他人限制
  • 从“云、边、端”的统一管理,为传统工厂数字化转型赋能的智慧地产开源了
  • OpenAI API Error: Resource not found - Text Summarization in NodeJS
  • QT中引入SQLITE3数据库
  • 自定义全局变量在SpringBoot的应用
  • 后端完成api顺序
  • 外卖霸王餐项目是什么?怎么搭建属于自己的外卖霸王餐小程序 ?
  • 灰度发布-介绍-全链路灰度实现
  • 由浅入深学习 C 语言:Hello World【提高篇】
  • 浏览器缓存
  • 网络安全-安全渗透简介和安全渗透环境准备
  • 【CSP:202109-2】非零段划分(Java)
  • 4.sklearn-K近邻算法、模型选择与调优
  • MySQL集群技术1——编译部署mysql
  • “重启就能解决一切问题”,iPhone重启方法大揭秘
  • 解决:无法从域控制器读取配置信息
  • 2024.8.29 C++
  • C#面:ASP.NET MVC 中还有哪些注释属性用来验证?
  • RKNPU2从入门到实践 ---- 【8】借助 RKNN Toolkit lite2 在RK3588开发板上部署RKNN模型
  • 设计模式--装饰器模式
  • 理解torch.argmax() ,我是错误的
  • 融资和融券分别是什么意思,融资融券开通后能融到多少资金?
  • Datawhale X 李宏毅苹果书 AI夏令营_深度学习基础学习心得Task2.2
  • Java 入门指南:Java NIO —— Selector(选择器)
  • 【hot100篇-python刷题记录】【搜索二维矩阵】
  • 分布式锁的实现:ZooKeeper 的解决方案
  • hive数据迁移
  • 低代码革命:JNPF平台如何简化企业应用开发