【问题标题】:Obfuscated Bytecode when uncompyling python pyc file解压缩python pyc文件时混淆的字节码
【发布时间】:2018-09-01 07:28:11
【问题描述】:

我正在尝试使用 uncompyle6 反编译一个 pyc 文件。正如这里所说,该操作在偏移量 966 处给出了解析错误。

Parse error at or near `POP_TOP' instruction at offset 996

Uncompyle 打印其反编译的结果,从中我可以看到在反编译我的代码的最后一行后引发了解析错误,这是 root.mainloop() 因为源代码是一个 tkinter gui。

如果有人能说明如何为绝对初学者修复字节码以及我应该从哪里开始,我将不胜感激。由于错误是在我的代码末尾引发的,我觉得错误是可以纠正的。 这是错误本身:

2295    6290  LOAD_NAME                'root'
        6292  LOAD_ATTR                'mainloop'
        6296  CALL_FUNCTION_0       0  ''
        6298  POP_TOP

Parse error at or near `POP_TOP' instruction at offset 996

这是错误行周围的字节码

 966 LOAD_NAME               23 (ttk)
 968 LOAD_ATTR              110 (Button)
 970 LOAD_NAME              107 (iS1cols)
 972 LOAD_NAME              112 (tools_be_xl)
 974 LOAD_NAME               43 (tools_browse_xls)
 976 LOAD_CONST             126 (('textvariable', 'command'))
 978 CALL_FUNCTION_KW         3
 980 LOAD_ATTR              108 (grid)
 982 LOAD_CONST               0 (0)
 984 LOAD_CONST             121 (20)
 986 LOAD_CONST             117 (4)
 988 LOAD_CONST             127 (2)
 990 LOAD_NAME              109 (W)
 992 LOAD_CONST             128 (('row', 'padx', 'pady', 'column', 'sticky'))
 994 CALL_FUNCTION_KW         5
 996 POP_TOP

 998 LOAD_NAME               23 (ttk)
1000 LOAD_ATTR              113 (LabelFrame)
1002 LOAD_NAME               91 (tab3Int)
1004 LOAD_CONST             129 (' Bulk Edit ')
1006 LOAD_CONST             107 (('text',))
1008 CALL_FUNCTION_KW         2
1010 STORE_NAME             114 (imgStep1)

【问题讨论】:

  • 这个字节码是从哪里来的?另外,我不认为CALL_FUNCTION_0 是一个指令。如果删除 _0 会发生什么?
  • 它来自一个 pyinstaller 提取器。最初由于损坏,我丢失了我的源文件,所以我使用源代码的 pyinstaller 最近导出的 exe 将可执行文件反转回我的 py 源代码。我现在有了那个 pyc 文件。
  • 我怎样才能删除它?
  • 别管最后一部分,我误解了一些东西。错误说它的偏移量是 966,而不是 6290。你能在该部分周围显示代码吗?
  • 我在错误之前用 more 编辑了问题。是的,这种差异对我来说也很独特

标签: python python-3.6 decompiling pyc


【解决方案1】:

您的程序长达数千行。将其缩减为更小的内容后,请通过https://github.com/rocky/python-uncompyle6/issues 报告。

但请注意,您可能需要付出一些努力才能将程序精简为易于处理的内容。如果您不想花费精力而是希望其他人为您完成工作,我有listed a service that may be willing to do this。如果人们希望我在该文档中列出其他服务,请与我联系。

我会说,根据我的经验,一旦一个 bug 被削弱,除了控制流 bug 的情况(这似乎与这里无关),通常会有一些小的变化然后使这些巨大的文件正确反编译。

有两种方法可以缩短程序以考虑 uncompyle6 错误修复....

最简单的方法是猜测导致问题的代码类型。由于您对问题所在有一些idea - 你说它在 tkinter gui 循环的最后一行 - 编写一些类似的新代码,字节编译它并查看反编译是否给出同类型的错误。

也许您有一些具有相同类型 tkinter gui 循环的旧源代码。试着拆开那个。然后把它删减到不超过几十行。

第二种方法是在xdis 包中找到的pydisasm 上使用--asm 选项。这将为您提供可以更轻松地修改的 Python 汇编代码,并且在这样做之后,xasmpyc-xasm 可以转回一个您可以反编译的 pyc 文件。

但是--xasm 选项有一些错误,需要一段时间才能完全消除,所以use what's on github。同样,uncompyle6 目前正在修复与您的情况相关的 Python 3.6 错误,因此use what's on github 也是如此

现在稍微介绍一下毫无疑问是 uncompyle6 的错误。 POP_TOP 丢弃 Python 评估堆栈中的值。例如,当不使用调用的返回值时,可能会发生这种情况——也许调用是它自己的语句。然而,这种未使用的值一直在发生,uncompyle6 像大多数反编译器一样对此感到满意。更有可能的是,有一种非平凡的调用(使用关键字参数,* 或 ** 调用),Python 3.6 现在创建的字节码与它在 3.5 或任何其他先前版本中所做的非常不同。

pycdc 可能会给出答案,并且可能会使用Warning: block stack is not empty! 发出警告

特别是对于 Python 3.6 上的 pycdc 来说,准备进行大量修复,尤其是在函数定义和函数调用方面。您可能也必须对 uncompyle6 做同样的事情,但它可能在语义上更正确。所以修复更多的是关于格式化的方式。

在处理 Python 3.6 方面,uncompyle6 仍有一段路要走,因为 Python 3.6 彻底改变了调用函数(可能是这里的情况)和创建函数时堆栈条目的语义。尽管 Python 3.6 与 3.5 相比发生了巨大的变化,但 3.7 中还有另一个巨大的变化,因此也需要一段时间才能使用。 (见下文关于评级以及这与我可能在项目上花费多少工作的关系)。

至于CALL_FUNCTIONCALL_FUNCTION_0,这是 uncompyle6 工作方式的产物。它使用上下文无关的语法分析器来构建程序的分析树。因此,某些作为指令操作数的信息有时会添加到操作码中,因为解析仅基于操作码进行。这被描述为here,而关于 uncompyle6 工作原理的更大图景被描述为here

最后一点,当我有时间从事某个项目时,我会使用 github 项目的评分(或星级)来决定哪些项目可以工作。 xasm、xdis 的评级可以忽略不计,这部分解释了为什么您会在其中发现错误。 (当然,另一个原因是缺乏时间或其中一些项目的难度)。

即使 uncompyle6 与其他(大部分被废弃的)Python 反编译器相比,也有相当低的评分,这些反编译器已经有一段时间没有工作了,而且做得不太好。

【讨论】:

    猜你喜欢
    • 2021-11-28
    • 1970-01-01
    • 2012-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-01
    • 2018-12-19
    相关资源
    最近更新 更多