diff --git a/me_cleaner.py b/me_cleaner.py index c2adf0e..473e761 100755 --- a/me_cleaner.py +++ b/me_cleaner.py @@ -22,6 +22,7 @@ import itertools import shutil import sys +import re from struct import pack, unpack @@ -44,6 +45,10 @@ "2011ae6df87c40fba09e3f20459b1ce0": ("ME", ("9.0.x.x", "9.1.x.x")), "e8427c5691cf8b56bc5cdd82746957ed": ("ME", ("9.5.x.x", "10.x.x.x")), "986a78e481f185f7d54e4af06eb413f6": ("ME", ("11.x.x.x",)), + "3efc26920b4bee901b624771c742887b": ("ME", ("12.x.x.x",)), + "8e4f834644da2bef03039d69d41ecf02": ("ME", ("14.x.x.x",)), + "b29411f89bf20ed177d411c46e8ec185": ("ME", ("15.x.x.x",)), + "5887caf9b677601ffb257cc98a13d2a9": ("ME", ("16.x.x.x",)), "bda0b6bb8ca0bf0cac55ac4c4d55e0f2": ("TXE", ("1.x.x.x",)), "b726a2ab9cd59d4e62fe2bead7cf6997": ("TXE", ("1.x.x.x",)), "0633d7f951a3e7968ae7460861be9cfb": ("TXE", ("2.x.x.x",)), @@ -64,6 +69,13 @@ def __init__(self, f, region_start, region_end): self.region_start = region_start self.region_end = region_end + def readall(self): + currentpos = self.f.tell() + self.f.seek(self.region_start) + toret = self.f.read(self.region_end - self.region_start) + self.f.seek(currentpos) + return toret + def read(self, n): if f.tell() + n <= self.region_end: return self.f.read(n) @@ -596,19 +608,16 @@ def start_end_to_flreg(start, end): sys.exit("Unknown image") if me_start < me_end: - mef.seek(0) - if mef.read(4) == b"$FPT": - fpt_offset = 0 - else: - mef.seek(0x10) - if mef.read(4) == b"$FPT": - fpt_offset = 0x10 - else: - if me_start > 0: - sys.exit("The ME/TXE region is valid but the firmware is " - "corrupted or missing") - else: - sys.exit("Unknown error") + medata = mef.readall() + fpt_matches = list((re.compile(br'\x24\x46\x50\x54.\x00\x00\x00', re.DOTALL)).finditer(medata)) + if (len(fpt_matches) == 0): + sys.exit("$FPT not found") + + if (len(fpt_matches) > 1): + sys.exit("more than one $FPT found") + + for fpt_match in fpt_matches: + fpt_offset = fpt_match.span()[0] if gen == 1: end_addr = 0 @@ -633,13 +642,21 @@ def start_end_to_flreg(start, end): break if ftpr_header == b"": - sys.exit("FTPR header not found, this image doesn't seem to be " - "valid") + # We might be dealing with IFWI firmware, look for $CPD with FPTR + ftpr_matches = list((re.compile(br'\x24\x43\x50\x44........\x46\x54\x50\x52', re.DOTALL)).finditer(medata)) - if ftpr_header[0x0:0x4] == b"CODE": - gen = 1 + if (len(ftpr_matches) == 1): + ftpr_offset = ftpr_matches[0].span()[0] + ftpr_length = 0 # As long as we only do soft-disable on IFWI, should be okay + else: + sys.exit("FTPR header not found, this image doesn't seem to be " + "valid") + else: + if ftpr_header[0x0:0x4] == b"CODE": + gen = 1 + + ftpr_offset, ftpr_length = unpack("= 15 seems to have 4 more bytes ## + ## I think the 4 bytes have to do something with Intel ME version or date, ## + ## but not sure. ## + ## Check for 'FTPR.man' ## + if bytes([0x46, 0x54, 0x50, 0x52, 0x2E, 0x6D, 0x61, 0x6E]) == data: + mef.seek(ftpr_offset + 0x14) + else: + mef.seek(ftpr_offset + 0x10) + ftpr_mn2_offset = -1 for i in range(0, num_entries): @@ -675,6 +703,16 @@ def start_end_to_flreg(start, end): mef.seek(ftpr_offset + ftpr_mn2_offset + 0x24) version = unpack(" me_end: - print(" {:<4} ({:^24}, 0x{:08x} total bytes): nothing to " - "remove" - .format(part_name, "no data here", part_length)) - else: - print(" {:<4} (0x{:08x} - 0x{:09x}, 0x{:08x} total bytes): " - .format(part_name, part_start, part_end, part_length), - end="") - if part_name in whitelist or (blacklist and - part_name not in blacklist): - unremovable_part_fpt += partition - if part_name != "FTPR": - extra_part_end = max(extra_part_end, part_end) - print("NOT removed") - else: - mef.fill_range(part_start, part_end, b"\xff") - print("removed") - - print("Removing partition entries in FPT...") - mef.write_to(0x30, unremovable_part_fpt) - mef.write_to(0x14, - pack("= 11 (except for - # 0x1b, the checksum itself). In other words, the sum of those - # bytes must be always 0x00. - mef.write_to(0x1b, pack("B", checksum)) - - print("Reading FTPR modules list...") - if gen == 3: - end_addr, ftpr_offset = \ - check_and_remove_modules_gen3(mef, me_end, - ftpr_offset, ftpr_length, - min_ftpr_offset, - args.relocate, - args.keep_modules) + if gen >= 4: + print("Module removal is not currently supported on IFWI firmware.") else: - end_addr, ftpr_offset = \ - check_and_remove_modules(mef, me_end, ftpr_offset, - min_ftpr_offset, args.relocate, - args.keep_modules) - - if end_addr > 0: - end_addr = max(end_addr, extra_part_end) - end_addr = (end_addr // 0x1000 + 1) * 0x1000 - end_addr += spared_blocks * 0x1000 - - print("The ME minimum size should be {0} bytes " - "({0:#x} bytes)".format(end_addr)) - - if me_start > 0: - print("The ME region can be reduced up to:\n" - " {:08x}:{:08x} me" - .format(me_start, me_start + end_addr - 1)) - elif args.truncate: - print("Truncating file at {:#x}...".format(end_addr)) - f.truncate(end_addr) + print("Reading partitions list...") + unremovable_part_fpt = b"" + extra_part_end = 0 + whitelist = [] + blacklist = [] + + whitelist += unremovable_partitions + + if args.blacklist: + blacklist = args.blacklist.split(",") + elif args.whitelist: + whitelist += args.whitelist.split(",") + + for i in range(entries): + partition = partitions[i * 0x20:(i + 1) * 0x20] + flags = unpack(" me_end: + print(" {:<4} ({:^24}, 0x{:08x} total bytes): nothing to " + "remove" + .format(part_name, "no data here", part_length)) + else: + print(" {:<4} (0x{:08x} - 0x{:09x}, 0x{:08x} total bytes): " + .format(part_name, part_start, part_end, part_length), + end="") + if part_name in whitelist or (blacklist and + part_name not in blacklist): + unremovable_part_fpt += partition + if part_name != "FTPR": + extra_part_end = max(extra_part_end, part_end) + print("NOT removed") + else: + mef.fill_range(part_start, part_end, b"\xff") + print("removed") + + print("Removing partition entries in FPT...") + mef.write_to(0x30, unremovable_part_fpt) + mef.write_to(0x14, + pack("= 11 (except for + # 0x1b, the checksum itself). In other words, the sum of those + # bytes must be always 0x00. + mef.write_to(0x1b, pack("B", checksum)) + + print("Reading FTPR modules list...") + if gen == 3: + end_addr, ftpr_offset = \ + check_and_remove_modules_gen3(mef, me_end, + ftpr_offset, ftpr_length, + min_ftpr_offset, + args.relocate, + args.keep_modules) + else: + end_addr, ftpr_offset = \ + check_and_remove_modules(mef, me_end, ftpr_offset, + min_ftpr_offset, args.relocate, + args.keep_modules) + + if end_addr > 0: + end_addr = max(end_addr, extra_part_end) + end_addr = (end_addr // 0x1000 + 1) * 0x1000 + end_addr += spared_blocks * 0x1000 + + print("The ME minimum size should be {0} bytes " + "({0:#x} bytes)".format(end_addr)) + + if me_start > 0: + print("The ME region can be reduced up to:\n" + " {:08x}:{:08x} me" + .format(me_start, me_start + end_addr - 1)) + elif args.truncate: + print("Truncating file at {:#x}...".format(end_addr)) + f.truncate(end_addr) if args.soft_disable or args.soft_disable_only: if gen == 3: print("Setting the HAP bit in PCHSTRP0 to disable Intel ME...") pchstrp0 |= (1 << 16) fdf.write_to(fpsba, pack("