Created
June 11, 2025 21:36
-
-
Save atucom/c6fb250cb88e2449474c672bb492a66c to your computer and use it in GitHub Desktop.
Get a consensus agreed rebuild of a firmware dump from multiple noisy dumps
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import argparse | |
import numpy as np | |
from collections import Counter | |
# atucom | |
# example: $ python3 clean_firmware.py --threshold=0.8 firmware-dump/full_backup*.bin | |
def load_dumps(paths): | |
dumps = [np.fromfile(path, dtype=np.uint8) for path in paths] | |
lengths = [len(d) for d in dumps] | |
if len(set(lengths)) != 1: | |
raise ValueError("All dumps must be the same length") | |
return np.vstack(dumps) | |
def majority_vote(data, threshold=0.5): | |
clean = [] | |
no_consensus = [] | |
num_dumps, num_bytes = data.shape | |
required_votes = int(threshold * num_dumps) | |
for i in range(num_bytes): | |
column = data[:, i] | |
counts = Counter(column) | |
byte, freq = counts.most_common(1)[0] | |
if freq > required_votes: | |
clean.append(byte) | |
else: | |
clean.append(0xFF) # placeholder for unresolved | |
no_consensus.append((i, dict(counts))) | |
return np.array(clean, dtype=np.uint8), no_consensus | |
def write_output(clean, no_consensus, out_file, log_file): | |
clean.tofile(out_file) | |
with open(log_file, 'w') as f: | |
for offset, variants in no_consensus: | |
variants_str = ', '.join(f"{k:#04x}:{v}" for k, v in variants.items()) | |
f.write(f"Offset {offset:#08x}: No consensus [{variants_str}]\n") | |
def main(): | |
parser = argparse.ArgumentParser(description="Clean firmware from multiple noisy dumps.") | |
parser.add_argument('dumps', nargs='+', help="Paths to firmware dump files") | |
parser.add_argument('--out', default='reconstructed.bin', help="Output cleaned firmware") | |
parser.add_argument('--log', default='no_consensus.log', help="Log file for disagreements") | |
parser.add_argument('--threshold', type=float, default=0.5, help="Consensus threshold (0-1)") | |
args = parser.parse_args() | |
data = load_dumps(args.dumps) | |
clean, no_consensus = majority_vote(data, threshold=args.threshold) | |
write_output(clean, no_consensus, args.out, args.log) | |
print(f"✅ Cleaned firmware saved to {args.out}") | |
if no_consensus: | |
print(f"⚠️ {len(no_consensus)} bytes had no consensus. See {args.log} for details.") | |
else: | |
print("🎉 Full consensus across all bytes.") | |
if __name__ == '__main__': | |
main() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment