Browse Source

Merge branch 'experiments_remove_lzma_modules'

Nicola Corna 7 years ago
parent
commit
d2e2308588
2 changed files with 99 additions and 21 deletions
  1. 3 11
      README.md
  2. 96 10
      me_cleaner.py

+ 3 - 11
README.md

@@ -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.
-

+ 96 - 10
me_cleaner.py

@@ -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")
@@ -40,8 +65,17 @@ else:
             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)
 
@@ -55,36 +89,88 @@ else:
                     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 "