二进制咸鱼的自我救赎

幸福往往是摸的透彻,而敬业的心却常常隐藏。

About RSS

继续完善不太能用的 Python 反编译器

#re

在之前的文章里,我实现了一个不太能用的 Python 反编译器,后来在不断咨询 LLM 修复建议,并手动分析和实现之后,现在能对简单的程序进行反编译了。在这篇文章里,我讲一下主要的修复项。

控制流图恢复

这里我使用了更成熟的方案。首先遍历所有汇编指令,根据不同类型的跳转语句,FOR_ITER 语句,来收集每一个 BB 的开头偏移,然后根据这些开头偏移,将一堆的指令切分到不同的 BB 中,最后再根据 BB 中的条件跳转,非条件跳转语句,来构建整个控制流图。如果两个 BB 相邻,而且前一个 BB 最后的指令不是跳转语句,那也将其连接。

相对于之前的方案,新的方案对 BB 切分更清晰,并且可以在 CFG 中添加边的类型,例如是条件为真的跳转,还是别的跳转。

控制流构建

在识别非循环控制流的时候,我优化了单个 if 存在多个条件的判断。现在是生成左右节点的支配者链,然后在左右节点的支配者链里找到共有的支配者,最后在共有支配者里找到最近的支配者。相对于之前的算法,避免了需要处理循环的情况,也不需要一直找前序节点。我还在识别非循环控制流的外层加入了循环,不断进行识别和合并,当识别不到新的节点时候再退出,防止有一些节点未被整合到 if 语句中。

在识别循环控制流的时候,对 Havlak 算法得到的结果进行了优化。现在会根据 Havlak 算法得到的结果,找到该循环的回边,出口节点。再根据回边,去计算该循环中是否有 break 语句,如果有的话,则插入 BreakNode 和 IfElseNode 节点,用于构造 AST。

在之前的识别之后,会将匹配到的 BB 替换成 AST Node,逐渐构造出一颗 AST 树,供后续反编译语句使用。

反编译语句

在反编译语句的时候,修复了之前存在的一些问题,例如自增语句解析,CALL 语句参数解析。

之前只能反编译一个 BB 中的语句,现在改成了遍历重新构造的 CFG 生成 AST 树,并遍历 AST 树输出反编译的结果。

成品

现在能反编译一些非常基础的汇编片段了...

$ uv run main.py test_prog/if_branch_1.txt
value = a
if a > b:
    value = a
else:
    value = b
return value

后续工作

总结

这次在 LLM 的帮助下修好了之前的反编译器。LLM 负责分析代码,给出修复建议,我来审核建议并编写代码。我尝试过让 LLM 自己去完善代码,它确实能完成功能,但是在代码结构上,会偏向于新增而不是重构之前的代码,导致在几轮对话之后,项目有点面目全非了,并且我还有点看不懂。最后考虑到这个项目的性质是偏向于让我学到一些东西,我还是选择了自己编写代码。

如果现在要做反编译工作的话,可以考虑将 Python 字节码直接给大模型,让他生成反编译后的 Python 代码。

代码:https://github.com/chenx6/gadget/tree/master/pydec