如何为 Lua 的 VM/编译器重新编译已编译的字节码列表?
Posted
技术标签:
【中文标题】如何为 Lua 的 VM/编译器重新编译已编译的字节码列表?【英文标题】:How to re-compile a compiled bytecode listing for Lua's VM/compiler? 【发布时间】:2019-07-01 03:37:48 【问题描述】:我正在尝试修改一款名为 Fun Run 2 的旧手机游戏的代码,作为我大学软件工程课程的一个独特研究项目。
该应用是使用 Corona SDK 制作的,因此使用 Lua 进行编程。因此,一旦我拿到 APK 并解压缩它,我需要解压缩 resource.car (Corona ARchive) 以访问 Lua 文件。所以我这样做了,并且该存档中的所有文件都是预编译的 .lu 文件。
为了修改 Lua 代码,我尝试的第一件事是使用 unluac/luadec 将 .lu 文件反编译为可读、可修改、可编译的源代码。我能够成功地对它们进行反编译、修改和重新编译,但是当它在游戏中实际执行修改后的 .lu 文件时,它因为尝试索引一个 nil 值而崩溃。我发现造成这种情况的原因是有一个叫做 upvalue 的东西,当从编译的 Lua 文件中剥离调试信息时,它是无法检索的,因此尝试反编译和重新编译 .lu 文件是行不通的上班。
所以我的下一个方法是使用luac -l
方法,它为 Lua 的虚拟机创建一个已编译字节码的列表。
luac -l lua.gameLogic.powerUpChance.lu
的结果是这样的
...
main <?:0,0> (11 instructions, 44 bytes at 025D7D80)
0+ params, 3 slots, 0 upvalues, 0 locals, 4 constants, 2 functions
1 [-] NEWTABLE 0 0 0
2 [-] GETGLOBAL 1 -1 ; require
3 [-] LOADK 2 -2 ; "composer"
4 [-] CALL 1 2 2
5 [-] CLOSURE 2 0 ; 025D8280
6 [-] MOVE 0 1
7 [-] SETTABLE 0 -3 2 ; "selectRandomPowerUp" -
...
鉴于此说明列表,我知道我需要修改什么以及在哪里修改它,并且我这样做了。这让我想到了我的问题 - 我如何获取修改后的字节码列表并将其编译回已编译的 .lu 文件?这甚至可能吗?这种修改已编译 Lua 文件的方法是在浪费我的时间吗?
【问题讨论】:
请上传您的字节码文件。 @EgorSkriptunoff 给你,这是未修改的版本 - pastebin.com/gZjFsKDL 我问的是字节码二进制文件,而不是它的列表。 @EgorSkriptunoff 我错了,你在这里 - ufile.io/hu26d 好的,通常是没有调试信息的 Lua 5.1 x86 字节码。这个文件应该被反编译和重新编译没有问题。所有的上值都在里面描述(除了它们的名字),不需要额外的信息。显示反编译结果(检查反编译是否正确)。 【参考方案1】:没有工具(至少我不知道)可以将字节码的字符串表示形式编译回正确的 Lua 字节码;主要是因为这不是要编辑的,而是作为检查 Lua 代码编译并可能对其进行优化的一种方式。
更好的解决方案是使用将字节码反编译为 Lua 代码的工具。使用哪种工具在很大程度上取决于您使用的 Lua 版本,但对于从 5.1 到 5.3 的任何东西,我都没有亲自尝试过 LuaDec,但应该可以完成工作。反编译源代码后,进行所有必要的修改并使用 luac 再次编译它,就像使用任何 Lua 文件一样。
希望这会有所帮助:)
【讨论】:
不幸的是,我尝试了这种方法,没有骰子 :( 我能够以这种方式反编译、修改和重新编译 Lua 文件,但在运行时我收到有关尝试访问 nil 值的错误。我发现这是因为局部变量有时是“upvalues”,由于某种原因无法看到/使用。更具体地说,在反编译之前,有“GETUPVAL”指令,当我重新编译时,它们变成“GETGLOBAL”指令. 我知道有可能解决这个问题,因为其他人已经使用这种方法成功修改了这个游戏的代码,但我不知道如何。 嗯...我看到了那里的问题,但很容易避免这个问题。您只需要确定哪些变量是上值,然后将它们作为局部变量添加到函数之外,因此函数会将它们作为上值。然后你应该能够string.dump
函数及其上值。
我明白了...找出哪些变量是上值很容易,但在这种情况下,如果上值被引用和使用,我将如何找出将本地声明为函数外部的内容所以? pastebin.com/bZAkELZa
在这种情况下,只需在函数前写入local _UPVALUE0_
就足够了,并且应该将其编译为上值。但请记住只切换方法本身的字节码,而不是实际创建闭包的部分:)
@xn 我建议寻找现有问题或为此创建一个新问题,因为它与您的原始问题越来越远。确保在使用时添加更多上下文,例如您如何准确地提取字节码、它是如何执行的、反编译代码的 /[ph]astebins/ 等。如果您不能将其归结为单个*** 的问题,你也可以在 lua subreddit 上问,它对问题的简洁和重点没有 SO 严格。【参考方案2】:
您使用的反编译器似乎无法正确反编译 for 循环。 以下片段:
if A1_3 == #A3_5 and A2_4 > 2 then
for _FORV_9_ = 1, #A3_5 do
end
if _FOR_ then
L5_7 = 11
end
end
必须是这样的:
if A1_3 == # A3_5 and A2_4 > 2 then
local R6 = true
for k = 1, #A3_5 do
if not A3_5[k].mainPlayer then
if A3_5[k].x < A0_2.x + 1200 then
R6 = false
end
end
end
if R6 then
L5_7 = 11
end
end
【讨论】:
以上是关于如何为 Lua 的 VM/编译器重新编译已编译的字节码列表?的主要内容,如果未能解决你的问题,请参考以下文章