当前位置: 首页 > 科技观察

python编译的pyd爆破

时间:2023-03-14 14:20:08 科技观察

最近接触到一个国外app的协议软件,是用python3.8写的。它将所有关键模块编译成pyd,然后使用pyinstaller打包发布给用户。软件启动后会检查机器码,然后需要输入授权码才能使用。它看起来很烦人,所以我想尝试破解它。关键应该是爆破pyd中的逻辑,修改汇编代码绕过授权。必备知识1.py、pyc、pyo、pydpy:python脚本文件(源代码)pyc:由编译器编译的脚本文件、二进制文件、python文件编译而成的字节码。可以提高文件加载速度。pyo:脚本文件启用优化编译选项(-O)来编译字节码、二进制文件和优化编译文件。可以通过python-Ofile.py生成。pyd:基本的WindowsDLL文件,python的动态链接库。2.编译pyd要编译的脚本:uitl1.pydeffun_hello(s):ifs==1:return'helloworld'elifs==2:return'222222222'提供编译脚本:setup.pyfromsetuptoolsimportsetupfromCython.Buildimportcythonizesetup(name='test',ext_modules=cythonize('util1.py'))在setup.py文件所在目录执行如下命令:pythonsetup.pybuild_ext--inplace这样就可以看到pyd文件是在同一个目录下生成的目录。32位的python生成的pyd文件是32位的,64位的python生成的是64位的。3.使用pydtest.pyimportutil1if__name__=='__main__':print(util1.fu??n_hello(2))4。pyinstallerpackagepytoexepiinstallpyinstallerpyinstallertest.py5。解压pyinstaller打包好的exepyinstxttractor.py。这段代码不长,大家可以调试一下,熟悉一下打包后的exe组成。需要注意的是,打包后的文件是经过zlib.compress压缩后以固定格式组合成exe的,所以直接修改打包后的exe的16进制码来爆破似乎比较困难。只能解包后修改pyd,然后找到所有的依赖库,重新打包pyinstaller,实现爆破。https://github.com/countercept/python-exe-unpacker6.pyc反编译uncompyle6支持python3.8的pyc的反编译。需要注意的是,如果是pyinstaller解压后得到的pyc文件,文件头部的magic已经被抹掉了,所以需要加上相应版本python的magic,安装相应版本的即可python,然后到安装目录下找一个pyc文件,看header,然后用010Editor复制到解压后的pyc中,就可以正常反编译了。下图是python3.8_32的魔头:https://github.com/rocky/python-uncompyle6pyd文件汇编代码和python脚本对应分析前面的前提知识可以搜索一下。但是我们如何直接修改pyd的汇编代码来实现python脚本流程的改变呢?在百度和谷歌上找了半天也没找到合适的资料。可能很少有人破解python编译打包的exe。所以下面就是我做的工作,也是这个帖子的价值所在。我自己写了一个小的python脚本,然后编译成pyd,会生成一个中间的util1.c文件,大概有3000行代码。只要你花时间和精力去熟悉这个c文件,再和ida对比一下,就可以明白python脚本转成C再编译成汇编指令,它们之间有一个大致的对应关系。下面略过1天左右的工作量,直接展示拿到pyd后如何快速找到我们要找的关键python代码。然后直接爆。将要分析的pyd文件拖到对应的32位或64位IDA中:大概所有的pyd都只有这一个导出功能。当这个pyd模块被其他py脚本导入时,会调用这个导出函数来初始化模块。跳转到dword_1000634C以查看具有关键成员__pyx_moduledef_slots的结构。该成员是一个结构数组。有一个关键函数__pyx_pymod_exec_util1,它负责初始化python脚本中的所有变量、函数、常量等,将它们映射到pyobjects,然后只使用这些pyobjects。所以编译时很难看出过程,因为没有明显的明文。定位到__pyx_pymod_exec_util1之后,我们的主要目的是找到常量和pyobject的对照表,以及python脚本中的函数名和汇编函数的对照表。有了这两张表,python脚本和程序集的对应关系就一目了然了。在这里你只能手动向下滚动。转到一个类似调用PyUnicode_InternFromString的地方,大概就是我们要找的常量对照表。那就是C文件中的表。其中,offsetdword_10006DFC是代表字符串“222222222”的pyobject。您可以通过直接查找其交叉引用来定位一些关键代码。我们继续在__pyx_pymod_exec_util1中找到汇编函数对应的python脚本函数表。跳过:aFunHello指向python脚本中的函数名。__pyx_pf_5util1_fun_hello是对应的汇编函数。可见,只要找到这张表,就很容易定位到我们要找的python脚本函数对应的程序集实现。其实我们大可不必像上面那么麻烦。只需仔细检查.data部分。或者字符串窗口可以通过查找感兴趣的字符串交叉引用快速找到这个表。你需要知道的是,aFunHello下面是对应的程序集实现函数。现在终于可以分析python脚本函数fun_hello对应的汇编函数了。可以看到脚本中s==1对应的程序集是__Pyx_PyInt_EqObjC,然后会用PyObject_IsTrue来判断这个函数的返回值。然后找到断点。将jzshortloc_10004753更改为jnzshortloc_10004753。IDA-》编辑-》补丁程序-》汇编修改,然后IDA-》编辑-》补丁程序-》对输入文件打补丁,得到修改后的pyd文件。这样就实现了修改python脚本的执行逻辑。正常的脚本应该输出22222222,因为我们的爆破输出的是helloworld!这里我只是简单分析一下if语句的修改,可以再写几个例子。实施对其他流程的修改。我只是在这里闲逛,给你一点参考。节省一点时间。另:看了半天大家都以为我在分析国外的app协议软件。其实我还没有解决破解,所以只贴出这段时间的分析工作,仅供参考。