转载

制作Python版Jar包

Java的Jar包是一个很方便的功能,特别是对于拥有大量依赖的程序,只需要将所有内容打包成一个jar包,即可分发给用户直接使用。

Python也是支持类似的功能的。我们可以尝试创建一个 __main__.py 文件:

print("hello world")

然后将其用zip打包,并且直接用python执行:

$ zip demo.zip ./*

adding: __main__.py (stored 0%)


$ python3 demo.zip

hello world

制作Python版Jar包

成功输出“hello world”。这说明Python同样支持使用一个包的方式来执行一个程序。

原理支撑

Python文档: https://docs.python.org/3/library/zipimport.html 中描述了zipimport模块:

This module adds the ability to import Python modules ( *.py , *.pyc ) and packages from ZIP-format archives. It is usually not needed to use the zipimport module explicitly; it is automatically used by the built-in import mechanism for sys.path items that are paths to ZIP archives.

zipimport支持Python从一个压缩包中导入模块,但是实际上我们平时不需要直接调用这个zipimport,因为Python默认的 import 语法是支持在压缩包里搜索模块的。

比如,我们拥有一个example.zip,其中包含模块 jwzthreading.py ,我们只需要将这个zip文件加入 sys.path ,在导入模块时就会在example.zip里搜索:

$ unzip -l example.zip

Archive: example.zip

Length Date Time Name

-------- ---- ---- ----

8467 11-26-02 22:30 jwzthreading.py

-------- -------

8467 1 file

$ python

>>> import sys

>>> sys.path.insert(0, 'example.zip') # Add .zip file to front of path

>>> import jwzthreading

>>> jwzthreading.__file__

'example.zip/jwzthreading.py'

Python执行zip文件也是类似原理,而我们提供的 __main__.py 只是一个执行入口。

那么,我们如何将一个Python工具打包成一个独立的zip包并使用呢?

如何打包

我以常用的子域名发现工具 Sublist3r 为例,首先,拉取Sublist3r源码,并创建一个干净的Python虚拟环境:

$ git clone https://github.com/aboul3la/Sublist3r.git

Cloning into 'Sublist3r'...

remote: Enumerating objects: 6, done.

remote: Counting objects: 100% (6/6), done.

remote: Compressing objects: 100% (4/4), done.

remote: Total 379 (delta 2), reused 6 (delta 2), pack-reused 373

Receiving objects: 100% (379/379), 1.12 MiB | 1.04 MiB/s, done.

Resolving deltas: 100% (210/210), done.


$ virtualenv env

Using base prefix '/usr'

New python executable in /tmp/www/env/bin/python3

Also creating executable in /tmp/www/env/bin/python

Installing setuptools, pip, wheel...

done.

再在这个虚拟环境里安装Sublist3r的一些第三方依赖:

$ source env/bin/activate


$ pip install -r Sublist3r/requirements.txt

Collecting argparse

Using cached argparse-1.4.0-py2.py3-none-any.whl (23 kB)

Collecting dnspython

Using cached dnspython-1.16.0-py2.py3-none-any.whl (188 kB)

Collecting requests

Using cached requests-2.23.0-py2.py3-none-any.whl (58 kB)

Collecting urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1

Using cached urllib3-1.25.9-py2.py3-none-any.whl (126 kB)

Collecting chardet<4,>=3.0.2

Using cached chardet-3.0.4-py2.py3-none-any.whl (133 kB)

Collecting idna<3,>=2.5

Using cached idna-2.9-py2.py3-none-any.whl (58 kB)

Collecting certifi>=2017.4.17

Using cached certifi-2020.4.5.1-py2.py3-none-any.whl (157 kB)

Installing collected packages: argparse, dnspython, urllib3, chardet, idna, certifi, requests

Successfully installed argparse-1.4.0 certifi-2020.4.5.1 chardet-3.0.4 dnspython-1.16.0 idna-2.9 requests-2.23.0 urllib3-1.25.9

此时,虚拟环境中包含了所有需要的依赖了。然后,我们将Sublist3r的源码拷贝到虚拟环境的 lib/python3.6/site-packages 目录下:

$ cp -r Sublist3r/subbrute Sublist3r/sublist3r.py env/lib/python3.6/site-packages

这时候,整体的环境就做好了,但是我们还需要一个入口文件,也就是 __main__.py 。我们可以直接将 env/lib/python3.6/site-packages/sublist3r.py 改名为 env/lib/python3.6/site-packages/__main__.py ,再打包即可:

$ cd env/lib/python3.6/site-packages


$ mv sublist3r.py __main__.py


$ zip -r sublister.zip ./

打包完成后大小有6MB,即可在任意有Python3的环境下直接运行了: 制作Python版Jar包

优势和缺点

这个特性具体有哪些优势和用处呢?我觉得主要可能在下面这些场景用到:

  • Python命令行工具,比如这里的Sublist3r,使用zip的形式一键分发,任意环境下使用,不再需要安装依赖,更加方便

  • 内网渗透或运维没有网络的场景下,无法使用pip,有些工具不方便安装,使用zip的形式也能摆脱这些烦恼

  • 可能会有杀毒软件只针对了Python文本恶意文件进行检测,但没有考虑压缩包的形式,导致可以使用这种形式免杀

但实际使用中,这个特性的缺点也更加明显:

  • 根据文档和实际测试发现,在import时只会搜索压缩包里的 *.py *.pyc 文件,如果你的工具依赖了 *.so *.pyd 等native模块,则会出现找不到模块的错误

  • 很多软件没有考虑被放在压缩包里执行的情况(如sqlmap),在操作文件系统时可能会出现找不到文件的错误

更多具体的使用优缺点,大家可以自己体验体验,在留言里告诉我。

原文  https://mp.weixin.qq.com/s/FaXlzVhcgwZ-W4yp4nkStA
正文到此结束
Loading...