Skip to content

Instantly share code, notes, and snippets.

@vi7
Last active September 5, 2026 08:32
Show Gist options
  • Select an option

  • Save vi7/5f4224c8d9cfb11b0900222b2d98d137 to your computer and use it in GitHub Desktop.

Select an option

Save vi7/5f4224c8d9cfb11b0900222b2d98d137 to your computer and use it in GitHub Desktop.
Macbook Pro 2010/2011 firmware password reset script. Tested on firmware dumped from MX25L6406E chip on Macbook Pro 15 early 2011

Macbook Pro Early 2011 firmware password reset

Info

Flash BIOS Chip

Macronix International
MXIC
MX25L6406E
M2I-12G

https://octopart.com/part/macronix/MX25L6406EM2I-12G

Removing a Mac's Firmware Password By Reflashing EFI ROM Guide

Details how to reach the actual firmware chip and connect to it: https://gist.github.com/willzhang05/e5b5563cdc65514dfb7ca131e03ca4b2

Commands: tested on macOS Tahoe 26.4

# check CH341B programmer

sudo flashrom -p ch341a_spi

# Read chip twice
sudo flashrom -p ch341a_spi -c "MX25L6406E/MX25L6408E" -r dump1.bin
sudo flashrom -p ch341a_spi -c "MX25L6406E/MX25L6408E" -r dump2.bin

# Compare binaries to ensure no read errors
sha256sum dump*.bin
# OR
cmp dump1.bin dump2.bin

# !!!! BACKUP locally and to the online storage !!!!
cp dump1.bin original.bin

# Reset password using script from this Gist (see internal details in the Gist mentioned above)
patch_svs.py dump1.bin modified.bin

# !!!!
# !!!! DANGEROUS !!!! Erase firmware chip
# INDFO: probably you would want to create one more dump for the original firmware
# and verify it before doing the actual erase/write
sudo flashrom -p ch341a_spi -E -V -c "MX25L6406E/MX25L6408E"

# !!!! DANGEROUS !!!! Write and verify
sudo flashrom -p ch341a_spi -V -c "MX25L6406E/MX25L6408E" -w modified.bin
#!/usr/bin/env python3
import sys
from pathlib import Path
MAGIC = b"$SVS"
FF_RUN = 8 # number of consecutive FF bytes defining an FF section
CONTEXT = 16 # bytes shown around each boundary
def hexline(data, start_offset):
return " ".join(f"{b:02X}" for b in data)
if len(sys.argv) != 3:
print(f"Usage: {sys.argv[0]} original.bin modified.bin")
sys.exit(1)
src = Path(sys.argv[1])
dst = Path(sys.argv[2])
data = bytearray(src.read_bytes())
print(f"Input: {src}")
print(f"Size: {len(data):,} bytes")
print()
if len(data) != 0x800000:
print("ERROR: input is not 8 MiB (0x800000 bytes)")
sys.exit(1)
positions = []
pos = 0
while True:
pos = data.find(MAGIC, pos)
if pos == -1:
break
positions.append(pos)
pos += len(MAGIC)
print(f"Found {len(positions)} '$SVS' block(s)")
print()
if not positions:
sys.exit("Nothing to modify.")
blocks = []
for start in positions:
# Search for first FF_RUN-length FF section after $SVS
search_from = start + len(MAGIC)
ff_start = None
for i in range(search_from, len(data) - FF_RUN + 1):
if data[i:i + FF_RUN] == b"\xFF" * FF_RUN:
ff_start = i
break
if ff_start is None:
print(f"ERROR: no FF section found after 0x{start:06X}")
sys.exit(1)
end = ff_start # FF section itself remains untouched
# Context around beginning
before_start = max(0, start - CONTEXT)
before = data[before_start:start]
# Context around end
after_end = min(len(data), ff_start + FF_RUN + CONTEXT)
after = data[ff_start:after_end]
print("=" * 70)
print(f"BLOCK")
print(f" start : 0x{start:06X} ({start:,})")
print(f" end : 0x{end - 1:06X} ({end - 1:,})")
print(f" size : {end - start:,} bytes")
print()
print("Before block:")
print(f" offset 0x{before_start:06X}: {hexline(before, before_start)}")
print()
print("Block beginning:")
print(f" offset 0x{start:06X}: {hexline(data[start:start + 32], start)}")
print()
print("Block ending / following FF:")
print(f" offset 0x{max(start, end - CONTEXT):06X}: "
f"{hexline(data[max(start, end - CONTEXT):after_end], max(start, end - CONTEXT))}")
print()
blocks.append((start, end))
print("=" * 70)
print()
print("Blocks found:")
for n, (start, end) in enumerate(blocks, 1):
print(
f"{n}: 0x{start:06X} - 0x{end - 1:06X} "
f"({end - start:,} bytes)"
)
print()
answer = input("Replace these blocks with FF? [y/N]: ").strip().lower()
if answer != "y":
print("Aborted. No output written.")
sys.exit(0)
for start, end in blocks:
data[start:end] = b"\xFF" * (end - start)
dst.write_bytes(data)
print()
print(f"Written: {dst}")
print(f"Size: {len(data):,} bytes")
if len(data) != len(src.read_bytes()):
print("ERROR: size changed!")
sys.exit(1)
print("Size verified: unchanged.")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment