Python Ast用于混淆。
Python Obfuscation Ast
简介
和一般高级语言差不多,Python也有构建抽象语法树的一环。此ast
模块就是用于此的。平时编程用处不多,但是由于能够操作ast
结点,所以能实现混淆。
基本使用
解析
1 | test = r"print('Hello')" |
打印
Py39以上支持
indent
参数,用于格式化打印。
1 | ast.dump(mod) |
编译且执行
compile
是内置函数,非ast
模块内函数。
1 | # compile(source, filename, mode, flags=0, dont_inherit=False, optimize=-1) |
概念解释
Python代码的三种形式
高级语言源码
普通的.py
文件。
AST抽象语法树
中间表示形式。一般用不上。供编译器使用,用于编译优化。本篇重点。
字节码
.pyc
文件
完全转化成了字节码文件。供CPython VM
虚拟机解释执行。人类难以阅读。
Modes
源代码到AST的编译过程可以以三种不同模式进行。AST的根节点依赖于传递给ast.parse()
的mode
参数,并且在从AST到目标代码的编译过程中传递给compile()
传递相同的mode
参数。
exec
:默认值是mode='exec'
。AST的根节点是ast.Module
,根节点的属性body
是一个子节点的列表。eval
:单独的表达式可以被编译为mode='eval'
的AST对象,AST的根是一个ast.Expression
,他的属性body
是一个单节点,例如ast.Call
或者ast.BinOp
。把这个AST对象传递给eval()
将会返回表达式的值。single
:单独的语句或者表达式可以被编译为mode='single'
的AST对象,AST的根是ast.Interactive
,它的属性body
是一个子节点的列表。如果这是一个表达式,sys.displayhook()
将会被调用并传入表达式的结果,就如同Python的交互式界面被调用了一样。
修正行列号
后文“删除节点”一块会用上。
编译出的AST对象,每一个节点都必须有行列号属性lineno
并且col_offset
。从普通源代码编译而来的AST对象已经具有了行列号。但是在程序中动态创建的节点没有行列好,有几个helper functions
可以做修正行列号。
ast.fix_missing_locations()
通过父节点的行列号递归的修正所有缺失行列号的节点。ast.copy_location()
用于从另一个节点拷贝行列号. 特别是当做节点替换的时候有用。ast.increment_lineno()
增加一个节点和其子节点的行号,一般用于把代码块移动到其他位置。
to Source
Python标准库不提供一种从字节码到AST,或者从AST到源码转化的办法。但一些第三方工具可以实现这些:
astor
可以把AST转化为可读的Python源码。Meta
also tries to decompile Python bytecode to an AST, but it appears to be unmaintained.uncompyle6
反编译器(反编译器的局限性都很大)
浏览与修改AST
NodeVisitor
NodeTransformer
NodeVisitor
1 | class NodeVisitor(builtins.object) |
NodeVisitor
用于浏览AST结点。官方文档上说不要使用此类来修改结点。但是我看很多博客照样用这个。不过官方特制的NodeTransformer
在修改节点上显然更优秀一点。
实际上也是可以用于修改的。
修改操作符
1 | m = "print(3%4)" |
NodeTransformer
1 | class NodeTransformer(NodeVisitor) |
删除结点
尝试删除if-else
中的else
分支
1 | data = """ |
混淆
字符串混淆
将所有的字符串转变成两个子字符串相加的形式。
1 | from ast import NodeTransformer, BinOp, Str, Add |
混淆示例
1 | import ast |
取自于
Python Source Obfuscation using ASTs | Development & Security (jbremer.org)
且进行了修改,将其从Py27移植到Py3。
不过codegen
模块似乎还是Py27的,所以有问题,暂时没用。
可视化(未实验)
1 | pip install graphviz |
1 | def visit(node, nodes, pindex, g): |
详见
[Python ast 模块使用 | Jckling’s Blog](https://jckling.github.io/2021/07/14/Other/Python ast 模块使用/)
ast
中的类
ast
中各种各样的类描述了AST树中各类节点的不同属性。比如上文用到了ast.Add()
和ast.Mod()
代表了加和求余两个二元操作。
其中内容较多,且不同版本删删减减也不少,更重要的是名字含义清晰,很容易理解,故不详细讲述。可参考
Python ast module | Mingjian’s Blog (retzzz.github.io)
或者各个版本的官方文档。
ast — Abstract Syntax Trees — Python 3.10.2 documentation
参考
Python Source Obfuscation using ASTs | Development & Security (jbremer.org)
Python ast module | Mingjian’s Blog (retzzz.github.io)
25. Design of CPython’s Compiler
ast — Abstract Syntax Trees — Python 3.10.2 documentation
- 本文作者: Taardis
- 本文链接: https://taardisaa.github.io/2022/02/17/Python Obfuscation Ast/
- 版权声明: 本博客所有文章除特别声明外,均采用 Apache License 2.0 许可协议。转载请注明出处!