您的浏览器禁用了JavaScript(一种计算机语言,用以实现您与网页的交互),请解除该禁用,或者联系我们。[山石网科]:c10udInk:由浅入深的cython逆向指南 - 发现报告
当前位置:首页/行业研究/报告详情/

c10udInk:由浅入深的cython逆向指南

信息技术2024-08-10-山石网科周***
AI智能总结
查看更多
c10udInk:由浅入深的cython逆向指南

由浅入深的Cython逆向指南 ——c10udlnk. AboutUs 山石网科安全技术研究院 >>>研究方向包括WEB安全、移动安全、智能安全和信创安全等,参编过多份安全标准。 >>>曾为上合峰会、财富论坛、港珠澳大桥的开通等重大活动提供了网络安保工作并获得感谢信。 >>>获得过苹果、红帽等知名企业的官网致谢,连续多年进入微软全球最具价值安全研究员榜 单,公布过多个具有全球影响力的严重漏洞,在Blackhat、Defcon、HITB、CanSecWest等国际安全大会分享过研究成果,获得了诸多CVE漏洞编号。 >>>荣获过红帽杯企业组冠军,补天杯最具价值漏洞奖,强网拟态防御国际精英挑战赛一等奖, 第五空间网络安全大赛特等奖,津门杯国际网络安全创新大赛一等奖,陇警杯网络安全大赛第一名等优异成绩。 AboutMe REerin[NEURON,S1uM4i, Sloth] >>>y[2020]=首次接触Python字节码,从Python不熟练到手撕字节码一天速成。 >>>y[2021:2023]=\ ...研究的魔改pyc越来越多,能直接被反编译的都是时代的眼泪; ...分析了Python字节码隐写工具stegosaurus,在版本不兼容的情况下手动抠出一个flag,赛后做了一些魔改使其兼容Python3.10(https://github.com/c10udlnk/stegosaurus); ...Python逆向开始卷到了Cython,静态分析慢慢上手,结合动态交互开始能解出flag了。 >>>y[2023]=毕设选题做的是Python代码保护相关,深入研究了Oxyry、pyc_obscure、Py***or等混淆保护,设计了一套加密器。 >>>y[2024]=结合xasm实现对手撕字节码的自动化(https://github.com/c10udlnk/dis2xasm)。 >>>目前正在研究Cython逆向的自动化(https://github.com/c10udlnk/cythonHelper)。 >>>#吃灰博客:https://c10udlnk.top/ 初探Cython及Cython逆向 Cython是什么? 和Python、CPython的关系CTF逆向中的Cython 关于Cython >>>https://cython.org/ >>>https://github.com/cython/cython >>>一个基于Pyrex的Python编译器,它使为Python编写C扩展就像编写Python本身一样简单。 >>>将代码段从动态Python语义移动到静态且快速的C语义,并可以直接操作外部库中定义的类型。 >>>源代码被转换为优化的C/C++代码并编译为Python扩展模块,从而加快了程序的执行速度,并可与外部C库紧密集成,同时保持Python语言的编写简易性。 >>>#关于Python的C扩展:https://docs.python.org/zh-cn/3/extending/extending.html >>>#“C扩展接口特指CPython,扩展模块无法在其他Python版本上工作。在大多数情况下,应该避免写C扩展,来保持可移植性。举个例子,如果你的用例调用了C库或系统调用,你应该考虑使用ctypes模块或cffi库,而不是自己写C代码。” 编写Python的C扩展 >>>添加C函数到扩展模块: >>>在模块的methodtable中添加对外调用接口: >>>在模块的定义结构中引用,并创建C扩展的EntryPoint: 用Cython编写Python的C扩展 >>>直接用Python编写 >>>cythonize一把梭 >>>然后就拥有了对应的C扩展文件和编译好的库 Cython?Python?CPython? >>>Cython=一个可以将Python转化为C的编译器,也是一种语言(Python的超集) >>>Python=一种众所周知的编程语言,可以让你快速工作并更有效地集成系统。 >>>CPython=Python解释器的源码,并给用户提供Python-CAPI支持以编写C扩展 ...#(https://github.com/python/cpython) PythoninCTFReverse >>>在源码层面混淆Python代码或只提供字节码文本 >>>.pyc字节码文件#pyc反编译 >>>魔改的.pyc字节码文件#修改魔改部分,反编译 ...修改或删除文件头 ...co_code中插入花指令 ...在冗余字节中嵌入密钥 ...魔改Python解释器+仅可用该解释器运行的代码 >>>Pyinstaller打包#解包,pyc反编译 >>>cython编译的扩展(.pyd/.so)#人工手撕+动态 ...给main函数,扩展中写入容易猜的加密(如xor) ...main函数中只写调用逻辑,全部加密都在扩展中 ...#Pyinstaller打包时对import进来的Python代码 都会调用Cython来编译以加快调用速度;或者单给扩展和代码。 Cython逆向之动态取巧与静态硬看 动态import,摸清大概思路静态分析,补充函数细节 动静结合,将flag收入囊中 通过动态交互来取巧解题 >>>首先判断给的扩展的文件格式和对应Python版本。 ...#有些题目看文件名就知道这些信息了,但大部分题目会改掉文件名 ...可见是Linux中编译的扩展,x86-64。 ...Python版本为3.10。 通过动态交互来取巧解题 >>>我们使用对应平台和架构的环境,运行对应版本的Python,即可成功导入该模块。 ...使用dir可以看到该模块对外的函数接口和全局变量: ...k是全局变量,可以轻松看到它的值。 ...而checkFlag和enc这两个函数由于是cyfunction,所以没办法使用类似dis等模块套出它们的字节码,因为它们这类在C层面上编写的函数根本就没有Python字节码:) 通过动态交互来取巧解题 >>>不过,我们还有其他方法可以旁敲侧击函数的一些性质。 ...比如co_varnames里包含其用到的变量名(参数+局部变量),co_argcount表示其参数个数,与 co_varnames结合就知道这个函数的参数名和用到的局部变量名了。 >>>当然,我们还可以实际调用这两个函数,来测试其功能,甚至还有一些可以通过触发报错来探测逻辑: ...一眼xor了属于是。#当然一些题目会banTraceback 通过动态交互来取巧解题 >>>假设没有Traceback,只有报错类型,同样也能测试出一些细节。 >>>chal.enc(1) TypeError:'int'objectisnotsubscriptable ...说明传入的参数是个可切片的数据类型,比如字符串或者列表。 >>>chal.enc([1,2]) TypeError:ord()expectedstringoflength1,butintfound ...说明参数需要是char。 >>>chal.enc("aaabc") IndexError:stringindexoutofrange ...说明参数长度不够,逐个长度爆破直到不报错为止。 >>>chal.enc("aaabcaaaaaaaaaa")IndexError:stringindexoutofrange >>>chal.enc("aaabcaaaaaaaaaaa") [53,9,8,17,42,18,32,42,4,24,64,64,64,64,64,64] ...现在知道了参数a的一些信息:需要长度为16的字符串。 通过动态交互来取巧解题 >>>我们前面输出的k刚好也是16字节,那首先可以猜一些一一对应的常见加密方法,比如xor;或者密钥块和明文块的长度都为16的对称密码算法,比如AES、SM4等,或使用了ECB加密模式(没有iv)的IDEA、Blowfish、TEA系列等,或密钥长度和明文长度不定的流密码如RC4等。#RE主打一个猜 ...总之一种种加密试过去,在该题被解出的次数多/难度不大/比赛不难的情况下很容易猜出来。 通过动态交互来取巧解题+是时候来点静态分析了 >>>那么该题只剩被比对的数组没有获取到了。 >>>常量在动态交互中获取不到,反编译.so文件试试(以ghidra为例): ...可以看到这里有一个plVar11=(long*)PyList_New(0x10);,开了一个长度为16的列表,而后有一系列赋值过程,这个很有可能就是我们要的数组。 ...这些全局变量可以通过找交叉引用找到它们代表的PyObject: ...DAT_0010cad8=PyLong_FromLong(0x6d),代表DAT_0010cad8这个变量其实是0x6d的PyObject,可以理解为plVar11[0]=0x6d,以此类推可以拿到这个被比对数组。 ...#pplVar1=(long**)plVar11[3] ...#=plVar11.ob_item 动态交互还有—— >>>Hook大法好! >>>可以将任何自定义的函数代替扩展里原来的函数。 ...定义一个函数hook_func,尽量还原该函数原本功能(不影响后续处理),插入print; ...使用MOD.dict["func"]=hook_func将自定义函数挂进去; ...调用函数,get中间值。 >>>函数越多越细,接口越多,就能获取越多的中间值。 通过静态分析来解题 >>>静态分析是在动态交互测试无法完全摸透函数逻辑的情况下才用的方法,一般用以摸清细节。 ...初接触时会觉得很复杂,摸熟了以后就很快上手了。 >>>全局代码一般位于pyx_pymod_exec_MODNAME(MODNAME为该模块的名字)通常其中还包括一些常量的初始化、ifmain、全局变量和函数的定义等。#如果不知道主要逻辑在哪个函数里一般就逆这个函数 >>>定义的函数一般以pyx_pw_*的形式,直接在函数表里搜需要的函数即可: 通过静态分析来解题 >>>静态分析.难点=Cython包装的框架代码+Python代码的一对多+特别长的反编译结果 >>>静态分析.关键点=排除无用的框架代码+(熟悉一些常见连招,分块逐个击破)+细心 ...#连招可以通过自己编一个Cython扩展、比对反编译结果和C代码,来进一步熟悉。 >>>无用(不影响函数逻辑)的框架代码包括: ...ErrorHandle ...引用计数的维护 ...对某些API调用的N重保障 >>>警惕函数套娃: ...#高版本的Cython会上wrapper,这里的param_2就是实际调用的参数对象 通过静态分析来解题-CbyCython pyx_t_2=b2i x=b2i(inp,inp_idx) pyx_t_1=pyx_t_2(pyx_v_inp,pyx_v_inp_idx) pyx_v_x=pyx_t_1 通过静态分析来解题-反编译byGhidra plVar5=b2i x=b2i(inp,inp_idx) (ErrorHandle) pyx_n_s_*是通过工具处理后的符号,原反编译结果中没有 通过静态分析来解题-反编译byGhidra (维护引用计数&& ErrorHandle) x=b2i(inp, plVar4=b2i(param_1,param_2) (ErrorHandle) inp_idx) 通过静态分析来解题-反编译byGhidra x=b2i(inp, pyx_n_s_*是通过工具处理后的符号,原反编译结果中没有 inp_idx) 通过静态分析来解题的一些常见小连招 >>>数字之间的运算通常调用PyNumber_*,少部分会直接用C的运算符 plVar13=(long*)PyNumber_O