Python 的 .egg 文件和 OpenVPN Access Server 破解补丁小研究

近期由于某地方需要一个能推路由且平台兼容性好一点的 VPN(wg 和 IPSec 之类都因为需要本机配路由或是兼容问题不想在 Windows 平台折腾)于是盯上了 openvpn,然后又由于懒得自己折腾 CA,又稍微看了看 openvpn 的收费版本 openvpn access server(简称 ovpnas 或 oas),在不激活的情况下,oas 支持两个设备同时连接,个人自己用其实是够了的,但是我出于好奇搜了一下有没有相关破解,并发现这个所谓的破解就是个 .egg 文件,听说将其替换就能绕过未激活版本的设备限制,于是又稍微花了点时间研究这个所谓的破解是怎么实现的。

声明:本文基于技术研究角度,笔者不支持对商业软件的破解行为,也不会传播相关破解补丁

小谈 .egg 文件

首先了解一下 egg 文件是什么,egg 文件和 whl 一样,是 python 的一种打包重分发文件格式,有句话叫 “Eggs are to Pythons as Jars are to Java”,进一步说,egg 是 pip 出现之前的事实标准,而 whl 是随着 pip 出现的 egg 的后继者,其对比官方有说明:https://packaging.python.org/discussions/wheel-vs-egg/ ,但是实质上,egg 和 whl 都是 zip,它们的处理上大同小异,欲知更多关于 python 打包的问题可以参见:https://blog.zengrong.net/post/python_packaging/ ,本文不主要讨论 python 包的重分发问题,因此只讨论 egg。一个最最简单的 egg 文件都来自于这样的一个 setup.py

可以使用python setup.py bdist_egg命令借助 setuptool 创建一个 egg 文件,创建后的目录大致如此:

easy_install /path/to/egg 即可安装一个 egg 包,但正如先前提到的,egg 是一个比较历史久远的打包格式,实践中基本已经被 whl 所替代,所以最新的 setuptool 甚至已经没有了easy_install,可以手动执行 wget https://bootstrap.pypa.io/ez_setup.py -O - | python 进行安装,注意到安装中也有提示告诉你 ez_setup 已经过时:ez_setup.py is deprecated and when using it setuptools will be pinned to 33.1.1 since it’s the last version that supports setuptools self upgrade/installation, check https://github.com/pypa/setuptools/issues/581 for more info; use pip to install setuptools

一般来说 egg 包会被安装到/usr/local/lib/python2.7/dist-packages/(dist-packages 和 site-packages 的主要区别在于前者是使用包管理器时的安装目录,apt 和 pip 都将文件安装在 dist-packages),然后就可以在 python 交互 shell 或是其他 py 文件中直接 import module

OAS 的破解逻辑

说完了 egg 文件是个啥,回来看看我们最初的目的,由于找到的这个补丁是针对 2.5 版本的,也想看看相同的破解套路能不能用于最新的 2.7.5 版本(这个 egg 文件包含了大部分 OAS 的业务逻辑,直接覆盖当然是不行的)。由于 egg 文件的本质是 zip,直接对 egg 文件解压后和原版解压结果进行 diff,根据 diff 结果发现主要改动在 /pyovpn/lic/uprop.pyo,从文件名来看 uprop.py 是 Usage Properties 的意思,但是 pyo 文件是 python 生成的字节码,我们还需要使用工具对字节码进行反编译,这里使用 https://github.com/rocky/python-uncompyle6 ,用法很简单,uncompyle6 /path/to/pyo > /path/to/py 即可,最终我们看见的实质性破解逻辑就只有这么几行:

发现实际上这个 uprop2 就是原本的 uprop 模块改名,原补丁通过暴力改名的方式将原本去往 uprop 的方法劫持掉,附上原 uprop 模块的部分代码逻辑:

可以看到UsageProperties.figure主要是一系列对授权有效期、授权数量等,然而没有对授权的内容(也就是 concurrent_connections)进行整体的 hash+ 签名防止篡改,因此原补丁使用exec(作用是执行一句或多句语句,和 eval 的主要区别是 exec 在 python2 中是一个内置语句,在 python3 中是函数且永远返回 None,exec 修改的变量可以在当前作用域外生效)直接修改 figure 方法的返回值,令 concurrent_connections 始终为 1024。

通过比对发现 OAS 在 2.5-2.7.5 版本之间验证授权的逻辑没有任何变化,将类似修改应用到最新的 egg 文件即可生效,python -O -m compileall /path/to/pyo 可以将 py 文件重新编译成 pyo(理论上 python runtime 不区分 py 和 pyo/pyc,只要文件名前缀相同就能运行,但是可能性能会差一些),直接将修改后的目录 zip 后覆盖回该 egg 的原本路径,重新初始化 OAS 即可生效。

OAS 很有一贯的老外写的企业级商业软件的风格,可以说是只要稍微有意就没有破解难度,虽然另一方面也是 Python 这种语言本身加密困难的原因,但是想要恶心一下我这种三脚猫选手还是没有什么问题,几个版本都没有改过验证授权逻辑且基本没有做校验和暗桩,相比行业毒瘤某杰某克丁而言实属良心,因此我也无意扩散 OAS 的破解,Just hacking for fun。

版权声明:
作者:心飞翔
链接:https://www.faystar.com/techshare/openvpn/1921.html
来源:心飞翔
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
海报
Python 的 .egg 文件和 OpenVPN Access Server 破解补丁小研究
近期由于某地方需要一个能推路由且平台兼容性好一点的 VPN(wg 和 IPSec 之类都因为需要本机配路由或是兼容问题不想在 Windows 平台折腾)于是盯上了 openvpn……
<<上一篇
下一篇>>