├── dump_me.py ├── padding └── rsagen.py /dump_me.py: -------------------------------------------------------------------------------- 1 | # Intel ME ROM image dumper/extractor 2 | # Copyright (c) 2012 Igor Skochinsky 3 | # Version 0.1 2012-10-10 4 | # Version 0.2 2013-08-15 5 | # 6 | # This software is provided 'as-is', without any express or implied 7 | # warranty. In no event will the authors be held liable for any damages 8 | # arising from the use of this software. 9 | # 10 | # Permission is granted to anyone to use this software for any purpose, 11 | # including commercial applications, and to alter it and redistribute it 12 | # freely, subject to the following restrictions: 13 | # 14 | # 1. The origin of this software must not be misrepresented; you must not 15 | # claim that you wrote the original software. If you use this software 16 | # in a product, an acknowledgment in the product documentation would be 17 | # appreciated but is not required. 18 | # 19 | # 2. Altered source versions must be plainly marked as such, and must not be 20 | # misrepresented as being the original software. 21 | # 22 | # 3. This notice may not be removed or altered from any source 23 | # distribution. 24 | # 25 | # Modified version 2013-12-29 Damien Zammit 26 | 27 | import ctypes 28 | import struct 29 | import sys 30 | import os 31 | import array 32 | import itertools 33 | from operator import itemgetter 34 | 35 | uint8_t = ctypes.c_ubyte 36 | char = ctypes.c_char 37 | uint32_t = ctypes.c_uint 38 | uint64_t = ctypes.c_uint64 39 | uint16_t = ctypes.c_ushort 40 | 41 | def replace_bad(value, deletechars): 42 | for c in deletechars: 43 | value = value.replace(c,'_') 44 | return value 45 | 46 | def read_struct(li, struct): 47 | s = struct() 48 | slen = ctypes.sizeof(s) 49 | bytes = li.read(slen) 50 | fit = min(len(bytes), slen) 51 | ctypes.memmove(ctypes.addressof(s), bytes, fit) 52 | return s 53 | 54 | def get_struct(str_, off, struct): 55 | s = struct() 56 | slen = ctypes.sizeof(s) 57 | bytes = str_[off:off+slen] 58 | fit = min(len(bytes), slen) 59 | ctypes.memmove(ctypes.addressof(s), bytes, fit) 60 | return s 61 | 62 | def DwordAt(f, off): 63 | return struct.unpack(">0)&1) 89 | print " Optional: %d" % ((self.Flags>>1)&1) 90 | if self.Flags >> 2: 91 | print " Unknown B2_31: %d" % ((self.Flags>>2)) 92 | 93 | def pprint(self): 94 | print "Header tag: %s" % (self.Tag) 95 | nm = self.Name.rstrip('\0') 96 | print "Module name: %s" % (nm) 97 | print "Guid: %s" % (" ".join("%02X" % v for v in self.Guid)) 98 | print "Version: %d.%d.%d.%d" % (self.MajorVersion, self.MinorVersion, self.HotfixVersion, self.BuildVersion) 99 | print "Hash: %s" % (" ".join("%02X" % v for v in self.Hash)) 100 | print "Size: 0x%08X" % (self.Size) 101 | if self.Offset != None: 102 | print "(Offset): 0x%08X" % (self.Offset) 103 | print "Flags: 0x%08X" % (self.Flags) 104 | self.print_flags() 105 | print "Unk48: 0x%08X" % (self.Unk48) 106 | print "Unk4C: 0x%08X" % (self.Unk4C) 107 | 108 | class MeModuleFileHeader1(ctypes.LittleEndianStructure): 109 | _fields_ = [ 110 | ("Tag", char*4), # $MOD 111 | ("Unk04", uint32_t), # 112 | ("Unk08", uint32_t), # 113 | ("MajorVersion", uint16_t), # 114 | ("MinorVersion", uint16_t), # 115 | ("HotfixVersion", uint16_t), # 116 | ("BuildVersion", uint16_t), # 117 | ("Unk14", uint32_t), # 118 | ("CompressedSize", uint32_t), # 119 | ("UncompressedSize", uint32_t), # 120 | ("LoadAddress", uint32_t), # 121 | ("MappedSize", uint32_t), # 122 | ("Unk28", uint32_t), # 123 | ("Unk2C", uint32_t), # 124 | ("Name", char*16), # 125 | ("Guid", uint8_t*16), # 126 | ] 127 | 128 | def pprint(self): 129 | print "Module tag: %s" % (self.Tag) 130 | nm = self.Name.rstrip('\0') 131 | print "Module name: %s" % (nm) 132 | print "Guid: %s" % (" ".join("%02X" % v for v in self.Guid)) 133 | print "Version: %d.%d.%d.%d" % (self.MajorVersion, self.MinorVersion, self.HotfixVersion, self.BuildVersion) 134 | print "Unk04: 0x%08X" % (self.Unk04) 135 | print "Unk08: 0x%08X" % (self.Unk08) 136 | print "Unk14: 0x%08X" % (self.Unk14) 137 | print "Compressed size: 0x%08X" % (self.CompressedSize) 138 | print "Uncompressed size: 0x%08X" % (self.UncompressedSize) 139 | print "Mapped address: 0x%08X" % (self.LoadAddress) 140 | print "Mapped size: 0x%08X" % (self.MappedSize) 141 | print "Unk28: 0x%08X" % (self.Unk28) 142 | print "Unk2C: 0x%08X" % (self.Unk2C) 143 | 144 | MeModulePowerTypes = ["POWER_TYPE_RESERVED", "POWER_TYPE_M0_ONLY", "POWER_TYPE_M3_ONLY", "POWER_TYPE_LIVE"] 145 | MeCompressionTypes = ["COMP_TYPE_NOT_COMPRESSED", "COMP_TYPE_HUFFMAN", "COMP_TYPE_LZMA", ""] 146 | COMP_TYPE_NOT_COMPRESSED = 0 147 | COMP_TYPE_HUFFMAN = 1 148 | COMP_TYPE_LZMA = 2 149 | MeModuleTypes = ["DEFAULT", "PRE_ME_KERNEL", "VENOM_TPM", "APPS_QST_DT", "APPS_AMT", "TEST"] 150 | MeApiTypes = ["API_TYPE_DATA", "API_TYPE_ROMAPI", "API_TYPE_KERNEL", ""] 151 | 152 | class HuffmanLUTHeader(ctypes.LittleEndianStructure): 153 | _fields_ = [ 154 | ("LLUT", char*4), # LLUT 155 | ("Unk04", uint32_t), # 156 | ("Unk08", uint32_t), # 157 | ("Unk0C", uint32_t), # 158 | ("Unk10", uint32_t), # 159 | ("DataStart", uint32_t), # Start of data 160 | ("Unk18", uint8_t*24), # 161 | ("LLUTLen", uint32_t), # 162 | ("Unk34", uint32_t), # 163 | ("Chipset", char*8), # PCH 164 | ] 165 | 166 | class MeModuleHeader2(ctypes.LittleEndianStructure): 167 | _fields_ = [ 168 | ("Tag", char*4), # $MME 169 | ("Name", char*16), # 170 | ("Hash", uint8_t*32), # 171 | ("Unk34", uint32_t), # 172 | ("Offset", uint32_t), # From the manifest 173 | ("Unk3C", uint32_t), # 174 | ("Size", uint32_t), # 175 | ("Unk44", uint32_t), # 176 | ("Unk48", uint32_t), # 177 | ("LoadBase", uint32_t), # 178 | ("Flags", uint32_t), # 179 | ("Unk54", uint32_t), # 180 | ("Unk58", uint32_t), # 181 | ("Unk5C", uint32_t), # 182 | ] 183 | 184 | def comptype(self): 185 | return (self.Flags>>4)&7 186 | 187 | def print_flags(self): 188 | print " Unknown B0: %d" % ((self.Flags>>0)&1) 189 | powtype = (self.Flags>>1)&3 190 | print " Power Type: %s (%d)" % (MeModulePowerTypes[powtype], powtype) 191 | print " Unknown B3: %d" % ((self.Flags>>3)&1) 192 | comptype = (self.Flags>>4)&7 193 | print " Compression: %s (%d)" % (MeCompressionTypes[comptype], comptype) 194 | modstage = (self.Flags>>7)&0xF 195 | if modstage < len(MeModuleTypes): 196 | smtype = MeModuleTypes[modstage] 197 | else: 198 | smtype = "STAGE %X" % modstage 199 | print " Stage: %s (%d)" % (smtype, modstage) 200 | apitype = (self.Flags>>11)&7 201 | print " API Type: %s (%d)" % (MeApiTypes[apitype], apitype) 202 | 203 | print " Unknown B14: %d" % ((self.Flags>>14)&1) 204 | print " Unknown B15: %d" % ((self.Flags>>15)&1) 205 | print " Privileged: %d" % ((self.Flags>>16)&1) 206 | print " Unknown B17_19: %d" % ((self.Flags>>17)&7) 207 | print " Unknown B20_21: %d" % ((self.Flags>>20)&3) 208 | if self.Flags >> 22: 209 | print " Unknown B22_31: %d" % ((self.Flags>>22)) 210 | 211 | def pprint(self): 212 | print "Header tag: %s" % (self.Tag) 213 | nm = self.Name.rstrip('\0') 214 | print "Module name: %s" % (nm) 215 | print "Hash: %s" % (" ".join("%02X" % v for v in self.Hash)) 216 | print "Unk34: 0x%08X" % (self.Unk34) 217 | print "Offset: 0x%08X" % (self.Offset) 218 | print "Unk3C: 0x%08X" % (self.Unk3C) 219 | print "Data length: 0x%08X" % (self.Size) 220 | print "Unk44: 0x%08X" % (self.Unk44) 221 | print "Unk48: 0x%08X" % (self.Unk48) 222 | print "LoadBase: 0x%08X" % (self.LoadBase) 223 | print "Flags: 0x%08X" % (self.Flags) 224 | self.print_flags() 225 | print "Unk54: 0x%08X" % (self.Unk54) 226 | print "Unk58: 0x%08X" % (self.Unk58) 227 | print "Unk5C: 0x%08X" % (self.Unk5C) 228 | 229 | 230 | def extract_code_mods(nm, f, soff): 231 | try: 232 | os.mkdir(nm) 233 | except: 234 | pass 235 | os.chdir(nm) 236 | print " extracting CODE partition %s" % (nm) 237 | manif = get_struct(f, soff, MeManifestHeader) 238 | manif.parse_mods(f, soff) 239 | manif.pprint() 240 | manif.extract(f, soff) 241 | os.chdir("..") 242 | 243 | class HuffmanOffsetBytes(ctypes.LittleEndianStructure): 244 | _fields_ = [ 245 | ("Offset", uint32_t, 24), 246 | ("Length", uint8_t), 247 | ] 248 | 249 | class HuffmanOffsets(ctypes.Union): 250 | _fields_ = [ 251 | ("b", HuffmanOffsetBytes), 252 | ("asword", uint32_t), 253 | ] 254 | 255 | class MeManifestHeader(ctypes.LittleEndianStructure): 256 | _fields_ = [ 257 | ("ModuleType", uint16_t), # 00 258 | ("ModuleSubType", uint16_t), # 02 259 | ("HeaderLen", uint32_t), # 04 in dwords 260 | ("HeaderVersion", uint32_t), # 08 261 | ("Flags", uint32_t), # 0C 0x80000000 = Debug 262 | ("ModuleVendor", uint32_t), # 10 263 | ("Date", uint32_t), # 14 BCD yyyy.mm.dd 264 | ("Size", uint32_t), # 18 in dwords 265 | ("Tag", char*4), # 1C $MAN or $MN2 266 | ("NumModules", uint32_t), # 20 267 | ("MajorVersion", uint16_t), # 24 268 | ("MinorVersion", uint16_t), # 26 269 | ("HotfixVersion", uint16_t), # 28 270 | ("BuildVersion", uint16_t), # 2A 271 | ("Unknown1", uint32_t*19), # 2C 272 | ("KeySize", uint32_t), # 78 273 | ("ScratchSize", uint32_t), # 7C 274 | ("RsaPubKey", uint32_t*64), # 80 275 | ("RsaPubExp", uint32_t), # 180 276 | ("RsaSig", uint32_t*64), # 184 277 | ("PartitionName", char*12), # 284 278 | # 290 279 | ] 280 | 281 | def parse_mods(self, f, offset): 282 | self.modules = [] 283 | self.updparts = [] 284 | orig_off = offset 285 | offset += self.HeaderLen*4 286 | offset += 12 287 | if self.Tag == '$MN2': 288 | htype = MeModuleHeader2 289 | hdrlen = ctypes.sizeof(htype) 290 | udc_fmt = "<4s32s16sII" 291 | udc_len = 0x3C 292 | elif self.Tag == '$MAN': 293 | htype = MeModuleHeader1 294 | hdrlen = ctypes.sizeof(htype) 295 | udc_fmt = "<4s20s16sII" 296 | udc_len = 0x30 297 | else: 298 | raise Exception("Don't know how to parse modules for manifest tag %s!" % self.Tag) 299 | 300 | modmap = {} 301 | self.huff_start = 0 302 | for i in range(self.NumModules): 303 | mod = get_struct(f, offset, htype) 304 | if not [mod.Tag in '$MME', '$MDL']: 305 | raise Exception("Bad module tag (%s) at offset %08X!" % (mod.Tag, offset)) 306 | nm = mod.Name.rstrip('\0') 307 | modmap[nm] = mod 308 | self.modules.append(mod) 309 | if mod.comptype() == COMP_TYPE_HUFFMAN: 310 | if self.huff_start and self.huff_start != orig_off + mod.Offset: 311 | print "Warning: inconsistent start offset for Huffman modules!" 312 | self.huff_start = orig_off + mod.Offset 313 | offset += hdrlen 314 | 315 | self.partition_end = None 316 | hdr_end = orig_off + self.Size*4 317 | while offset < hdr_end: 318 | print "tags %08X" % offset 319 | hdr = f[offset:offset+8] 320 | if hdr == '\xFF' * 8: 321 | offset += hdrlen 322 | continue 323 | if len(hdr) < 8 or hdr[0] != '$': 324 | break 325 | tag, elen = hdr[:4], struct.unpack(" %s" % (fnametab), 404 | open(fnametab, "wb").write(f[soff:soff+size]) 405 | 406 | #ext = "huff" 407 | #soff = self.huff_start 408 | #size = huff_end - mod.Offset 409 | 410 | ext = "huff" 411 | soff = self.datastart 412 | size = self.datalen 413 | else: 414 | ext = "bin" 415 | if self.Tag == '$MAN': 416 | ext = "mod" 417 | moff = soff+0x50 418 | if f[moff:moff+5] == '\x5D\x00\x00\x80\x00': 419 | lzf = open("%s_mod.lzma" % nm, "wb") 420 | lzf.write(f[moff:moff+5]) 421 | lzf.write(struct.pack(" %s" % (fnamemod) 425 | open(fnamemod, "wb").write(f[soff:soff+size]) 426 | for subtag, soff, subsize in self.updparts: 427 | fname = "%s_udc.bin" % subtag 428 | print "Update part: %r %08X/%08X" % (subtag, soff, subsize), 429 | print " => %s" % (fname) 430 | open(fname, "wb").write(f[soff:soff+subsize]) 431 | extract_code_mods(subtag, f, soff) 432 | 433 | # Huffman chunks 434 | fhufftab = open("%s_mod.huffchunksummary" % self.PartitionName, "w") 435 | fhufftab.write("Huffman chunks:\n") 436 | chunksize = self.chunksize 437 | 438 | huffmanoffsets = [] 439 | for huffoff in range(self.chunkcount): 440 | soff = self.huff_start + 0x40 + huffoff*4 441 | huffmanoffsets.append([struct.unpack("> 24) & 0xFF 443 | huffmanoffsets[huffoff][0] = huffmanoffsets[huffoff][0] & 0xFFFFFF 444 | print "0x%04X 0x%02X (0x%06X)" % (huffoff, huffmanoffsets[huffoff][1], huffmanoffsets[huffoff][0]) 445 | fhufftab.write("0x%04X 0x%02X (0x%06X) 0x%04X\n" % (huffoff, huffmanoffsets[huffoff][1], huffmanoffsets[huffoff][0], huffmanoffsets[huffoff][0] - huffmanoffsets[huffoff-1][0])) 446 | fhufftab.close() 447 | huffmanoffsets.append([self.datastart, 0x00]) 448 | huffmanoffsets = sorted(huffmanoffsets, key=itemgetter(0)) 449 | for huffoff in range(self.chunkcount): 450 | flag = huffmanoffsets[huffoff][1] 451 | if flag != 0x80: 452 | offset0 = huffmanoffsets[huffoff][0] 453 | offset1 = huffmanoffsets[huffoff+1][0] 454 | chunklen = offset1 - offset0 455 | open("%s_chunk_%02X_%04d.huff" % (self.PartitionName, flag, huffoff), "wb").write(f[offset0:offset1]) 456 | 457 | def pprint(self): 458 | print "Module Type: %d, Subtype: %d" % (self.ModuleType, self.ModuleSubType) 459 | print "Header Length: 0x%02X (0x%X bytes)" % (self.HeaderLen, self.HeaderLen*4) 460 | print "Header Version: %d.%d" % (self.HeaderVersion>>16, self.HeaderVersion&0xFFFF) 461 | print "Flags: 0x%08X" % (self.Flags), 462 | print " [%s signed] [%s flag]" % (["production","debug"][(self.Flags>>31)&1], ["production","pre-production"][(self.Flags>>30)&1]) 463 | print "Module Vendor: 0x%04X" % (self.ModuleVendor) 464 | print "Date: %08X" % (self.Date) 465 | print "Total Manifest Size: 0x%02X (0x%X bytes)" % (self.Size, self.Size*4) 466 | print "Tag: %s" % (self.Tag) 467 | print "Number of modules: %d" % (self.NumModules) 468 | print "Version: %d.%d.%d.%d" % (self.MajorVersion, self.MinorVersion, self.HotfixVersion, self.BuildVersion) 469 | print "Unknown data 1: %s" % ([n for n in self.Unknown1]) 470 | print "Key size: 0x%02X (0x%X bytes)" % (self.KeySize, self.KeySize*4) 471 | print "Scratch size: 0x%02X (0x%X bytes)" % (self.ScratchSize, self.ScratchSize*4) 472 | print "RSA Public Key: [skipped]" 473 | print "RSA Public Exponent: %d" % (self.RsaPubExp) 474 | print "RSA Signature: [skipped]" 475 | pname = self.PartitionName.rstrip('\0') 476 | if not pname: 477 | pname = "(none)" 478 | print "Partition name: %s" % (pname) 479 | print "---Modules---" 480 | for mod in self.modules: 481 | mod.pprint() 482 | print 483 | print "------End-------" 484 | 485 | 486 | PartTypes = ["Code", "BlockIo", "Nvram", "Generic", "Effs", "Rom"] 487 | 488 | PT_CODE = 0 489 | PT_BLOCKIO = 1 490 | PT_NVRAM = 2 491 | PT_GENERIC = 3 492 | PT_EFFS = 4 493 | PT_ROM = 5 494 | 495 | class MeFptEntry(ctypes.LittleEndianStructure): 496 | _fields_ = [ 497 | ("Name", char*4), # 00 partition name 498 | ("Owner", char*4), # 04 partition owner? 499 | ("Offset", uint32_t), # 08 from the start of FPT, or 0 500 | ("Size", uint32_t), # 0C 501 | ("TokensOnStart", uint32_t), # 10 502 | ("MaxTokens", uint32_t), # 14 503 | ("ScratchSectors", uint32_t), # 18 504 | ("Flags", uint32_t), # 1C 505 | ] 506 | #def __init__(self, f, offset): 507 | #self.sig1, self.Owner, self.Offset, self.Size = struct.unpack("<4s4sII", f[offset:offset+0x10]) 508 | #self.TokensOnStart, self.MaxTokens, self.ScratchSectors, self.Flags = struct.unpack(">7)&1) 521 | print " Read: %d" % ((self.Flags>>8)&1) 522 | print " Write: %d" % ((self.Flags>>9)&1) 523 | print " Execute: %d" % ((self.Flags>>10)&1) 524 | print " Logical: %d" % ((self.Flags>>11)&1) 525 | print " WOPDisable: %d" % ((self.Flags>>12)&1) 526 | print " ExclBlockUse: %d" % ((self.Flags>>13)&1) 527 | 528 | 529 | def pprint(self): 530 | print "Partition: %r" % self.Name 531 | print "Owner: %s" % [repr(self.Owner), "(none)"][self.Owner == '\xFF\xFF\xFF\xFF'] 532 | print "Offset/size: %08X/%08X" % (self.Offset, self.Size) 533 | print "TokensOnStart: %08X" % (self.TokensOnStart) 534 | print "MaxTokens: %08X" % (self.MaxTokens) 535 | print "ScratchSectors: %08X" % (self.ScratchSectors) 536 | print "Flags: %04X" % self.Flags 537 | self.print_flags() 538 | 539 | class MeFptTable: 540 | def __init__(self, f, offset): 541 | hdr = f[offset:offset+0x30] 542 | if hdr[0x10:0x14] == '$FPT': 543 | base = offset + 0x10 544 | elif hdr[0:4] == '$FPT': 545 | base = offset 546 | else: 547 | raise Exception("FPT format not recognized") 548 | num_entries = DwordAt(f, base+4) 549 | self.BCDVer, self.FPTEntryType, self.HeaderLen, self.Checksum = struct.unpack(" %s" % (fname) 572 | open(fname, "wb").write(f[soff:soff+part.Size]) 573 | if part.ptype() == PT_CODE: 574 | extract_code_mods(nm, f, soff) 575 | 576 | def pprint(self): 577 | print "===ME Flash Partition Table===" 578 | print "NumEntries: %d" % len(self.parts) 579 | print "Version: %d.%d" % (self.BCDVer >> 4, self.BCDVer & 0xF) 580 | print "EntryType: %02X" % (self.FPTEntryType) 581 | print "HeaderLen: %02X" % (self.HeaderLen) 582 | print "Checksum: %02X" % (self.Checksum) 583 | print "FlashCycleLifetime: %d" % (self.FlashCycleLifetime) 584 | print "FlashCycleLimit: %d" % (self.FlashCycleLimit) 585 | print "UMASize: %d" % self.UMASize 586 | print "Flags: %08X" % self.Flags 587 | print " EFFS present: %d" % (self.Flags&1) 588 | print " ME Layout Type: %d" % ((self.Flags>>1)&0xFF) 589 | print "---Partitions---" 590 | for part in self.parts: 591 | part.pprint() 592 | print 593 | print "------End-------" 594 | 595 | 596 | region_names = ["Descriptor", "BIOS", "ME", "GbE", "PDR", "Region 5", "Region 6", "Region 7" ] 597 | region_fnames =["Flash Descriptor", "BIOS Region", "ME Region", "GbE Region", "PDR Region", "Region 5", "Region 6", "Region 7" ] 598 | 599 | def print_flreg(val, name): 600 | print "%s region:" % name 601 | lim = ((val >> 4) & 0xFFF000) 602 | base = (val << 12) & 0xFFF000 603 | if lim == 0 and base == 0xFFF000: 604 | print " [unused]" 605 | return None 606 | lim |= 0xFFF 607 | print " %08X - %08X (0x%08X bytes)" % (base, lim, lim - base + 1) 608 | return (base, lim) 609 | 610 | def parse_descr(f, offset, extract): 611 | mapoff = offset 612 | if f[offset+0x10:offset+0x14] == "\x5A\xA5\xF0\x0F": 613 | mapoff = offset + 0x10 614 | elif f[offset:offset+0x4] != "\x5A\xA5\xF0\x0F": 615 | return -1 616 | print "Flash Descriptor found at %08X" % offset 617 | FLMAP0, FLMAP1, FLMAP2 = struct.unpack("> 24) & 0x7 619 | frba = (FLMAP0 >> 12) & 0xFF0 620 | nc = (FLMAP0 >> 8) & 0x3 621 | fcba = (FLMAP0 << 4) & 0xFF0 622 | print "Number of regions: %d (besides Descriptor)" % nr 623 | print "Number of components: %d" % (nc+1) 624 | print "FRBA: 0x%08X" % frba 625 | print "FCBA: 0x%08X" % fcba 626 | me_offset = -1 627 | for i in range(nr+1): 628 | FLREG = struct.unpack(" %s" % (fname) 637 | open(fname, "wb").write(f[offset + base:offset + base + lim + 1]) 638 | return me_offset 639 | 640 | class AcManifestHeader(ctypes.LittleEndianStructure): 641 | _fields_ = [ 642 | ("ModuleType", uint16_t), # 00 643 | ("ModuleSubType", uint16_t), # 02 644 | ("HeaderLen", uint32_t), # 04 in dwords 645 | ("HeaderVersion", uint32_t), # 08 646 | ("ChipsetID", uint16_t), # 0C 647 | ("Flags", uint16_t), # 0E 0x80000000 = Debug 648 | ("ModuleVendor", uint32_t), # 10 649 | ("Date", uint32_t), # 14 BCD yyyy.mm.dd 650 | ("Size", uint32_t), # 18 in dwords 651 | ("Reserved1", uint32_t), # 1C 652 | ("CodeControl", uint32_t), # 20 653 | ("ErrorEntryPoint",uint32_t), # 24 654 | ("GDTLimit", uint32_t), # 28 655 | ("GDTBasePtr", uint32_t), # 2C 656 | ("SegSel", uint32_t), # 30 657 | ("EntryPoint", uint32_t), # 34 658 | ("Reserved2", uint32_t*16), # 38 659 | ("KeySize", uint32_t), # 78 660 | ("ScratchSize", uint32_t), # 7C 661 | ("RsaPubKey", uint32_t*64), # 80 662 | ("RsaPubExp", uint32_t), # 180 663 | ("RsaSig", uint32_t*64), # 184 664 | # 284 665 | ] 666 | 667 | def pprint(self): 668 | print "Module Type: %d, Subtype: %d" % (self.ModuleType, self.ModuleSubType) 669 | print "Header Length: 0x%02X (0x%X bytes)" % (self.HeaderLen, self.HeaderLen*4) 670 | print "Header Version: %d.%d" % (self.HeaderVersion>>16, self.HeaderVersion&0xFFFF) 671 | print "ChipsetID: 0x%04X" % (self.ChipsetID) 672 | print "Flags: 0x%04X" % (self.Flags), 673 | print " [%s signed] [%s flag]" % (["production","debug"][(self.Flags>>15)&1], ["production","pre-production"][(self.Flags>>14)&1]) 674 | print "Module Vendor: 0x%04X" % (self.ModuleVendor) 675 | print "Date: %08X" % (self.Date) 676 | print "Total Module Size: 0x%02X (0x%X bytes)" % (self.Size, self.Size*4) 677 | print "Reserved1: 0x%08X" % (self.Reserved1) 678 | print "CodeControl: 0x%08X" % (self.CodeControl) 679 | print "ErrorEntryPoint: 0x%08X" % (self.ErrorEntryPoint) 680 | print "GDTLimit: 0x%08X" % (self.GDTLimit) 681 | print "GDTBasePtr: 0x%08X" % (self.GDTBasePtr) 682 | print "SegSel: 0x%04X" % (self.SegSel) 683 | print "EntryPoint: 0x%08X" % (self.EntryPoint) 684 | print "Key size: 0x%02X (0x%X bytes)" % (self.KeySize, self.KeySize*4) 685 | print "Scratch size: 0x%02X (0x%X bytes)" % (self.ScratchSize, self.ScratchSize*4) 686 | print "RSA Public Key: [skipped]" 687 | print "RSA Public Exponent: %d" % (self.RsaPubExp) 688 | print "RSA Signature: [skipped]" 689 | print "------End-------" 690 | 691 | print "Intel ME dumper/extractor v0.1" 692 | if len(sys.argv) < 2: 693 | print "Usage: dump_me.py MeImage.bin [-x] [offset]" 694 | print " -x: extract ME partitions and code modules" 695 | else: 696 | fname = sys.argv[1] 697 | extract = False 698 | offset = 0 699 | for opt in sys.argv[2:]: 700 | if opt == "-x": 701 | extract = True 702 | else: 703 | offset = int(opt, 16) 704 | f = open(fname, "rb").read() 705 | off2 = parse_descr(f, offset, extract) 706 | if off2 != -1: 707 | offset = off2 708 | try: 709 | os.mkdir("ME Region") 710 | except: 711 | pass 712 | os.chdir("ME Region") 713 | if f[offset:offset+8] == "\x04\x00\x00\x00\xA1\x00\x00\x00": 714 | while True: 715 | manif = get_struct(f, offset, MeManifestHeader) 716 | manif.parse_mods(f, offset) 717 | manif.pprint() 718 | if extract: 719 | manif.extract(f, offset) 720 | if manif.partition_end: 721 | offset += manif.partition_end 722 | print "Next partition: +%08X (%08X)" % (manif.partition_end, offset) 723 | else: 724 | break 725 | if f[offset:offset+8] != "\x04\x00\x00\x00\xA1\x00\x00\x00": 726 | break 727 | elif f[offset:offset+8] == "\x02\x00\x00\x00\xA1\x00\x00\x00": 728 | manif = get_struct(f, offset, AcManifestHeader) 729 | manif.pprint() 730 | else: 731 | fpt = MeFptTable(f, offset) 732 | fpt.pprint() 733 | if extract: 734 | fpt.extract(f, offset) 735 | if off2 != -1: 736 | os.chdir("..") 737 | -------------------------------------------------------------------------------- /padding: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zamaudio/dump_me/b6a3d9c0f6b8e9b43369687425326eeaf84a70f9/padding -------------------------------------------------------------------------------- /rsagen.py: -------------------------------------------------------------------------------- 1 | from Crypto.Util.number import bytes_to_long 2 | from Crypto.Hash import SHA256 3 | from Crypto.PublicKey import RSA 4 | from Crypto import Random 5 | import sys 6 | 7 | args=sys.argv 8 | if len(sys.argv) == 1: 9 | print "Usage: python rsagen.py " 10 | sys.exit() 11 | 12 | keypair = RSA.generate(2048, e=17) 13 | 14 | print "new user keys:" 15 | print keypair.publickey().exportKey() 16 | print keypair.exportKey() 17 | print 18 | 19 | import struct, hashlib 20 | 21 | def bytes2int(s, swap=True): 22 | num = 0L 23 | if swap: s = s[::-1] 24 | for c in s: 25 | num = num*256 + ord(c) 26 | return num 27 | 28 | def bytearr2int(s): 29 | num = 0 30 | for b in s: 31 | num = num*256 + b 32 | return num 33 | 34 | p = open("padding", "rb") 35 | padding = p.read(223) 36 | p.close() 37 | 38 | f = open(args[1], "rb") 39 | hdr1 = f.read(0x80) 40 | pubkey = bytes2int(f.read(0x100)) 41 | pubexp = bytes2int(f.read(0x4)) 42 | rsasig = bytes2int(f.read(0x100)) 43 | 44 | # header length 45 | hlen = struct.unpack("