解读隐藏代码
Posted
技术标签:
【中文标题】解读隐藏代码【英文标题】:Interpreting Hidden Code 【发布时间】:2013-08-26 08:36:12 【问题描述】:我正在尝试查看我玩的游戏的这个文件里面有什么(用 L u a 写的),这样我就可以学习并看看它是如何完成的。但在一开始,它定义了使所有内容都无法读取的函数 - 代码在文件中。
随着代码的继续,您将使用### 获得更多“美化”的编码。有人可以告诉我如何使它再次可读吗?
【问题讨论】:
似乎故意混淆了这段代码以使其难以阅读。所以你在这里不会有太多运气。 这似乎不是有效的 Lua 代码:前十行末尾的反斜杠 (\) 是可疑的。你确定那些反斜杠出现在原始代码中吗?或者,也许您使用编辑器、浏览器或用于可视化文件的其他程序的输出进行了剪切和粘贴? 也许整个文件的链接会有所帮助。 那些反斜杠只是八进制 AFAIR 中指定的字符。 我已经回滚了这个问题以删除感谢,这在 SO 中并不是真正必要的,获得一些声誉(只有 5 个以上)并投票回答是表达感谢的方式。 【参考方案1】:您的file 包含[===[
和]===]
之间的压缩代码块。压缩只是一个dictionary coder,其中关键字映射到单个字节值。解压是通过prettify
完成的(参见 Lorenzo 的帖子)。
通过prettify
运行压缩代码会得到this code(压缩率~46%),这恰好是另一个解压程序!事实上,它似乎是this code 的最小化版本。
然后使用“ungzip”例程处理文件中包含的另一个约 150KB 的字符串,该字符串扩展为 675KB 的文本。
信不信由你,该文本也通过与 ungzip 代码相同的方案进行压缩,并包含其 自己的prettify
副本。通过它的prettify
运行该文本会给我们最终的 963KB Lua,然后执行。
这是final, decompressed code,发布到我发现的第一个允许上传 963KB 的网站。格式与来自prettify
的格式相同。
【讨论】:
真的很好找! :-) @Jonathan 现在我已经看到了原始文件,我了解所有这些反斜杠的存在:原始文件是用 UTF-8 编码的,可能你使用另一种编码打开文件并且搞砸了-up 复制粘贴过程。 非常感谢!确实是一个非常好的发现,感谢你们俩的帮助! :) @Jonathan IMO 你应该已经接受了 Mud 的回答,因为它更准确,更中肯,虽然不那么详细。我是 SO 的新手,所以我不知道在这些情况下您是否可以更改您的选择或 SO 政策是什么。 哦,我不知道你只能接受一个。感谢您让我知道...我确实切换了它。虽然我也很欣赏你的回答。【参考方案2】:我是用于创建该文件的实用程序 Squish 的作者。
有些 Squish 的过滤器是可逆的,有些则不是。以下是尽可能轻松地倒车的提示:
在文件顶部,粘贴这段代码sn -p:
local _ls = loadstring;
function loadstring(...)
local f = assert(io.open("unsquished.lua", "w+"));
f:write((...));
f:close();
return _ls(...)
end
然后用 Lua 运行文件。它将在当前目录中生成一个新文件unsquished.lua
。这个文件现在是 100% 纯 Lua。
但是,您不会发现它特别容易阅读,因为所有不必要的空格都会被删除,并且一些变量名会被简短的替代名称所取代。您可以查看lunadry 重新格式化代码,但原始变量名称无法恢复。
此外,该文件包含合并为一个的多个模块。你会看到这些看起来像:
package.preload['modulename']=(function(...)
--code here--
end)
如果您愿意,可以将它们拆分成单独的文件,以提高可读性。
希望这会有所帮助!
编辑:在您不信任的文件上使用此技术时要小心,因为它实际上会在您运行时执行它们。如果您还不知道他们在做什么,这不是一个好主意!
【讨论】:
【参考方案3】:由于发布的代码不完整,而且可能搞砸了,我的只是有根据的猜测。
似乎整个代码将调用“匿名函数”的结果存储在变量ungz
中:(function ()
片段可能像这样关闭:
ungz = (function() -- "anonymous function"
-- ...
-- definition of `prettify` + helper data
-- ...
return assert( loadstring(
prettify [===[
...obfuscated code in this long string...
]===]
) ) -- end of `loadstring` and of `assert` calls
end)() --<<-- note the () to call the "anonymous function"
在此函数中,您可能会看到函数 prettify
及其辅助数据的定义,可以通过这种方式重新格式化以便更好地理解:
local base_char,keywords=128,
"and","break","do","else","elseif","end","false","for",
"function","if","in","local","nil","not","or","repeat","return",
"then","true","until","while","read","nbits","nbits_left_in_byte",
"wnd_pos","output","val","input",;
function prettify(code)
return code:gsub(
"["..string.char(base_char).."-"..string.char(base_char+#keywords).."]",
function (c)
return keywords[c:byte()-base_char];
end
)
end
函数prettify
应用于字符串时,将返回相同的字符串,其中任何具有base_char
-base_char+#keywords
范围内的数字代码的字符都将替换为keyword
列表的关键字。
这用于使用assert(loadstring(prettify[===[xxxx]===]))
对“混淆”代码进行“反混淆”,其中我将混淆代码表示为xxxx
。
附录:请注意,将prettify
应用于片段[===[xxxx]===]
不会返回有意义的代码(202
的base_char
值会产生更好的结果,尽管并不完美) .此外,您必须合并该长字符串中的所有行并将其替换为普通字符串,即将其转换为"yyyy"
,其中yyyy
是xxxx
,并删除了所有硬换行符。
可能所有代码都以某种更进一步的方式进行了预处理。
【讨论】:
以上是关于解读隐藏代码的主要内容,如果未能解决你的问题,请参考以下文章