AlpacaHack Round 4 - pytecode
お仕事のためリアタイできなかったですが、pytecode面白そうだったのでupsolveしました。
(アセンブリではないバイトコードやpickleを変換することを「ディスアセンブル」「デコンパイル」と呼ぶことが正確かどうかはよく知らないですが、この記事では可読性のためにラベル付けを行うことを「ディスアセンブル」、実行可能なpythonコードに変換することを「デコンパイル」と呼ぶことにします。)
Step 1: Pickleの解析
Pickleのデコンパイラといえば、fickling。とりあえず一度デコンパイルしてみよう。
from fickling import fickle, tracing
from astunparse import unparse
hex_code = "..."
bts = bytes.fromhex(hex_code)
stacked_pickled = fickle.StackedPickle.load(bts)
interpreter = fickle.Interpreter(stacked_pickled[0])
trace = tracing.Trace(interpreter)
code = unparse(trace.run())
open("disasmed.py", "w").write(code)
実行結果
Traceback (most recent call last):
File "/workspaces/pytecode/disasm.py", line 6, in <module>
stacked_pickled = fickle.StackedPickle.load(bts)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/workspaces/pytecode/venv/lib/python3.11/site-packages/fickling/fickle.py", line 1607, in load
p = Pickled.load(pickled)
^^^^^^^^^^^^^^^^^^^^^
File "/workspaces/pytecode/venv/lib/python3.11/site-packages/fickling/fickle.py", line 668, in load
opcodes.append(Opcode(info=info, argument=arg, data=data, position=pos))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/workspaces/pytecode/venv/lib/python3.11/site-packages/fickling/fickle.py", line 137, in __new__
raise NotImplementedError(f"TODO: Add support for Opcode {info.name}")
NotImplementedError: TODO: Add support for Opcode INST
どうやら、INST
という命令が実装されていないようだ。pickle.pyを読むと、クラスのimportとインスタンス化を同時に行う命令のようだ。STACK_GLOBALの実装やOBJの実装を参考にしながら、ficklingのクラスを実装してみる。
1616a1617,1625
> class Inst(StackSliceOpcode):
> name = "INST"
>
> def run(self, interpreter: Interpreter, stack_slice: List[ast.expr]):
> module, name = self.arg.split(" ")
> alias = ast.alias(name)
> interpreter.module_body.append(ast.ImportFrom(module=module, names=[alias], level=0))
> interpreter.stack.append(ast.Call(ast.Name(name, ast.Load()), stack_slice, []))
>
追記
なんと二週間前にINSTのサポートのコミットが作成されていました。バージョンのアップデートが楽しみです。
これでficklingはコードを吐き出すが、次のようなエラーが出てしまう。
Traceback (most recent call last):
File "/workspaces/pytecode/disasmed.py", line 12, in <module>
_var4.update({0: 3, 6: b'\x97\x00|\x00|\x01x\x02x\x02\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00|\x02z\x19\x00\x00c\x03c\x02<\x00\x00\x00|\x00S\x00'})
^^^^^^^^^^^^
AttributeError: 'list' object has no attribute 'update'
これは、ficklingのSETITEMSの実装が間違っていて、SETITEMS
される先が辞書型しか想定されておらず、dict.update
が利用されているのが原因である。(参考: pickle.py)
それを修正したのが以下であるが、正直生成コードを直接いじってもよかったかな、と思った。
1338,1344c1338,1342
< update_dict = ast.Dict(keys=update_dict_keys, values=update_dict_values)
< interpreter.module_body.append(
< ast.Expr(
< ast.Call(
< ast.Attribute(ast.Name(dict_name, ast.Load()), "update"),
< [update_dict],
< [],
---
> for key, value in zip(update_dict_keys, update_dict_values):
> interpreter.module_body.append(
> ast.Assign(
> [ast.Subscript(ast.Name(dict_name, ast.Load()), key, ast.Store())],
> value
これでinp
の値を書き換えて実行すると、正しく動いていることが確認できた。
実際にデコンパイルされるコード
from types import FunctionType
from types import CodeType
_var0 = getattr('?', '__mul__')
_var1 = _var0(1337)
from builtins import tuple
from builtins import tuple
from __main__ import inp
_var2 = getattr(int, 'from_bytes')
_var3 = FunctionType(CodeType(*tuple([2, 0, 0, 1337, 1337, 0, b'\x97\x00|\x00|\x00k\x03\x00\x00\x00\x00}\x02|\x00|\x02\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00}\x03|\x03|\x03z\n\x00\x00}\x04|\x04|\x04z\x08\x00\x00}\x05|\x05|\x05z\x03\x00\x00}\x06|\x05|\x06z\x03\x00\x00}\x07|\x07|\x05z\x03\x00\x00}\x08|\x07|\x05z\n\x00\x00}\t|\x08|\tz\n\x00\x00}\n|\x08|\x06z\n\x00\x00}\x0b|\x08|\x05z\n\x00\x00}\x0c|\x04|\x05|\x06|\t|\x07|\n|\x0b|\x0cg\x08}\r|\x04g\x01|\x08z\x05\x00\x00}\x0e|\rD\x00]"}\x0f|\x0f|\x08z\x05\x00\x00}\x10|\x10|\x08z\x00\x00\x00}\x11\x02\x00|\x01|\x00|\x10|\x11\x85\x02\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa6\x01\x00\x00\xab\x01\x00\x00\x00\x00\x00\x00\x00\x00|\x0e|\x0f<\x00\x00\x00\x8c#|\x0eS\x00', (), (), tuple(_var1), 'the', 'cake', 'is', 1337, b'a', b'lie'])), {})(inp, _var2)
_var4 = [2, 0, 0, 1337, 1337, 0, b'\x97\x00|\x00|\x00k\x03\x00\x00\x00\x00}\x02|\x00|\x02\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00}\x03|\x03|\x03z\n\x00\x00}\x04|\x04|\x04z\x08\x00\x00}\x05|\x05|\x05z\x03\x00\x00}\x06|\x05|\x06z\x03\x00\x00}\x07|\x07|\x05z\x03\x00\x00}\x08|\x07|\x05z\n\x00\x00}\t|\x08|\tz\n\x00\x00}\n|\x08|\x06z\n\x00\x00}\x0b|\x08|\x05z\n\x00\x00}\x0c|\x04|\x05|\x06|\t|\x07|\n|\x0b|\x0cg\x08}\r|\x04g\x01|\x08z\x05\x00\x00}\x0e|\rD\x00]"}\x0f|\x0f|\x08z\x05\x00\x00}\x10|\x10|\x08z\x00\x00\x00}\x11\x02\x00|\x01|\x00|\x10|\x11\x85\x02\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa6\x01\x00\x00\xab\x01\x00\x00\x00\x00\x00\x00\x00\x00|\x0e|\x0f<\x00\x00\x00\x8c#|\x0eS\x00', (), (), tuple(_var1), 'the', 'cake', 'is', 1337, b'a', b'lie']
_var4[0] = 3
_var4[6] = b'\x97\x00|\x00|\x01x\x02x\x02\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00|\x02z\x19\x00\x00c\x03c\x02<\x00\x00\x00|\x00S\x00'
from builtins import tuple
_var5 = FunctionType(CodeType(*tuple(_var4)), {})(_var3, 0, 1384820248286204727)
_var6 = [2, 0, 0, 1337, 1337, 0, b'\x97\x00|\x00|\x00k\x03\x00\x00\x00\x00}\x02|\x00|\x02\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00}\x03|\x03|\x03z\n\x00\x00}\x04|\x04|\x04z\x08\x00\x00}\x05|\x05|\x05z\x03\x00\x00}\x06|\x05|\x06z\x03\x00\x00}\x07|\x07|\x05z\x03\x00\x00}\x08|\x07|\x05z\n\x00\x00}\t|\x08|\tz\n\x00\x00}\n|\x08|\x06z\n\x00\x00}\x0b|\x08|\x05z\n\x00\x00}\x0c|\x04|\x05|\x06|\t|\x07|\n|\x0b|\x0cg\x08}\r|\x04g\x01|\x08z\x05\x00\x00}\x0e|\rD\x00]"}\x0f|\x0f|\x08z\x05\x00\x00}\x10|\x10|\x08z\x00\x00\x00}\x11\x02\x00|\x01|\x00|\x10|\x11\x85\x02\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa6\x01\x00\x00\xab\x01\x00\x00\x00\x00\x00\x00\x00\x00|\x0e|\x0f<\x00\x00\x00\x8c#|\x0eS\x00', (), (), tuple(_var1), 'the', 'cake', 'is', 1337, b'a', b'lie']
_var6[0] = 3
_var6[6] = b'\x97\x00|\x00|\x02\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00|\x00|\x01\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00c\x02|\x00|\x01<\x00\x00\x00|\x00|\x02<\x00\x00\x00|\x00S\x00'
from builtins import tuple
_var7 = FunctionType(CodeType(*tuple(_var6)), {})(_var3, 2, 7)
_var8 = [2, 0, 0, 1337, 1337, 0, b'\x97\x00|\x00|\x00k\x03\x00\x00\x00\x00}\x02|\x00|\x02\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00}\x03|\x03|\x03z\n\x00\x00}\x04|\x04|\x04z\x08\x00\x00}\x05|\x05|\x05z\x03\x00\x00}\x06|\x05|\x06z\x03\x00\x00}\x07|\x07|\x05z\x03\x00\x00}\x08|\x07|\x05z\n\x00\x00}\t|\x08|\tz\n\x00\x00}\n|\x08|\x06z\n\x00\x00}\x0b|\x08|\x05z\n\x00\x00}\x0c|\x04|\x05|\x06|\t|\x07|\n|\x0b|\x0cg\x08}\r|\x04g\x01|\x08z\x05\x00\x00}\x0e|\rD\x00]"}\x0f|\x0f|\x08z\x05\x00\x00}\x10|\x10|\x08z\x00\x00\x00}\x11\x02\x00|\x01|\x00|\x10|\x11\x85\x02\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa6\x01\x00\x00\xab\x01\x00\x00\x00\x00\x00\x00\x00\x00|\x0e|\x0f<\x00\x00\x00\x8c#|\x0eS\x00', (), (), tuple(_var1), 'the', 'cake', 'is', 1337, b'a', b'lie']
_var8[0] = 3
_var8[6] = b'\x97\x00|\x00|\x01\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00}\x03|\x03|\x02z\n\x00\x00}\x04|\x04|\x04z\n\x00\x00}\x05|\x04|\x05k\x00\x00\x00\x00\x00r\x03|\x04\x0b\x00n\x01|\x04|\x00|\x01<\x00\x00\x00|\x00S\x00'
from builtins import tuple
_var9 = FunctionType(CodeType(*tuple(_var8)), {})(_var3, 4, 9259542123273814144)
_var10 = [2, 0, 0, 1337, 1337, 0, b'\x97\x00|\x00|\x00k\x03\x00\x00\x00\x00}\x02|\x00|\x02\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00}\x03|\x03|\x03z\n\x00\x00}\x04|\x04|\x04z\x08\x00\x00}\x05|\x05|\x05z\x03\x00\x00}\x06|\x05|\x06z\x03\x00\x00}\x07|\x07|\x05z\x03\x00\x00}\x08|\x07|\x05z\n\x00\x00}\t|\x08|\tz\n\x00\x00}\n|\x08|\x06z\n\x00\x00}\x0b|\x08|\x05z\n\x00\x00}\x0c|\x04|\x05|\x06|\t|\x07|\n|\x0b|\x0cg\x08}\r|\x04g\x01|\x08z\x05\x00\x00}\x0e|\rD\x00]"}\x0f|\x0f|\x08z\x05\x00\x00}\x10|\x10|\x08z\x00\x00\x00}\x11\x02\x00|\x01|\x00|\x10|\x11\x85\x02\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa6\x01\x00\x00\xab\x01\x00\x00\x00\x00\x00\x00\x00\x00|\x0e|\x0f<\x00\x00\x00\x8c#|\x0eS\x00', (), (), tuple(_var1), 'the', 'cake', 'is', 1337, b'a', b'lie']
_var10[0] = 3
_var10[6] = b'\x97\x00|\x00|\x01\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00}\x03|\x03|\x03z\x02\x00\x00}\x04|\x04|\x02z\x03\x00\x00|\x04z\n\x00\x00}\x05|\x03|\x05z\x01\x00\x00}\x06|\x03|\x02z\x16\x00\x00}\x03|\x04|\x04z\x00\x00\x00}\x07|\x07|\x07z\x05\x00\x00|\x07z\x00\x00\x00}\x08|\x04|\x08z\x03\x00\x00}\t|\t|\x02z\n\x00\x00}\n|\x03|\x06|\nz\x03\x00\x00z\x14\x00\x00}\x03|\x03|\x00|\x01<\x00\x00\x00|\x00S\x00'
from builtins import tuple
_var11 = FunctionType(CodeType(*tuple(_var10)), {})(_var3, 1, 13)
_var12 = [2, 0, 0, 1337, 1337, 0, b'\x97\x00|\x00|\x00k\x03\x00\x00\x00\x00}\x02|\x00|\x02\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00}\x03|\x03|\x03z\n\x00\x00}\x04|\x04|\x04z\x08\x00\x00}\x05|\x05|\x05z\x03\x00\x00}\x06|\x05|\x06z\x03\x00\x00}\x07|\x07|\x05z\x03\x00\x00}\x08|\x07|\x05z\n\x00\x00}\t|\x08|\tz\n\x00\x00}\n|\x08|\x06z\n\x00\x00}\x0b|\x08|\x05z\n\x00\x00}\x0c|\x04|\x05|\x06|\t|\x07|\n|\x0b|\x0cg\x08}\r|\x04g\x01|\x08z\x05\x00\x00}\x0e|\rD\x00]"}\x0f|\x0f|\x08z\x05\x00\x00}\x10|\x10|\x08z\x00\x00\x00}\x11\x02\x00|\x01|\x00|\x10|\x11\x85\x02\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa6\x01\x00\x00\xab\x01\x00\x00\x00\x00\x00\x00\x00\x00|\x0e|\x0f<\x00\x00\x00\x8c#|\x0eS\x00', (), (), tuple(_var1), 'the', 'cake', 'is', 1337, b'a', b'lie']
_var12[0] = 4
_var12[6] = b'\x97\x00|\x00|\x01\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00|\x00|\x02\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00z\x0c\x00\x00|\x00|\x03<\x00\x00\x00|\x00S\x00'
from builtins import tuple
_var13 = FunctionType(CodeType(*tuple(_var12)), {})(_var3, 1, 6, 1)
_var14 = [2, 0, 0, 1337, 1337, 0, b'\x97\x00|\x00|\x00k\x03\x00\x00\x00\x00}\x02|\x00|\x02\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00}\x03|\x03|\x03z\n\x00\x00}\x04|\x04|\x04z\x08\x00\x00}\x05|\x05|\x05z\x03\x00\x00}\x06|\x05|\x06z\x03\x00\x00}\x07|\x07|\x05z\x03\x00\x00}\x08|\x07|\x05z\n\x00\x00}\t|\x08|\tz\n\x00\x00}\n|\x08|\x06z\n\x00\x00}\x0b|\x08|\x05z\n\x00\x00}\x0c|\x04|\x05|\x06|\t|\x07|\n|\x0b|\x0cg\x08}\r|\x04g\x01|\x08z\x05\x00\x00}\x0e|\rD\x00]"}\x0f|\x0f|\x08z\x05\x00\x00}\x10|\x10|\x08z\x00\x00\x00}\x11\x02\x00|\x01|\x00|\x10|\x11\x85\x02\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa6\x01\x00\x00\xab\x01\x00\x00\x00\x00\x00\x00\x00\x00|\x0e|\x0f<\x00\x00\x00\x8c#|\x0eS\x00', (), (), tuple(_var1), 'the', 'cake', 'is', 1337, b'a', b'lie']
_var14[0] = 3
_var14[6] = b'\x97\x00|\x00|\x01\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00|\x00|\x01\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00|\x02z\t\x00\x00z\x0c\x00\x00|\x00|\x01<\x00\x00\x00|\x00S\x00'
from builtins import tuple
_var15 = FunctionType(CodeType(*tuple(_var14)), {})(_var3, 5, 12)
_var16 = [2, 0, 0, 1337, 1337, 0, b'\x97\x00|\x00|\x00k\x03\x00\x00\x00\x00}\x02|\x00|\x02\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00}\x03|\x03|\x03z\n\x00\x00}\x04|\x04|\x04z\x08\x00\x00}\x05|\x05|\x05z\x03\x00\x00}\x06|\x05|\x06z\x03\x00\x00}\x07|\x07|\x05z\x03\x00\x00}\x08|\x07|\x05z\n\x00\x00}\t|\x08|\tz\n\x00\x00}\n|\x08|\x06z\n\x00\x00}\x0b|\x08|\x05z\n\x00\x00}\x0c|\x04|\x05|\x06|\t|\x07|\n|\x0b|\x0cg\x08}\r|\x04g\x01|\x08z\x05\x00\x00}\x0e|\rD\x00]"}\x0f|\x0f|\x08z\x05\x00\x00}\x10|\x10|\x08z\x00\x00\x00}\x11\x02\x00|\x01|\x00|\x10|\x11\x85\x02\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa6\x01\x00\x00\xab\x01\x00\x00\x00\x00\x00\x00\x00\x00|\x0e|\x0f<\x00\x00\x00\x8c#|\x0eS\x00', (), (), tuple(_var1), 'the', 'cake', 'is', 1337, b'a', b'lie']
_var16[0] = 3
_var16[6] = b'\x97\x00|\x00|\x02\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00|\x00|\x01\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00c\x02|\x00|\x01<\x00\x00\x00|\x00|\x02<\x00\x00\x00|\x00S\x00'
from builtins import tuple
_var17 = FunctionType(CodeType(*tuple(_var16)), {})(_var3, 3, 6)
_var18 = [2, 0, 0, 1337, 1337, 0, b'\x97\x00|\x00|\x00k\x03\x00\x00\x00\x00}\x02|\x00|\x02\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00}\x03|\x03|\x03z\n\x00\x00}\x04|\x04|\x04z\x08\x00\x00}\x05|\x05|\x05z\x03\x00\x00}\x06|\x05|\x06z\x03\x00\x00}\x07|\x07|\x05z\x03\x00\x00}\x08|\x07|\x05z\n\x00\x00}\t|\x08|\tz\n\x00\x00}\n|\x08|\x06z\n\x00\x00}\x0b|\x08|\x05z\n\x00\x00}\x0c|\x04|\x05|\x06|\t|\x07|\n|\x0b|\x0cg\x08}\r|\x04g\x01|\x08z\x05\x00\x00}\x0e|\rD\x00]"}\x0f|\x0f|\x08z\x05\x00\x00}\x10|\x10|\x08z\x00\x00\x00}\x11\x02\x00|\x01|\x00|\x10|\x11\x85\x02\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa6\x01\x00\x00\xab\x01\x00\x00\x00\x00\x00\x00\x00\x00|\x0e|\x0f<\x00\x00\x00\x8c#|\x0eS\x00', (), (), tuple(_var1), 'the', 'cake', 'is', 1337, b'a', b'lie']
_var18[0] = 2
_var18[6] = b'\x97\x00|\x00|\x00z\x06\x00\x00}\x02|\x00|\x00z\x02\x00\x00}\x03|\x03|\x03z\x00\x00\x00}\x04|\x03|\x04z\x00\x00\x00}\x05|\x04|\x04z\x08\x00\x00}\x06|\x04|\x05z\x00\x00\x00}\x07|\x05|\x04z\x05\x00\x00}\x08|\x06|\x04z\x05\x00\x00|\x03z\n\x00\x00}\t|\x03|\x08z\x03\x00\x00}\n|\n|\x04z\x05\x00\x00}\x0b|\x03|\nz\x03\x00\x00|\x03z\n\x00\x00}\x0c|\t|\x08z\x05\x00\x00}\r|\t|\x0b|\nz\x00\x00\x00|\x03z\n\x00\x00z\x05\x00\x00}\x0e|\x02|\x03|\x04|\x05|\x06|\x07|\x08|\tg\x08}\x0f|\x0fD\x00]\x1b}\x10|\x01|\x10\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00|\x00z\x0c\x00\x00|\x01|\x10<\x00\x00\x00|\r|\x00z\x05\x00\x00|\x0ez\x00\x00\x00|\x0cz\x01\x00\x00}\x00\x8c\x1c|\x01S\x00'
from builtins import tuple
_var19 = FunctionType(CodeType(*tuple(_var18)), {})(1384596539316466481, _var3)
_var20 = [2, 0, 0, 1337, 1337, 0, b'\x97\x00|\x00|\x00k\x03\x00\x00\x00\x00}\x02|\x00|\x02\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00}\x03|\x03|\x03z\n\x00\x00}\x04|\x04|\x04z\x08\x00\x00}\x05|\x05|\x05z\x03\x00\x00}\x06|\x05|\x06z\x03\x00\x00}\x07|\x07|\x05z\x03\x00\x00}\x08|\x07|\x05z\n\x00\x00}\t|\x08|\tz\n\x00\x00}\n|\x08|\x06z\n\x00\x00}\x0b|\x08|\x05z\n\x00\x00}\x0c|\x04|\x05|\x06|\t|\x07|\n|\x0b|\x0cg\x08}\r|\x04g\x01|\x08z\x05\x00\x00}\x0e|\rD\x00]"}\x0f|\x0f|\x08z\x05\x00\x00}\x10|\x10|\x08z\x00\x00\x00}\x11\x02\x00|\x01|\x00|\x10|\x11\x85\x02\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa6\x01\x00\x00\xab\x01\x00\x00\x00\x00\x00\x00\x00\x00|\x0e|\x0f<\x00\x00\x00\x8c#|\x0eS\x00', (), (), tuple(_var1), 'the', 'cake', 'is', 1337, b'a', b'lie']
_var20[0] = 2
_var20[6] = b'\x97\x00|\x00|\x01k\x02\x00\x00\x00\x00S\x00'
from builtins import tuple
_var21 = FunctionType(CodeType(*tuple(_var20)), {})(_var3, [4714351799183481704, 9920649113211881281, 1577726041120304458, 11479115687019652446, 3159180328194279316, 7893169807958830647, 9845433486767146114, 7349253534905816330])
result = _var21
Step 2: pythonバイトコードの解読
デコンパイルされたコードを軽くまとめると次のようになる。
from types import FunctionType, CodeType
_var1 = '?' * 1337
inp = b"Alpaca{abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123}" # 制約より64文字
_var3 = FunctionType(CodeType(*tuple([2, 0, 0, 1337, 1337, 0, b'\x97\x00|\x00|\x00k\x03\x00\x00\x00\x00}\x02|\x00|\x02\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00}\x03|\x03|\x03z\n\x00\x00}\x04|\x04|\x04z\x08\x00\x00}\x05|\x05|\x05z\x03\x00\x00}\x06|\x05|\x06z\x03\x00\x00}\x07|\x07|\x05z\x03\x00\x00}\x08|\x07|\x05z\n\x00\x00}\t|\x08|\tz\n\x00\x00}\n|\x08|\x06z\n\x00\x00}\x0b|\x08|\x05z\n\x00\x00}\x0c|\x04|\x05|\x06|\t|\x07|\n|\x0b|\x0cg\x08}\r|\x04g\x01|\x08z\x05\x00\x00}\x0e|\rD\x00]"}\x0f|\x0f|\x08z\x05\x00\x00}\x10|\x10|\x08z\x00\x00\x00}\x11\x02\x00|\x01|\x00|\x10|\x11\x85\x02\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa6\x01\x00\x00\xab\x01\x00\x00\x00\x00\x00\x00\x00\x00|\x0e|\x0f<\x00\x00\x00\x8c#|\x0eS\x00', (), (), tuple(_var1), 'the', 'cake', 'is', 1337, b'a', b'lie'])), {})(inp, int.from_bytes)
_var4 = [3, 0, 0, 1337, 1337, 0, b'\x97\x00|\x00|\x01x\x02x\x02\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00|\x02z\x19\x00\x00c\x03c\x02<\x00\x00\x00|\x00S\x00', (), (), tuple(_var1), 'the', 'cake', 'is', 1337, b'a', b'lie']
FunctionType(CodeType(*tuple(_var4)), {})(_var3, 0, 1384820248286204727)
_var6 = [3, 0, 0, 1337, 1337, 0, b'\x97\x00|\x00|\x02\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00|\x00|\x01\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00c\x02|\x00|\x01<\x00\x00\x00|\x00|\x02<\x00\x00\x00|\x00S\x00', (), (), tuple(_var1), 'the', 'cake', 'is', 1337, b'a', b'lie']
FunctionType(CodeType(*tuple(_var6)), {})(_var3, 2, 7)
_var8 = [3, 0, 0, 1337, 1337, 0, b'\x97\x00|\x00|\x01\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00}\x03|\x03|\x02z\n\x00\x00}\x04|\x04|\x04z\n\x00\x00}\x05|\x04|\x05k\x00\x00\x00\x00\x00r\x03|\x04\x0b\x00n\x01|\x04|\x00|\x01<\x00\x00\x00|\x00S\x00', (), (), tuple(_var1), 'the', 'cake', 'is', 1337, b'a', b'lie']
FunctionType(CodeType(*tuple(_var8)), {})(_var3, 4, 9259542123273814144)
_var10 = [3, 0, 0, 1337, 1337, 0, b'\x97\x00|\x00|\x01\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00}\x03|\x03|\x03z\x02\x00\x00}\x04|\x04|\x02z\x03\x00\x00|\x04z\n\x00\x00}\x05|\x03|\x05z\x01\x00\x00}\x06|\x03|\x02z\x16\x00\x00}\x03|\x04|\x04z\x00\x00\x00}\x07|\x07|\x07z\x05\x00\x00|\x07z\x00\x00\x00}\x08|\x04|\x08z\x03\x00\x00}\t|\t|\x02z\n\x00\x00}\n|\x03|\x06|\nz\x03\x00\x00z\x14\x00\x00}\x03|\x03|\x00|\x01<\x00\x00\x00|\x00S\x00', (), (), tuple(_var1), 'the', 'cake', 'is', 1337, b'a', b'lie']
FunctionType(CodeType(*tuple(_var10)), {})(_var3, 1, 13)
_var12 = [4, 0, 0, 1337, 1337, 0, b'\x97\x00|\x00|\x01\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00|\x00|\x02\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00z\x0c\x00\x00|\x00|\x03<\x00\x00\x00|\x00S\x00', (), (), tuple(_var1), 'the', 'cake', 'is', 1337, b'a', b'lie']
FunctionType(CodeType(*tuple(_var12)), {})(_var3, 1, 6, 1)
_var14 = [3, 0, 0, 1337, 1337, 0, b'\x97\x00|\x00|\x01\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00|\x00|\x01\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00|\x02z\t\x00\x00z\x0c\x00\x00|\x00|\x01<\x00\x00\x00|\x00S\x00', (), (), tuple(_var1), 'the', 'cake', 'is', 1337, b'a', b'lie']
FunctionType(CodeType(*tuple(_var14)), {})(_var3, 5, 12)
_var16 = [3, 0, 0, 1337, 1337, 0, b'\x97\x00|\x00|\x02\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00|\x00|\x01\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00c\x02|\x00|\x01<\x00\x00\x00|\x00|\x02<\x00\x00\x00|\x00S\x00', (), (), tuple(_var1), 'the', 'cake', 'is', 1337, b'a', b'lie']
FunctionType(CodeType(*tuple(_var16)), {})(_var3, 3, 6)
_var18 = [2, 0, 0, 1337, 1337, 0, b'\x97\x00|\x00|\x00z\x06\x00\x00}\x02|\x00|\x00z\x02\x00\x00}\x03|\x03|\x03z\x00\x00\x00}\x04|\x03|\x04z\x00\x00\x00}\x05|\x04|\x04z\x08\x00\x00}\x06|\x04|\x05z\x00\x00\x00}\x07|\x05|\x04z\x05\x00\x00}\x08|\x06|\x04z\x05\x00\x00|\x03z\n\x00\x00}\t|\x03|\x08z\x03\x00\x00}\n|\n|\x04z\x05\x00\x00}\x0b|\x03|\nz\x03\x00\x00|\x03z\n\x00\x00}\x0c|\t|\x08z\x05\x00\x00}\r|\t|\x0b|\nz\x00\x00\x00|\x03z\n\x00\x00z\x05\x00\x00}\x0e|\x02|\x03|\x04|\x05|\x06|\x07|\x08|\tg\x08}\x0f|\x0fD\x00]\x1b}\x10|\x01|\x10\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00|\x00z\x0c\x00\x00|\x01|\x10<\x00\x00\x00|\r|\x00z\x05\x00\x00|\x0ez\x00\x00\x00|\x0cz\x01\x00\x00}\x00\x8c\x1c|\x01S\x00', (), (), tuple(_var1), 'the', 'cake', 'is', 1337, b'a', b'lie']
FunctionType(CodeType(*tuple(_var18)), {})(1384596539316466481, _var3)
_var20 = [2, 0, 0, 1337, 1337, 0, b'\x97\x00|\x00|\x01k\x02\x00\x00\x00\x00S\x00', (), (), tuple(_var1), 'the', 'cake', 'is', 1337, b'a', b'lie']
result = FunctionType(CodeType(*tuple(_var20)), {})(_var3, [4714351799183481704, 9920649113211881281, 1577726041120304458, 11479115687019652446, 3159180328194279316, 7893169807958830647, 9845433486767146114, 7349253534905816330])
このCodeType
とかFunctionType
は何なのか調べてみると、どうやら通常はcompile
関数の成果物として想定されているクラスのようだ。ドキュメントにはどの引数が何を表しているか詳細は載っていないが、見るからに第六引数がpythonのバイトコードなのだろう。
バイトコードのデコンパイルはpycdcを使ってみる。
_var3
の生成で利用されるコードであれば、次のように記述することでmarshalファイルを生成することができる。
marshal.dump(CodeType(*tuple([2, 0, 0, 1337, 1337, 0, b'\x97\x00|\x00|\x00k\x03\x00\x00\x00\x00}\x02|\x00|\x02\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00}\x03|\x03|\x03z\n\x00\x00}\x04|\x04|\x04z\x08\x00\x00}\x05|\x05|\x05z\x03\x00\x00}\x06|\x05|\x06z\x03\x00\x00}\x07|\x07|\x05z\x03\x00\x00}\x08|\x07|\x05z\n\x00\x00}\t|\x08|\tz\n\x00\x00}\n|\x08|\x06z\n\x00\x00}\x0b|\x08|\x05z\n\x00\x00}\x0c|\x04|\x05|\x06|\t|\x07|\n|\x0b|\x0cg\x08}\r|\x04g\x01|\x08z\x05\x00\x00}\x0e|\rD\x00]"}\x0f|\x0f|\x08z\x05\x00\x00}\x10|\x10|\x08z\x00\x00\x00}\x11\x02\x00|\x01|\x00|\x10|\x11\x85\x02\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa6\x01\x00\x00\xab\x01\x00\x00\x00\x00\x00\x00\x00\x00|\x0e|\x0f<\x00\x00\x00\x8c#|\x0eS\x00', (), (), tuple(_var1), 'the', 'cake', 'is', 1337, b'a', b'lie'])), open("var3.mshl", "wb"))
これをデコンパイルすると、実行結果は以下のようになった。
$ ./pycdc/pycdc -c -v 3.11 var3.mshl
# Source Generated with Decompyle++
# File: var3.mshl (Python 3.11)
Unsupported opcode: JUMP_BACKWARD
? = ? != ?
? = ?[?]
? = ? - ?
? = ? ** ?
? = ? << ?
? = ? << ?
? = ? << ?
? = ? - ?
? = ? - ?
? = ? - ?
? = ? - ?
? = [
?,
?,
?,
?,
?,
?,
?,
?]
? = [
?] * ?
# WARNING: Decompyle incomplete
"?"ばかり表示されているのは、第九引数の_var1
は変数名のリストなのだが、これの要素が全て"?"
となっているからである。つまり、_var1
を
_var1 = [f"v{i}" for i in range(1337)]
のように書き換えれば
$ ./pycdc/pycdc -c -v 3.11 var3.mshl
# Source Generated with Decompyle++
# File: var3.mshl (Python 3.11)
Unsupported opcode: JUMP_BACKWARD
v2 = v0 != v0
v3 = v0[v2]
v4 = v3 - v3
v5 = v4 ** v4
v6 = v5 << v5
v7 = v5 << v6
v8 = v7 << v5
v9 = v7 - v5
v10 = v8 - v9
v11 = v8 - v6
v12 = v8 - v5
v13 = [
v4,
v5,
v6,
v9,
v7,
v10,
v11,
v12]
v14 = [
v4] * v8
# WARNING: Decompyle incomplete
のように変数名がわかりやすくなる。
また、Unsupported opcode: JUMP_BACKWARD
と出力されていることからもわかる通り、対応しているopcodeまでしか出力されない(_var3、_var4、var18以外はデコンパイル可能)。代わりに
$ ./pycdc/pycdas -c -v 3.11 var3.mshl
を実行することで、ディスアセンブルすることができるので、ドキュメントを読みながら地道にコード化していく。
ポイントとしては、_var3
と_var18
には
v2 = v0 % v0
v3 = v0 // v0
v4 = v3 + v3
v5 = v3 + v4
v6 = v4 ** v4
v7 = v4 + v5
v8 = v5 * v4
v9 = v6 * v4 - v3
v10 = v3 << v8
v11 = v10 * v4
v12 = (v3 << v10) - v3
v13 = v9 * v8
v14 = v9 * (v11 + v10 - v3)
v15 = [
v2,
v3,
v4,
v5,
v6,
v7,
v8,
v9]
のようなコードが出現するが、よく見るとv0 % v0
は必ず0
だし、v0//v0
は必ず1
、のように入力依存であるように見せかけて実はそうではない変数が出現することに注意が必要。上記の例だと、v15
は[0,1,2,3,4,5,6,7]
と等しくなる。
inp = b"Alpaca{abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123}" # 制約より64文字
_var3 = [0] * 8
for i in range(8):
_var3[i] = int.from_bytes(inp[i * 8: i * 8 + 8])
_var3[0] ^= 1384820248286204727
_var3[2], _var3[7] = _var3[7], _var3[2]
_var3[4] = abs(_var3[4] - 9259542123273814144)
_var3[1] = (_var3[1] >> 13) | (_var3[1] & 0x1fff) << 51 # 右に13ビット分ローテートシフト
_var3[1] = _var3[1] ^ _var3[6]
_var3[5] = _var3[5] ^ _var3[5] >> 12
_var3[3], _var3[6] = _var3[6], _var3[3]
v0 = 1384596539316466481
for i in range(8):
_var3[i] ^= v0
v0 = (42 * v0 + 1337) & 0xffffffffffffffff
result = _var3 == [4714351799183481704, 9920649113211881281, 1577726041120304458, 11479115687019652446, 3159180328194279316, 7893169807958830647, 9845433486767146114, 7349253534905816330]
print(result)
あとはコードを逆算するだけである。大体はシンプルに逆算できるが、以下のコードは少し考える必要がある。
_var3[5] = _var3[5] ^ _var3[5] >> 12
右に12ビットシフトした値とXORしているので、上位12ビットは変化していない。つまり、上記と同じ演算を行うと、上位24ビットのみが逆算できる。これを5回繰り返すことによって、上位36、48、60、64ビットと順に正しいビットが計算できる。
それを踏まえて以下のように逆算するコードを書いた。
ans = [4714351799183481704, 9920649113211881281, 1577726041120304458, 11479115687019652446, 3159180328194279316, 7893169807958830647, 9845433486767146114, 7349253534905816330]
v0 = 1384596539316466481
for i in range(8):
ans[i] = ans[i] ^ v0
v0 = (42 * v0 + 1337) & 0xffffffffffffffff
ans[3], ans[6] = ans[6], ans[3]
orig = ans[5]
for _ in range(5):
ans[5] = orig ^ (ans[5] >> 12)
ans[1] = ans[1] ^ ans[6]
ans[1] = (ans[1] >> 51) | (ans[1] & 0x7ffffffffffff) << 13
if ans[4] + 9259542123273814144 > 64:
ans[4] = 9259542123273814144 - ans[4]
else:
ans[4] = ans[4] + 9259542123273814144
ans[2], ans[7] = ans[7], ans[2]
ans[0] ^= 1384820248286204727
res = b""
for i in range(8):
res += ans[i].to_bytes(8)
print(res)
まとめ
pickle最高!
Discussion