Implementation:Trailofbits Fickling Trace Run
| Knowledge Sources | |
|---|---|
| Domains | Security, Reverse_Engineering, Forensics |
| Last Updated | 2026-02-14 14:00 GMT |
Overview
Concrete tool for step-by-step pickle VM execution tracing provided by the Fickling library.
Description
The Trace class wraps an Interpreter instance and executes it one opcode at a time via interpreter.step(). After each step, it computes state diffs (stack changes, memo changes, new statements) and invokes callback methods that print the trace to stdout. The run() method drives the full tracing loop and returns the final AST.
Usage
Use this for forensic analysis of suspicious pickle files. Create a Trace from an Interpreter (which must not have been run yet) and call run() to see the full execution trace.
Code Reference
Source Location
- Repository: fickling
- File: fickling/tracing.py
- Lines: L7-66
Signature
class Trace:
def __init__(self, interpreter: Interpreter):
"""
Args:
interpreter: An Interpreter instance that has not been run yet.
"""
def run(self) -> ast.AST:
"""Execute all opcodes with tracing and return the final AST.
Side effect: Prints step-by-step trace to stdout showing
opcode names, stack pushes/pops, memo operations, and
generated statements.
Returns:
ast.AST (same as interpreter.to_ast())
"""
def on_opcode(self, opcode: Opcode): ...
def on_pop(self, popped_value: ast.expr | MarkObject): ...
def on_push(self, pushed_value: ast.expr | MarkObject): ...
def on_memoize(self, index: int, value: ast.expr): ...
def on_update_memo(self, index: int, old_value: ast.expr, new_value: ast.expr): ...
def on_statement(self, statement: ast.stmt): ...
Import
from fickling.tracing import Trace
from fickling.fickle import Interpreter
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| interpreter | Interpreter | Yes | An Interpreter instance constructed from Pickled; must not have been run yet |
Outputs
| Name | Type | Description |
|---|---|---|
| run() returns | ast.AST | The final AST (same as interpreter.to_ast()) |
| Side effect | stdout | Step-by-step trace printed to stdout |
Usage Examples
Trace a Pickle File
from fickling.fickle import Pickled, Interpreter
from fickling.tracing import Trace
with open("suspect.pkl", "rb") as f:
pickled = Pickled.load(f)
interpreter = Interpreter(pickled)
trace = Trace(interpreter)
# Run with tracing - prints step-by-step to stdout
ast_result = trace.run()
# Also get decompiled source
import ast
print("\n--- Decompiled Source ---")
print(ast.unparse(ast_result))