Oracle interface
A memdiver oracle is a short Python script that answers a single yes/no question per candidate: is this byte string the real key?
You write the oracle. Memdiver owns the rest of the pipeline:
consensus-begin/add/finalizebuilds the variance matrix.search-reducenarrows the candidate set via alignment + entropy.brute-forceiterates every(offset, key_size)slice through your oracle. When one returnsTrue, memdiver records the hit and the neighborhood variance slice from the stored Welford state.emit-pluginturns that neighborhood into a Volatility3 plugin.
The oracle is invoked via --oracle /abs/path/to/script.py. Memdiver
prints the SHA-256 of the loaded file to stderr on startup and refuses
to load oracles from world-writable files or directories. Beyond that
it is equivalent to find -exec — the script runs with your privileges,
on your evidence, with full filesystem and network access. There is no
sandbox because sandboxes break legitimate network-replay and
filesystem-probe oracles. Treat unknown oracles like any other piece of
untrusted code.
Two accepted shapes
Memdiver auto-detects which shape you used and wraps both into a flat
verify(bytes) -> bool callable internally.
Shape 1 — stateless function
Use this when your verification is cheap and has no setup cost.
# my_oracle.py
EXPECTED = bytes.fromhex("deadbeef" * 8)
def verify(candidate: bytes) -> bool:
return candidate == EXPECTED
Run it with:
memdiver brute-force \
--candidates candidates.json \
--dump reference.msl \
--oracle /abs/path/to/my_oracle.py \
--key-sizes 32 \
-o hits.json
Shape 2 — stateful factory
Use this when verification needs to cache derivations (KDF, scrypt), hold a network socket open, or mmap a large ciphertext once.
# tls_oracle.py
from pathlib import Path
def build_oracle(config: dict):
return TlsOracle(config)
class TlsOracle:
def __init__(self, config: dict):
self.record = Path(config["encrypted_record"]).read_bytes()
self.nonce = bytes.fromhex(config["record_nonce_hex"])
self.handshake_hash = bytes.fromhex(config["handshake_hash_hex"])
def verify(self, candidate: bytes) -> bool:
if len(candidate) not in (32, 48):
return False
try:
# derive keys from candidate as traffic-secret, AEAD-decrypt
...
return True
except Exception:
return False
def close(self): # optional, called on teardown
pass
The config dict comes from an optional TOML file:
memdiver brute-force \
--candidates candidates.json \
--dump reference.msl \
--oracle /abs/path/to/tls_oracle.py \
--oracle-config /abs/path/to/tls_oracle.toml \
--key-sizes 32,48 \
-o hits.json
# tls_oracle.toml
encrypted_record = "/home/you/captures/record_0.bin"
record_nonce_hex = "001122..."
handshake_hash_hex = "aabbcc..."
Contract notes
Always return a plain
bool— notTrue/False/None, not an int. Non-bool returns are coerced viabool()but explicit beats implicit.Reject the wrong key length cheaply. The hot loop may try 16, 24, and 32-byte candidates at every offset — a fast length-check keeps expensive derivations off the short-key path.
Catch exceptions internally. A raised exception is treated as a
Falsereturn and logged at debug level, but a deterministicFalsemakes stacks and latency easier to read.Do not hold global state across runs. Each
memdiver brute-forceinvocation loads the module fresh; if you use Shape 2 with--jobs > 1, each worker process re-imports and re-runsbuild_oracle, so any caching must live in instance state.The oracle has no visibility into which offset is being tested. This is by design — memdiver owns the offset bookkeeping so the hit metadata (offset, neighborhood variance, vol3 anchor) stays consistent across all users of the interface.
Ready-made templates
docs/oracle/examples/generic_aes_gcm.py— stateless AES-GCM boilerplate.docs/oracle/examples/gocryptfs.py— HKDF + AES-GCM verification of a gocryptfs file-content key derived from a candidate master key.docs/oracle/examples/tls13_stub.py— TLS 1.3 traffic-secret scaffolding (stateful; you fill in the HKDF-Expand-Label derivation).
Copy any of these into your experiment directory, adjust the config
keys for your target, and point --oracle at the result.