前言:
关于Pickle模块的学习,可以看DT师傅的文章
https://xz.aliyun.com/t/14571?time__1311=mqmx9QKiqQw40DBT4%2BxCqPEQmQAKNPx&alichlgref=https%3A%2F%2Fxz.aliyun.com%2Fu%2F34589
pickle模块:https://github.com/python/cpython/blob/7e87d30f1f30d39c3005e03195f3d7648b38a1e2/Lib/pickle.py
字节码解析:
PROTO
PROTO + '\x04'(协议版本) + \
协议版本指示器,随着协议版本的不同,使用的python版本也会改变
GLOBAL
self.find_class(module, class),第一个参数为模块名,第二个参数为类名
GLOBAL + b'types\nFunctionType\n' + \
STOP
MARK
标记变量为markobject
INT
写入一个整数或布尔值
INT + b'1\n' + \
INT + b'8\n' + \
STOP
LONG/LONG1/LONG4
写入一个长整型
LONG + b'1\n' + \
STOP
UNICODE
写入一个字符串
UNICODE + b'YUYU\n' + \
STOP
ADDITEMS
将最上面的markobject后面的切片当作一个项目序列
EMPTY_DICT
在堆栈上创建一个空字典
EMPTY_LIST
在堆栈上创建一个空列表
EMPTY_SET
在堆栈上创建一个空集
EMPTY_TUPLE
在堆栈上创建一个空元组
NONE
在堆栈上创建一个空字节
APPEND
在列表中插入新值
EMPTY_LIST + \
INT + b'2005\n' + \
APPEND + \
STOP
APPENDS
获取列表切片的值
EMPTY_LIST + \
INT + b'2005\n' + \
UNICODE + B'YUYU\n' + \
MARK + \
APPENDS + \
STOP
TUPLE1/TUPLE2/TUPLE3
从堆栈中自上而下获取1/2/3个值
UNICODE + b'int\n' + \
UNICODE + b'from_bytes\n' + \
UNICODE + b'bin\n' + \
UNICODE + b'range\n' + \
UNICODE + b'len\n' + \
UNICODE + b'chr\n' + \
TUPLE3(TUPLE1/TUPLE2) + \
STOP
REDUCE
输出可调用的对象
NEWOBJ
输出一个对象和一个参数
MEMOIZE
将栈上的值存放到memo中
STOP
结束序列化
DBG调试
首先从DT的文章里copy一段序列化的内容,并保存为pickle文件
import pickletools
data = b"\x80\x03cbuiltins\nexec\nq\x00X\x13\x00\x00\x00key1=b'1'\nkey2=b'2'q\x01\x85q\x02Rq\x03."
with open('./test.pickle', 'wb') as f:
f.write(data)
开始调试
start开始
next进入下一步
这里我们可以看到已经将exec函数的地址存放到了堆栈上,随后存放到memo中下标为0的位置
随后又将相关的变量相继存放到堆栈上,后又保存到memo中1和2中
最后推送可调用对象和参数元组构建的对象,即清空堆栈
最后STOP结束程序
参考文章:https://docs.juliahub.com/Pickle/LAUNc/0.1.0/opcode/
dbg项目地址:https://github.com/Legoclones/pickledbg
未完待续………………
最新评论