首页
社区
课程
招聘
[原创] Python 分发的文件类型及解析
发表于: 2019-12-10 13:22 7960

[原创] Python 分发的文件类型及解析

2019-12-10 13:22
7960

介绍

在实际开发中,Python作为解释型语言,在实际的代码分发过程中,有比较多的格式定义:.pyc\.pyd\.pyo\.pyz。一直想对它们理一下,东拼西凑的整理了下面的内容,主要也回答了自己的一些问题。

文件介绍

.pyc : python编译后的二进制文件

当您导入一个模块时,类型为.pyc的文件将由解释器自动生成,这将加速该模块未来的导入。因此,这些文件仅在由另一个.py文件或模块导入时从.py文件创建。

注意,使用.pyc文件只会加快程序的加载速度,而不会加快程序的实际执行速度。这意味着您可以通过在一个模块中编写主程序来提高启动时间,这个模块由另一个更小的模块导入。

pyc主要写入三个内容:

1.       Magic num

2.       Pyc创建时间

3.       PyCodeObject.(python/marshal.c)

Python在不同的版本,pyc的头部长度和内容是不同的:

l  PEP 3147:


.pyc文件包含两个32位大端数字,后面跟的序列化的PyCodeObject。32位数字表示一个Magic Num和Timestamp。每当Python改变字节码格式时,Magic Num会改变,例如,通过向其虚拟机添加新的字节码。这确保为以前版本的VM构建的pyc文件不会造成问题。Timestamp用于确保pyc文件与用于创建它的py文件匹配。当Magic Num或Timestamp不匹配时,将重新编译py文件并写入新的pyc文件。

l  PEP 552:


pyc头文件目前由3个32位的字组成。我们将把它扩大到4个。第一个单词将继续是magic number,对字节码和pyc格式进行版本控制。第二个4byte新增加的字段,将是一个位字段(bit field),对报头其余部分的解释和pyc的失效行为取决于位字段的内容。

如果位字段(bit field)为0,则pyc是传统的基于时间戳的pyc。即第三个和第四个4字节内容分别是时间戳和文件大小,通过比较源文件的元数据和头文件中的元数据来进行无效判断。

如果位字段的最低位被设置,则pyc是基于哈希的pyc。我们将第二个最低位称为check_source标志。位字段之后是源文件的64位散列。我们将使用带有源文件内容硬编码密钥。另一个类似MD5或BLAKE2的快速散列也可以。我们选择SipHash是因为Python已经从PEP 456中获得了它的内置实现,尽管允许选择SipHash键的接口必须公开给Python。散列的安全性不是一个问题,尽管我们传递完全破碎的散列(如MD5)来简化在受控环境中对Python的审计。



对于Magic值,它的逻辑为:后2bytes为0D0A,前面的值满足:  [min, max]范围,版本信息定义参考结构内容,示例分析代码如下:


Magic Num(4 bytes)

```

typedef struct {

    unsigned short min;

    unsigned short max;

    wchar_t version[MAX_VERSION_SIZE];

} PYC_MAGIC;

static PYC_MAGIC magic_values[] = {

    { 50823, 50823, L"2.0" },

    { 60202, 60202, L"2.1" },

    { 60717, 60717, L"2.2" },

    { 62011, 62021, L"2.3" },

    { 62041, 62061, L"2.4" },

    { 62071, 62131, L"2.5" },

    { 62151, 62161, L"2.6" },

    { 62171, 62211, L"2.7" },

    { 3000, 3131, L"3.0" },

    { 3141, 3151, L"3.1" },

    { 3160, 3180, L"3.2" },

    { 3190, 3230, L"3.3" },

    { 3250, 3310, L"3.4" },

    { 3320, 3351, L"3.5" },

    { 3360, 3379, L"3.6" },

    { 3390, 3399, L"3.7" },

    { 3400, 3419, L"3.8" },

    { 0 }

};

```

已经知的一些Magic例子

Timestamp (4bytes)

1970.01.01到产生pyc时候的秒数.

PyCodeObject:

这个对象比较复杂,不展开,可参考一个整理进行了解,不同的版本还会有变化。


python27参考

.pyo文件

.pyo文件类型也是由解释器在导入模块时创建的。但是,.pyo文件是在启用优化设置时运行解释器的结果。

当我们调用Python解释器时,通过添加“-O”标志来启用优化器。下面是一个代码示例,演示如何使用优化。首先,我们有一个定义lambda的模块。在Python中,lambda就像一个函数,但是定义得更简洁。

.pyd文件

.pyd文件类型是特定于Windows操作系统类平台的。因此,在个人版和企业版的Windows 10、Windows 8、Windows 7和其他版本中可能经常遇到这种情况。

在Windows生态系统中,.pyd文件是一个包含Python代码的库文件,可以被其他Python应用程序调用和使用。为了使这个库对其他Python程序可用,它被打包为一个动态链接库。

动态链接库(dll)是在运行时链接到调用程序的Windows代码库。在像dll这样的运行时链接到库的主要优点是,它促进了代码重用、模块化架构和更快的程序启动。因此,dll提供了许多与Windows操作系统相关的功能。

.pyd文件是一个动态链接库,它包含一个Python模块,或一组模块,由其他Python代码调用。要创建.pyd文件,需要创建一个名为example.pyd的模块。在这个模块中,您将需要创建一个名为PyInit_example()的函数。当程序调用这个库时,它们需要调用import foo, PyInit_example()函数将运行。

.pyz文件: executable python zip archives

具体内容参见:ZlibArchive

PyInstaller打包

Python打包文件

打包文件是包含其他文件的文件,例如.tar文件、.jar文件或.zip文件。PyInstaller中使用了两种存档。一个是ZlibArchive,它允许高效地存储Python模块,并通过一些导入钩子直接导入。另一个是CArchive,类似于.zip文件,这是一种打包(或压缩)任意数据块的通用方法。它的名字来源于这样一个事实,即它可以很容易地从C和Python中操作。这两个类都来自一个公共基类,这使得创建新类型的归档变得相当容易。

ZlibArchive

ZlibArchive包含压缩的.pyc或.pyo文件。spec文件中的PYZ类调用创建了一个ZlibArchive。

ZlibArchive中的目录是一个Python字典,它的Key(import语句中给定的成员名)与ZlibArchive中的查找位置和长度相关联。ZlibArchive的所有部分都以编组格式存储,因此与平台无关。

ZlibArchive在运行时用于导入绑定的python模块。即使使用最大压缩,这也比正常导入快。而不是搜索系统。路径,在字典里有一个查找。没有目录操作,也没有要打开的文件(该文件已经打开)。只有一次搜索,一次读取和一次解压。

Python错误跟踪将指向创建归档条目的源文件(.pyc编译、捕获并保存到归档时的_file__属性)。这不会告诉您的用户任何有用的东西,但是如果他们向您发送Python错误跟踪,您可以理解它。


ZlibArchive文档结构

CArchive

CArchive可以包含任何类型的文件。它很像一个.zip文件。它们很容易用Python创建,也很容易从C代码中解包。CArchive可以附加到另一个文件,比如ELF和COFF可执行文件。为了实现这一点,存档是在文件的末尾用它的目录创建的,后面只跟一个cookie,它告诉目录从哪里开始以及存档本身从哪里开始。

CArchive可以嵌入到另一个CArchive中。内部存档可以在适当的地方打开和使用,而不必提取它。

每个目录条目都有可变的长度。条目中的第一个字段给出了条目的长度。最后一个字段是相应打包文件的名称。名称以空结尾。压缩对于每个成员都是可选的。

还有一个与每个成员相关联的类型代码。类型代码由自提取的可执行程序使用。如果使用CArchive作为.zip文件,则不必担心代码。

ELF可执行格式(Windows、GNU/Linux和其他一些格式)允许将任意数据连接到可执行文件的末尾,而不影响其功能。因此,CArchive的目录在归档的最后。可执行文件可以以二进制文件的形式打开自己,查找到最后并“打开”CArchive。


Carchive结构


自解压执行文件结构

解析工具

pyi-archive_viewer

可以检查和提取任何使用PyInstaller (PYZ或PKG)构建的归档文件的内容,或任何可执行文件(.exe文件或ELF或COFF二进制文件)的内容。

简单点说是:支持对pyinstaller打包的exe和pyz文件进行内容查看和提取。需要说明:提取出来的pyc文件缺少头部信息,需要自己添加上,具体的头部信息需要根据上面提到的头部版本进行添加。

pyinstxtractor.py

支持对.exe文件的内容进行分析和提取(因为作者没有更新了,功能支持有限,其实它也支持pyz的提取,只是没有单独列出来)。

pyc/pyo解析:

功能强大的在线工具:https://python-decompiler.com/ ,比较之下比uncompile6和Easy python Decompiler 要兼容的情况多。

参考:

https://kdr2.com/tech/python/pyc-format.html

https://www.python.org/dev/peps/pep-0552/

https://www.python.org/dev/peps/pep-3147/

https://docs.python.org/3/library/zipapp.html

https://nedbatchelder.com/blog/200804/the_structure_of_pyc_files.html

http://code.activestate.com/recipes/577880-inspect-a-pyc-file/

https://qiita.com/amedama/items/698a7c4dbdd34b03b427

https://pyinstaller.readthedocs.io/en/stable/advanced-topics.html#the-bootstrap-process-in-detail


[课程]Android-CTF解题方法汇总!

最后于 2019-12-16 11:57 被nevinhappy编辑 ,原因: 上传附件。
上传的附件:
收藏
免费 5
支持
分享
最新回复 (5)
雪    币: 21449
活跃值: (62253)
能力值: (RANK:125 )
在线值:
发帖
回帖
粉丝
2
感谢分享!
2019-12-10 13:51
0
雪    币: 1706
活跃值: (9630)
能力值: ( LV13,RANK:385 )
在线值:
发帖
回帖
粉丝
3
感谢分享.好文章.
2019-12-10 14:21
0
雪    币: 1048
活跃值: (65)
能力值: ( LV1,RANK:10 )
在线值:
发帖
回帖
粉丝
4
又发现大佬一枚
2019-12-12 16:35
0
雪    币: 1457
活跃值: (29)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
不错不错
2019-12-17 16:01
0
雪    币: 42
活跃值: (1506)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
6
写的非常仔细了,可惜少写一部分内容:pyd文件的解析之后没有研究和如何通过pyd还原py源代码。
2020-2-8 23:49
1
游客
登录 | 注册 方可回帖
返回
//