如何手写opcode

📅 2026/7/1 2:36:59
如何手写opcode
在CTF中很多时候需要一次执行多个函数或一次进行多个指令此时就不能光用__reduce__来解决问题reduce一次只能执行一个函数当exec被禁用时就不能一次执行多条指令了而需要手动拼接或构造opcode了。手写opcode是pickle反序列化比较难的地方。在这里可以体会到为何pickle是一种语言直接编写的opcode灵活性比使用pickle序列化生成的代码更高只要符合pickle语法就可以进行变量覆盖、函数执行等操作。根据前文不同版本的opcode可以看出版本0的opcode更方便阅读所以手动编写时一般选用版本0的opcode。这里列举了几个opcode更多的可以去https://github.com/python/cpython/blob/master/Lib/pickle.py#L111opcode描述具体写法栈上的变化memo上的变化c获取一个全局对象或import一个模块注会调用import语句能够引入新的包c[module]\n[instance]\n获得的对象入栈无o寻找栈中的上一个MARK以之间的第一个数据必须为函数为callable第二个到第n个数据为参数执行该函数或实例化一个对象o这个过程中涉及到的数据都出栈函数的返回值或生成的对象入栈无i相当于c和o的组合先获取一个全局函数然后寻找栈中的上一个MARK并组合之间的数据为元组以该元组为参数执行全局函数或实例化一个对象i[module]\n[callable]\n这个过程中涉及到的数据都出栈函数返回值或生成的对象入栈无N实例化一个NoneN获得的对象入栈无S实例化一个字符串对象Sxxx\n也可以使用双引号、等python字符串形式获得的对象入栈无V实例化一个UNICODE字符串对象Vxxx\n获得的对象入栈无I实例化一个int对象Ixxx\n获得的对象入栈无F实例化一个float对象Fx.x\n获得的对象入栈无R选择栈上的第一个对象作为函数、第二个对象作为参数第二个对象必须为元组然后调用该函数R函数和参数出栈函数的返回值入栈无.程序结束栈顶的一个元素作为pickle.loads()的返回值.无无(向栈中压入一个MARK标记(MARK标记入栈无t寻找栈中的上一个MARK并组合之间的数据为元组tMARK标记以及被组合的数据出栈获得的对象入栈无)向栈中直接压入一个空元组)空元组入栈无l寻找栈中的上一个MARK并组合之间的数据为列表lMARK标记以及被组合的数据出栈获得的对象入栈无]向栈中直接压入一个空列表]空列表入栈无d寻找栈中的上一个MARK并组合之间的数据为字典数据必须有偶数个即呈key-value对dMARK标记以及被组合的数据出栈获得的对象入栈无}向栈中直接压入一个空字典}空字典入栈无p将栈顶对象储存至memo_npn\n无对象被储存g将memo_n的对象压栈gn\n对象被压栈无0丢弃栈顶对象0栈顶对象被丢弃无b使用栈中的第一个元素储存多个属性名: 属性值的字典对第二个元素对象实例进行属性设置b栈上第一个元素出栈无s将栈的第一个和第二个对象作为key-value对添加或更新到栈的第三个对象必须为列表或字典列表以数字作为key中s第一、二个元素出栈第三个元素列表或字典添加新值或被更新无u寻找栈中的上一个MARK组合之间的数据数据必须有偶数个即呈key-value对并全部添加或更新到该MARK之前的一个元素必须为字典中uMARK标记以及被组合的数据出栈字典被更新无a将栈的第一个元素append到第二个元素(列表)中a栈顶元素出栈第二个元素列表被更新无e寻找栈中的上一个MARK组合之间的数据并extends到该MARK之前的一个元素必须为列表中eMARK标记以及被组合的数据出栈列表被更新无对于做题而言会opache改写就行了INSTi、OBJo、REDUCER都可以调用一个 callable 对象RCE demo:R:bcos\nsystem\n(Swhoami\ntR.c获取全局对象指令。格式为 c[模块]\n[对象]\n这里是加载 os 模块的 system 函数。(压入 MARK 标记。Swhoami压入字符串 whoami 作为参数。t构建元组将 MARK 到当前位置的元素打包成元组。R调用指令REDUCE执行栈顶的可调用对象os.system并传入元组参数。.结束返回结果。ib(Swhoami\nios\nsystem\n.(压入 MARK 标记。Swhoami压入参数 whoami。i实例化指令INST需要栈顶是类 / 函数其下是参数。os\nsystem加载 os.system 函数作为可调用对象。.结束执行函数调用。ob(cos\nsystem\nSwhoami\no.o调用指令OBJECT找到 MARK 标记将 MARK 后的第一个元素作为可调用对象后续作为参数执行调用。无R,i,o os可过b(cos\nsystem\nScalc\nos.无R,i,o os 可过 关键词过滤b(Skey1\nSval1\ndSvul\n(cos\nsystem\nVcalc\nos.V操作码是可以识别\u (unicode编码绕过)特别是命令有特殊功能字符