解读隐藏代码

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]===] 不会返回有意义的代码(202base_char 值会产生更好的结果,尽管并不完美) .此外,您必须合并该长字符串中的所有行并将其替换为普通字符串,即将其转换为"yyyy",其中yyyyxxxx,并删除了所有硬换行符。

可能所有代码都以某种更进一步的方式进行了预处理。

【讨论】:

以上是关于解读隐藏代码的主要内容,如果未能解决你的问题,请参考以下文章

求C语言隐藏光标函数的详细解释

解读全球海缆地图,带你看懂隐藏的秘密

解读反向传播算法(BackPropagation)

DDIM代码详细解读:核心采样代码超分辨率重建

SpringMVC源码解读--HandlerMapping代码解读

SpringMVC源码解读--HandlerMapping代码解读