前言:

关于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
file

MARK

标记变量为markobject

INT

写入一个整数或布尔值
INT + b'1\n' + \
INT + b'8\n' + \
STOP
file

LONG/LONG1/LONG4

写入一个长整型
LONG + b'1\n' + \
STOP
file

UNICODE

写入一个字符串
UNICODE + b'YUYU\n' + \
STOP
file

ADDITEMS

将最上面的markobject后面的切片当作一个项目序列
file

EMPTY_DICT

在堆栈上创建一个空字典
file

EMPTY_LIST

在堆栈上创建一个空列表
file

EMPTY_SET

在堆栈上创建一个空集
file

EMPTY_TUPLE

在堆栈上创建一个空元组
file

NONE

在堆栈上创建一个空字节
file

APPEND

在列表中插入新值
EMPTY_LIST + \
INT + b'2005\n' + \
APPEND + \
STOP
file

APPENDS

获取列表切片的值
EMPTY_LIST + \
INT + b'2005\n' + \
UNICODE + B'YUYU\n' + \
MARK + \
APPENDS + \
STOP
file

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
file

REDUCE

输出可调用的对象
file

NEWOBJ

输出一个对象和一个参数
file

MEMOIZE

将栈上的值存放到memo中
file

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)

开始调试
file
start开始
file
next进入下一步
file
file
这里我们可以看到已经将exec函数的地址存放到了堆栈上,随后存放到memo中下标为0的位置
file
随后又将相关的变量相继存放到堆栈上,后又保存到memo中1和2中
file
最后推送可调用对象和参数元组构建的对象,即清空堆栈
最后STOP结束程序

参考文章:https://docs.juliahub.com/Pickle/LAUNc/0.1.0/opcode/
dbg项目地址:https://github.com/Legoclones/pickledbg

未完待续………………