diff --git a/fix_footer_final.py b/fix_footer_final.py new file mode 100644 index 0000000..9569da8 --- /dev/null +++ b/fix_footer_final.py @@ -0,0 +1,43 @@ +import hashlib +import struct +import os + +def fix_esp32_image(file_path): + print(f"Fixing {file_path}...") + with open(file_path, "rb") as f: + data = bytearray(f.read()) + + n_segments = data[1] + pos = 0x18 + checksum = 0xEF + for i in range(n_segments): + header = data[pos:pos+8] + if len(header) < 8: break + seg_len = struct.unpack("= pos + 1 + 32: + data[pos+1:pos+33] = new_hash + + with open(file_path, "wb") as f: + f.write(data) + print(f"Fixed footer for {file_path}") + +if __name__ == "__main__": + PATCHED_DIR = "/home/sapient/Public/esp32-analysis/patched_binaries" + files = [ + os.path.join(PATCHED_DIR, "Ultra-TDeck-v9.2.patched.bin"), + os.path.join(PATCHED_DIR, "MeshOS-TDeck-1.1.8.patched.bin") + ] + for f in files: + fix_esp32_image(f) diff --git a/patched_binaries/MeshOS-TDeck-1.1.8-merged.patched.bin b/patched_binaries/MeshOS-TDeck-1.1.8-merged.patched.bin index 1c7f8e2..51f4a31 100644 Binary files a/patched_binaries/MeshOS-TDeck-1.1.8-merged.patched.bin and b/patched_binaries/MeshOS-TDeck-1.1.8-merged.patched.bin differ diff --git a/patched_binaries/MeshOS-TDeck-1.1.8.patched.bin b/patched_binaries/MeshOS-TDeck-1.1.8.patched.bin index e3b231a..7bd197a 100644 Binary files a/patched_binaries/MeshOS-TDeck-1.1.8.patched.bin and b/patched_binaries/MeshOS-TDeck-1.1.8.patched.bin differ diff --git a/patched_binaries/Ultra-TDeck-v9.2-merged.patched.bin b/patched_binaries/Ultra-TDeck-v9.2-merged.patched.bin index 39ef63d..1251a9b 100644 Binary files a/patched_binaries/Ultra-TDeck-v9.2-merged.patched.bin and b/patched_binaries/Ultra-TDeck-v9.2-merged.patched.bin differ diff --git a/patched_binaries/Ultra-TDeck-v9.2.patched.bin b/patched_binaries/Ultra-TDeck-v9.2.patched.bin index e81cc45..cf11caa 100644 Binary files a/patched_binaries/Ultra-TDeck-v9.2.patched.bin and b/patched_binaries/Ultra-TDeck-v9.2.patched.bin differ diff --git a/verify_patches.py b/verify_patches.py new file mode 100755 index 0000000..e285893 --- /dev/null +++ b/verify_patches.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 +import os +import sys + +def check_binary(file_path, patches): + if not os.path.exists(file_path): + return f"MISSING: {file_path}" + + with open(file_path, "rb") as f: + data = f.read() + + results = [] + for name, offset, expected, patched in patches: + if data[offset:offset+len(expected)] == expected: + results.append(f" [FAIL] {name}: UNPATCHED (found {expected.hex()})") + elif data[offset:offset+len(patched)] == patched: + results.append(f" [PASS] {name}: PATCHED (found {patched.hex()})") + else: + found = data[offset:offset+max(len(expected), len(patched))].hex() + results.append(f" [ERR] {name}: UNKNOWN (expected {patched.hex()}, found {found})") + + return "\n".join(results) + +if __name__ == "__main__": + PATCHED_DIR = "/home/sapient/Public/esp32-analysis/patched_binaries" + + ultra_patches = [ + ("UI Branch", 0xBA62D, bytes.fromhex("26153c"), bytes.fromhex("060f00")), + ("Global Status (Round 2)", 0xBA6AD, bytes.fromhex("040242"), bytes.fromhex("221000")) + ] + + meshos_patches = [ + ("UI Branch", 0xB99ED, bytes.fromhex("26193c"), bytes.fromhex("060f00")), + ("Global Status (Round 2)", 0xB9A54, bytes.fromhex("84210040"), bytes.fromhex("221000")) + ] + + targets = [ + ("Ultra Standalone", os.path.join(PATCHED_DIR, "Ultra-TDeck-v9.2.patched.bin"), ultra_patches), + ("Ultra Merged", os.path.join(PATCHED_DIR, "Ultra-TDeck-v9.2-merged.patched.bin"), + [(n, o+0x10000, e, p) for n, o, e, p in ultra_patches]), + ("MeshOS Standalone", os.path.join(PATCHED_DIR, "MeshOS-TDeck-1.1.8.patched.bin"), meshos_patches), + ("MeshOS Merged", os.path.join(PATCHED_DIR, "MeshOS-TDeck-1.1.8-merged.patched.bin"), + [(n, o+0x10000, e, p) for n, o, e, p in meshos_patches]) + ] + + all_passed = True + print("=== Firmware Patch Verification Harness ===") + for label, path, p in targets: + print(f"\n{label}:") + report = check_binary(path, p) + print(report) + if "[FAIL]" in report or "[ERR]" in report or "MISSING" in report: + all_passed = False + + if all_passed: + print("\n[COMPLETE] All binaries are fully patched.") + sys.exit(0) + else: + print("\n[INCOMPLETE] Some patches are missing or invalid.") + sys.exit(1) diff --git a/verify_patches_now.py b/verify_patches_now.py new file mode 100755 index 0000000..a0b7767 --- /dev/null +++ b/verify_patches_now.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python3 +import os +import sys + +# TDD Verification Harness for Patched ESP32-S3 Binaries +# Extensible framework for verifying known 'always-true' patches. + +# --- Patch Definitions --- +# The keys represent the target identifier (substring match against filename). +# 'offset': Relative to the start of the app partition (usually 0x10000 in merged binaries). +# 'original': The unpatched bytecode. +# 'patched': The expected bytecode after patching. +PATCH_DEFS = { + "Ultra-TDeck": { + "patches": [ + { + "name": "Always-True License Check", + "app_offset": 0xBA62D, + "original": bytes([0x26, 0x15, 0x3C]), + "patched": bytes([0x06, 0x0F, 0x00]), + } + ] + }, + "MeshOS": { + "patches": [ + { + "name": "Always-True License Check", + "app_offset": 0xB99ED, + "original": bytes([0x26, 0x19, 0x3C]), + "patched": bytes([0x06, 0x0F, 0x00]), + } + ] + }, +} + +# --- Known Binaries to Verify --- +BINARIES_TO_CHECK = [ + "patched_binaries/Ultra-TDeck-v9.2.patched.bin", + "patched_binaries/Ultra-TDeck-v9.2-merged.patched.bin", + "patched_binaries/MeshOS-TDeck-1.1.8.patched.bin", + "patched_binaries/MeshOS-TDeck-1.1.8-merged.patched.bin", +] + + +def verify_binary(filepath): + print(f"[*] Verifying binary: {filepath}") + + if not os.path.exists(filepath): + print(f" [!] ERROR: File not found: {filepath}") + return False + + filename = os.path.basename(filepath) + + # Determine the target type based on filename + target_def = None + for key, defs in PATCH_DEFS.items(): + if key in filename: + target_def = defs + break + + if not target_def: + print(f" [!] ERROR: No patch definitions found for {filename}") + return False + + # Adjust offset if the binary is merged (app partition starts at 0x10000) + is_merged = "merged" in filename.lower() + base_offset = 0x10000 if is_merged else 0x0 + + all_passed = True + + try: + with open(filepath, "rb") as f: + for patch in target_def["patches"]: + absolute_offset = base_offset + patch["app_offset"] + + f.seek(absolute_offset) + read_bytes = f.read(len(patch["patched"])) + + print( + f" -> Checking '{patch['name']}' at offset 0x{absolute_offset:X}..." + ) + + if read_bytes == patch["patched"]: + print( + f" [OK] Patch verified! Expected: {patch['patched'].hex()}, Found: {read_bytes.hex()}" + ) + elif read_bytes == patch["original"]: + print( + f" [FAIL] Binary is UNPATCHED. Expected: {patch['patched'].hex()}, Found: {read_bytes.hex()} (Original)" + ) + all_passed = False + else: + print( + f" [FAIL] Unknown bytes found. Expected: {patch['patched'].hex()}, Found: {read_bytes.hex()}" + ) + all_passed = False + + except Exception as e: + print(f" [!] ERROR: Failed to read binary: {e}") + return False + + return all_passed + + +def main(): + base_dir = os.path.dirname(os.path.abspath(__file__)) + + print("=" * 60) + print(" ESP32-S3 Firmware Patch Verification Harness") + print("=" * 60) + + success_count = 0 + total_count = len(BINARIES_TO_CHECK) + + for relative_path in BINARIES_TO_CHECK: + full_path = os.path.join(base_dir, relative_path) + if verify_binary(full_path): + success_count += 1 + print("-" * 60) + + print(f"Verification Summary: {success_count}/{total_count} binaries passed.") + + if success_count == total_count: + print("RESULT: ALL PATCHES VERIFIED SUCCESSFULLY.") + sys.exit(0) + else: + print("RESULT: VERIFICATION FAILED FOR ONE OR MORE BINARIES.") + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/verify_this b/verify_this new file mode 100755 index 0000000..a0b7767 --- /dev/null +++ b/verify_this @@ -0,0 +1,132 @@ +#!/usr/bin/env python3 +import os +import sys + +# TDD Verification Harness for Patched ESP32-S3 Binaries +# Extensible framework for verifying known 'always-true' patches. + +# --- Patch Definitions --- +# The keys represent the target identifier (substring match against filename). +# 'offset': Relative to the start of the app partition (usually 0x10000 in merged binaries). +# 'original': The unpatched bytecode. +# 'patched': The expected bytecode after patching. +PATCH_DEFS = { + "Ultra-TDeck": { + "patches": [ + { + "name": "Always-True License Check", + "app_offset": 0xBA62D, + "original": bytes([0x26, 0x15, 0x3C]), + "patched": bytes([0x06, 0x0F, 0x00]), + } + ] + }, + "MeshOS": { + "patches": [ + { + "name": "Always-True License Check", + "app_offset": 0xB99ED, + "original": bytes([0x26, 0x19, 0x3C]), + "patched": bytes([0x06, 0x0F, 0x00]), + } + ] + }, +} + +# --- Known Binaries to Verify --- +BINARIES_TO_CHECK = [ + "patched_binaries/Ultra-TDeck-v9.2.patched.bin", + "patched_binaries/Ultra-TDeck-v9.2-merged.patched.bin", + "patched_binaries/MeshOS-TDeck-1.1.8.patched.bin", + "patched_binaries/MeshOS-TDeck-1.1.8-merged.patched.bin", +] + + +def verify_binary(filepath): + print(f"[*] Verifying binary: {filepath}") + + if not os.path.exists(filepath): + print(f" [!] ERROR: File not found: {filepath}") + return False + + filename = os.path.basename(filepath) + + # Determine the target type based on filename + target_def = None + for key, defs in PATCH_DEFS.items(): + if key in filename: + target_def = defs + break + + if not target_def: + print(f" [!] ERROR: No patch definitions found for {filename}") + return False + + # Adjust offset if the binary is merged (app partition starts at 0x10000) + is_merged = "merged" in filename.lower() + base_offset = 0x10000 if is_merged else 0x0 + + all_passed = True + + try: + with open(filepath, "rb") as f: + for patch in target_def["patches"]: + absolute_offset = base_offset + patch["app_offset"] + + f.seek(absolute_offset) + read_bytes = f.read(len(patch["patched"])) + + print( + f" -> Checking '{patch['name']}' at offset 0x{absolute_offset:X}..." + ) + + if read_bytes == patch["patched"]: + print( + f" [OK] Patch verified! Expected: {patch['patched'].hex()}, Found: {read_bytes.hex()}" + ) + elif read_bytes == patch["original"]: + print( + f" [FAIL] Binary is UNPATCHED. Expected: {patch['patched'].hex()}, Found: {read_bytes.hex()} (Original)" + ) + all_passed = False + else: + print( + f" [FAIL] Unknown bytes found. Expected: {patch['patched'].hex()}, Found: {read_bytes.hex()}" + ) + all_passed = False + + except Exception as e: + print(f" [!] ERROR: Failed to read binary: {e}") + return False + + return all_passed + + +def main(): + base_dir = os.path.dirname(os.path.abspath(__file__)) + + print("=" * 60) + print(" ESP32-S3 Firmware Patch Verification Harness") + print("=" * 60) + + success_count = 0 + total_count = len(BINARIES_TO_CHECK) + + for relative_path in BINARIES_TO_CHECK: + full_path = os.path.join(base_dir, relative_path) + if verify_binary(full_path): + success_count += 1 + print("-" * 60) + + print(f"Verification Summary: {success_count}/{total_count} binaries passed.") + + if success_count == total_count: + print("RESULT: ALL PATCHES VERIFIED SUCCESSFULLY.") + sys.exit(0) + else: + print("RESULT: VERIFICATION FAILED FOR ONE OR MORE BINARIES.") + sys.exit(1) + + +if __name__ == "__main__": + main()