制作Python版Jar包

  • A+
所属分类:安全闲碎

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

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

print("hello world")

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

$ zip demo.zip ./*  adding: __main__.py (stored 0%)
$ python3 demo.ziphello 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.zipArchive:  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.gitCloning 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 373Receiving objects: 100% (379/379), 1.12 MiB | 1.04 MiB/s, done.Resolving deltas: 100% (210/210), done.
$ virtualenv envUsing base prefix '/usr'New python executable in /tmp/www/env/bin/python3Also creating executable in /tmp/www/env/bin/pythonInstalling 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, requestsSuccessfully 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),在操作文件系统时可能会出现找不到文件的错误

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

本文始发于微信公众号(代码审计):制作Python版Jar包

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: