Principle:Trailofbits Fickling Pickle VM Tracing
| Knowledge Sources | |
|---|---|
| Domains | Security, Reverse_Engineering, Forensics |
| Last Updated | 2026-02-14 14:00 GMT |
Overview
A step-by-step execution tracing technique for the pickle virtual machine that logs every opcode, stack operation, memo change, and generated statement during symbolic interpretation.
Description
Pickle VM Tracing provides visibility into the internal state changes of the pickle interpreter as it processes each opcode. While decompilation produces the final Python code, tracing shows the journey — which opcodes were executed, what was pushed to and popped from the stack, how the memo dictionary evolved, and which Python statements were generated.
This is essential for:
- Forensic analysis: Understanding exactly how a malicious pickle constructs its payload
- Debugging: Diagnosing why interpretation produces unexpected results
- Education: Learning how the pickle protocol works at the VM level
The tracer uses a callback pattern, invoking hooks for each event type (opcode execution, stack push/pop, memo write/update, statement generation).
Usage
Use this principle when you need to understand the step-by-step behavior of a pickle file, especially for forensic investigation of malicious payloads where the final decompiled output alone is insufficient to understand the attack technique.
Theoretical Basis
# Pseudocode: Event-driven tracing
while has_next_opcode:
state_before = snapshot(stack, memo, statements)
opcode = interpreter.step()
on_opcode(opcode)
for new_statement in statements_since(state_before):
on_statement(new_statement)
for popped in stack_diff.removed:
on_pop(popped)
for pushed in stack_diff.added:
on_push(pushed)
for key, value in memo_diff.new:
on_memoize(key, value)
for key, old, new in memo_diff.changed:
on_update_memo(key, old, new)