Skip to content

Commit

Permalink
Merge branch 'experiments_remove_lzma_modules'
Browse files Browse the repository at this point in the history
  • Loading branch information
corna committed Dec 11, 2016
2 parents b4de4a4 + 86f9d02 commit d2e2308
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 21 deletions.
14 changes: 3 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,14 @@ Currently this tool:
* Scans the FPT (partition table) and checks that everything is correct
* Removes any partition entry (except for FTPR) from FPT
* Removes any partition except for the fundamental one (FTPR)
* Removes the EFFS presence flag
* Removes any LZMA-compressed module
* Corrects the FPT checksum

Don't forget to power cycle your PC after flashing the modified ME image (power
off and power on, not just reboot).

Current status:

| Architecture | Status |
|---------------|-----------------------|
| Nehalem | DOESN'T WORK (yet) |
| Sandy Bridge | WORKS |
| Ivy Bridge | WORKS |
| Haswell | SHOULD WORK |
| Broadwell | SHOULD WORK |
| Skylake | WORKS |
See the current status [in the wiki](https://github.com/corna/me_cleaner/wiki/me_cleaner-status).

Special thanks to Federico Amedeo Izzo for his help during the study of Intel
ME.

106 changes: 96 additions & 10 deletions me_cleaner.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,32 @@ def fill_range(f, start, end, fill):
block = fill * 4096
f.seek(start, 0)
f.writelines(itertools.repeat(block, (end - start) // 4096))
f.write(fill[:(end - start) % 4096])
f.write(block[:(end - start) % 4096])


def remove_module(f, mod_header, ftpr_offset, lzma_start_rel, lzma_end_rel):
name = mod_header[0x04:0x14].decode("ascii")
start = unpack("<I", mod_header[0x38:0x3C])[0]
size = unpack("<I", mod_header[0x40:0x44])[0]
flags = unpack("<I", mod_header[0x50:0x54])[0]
comp_type = (flags >> 4) & 7

if comp_type == 0x00 or comp_type == 0x02:
if start >= lzma_start_rel and start + size <= lzma_end_rel:
# Already removed
print(" {:<16}: removed (0x{:0X} - 0x{:0X})"
.format(name, ftpr_offset + start,
ftpr_offset + start + size))
else:
print(" {:<16}: is outside the LZMA region (module 0x{:0X} - "
"0x{:0X}, LZMA 0x{:0X} - 0x{:0X}), skipping"
.format(name, start, start+size, lzma_start_rel,
lzma_end_rel))
elif comp_type == 0x01:
print(" {:<16}: removal of Huffman modules is not supported yet, "
"skipping".format(name))
else:
print(" {:<16}: unknown compression, skipping".format(name))

if len(sys.argv) != 2 or sys.argv[1] == "-h" or sys.argv[1] == "--help":
print("Usage: me_cleaner.py me_image.bin")
Expand All @@ -40,8 +65,17 @@ def fill_range(f, start, end, fill):
entries = unpack("<I", f.read(4))[0]
print("Found {} partition(s)".format(entries))

f.seek(0x02, 1)
f.seek(0x14, 0)
header_len = unpack("<B", f.read(1))[0]
f.seek(0x28, 0)
version = unpack("<HHHH", f.read(8))

if version == (0, 0, 0, 0):
print("Unspecified ME firmware version")
else:
print("ME firmware version {}"
.format('.'.join(str(i) for i in version)))

f.seek(0x30, 0)
partitions = f.read(entries * 0x20)

Expand All @@ -55,36 +89,88 @@ def fill_range(f, start, end, fill):
break

if ftpr_header != b"":
ftpr_offset = unpack("<I", ftpr_header[0x08:0x0C])[0]
ftpr_lenght = unpack("<I", ftpr_header[0x0C:0x10])[0]
ftpr_offset, ftpr_lenght = unpack("<II", ftpr_header[0x08:0x10])
print("Found FTPR header: FTPR partition spans from "
"0x{:02x} to 0x{:02x}".format(ftpr_offset,
ftpr_offset + ftpr_lenght))
print("Removing extra partitions...")

fill_range(f, 0x30, ftpr_offset, b"\xFF")
fill_range(f, 0x30, ftpr_offset, b"\xff")
f.seek(0, 2)
fill_range(f, ftpr_offset + ftpr_lenght, f.tell(), b"\xFF")
fill_range(f, ftpr_offset + ftpr_lenght, f.tell(), b"\xff")

print("Removing extra partition entries in FPT...")
f.seek(0x30, 0)
f.write(ftpr_header)
f.seek(0x14, 0)
f.write(pack("<I", 1))
f.seek(0x00, 0)
checksum_bytes = f.read(0x30)
f.seek(0x1b, 0)

print("Removing EFFS presence flag...")
f.seek(0x24, 0)
flags = unpack("<I", f.read(4))[0]
flags &= ~(0x00000001)
f.seek(0x24, 0)
f.write(pack("<I", flags))

f.seek(ftpr_offset, 0)
if version[0] < 11 and f.read(4) != b"$CPD":
print("Reading FTPR modules list...")
f.seek(ftpr_offset + 0x1c, 0)
tag = f.read(4)
if tag == b"$MN2":
f.seek(ftpr_offset + 0x20, 0)
num_modules = unpack("<I", f.read(4))[0]
f.seek(ftpr_offset + 0x290, 0)
mod_hs = [f.read(0x60) for i in range(0, num_modules)]

if any(mod_h.startswith(b"$MME") for mod_h in mod_hs):
f.seek(ftpr_offset + 0x18, 0)
size = unpack("<I", f.read(4))[0]
llut_start = ftpr_offset + (size * 4 + 0x3f) & ~0x3f

f.seek(llut_start + 0x10, 0)
huff_start, huff_size = unpack("<II", f.read(8))
lzma_start = huff_start + huff_size

print("Wiping LZMA section (0x{:0X} - 0x{:0X})"
.format(lzma_start,
ftpr_offset + ftpr_lenght))
fill_range(f, lzma_start,
ftpr_offset + ftpr_lenght, b"\xff")

f.seek(llut_start, 0)
if f.read(4) == b"LLUT":
for mod_header in mod_hs:
remove_module(f, mod_header, ftpr_offset,
lzma_start - ftpr_offset,
ftpr_lenght)

else:
print("Can't find the LLUT region in the FTPR "
"partition")
else:
print("Can't find the $MN2 modules in the FTPR "
"partition")
else:
print("Wrong FTPR partition tag ({})".format(tag))

else:
print("Modules removal in ME v11 or greater is not yet "
"supported")

print("Correcting checksum...")
# The checksum is just the two's complement of the sum of the
# first 0x30 bytes (except for 0x1b, the checksum itself). In
# other words, the sum of the first 0x30 bytes must be always
# 0x00.
f.seek(0x00, 0)
checksum_bytes = f.read(0x30)
f.seek(0x1b, 0)
f.write(pack("B", (0x100 -
(sum(checksum_bytes) - checksum_bytes[0x1b]) &
0xff) & 0xff))

print("All done! Good luck!")
print("Done! Good luck!")

else:
print("FTPR header not found, this image doesn't seem to be "
Expand Down

0 comments on commit d2e2308

Please sign in to comment.