用 Python 编写的逆向工程程序,用“freeze”编译

逆向工程 Python
2021-06-26 05:25:49

我正在尝试对使用 Python 附带的实用程序“Freeze”或“pfreeze”编译的 EXE 进行逆向工程(不要与“cx_freeze”混淆)。在 EXE 中,有一个名为PyImport_FrozenModules. 当程序启动时,该数组将填充程序字节码(又名 .pyo/.pyc 文件)。我已经研究这个几个月了,我有点停滞不前。我需要找到一种方法来从该数组中提取字节码。该程序最初连接到服务器,因此一旦执行 EXE,它会在崩溃之前运行大约 10-20 秒。为了延长 10-20 秒,我需要暂停程序(这很容易用“进程资源管理器”完成)

我需要帮助的实际上是倾倒PyImport_FrozenModules.pyc,这样我就可以获取 .pyc 并从那里继续。

我已经能够做到这一点: 在此处输入图片说明
链接:http : //gyazo.com/83bcde5240df7fb9ec34e7e3de7699ba

通过在像 ollydbg 这样的调试器中加载 exe,找到导入的行,然后将它们设置为 NOP'S。有人说我必须为此编写脚本,而其他人说这比我想象的要容易。我只是不知道从哪里开始。

任何帮助表示赞赏。谢谢。

1个回答

在这种情况下,您应该这样做。

第 1 步:在像 Ollydbg 这样的调试器中加载可执行文件。

第 2 步:在内存转储窗口中,PyImport_FrozenModulesCtrl+导航到G

第 3 步PyImport_FrozenModules是一个指针,它被初始化为指向一个struct _frozen记录数组跟随这个指针在dump.

第 4 步:现在您处于有_frozen结构数组的位置该结构定义为

struct _frozen {
    char *name;
    unsigned char *code;
    int size;
};

上述数组由其所有成员都为空的结构终止。

第五步:在上面的结构中,第一个成员是指向冻结模块名称的指针,第二个成员是一个指向模块字节码的指针。(这就是你要找的东西)最后一个成员将为您提供字节码的大小(以字节为单位)。使用大小,将字节码转储到文件中。

第 6 步:您刚刚转储的字节码不包含 pyc 文件的魔术头值(对于 python 2.7,这是 03 F3 0D 0A,后跟 4 字节时间戳) 添加头,现在文件应该被反编译 -有能力的。

要自动执行上述过程,您还可以编写一个脚本。


更新

这是一个 PyCommand(一个免疫调试器脚本)来转储冻结的模块。您需要在加载所有冻结的模块后运行脚本。为此,您可以在函数上设置断点,PyImport_ImportFrozenModule()以便您可以在加载时跟踪每个冻结的模块。如果您是 Immunity Debugger 的新手,请查看

import immlib

DESC = 'PyCommand to dump frozen python modules'
PYTHONMAGIC = '\x03\xF3\x0D\x0A\x00\x00\x00\x00' # Change this value according to the version of python used. The value given here is for Python 2.7

'''
Run this pycommand when all frozen modules are loaded.
This will dump each frozen module in a .pyc file in 
immunity debugger installation directory
'''

def main(args):
    imm = immlib.Debugger()
    addr = imm.getAddress('PyImport_FrozenModules')
    structAddr = imm.readLong(addr)

    while True:
        ptrToName = imm.readLong(structAddr)
        ptrToCode = imm.readLong(structAddr + 4)
        sizeOfCode = imm.readLong(structAddr + 8)
        structAddr += 12

        # The array is terminated by a structure whose members are null
        if ptrToName == 0 and ptrToCode == 0 and sizeOfCode == 0:
            break

        if sizeOfCode > 0 and sizeOfCode < 2147483647:            
            moduleName = imm.readString(ptrToName)
            moduleCode = imm.readMemory(ptrToCode, sizeOfCode)

            # You can change the output path here
            open(moduleName + '.pyc', 'wb').write(PYTHONMAGIC + moduleCode) 

    return '[*] Frozen modules dumped'

转储冻结的模块后,对生成的pyc文件使用反编译器您可以为此使用Easy Python Decompiler