Container Transforms¶
Container Transforms are specialized transforms that enable Binary Ninja to extract and navigate files within container formats such as ZIP archives, disk images, and other multi-file structures. Unlike simple encoding transforms (Base64, Hex, etc.), container transforms can produce multiple output files and interact with the Container Browser UI.
You can list all available container transforms (those with detection support) using:
>>> [x.name for x in Transform if getattr(x, "supports_detection", False)]
['Gzip', 'Zlib', 'Zip', 'CaRT', 'IntelHex', 'SRec', 'TiTxt', 'IMG4', 'LZFSE']
Overview¶
The Transform API provides the foundation for creating custom container decoders. Container transforms differ from standard transforms in that they:
- Support context-aware decoding via
perform_decode_with_context() - Can produce multiple output files from a single input
- Support password protection and other interactive parameters
- Integrate with the Container Browser UI for file selection
Basic Transform Structure¶
All transforms, including container transforms, inherit from the Transform base class. Here's a minimal example:
from binaryninja import Transform, TransformType, TransformCapabilities
class MyContainerTransform(Transform):
transform_type = TransformType.DecodeTransform
capabilities = TransformCapabilities.TransformSupportsContext | TransformCapabilities.TransformSupportsDetection
name = "MyContainer"
long_name = "My Container Format"
group = "Container"
def can_decode(self, input):
"""Check if this transform can decode the input"""
# Check for magic bytes or other signatures
head = input.read(0, 4)
return head == b"MYCN" # Your format's magic bytes
def perform_decode_with_context(self, context, params):
"""Context-aware extraction for multi-file containers"""
# Implementation details below
pass
# Register the transform
MyContainerTransform.register()
Container Extraction Protocol¶
Container transforms typically operate in two phases:
Phase 1: Discovery¶
During discovery, the transform enumerates all available files and populates context.available_files:
def perform_decode_with_context(self, context, params):
# Parse the container format
container = parse_my_format(context.input)
# Phase 1: Discovery
if not context.has_available_files:
file_list = [entry.name for entry in container.entries]
context.set_available_files(file_list)
return False # More user interaction needed
Returning False indicates that the Container Browser should present these files to the user for selection.
Phase 2: Extraction¶
Once the user selects files, the transform extracts them and creates child contexts:
def perform_decode_with_context(self, context, params):
container = parse_my_format(context.input)
# Phase 1: Discovery (as above)
if not context.has_available_files:
# ... discovery code ...
return False
# Phase 2: Extraction
requested = context.requested_files
if not requested:
return False # No files selected yet
complete = True
for filename in requested:
try:
data = container.extract(filename)
context.create_child(DataBuffer(data), filename)
except Exception as e:
# Create child with error status
context.create_child(
DataBuffer(b""),
filename,
result=TransformResult.TransformFailure,
message=str(e)
)
complete = False
return complete # True if all files extracted successfully
Complete Example: ZipPython¶
Binary Ninja includes a reference implementation of a ZIP container transform in api/python/transform.py.
Transform Results and Error Handling¶
Use TransformResult values to communicate extraction status:
TransformResult.TransformSuccess: Extraction completed successfullyTransformResult.TransformNotAttempted: Extraction not attemptedTransformResult.TransformFailure: Generic extraction failureTransformResult.TransformRequiresPassword: File is encrypted and needs a password
Set results on individual child contexts:
context.create_child(
data=databuffer.DataBuffer(extracted_data),
filename="file.bin",
result=TransformResult.TransformSuccess,
message="" # Optional success message
)
Working with Passwords¶
Container transforms should integrate with Binary Ninja's password management system:
# Get passwords from settings
passwords = Settings().get_string_list('files.container.defaultPasswords')
# Check for password in transform parameters
if "password" in params:
p = params["password"]
pwd = p.decode("utf-8", "replace") if isinstance(p, (bytes, bytearray)) else str(p)
passwords.insert(0, pwd)
# Try each password
for password in passwords:
try:
content = extract_with_password(container, filename, password)
break # Success!
except PasswordError:
continue # Try next password
When a file requires a password that wasn't provided, use TransformResult.TransformRequiresPassword to signal the UI to prompt the user.
Metadata and Virtual Paths¶
Container transforms automatically create metadata that tracks the extraction chain:
# After opening a file extracted through containers:
>>> bv.parent_view.auto_metadata['container']
{
'chain': [
{'transform': 'Zip'},
{'transform': 'Base64'}
],
'virtualPath': 'Zip(/path/to/archive.zip)::Base64(encoded_file)::extracted'
}
You can also add custom metadata to child contexts:
child = context.create_child(data, filename)
if child.metadata_obj:
child.metadata_obj["custom_field"] = "value"
Testing Container Transforms¶
When testing your container transform, you can use the Python API directly:
from binaryninja import TransformSession
# Test with a file
session = TransformSession("test_container.bin")
# Process and check results
if session.process():
print(f"Extraction complete: {session.current_context.filename}")
else:
print("User interaction required")
ctx = session.current_context
if ctx.parent and ctx.parent.has_available_files:
print(f"Available files: {ctx.parent.available_files}")
For interactive testing in the UI:
- Full Mode: Settings →
files.container.mode→ "Full" - Opens your container and shows all extracted files immediately
- Interactive Mode: Settings →
files.container.mode→ "Interactive" - Requires clicking through each level of the container hierarchy
API Reference¶
For complete API documentation, see:
Transform- Base transform classTransformContext- Container extraction contextTransformSession- Multi-stage extraction workflowTransformResult- Extraction result codesTransformCapabilities- Transform capability flags