Implementation:Trailofbits Fickling Interpreter To Ast
| Knowledge Sources | |
|---|---|
| Domains | Security, Reverse_Engineering, Static_Analysis |
| Last Updated | 2026-02-14 14:00 GMT |
Overview
Concrete tool for converting pickle opcodes into a Python AST through symbolic VM interpretation, provided by the Fickling library.
Description
The Interpreter class symbolically executes pickle opcodes, maintaining a symbolic stack and memo dictionary. Each opcode is translated to its AST equivalent. The to_ast() method runs the full interpretation and returns an ast.Module node. The result can be unparsed with ast.unparse() to produce human-readable Python source code.
Usage
Use this when you need the Python AST representation of a pickle file — for safety analysis (walking the AST for dangerous patterns) or for decompilation (converting to readable source).
Code Reference
Source Location
- Repository: fickling
- File: fickling/fickle.py
- Lines: L1145-1166
Signature
class Interpreter:
def __init__(
self,
pickled: Pickled,
first_variable_id: int = 0,
result_variable: str = "result"
):
"""
Args:
pickled: Parsed pickle opcodes from Pickled.load().
first_variable_id: Starting counter for generated variable
names (useful for stacked pickles).
result_variable: Name for the final result variable
in the generated AST.
"""
def to_ast(self) -> ast.Module:
"""Run symbolic interpretation and return Python AST.
Returns:
ast.Module representing equivalent Python code.
"""
Import
from fickling.fickle import Interpreter
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| pickled | Pickled | Yes | Parsed pickle opcodes from Pickled.load() |
| first_variable_id | int | No | Starting counter for variable names (default: 0) |
| result_variable | str | No | Name for result variable (default: "result") |
Outputs
| Name | Type | Description |
|---|---|---|
| to_ast() returns | ast.Module | Python AST representing equivalent deserialization code |
| .stack | Stack | Symbolic stack state after interpretation |
| .memory | dict[int, ast.expr] | Symbolic memo dictionary state |
| .module_body | ModuleBody | Generated AST statements |
Usage Examples
Decompile a Pickle File
import ast
from fickling.fickle import Pickled, Interpreter
# Parse pickle
with open("model.pkl", "rb") as f:
pickled = Pickled.load(f)
# Convert to AST
interpreter = Interpreter(pickled)
module = interpreter.to_ast()
# Unparse to readable Python
source = ast.unparse(module)
print(source)
Inspect AST Properties
from fickling.fickle import Pickled, Interpreter
with open("suspect.pkl", "rb") as f:
pickled = Pickled.load(f)
interpreter = Interpreter(pickled)
module = interpreter.to_ast()
# Walk AST to find imports
import ast
for node in ast.walk(module):
if isinstance(node, ast.ImportFrom):
print(f"Import: from {node.module} import {[a.name for a in node.names]}")