Ivan Holmes
5 years ago
commit
616238aaad
7 changed files with 257 additions and 0 deletions
-
37auto.py
-
78clishared.py
-
19patchbios.py
-
8patches.py
-
31readbios.py
-
63romtools.py
-
21writebios.py
@ -0,0 +1,37 @@ |
|||||
|
from pathlib import Path |
||||
|
|
||||
|
from clishared import cli_connect_rom, cli_read_rom, cli_patch_rom, cli_write_rom, cli_choose_patches |
||||
|
|
||||
|
print("ThinkPad X230 Automatic Firmware Extract and Patch v1") |
||||
|
|
||||
|
project_name = input("What would you like to name your project? ") |
||||
|
project_name = project_name.replace("\\", "") # Remove backslashes so I can drag and drop folders |
||||
|
project_path = Path(project_name).resolve() |
||||
|
|
||||
|
if project_path.exists(): |
||||
|
if project_path.is_file(): |
||||
|
raise FileExistsError(f"Cannot create project folder {project_path}, a file already exists here.") |
||||
|
elif project_path.is_dir(): |
||||
|
response = input("Folder already exists at this location. Proceed and risk overwriting existing files? (y/N): ") |
||||
|
if not response or (response.strip()[0] not in ['y', 'Y']): |
||||
|
raise FileExistsError(f"Cannot create project folder {project_path}, a directory already exists here.") |
||||
|
else: |
||||
|
project_path.mkdir() |
||||
|
|
||||
|
clean_path = project_path / "clean" |
||||
|
if not clean_path.exists(): |
||||
|
clean_path.mkdir() |
||||
|
|
||||
|
patched_path = project_path / "patched" |
||||
|
if not patched_path.exists(): |
||||
|
patched_path.mkdir() |
||||
|
|
||||
|
patches = cli_choose_patches() |
||||
|
|
||||
|
cli_connect_rom("top") |
||||
|
|
||||
|
cli_read_rom("top", clean_path) |
||||
|
cli_patch_rom(patches, clean_path, patched_path) |
||||
|
cli_write_rom("top", patched_path) |
||||
|
|
||||
|
print("All done.") |
@ -0,0 +1,78 @@ |
|||||
|
from pathlib import Path |
||||
|
import filecmp |
||||
|
|
||||
|
from romtools import * |
||||
|
|
||||
|
def cli_join_rom(clean_path): |
||||
|
print("Joining dumps in to full firmware ROM... ", end="") |
||||
|
with open(clean_path / "bottom.bin", "rb") as bottom, open(clean_path / "top.bin", "rb") as top, open(clean_path / "clean.rom", "wb+") as rom: |
||||
|
rom.write(bottom.read() + top.read()) |
||||
|
print("Done.") |
||||
|
|
||||
|
def cli_split_rom(patched_path): |
||||
|
print("Splitting full rom in to images for each chip... ", end="") |
||||
|
with open(patched_path / "bottom.bin", "wb+") as bottom, open(patched_path / "top.bin", "wb+") as top, open(patched_path / "patched.rom", "rb") as rom: |
||||
|
rom_array = rom.read() |
||||
|
bottom.write(rom_array[:0x800000]) |
||||
|
top.write(rom_array[0x800000:]) |
||||
|
print("Done.") |
||||
|
|
||||
|
def cli_connect_rom(chip_loc): |
||||
|
input(f"Please connect programming clip to {chip_loc} flash chip. Press Enter when done...") |
||||
|
cli_reconnect_rom(chip_loc) |
||||
|
|
||||
|
def cli_reconnect_rom(chip_loc): |
||||
|
print("Checking if ROM is connected... ", end="") |
||||
|
try: |
||||
|
check_rom(chip_loc) |
||||
|
print("ROM is reachable.") |
||||
|
except: |
||||
|
response = input("ROM is not reachable. Try again? (Y/q): ") |
||||
|
if response in ['q', 'Q']: |
||||
|
raise ROMError("Could not connect to ROM. User elected to quit.") |
||||
|
else: |
||||
|
cli_reconnect_rom(chip_loc) |
||||
|
|
||||
|
def cli_read_rom(chip_loc, clean_path, verify=True): |
||||
|
files = [chip_loc + ".bin", chip_loc + "_2.bin"] if verify else [chip_loc + ".bin"] |
||||
|
for count, file_name in enumerate(files): |
||||
|
print(f"Reading {chip_loc} ROM, pass {count+1} of {len(files)}... ", end="", flush=True) |
||||
|
read_rom(chip_loc, clean_path, file_name) |
||||
|
print("Success.") |
||||
|
|
||||
|
if verify: |
||||
|
print("Comparing ROM files... ", end="") |
||||
|
if filecmp.cmp(clean_path / files[0], clean_path / files[1]): |
||||
|
print("Files match.") |
||||
|
else: |
||||
|
raise ROMError("ROM files do not match. Read the log and try again.") |
||||
|
else: |
||||
|
print("ROM file will not be verified, proceed at your own risk!") |
||||
|
|
||||
|
print(f"{chip_loc.capitalize()} ROM read successfully.") |
||||
|
|
||||
|
def cli_write_rom(chip_loc, patched_path, verify=True): |
||||
|
file_name = chip_loc + '_patched.bin' |
||||
|
print(f"Writing {chip_loc} ROM (takes a while)... ", end="", flush=True) |
||||
|
write_rom(chip_loc, patched_path, file_name) |
||||
|
print("Success.") |
||||
|
|
||||
|
print(f"{chip_loc.capitalize()} ROM written successfully.") |
||||
|
|
||||
|
def cli_choose_patches(): |
||||
|
which_patches = input("Patch (W)LAN whitelist, (A)dvanced menu or (B)oth? ") |
||||
|
|
||||
|
if which_patches.strip()[0] in ['w', 'W']: |
||||
|
patches = ["wifi"] |
||||
|
elif which_patches.strip()[0] in ['a', 'A']: |
||||
|
patches = ["advanced"] |
||||
|
elif which_patches.strip()[0] in ['b', 'B']: |
||||
|
patches = ["wifi", "advanced"] |
||||
|
else: |
||||
|
raise ValueError("Selection invalid.") |
||||
|
|
||||
|
return patches |
||||
|
|
||||
|
def cli_patch_rom(patches, clean_path, patched_path): |
||||
|
patch_rom(patches, clean_path / "top.bin", patched_path / "top_patched.bin") |
||||
|
print("ROM patched successfully.") |
@ -0,0 +1,19 @@ |
|||||
|
import os, subprocess |
||||
|
from pathlib import Path |
||||
|
|
||||
|
from clishared import cli_patch_rom, cli_choose_patches |
||||
|
|
||||
|
print("ThinkPad X230 Bios Patcher v1") |
||||
|
|
||||
|
project_name = input("Where is your project folder? ") |
||||
|
project_name = project_name.replace("\\", "") # Remove backslashes so I can drag and drop folders |
||||
|
project_path = Path(project_name).resolve() |
||||
|
|
||||
|
patched_path = project_path / "patched" |
||||
|
clean_path = project_path / "clean" |
||||
|
|
||||
|
if not patched_path.exists(): |
||||
|
patched_path.mkdir() |
||||
|
|
||||
|
patches = cli_choose_patches() |
||||
|
cli_patch_rom(patches, clean_path, patched_path) |
@ -0,0 +1,8 @@ |
|||||
|
PATCH_DATA = {"wifi": """# Remove WLAN whitelist |
||||
|
79E0EDD7-9D1D-4F41-AE1A-F896169E5216 10 O:C83:90E9 |
||||
|
79E0EDD7-9D1D-4F41-AE1A-F896169E5216 10 O:CD9:00 |
||||
|
79E0EDD7-9D1D-4F41-AE1A-F896169E5216 10 O:CEE:EB |
||||
|
""", |
||||
|
"advanced": """# Replace Date tab with Advanced tab |
||||
|
32442D09-1D11-4E27-8AAB-90FE6ACB0489 10 P:04320b483cc2e14abb16a73fadda475f:778b1d826d24964e8e103467d56ab1ba |
||||
|
"""} |
@ -0,0 +1,31 @@ |
|||||
|
from pathlib import Path |
||||
|
|
||||
|
from clishared import cli_join_rom, cli_read_rom |
||||
|
|
||||
|
print("ThinkPad X230 Bios Dumper v1") |
||||
|
|
||||
|
project_name = input("What would you like to name your project? ") |
||||
|
project_path = Path(project_name).resolve() |
||||
|
|
||||
|
if project_path.exists(): |
||||
|
if project_path.is_file(): |
||||
|
raise FileExistsError(f"Cannot create project folder {project_path}, a file already exists here.") |
||||
|
elif project_path.is_dir(): |
||||
|
response = input("Folder already exists at this location. Proceed and risk overwriting existing files? (y/N): ") |
||||
|
if not response or (response.strip()[0] not in ['y', 'Y']): |
||||
|
raise FileExistsError(f"Cannot create project folder {project_path}, a directory already exists here.") |
||||
|
else: |
||||
|
project_path.mkdir() |
||||
|
|
||||
|
clean_path = project_path / "clean" |
||||
|
if not clean_path.exists(): |
||||
|
clean_path.mkdir() |
||||
|
|
||||
|
cli_read_rom("bottom", clean_path) |
||||
|
# Bell to remind user to move clip |
||||
|
print("\a", end="") |
||||
|
cli_read_rom("top", clean_path) |
||||
|
|
||||
|
cli_join_rom(clean_path) |
||||
|
|
||||
|
print("All done.") |
@ -0,0 +1,63 @@ |
|||||
|
import subprocess |
||||
|
from pathlib import Path |
||||
|
|
||||
|
from patches import PATCH_DATA |
||||
|
|
||||
|
TOP_ROM_TYPE = "MX25L3206E/MX25L3208E" |
||||
|
BOTTOM_ROM_TYPE = "MX25L6406E/MX25L6408E" |
||||
|
PROGRAMMER = "ch341a_spi" |
||||
|
|
||||
|
UEFIPATCH_LOCATION = "./UEFIPatch_0.28.0_mac/UEFIPatch" |
||||
|
|
||||
|
LOG_FILE_NAME = "x230patch.log" |
||||
|
|
||||
|
class ROMError(Exception): |
||||
|
pass |
||||
|
|
||||
|
def log(text): |
||||
|
with open(LOG_FILE_NAME, 'a') as f: |
||||
|
f.write(text) |
||||
|
|
||||
|
def check_rom(chip_loc): |
||||
|
if chip_loc == "top": |
||||
|
chip = TOP_ROM_TYPE |
||||
|
elif chip_loc == "bottom": |
||||
|
chip = BOTTOM_ROM_TYPE |
||||
|
|
||||
|
fr = subprocess.run(["flashrom", "-p", PROGRAMMER, "-c", chip], capture_output=True) |
||||
|
log(fr.stdout.decode('ascii')) |
||||
|
if fr.returncode != 0: |
||||
|
raise ROMError("ROM not found.") |
||||
|
|
||||
|
def read_rom(chip_loc, save_dir, file_name): |
||||
|
if chip_loc == "top": |
||||
|
chip = TOP_ROM_TYPE |
||||
|
elif chip_loc == "bottom": |
||||
|
chip = BOTTOM_ROM_TYPE |
||||
|
|
||||
|
fr = subprocess.run(["flashrom", "-p", PROGRAMMER, "-c", chip, "-r", file_name], cwd=save_dir, capture_output=True) |
||||
|
log(fr.stdout.decode('ascii')) |
||||
|
if fr.returncode != 0: |
||||
|
raise ROMError |
||||
|
|
||||
|
def write_rom(chip_loc, open_dir, file_name): |
||||
|
if chip_loc == "top": |
||||
|
chip = TOP_ROM_TYPE |
||||
|
elif chip_loc == "bottom": |
||||
|
chip = BOTTOM_ROM_TYPE |
||||
|
|
||||
|
fr = subprocess.run(["flashrom", "-p", PROGRAMMER, "-c", chip, "-w", file_name], cwd=open_dir, capture_output=True) |
||||
|
log(fr.stdout.decode('ascii')) |
||||
|
if fr.returncode != 0: |
||||
|
raise ROMError |
||||
|
|
||||
|
def patch_rom(patches, open_path, save_path): |
||||
|
patches_path = save_path.parent / "patches.txt" |
||||
|
with open(patches_path, 'w') as patches_file: |
||||
|
for patch in patches: |
||||
|
patches_file.write(PATCH_DATA[patch]) |
||||
|
|
||||
|
up = subprocess.run([UEFIPATCH_LOCATION, open_path, patches_path, "-o", save_path], capture_output=True) |
||||
|
log(up.stdout.decode('ascii')) |
||||
|
if up.returncode != 0: |
||||
|
raise ROMError("Patching failed.") |
@ -0,0 +1,21 @@ |
|||||
|
import os, subprocess |
||||
|
from pathlib import Path |
||||
|
|
||||
|
from clishared import cli_split_rom, cli_write_rom |
||||
|
|
||||
|
print("ThinkPad X230 Bios Writer v1") |
||||
|
|
||||
|
project_name = input("Where is your project folder? ") |
||||
|
project_path = Path(project_name).resolve() |
||||
|
|
||||
|
patched_path = project_path / "patched" |
||||
|
clean_path = project_path / "clean" |
||||
|
|
||||
|
cli_split_rom(patched_path) |
||||
|
|
||||
|
cli_write_rom("bottom", patched_path) |
||||
|
# Bell to remind user to move clip |
||||
|
print("\a", end="") |
||||
|
cli_write_rom("top", patched_path) |
||||
|
|
||||
|
print("All done.") |
Write
Preview
Loading…
Cancel
Save
Reference in new issue