133 lines
4.6 KiB
Python
133 lines
4.6 KiB
Python
|
from construct import *
|
||
|
from zipfile import crc32
|
||
|
|
||
|
GPT_HFS = "005346480000aa11aa1100306543ecac".decode("hex")
|
||
|
GPT_EMF = "00464d450000aa11aa1100306543ecac".decode("hex")
|
||
|
|
||
|
LWVM_partitionRecord = Struct("LWVM_partitionRecord",
|
||
|
String("type", 16),
|
||
|
String("guid", 16),
|
||
|
ULInt64("begin"),
|
||
|
ULInt64("end"),
|
||
|
ULInt64("attribute"),
|
||
|
String("name", 0x48, encoding="utf-16-le", padchar="\x00")
|
||
|
)
|
||
|
|
||
|
LWVM_MAGIC = "6a9088cf8afd630ae351e24887e0b98b".decode("hex")
|
||
|
LWVM_header = Struct("LWVM_header",
|
||
|
String("type",16),
|
||
|
String("guid", 16),
|
||
|
ULInt64("mediaSize"),
|
||
|
ULInt32("numPartitions"),
|
||
|
ULInt32("crc32"),
|
||
|
Padding(464),
|
||
|
Array(12, LWVM_partitionRecord),
|
||
|
Array(1024, ULInt16("chunks"))
|
||
|
)
|
||
|
|
||
|
GPT_header = Struct("GPT_header",
|
||
|
String("signature", 8),
|
||
|
ULInt32("revision"),
|
||
|
ULInt32("header_size"),
|
||
|
SLInt32("crc"), #hax to match python signed crc
|
||
|
ULInt32("zero"),
|
||
|
ULInt64("current_lba"),
|
||
|
ULInt64("backup_lba"),
|
||
|
ULInt64("first_usable_lba"),
|
||
|
ULInt64("last_usable_lba"),
|
||
|
String("disk_guid", 16),
|
||
|
ULInt64("partition_entries_lba"),
|
||
|
ULInt32("num_partition_entries"),
|
||
|
ULInt32("size_partition_entry"),
|
||
|
ULInt32("crc_partition_entries")
|
||
|
)
|
||
|
|
||
|
GPT_entry = Struct("GPT_entry",
|
||
|
String("partition_type_guid", 16),
|
||
|
String("partition_guid", 16),
|
||
|
ULInt64("first_lba"),
|
||
|
ULInt64("last_lba"),
|
||
|
ULInt64("attributes"),
|
||
|
String("name", 72, encoding="utf-16-le", padchar="\x00"),
|
||
|
)
|
||
|
|
||
|
GPT_partitions = RepeatUntil(lambda obj, ctx: obj["partition_type_guid"] == "\x00"*16, GPT_entry)
|
||
|
|
||
|
APPLE_ENCRYPTED = 0xAE
|
||
|
MBR_entry = Struct("MBR_entry",
|
||
|
Byte("status"),
|
||
|
Bytes("chs_start",3),
|
||
|
Byte("type"),
|
||
|
Bytes("chs_last",3),
|
||
|
ULInt32("lba_start"),
|
||
|
ULInt32("num_sectors")
|
||
|
)
|
||
|
|
||
|
MBR = Struct("MBR",
|
||
|
String("code",440),
|
||
|
ULInt32("signature"),
|
||
|
ULInt16("zero"),
|
||
|
Array(4, MBR_entry),
|
||
|
OneOf(ULInt16("magic"), [0xAA55])
|
||
|
)
|
||
|
|
||
|
def parse_mbr(data):
|
||
|
try:
|
||
|
mbr = MBR.parse(data)
|
||
|
if mbr.MBR_entry[0].type == 0xEE:
|
||
|
print "Found protective MBR"
|
||
|
return None
|
||
|
res = mbr.MBR_entry[:2]
|
||
|
for p in res:
|
||
|
p.first_lba = p.lba_start
|
||
|
p.last_lba = p.lba_start + p.num_sectors
|
||
|
return res
|
||
|
except:
|
||
|
return None
|
||
|
|
||
|
def parse_gpt(data):
|
||
|
gpt = GPT_header.parse(data)
|
||
|
if gpt.signature != "EFI PART":
|
||
|
return None
|
||
|
print "Found GPT header current_lba=%d partition_entries_lba=%d" % (gpt.current_lba, gpt.partition_entries_lba)
|
||
|
assert gpt.partition_entries_lba > gpt.current_lba
|
||
|
check = gpt.crc
|
||
|
gpt.crc = 0
|
||
|
actual = crc32(GPT_header.build(gpt))
|
||
|
if actual != check:
|
||
|
print "GPT crc check fail %d vs %d" % (actual, check)
|
||
|
return None
|
||
|
return gpt
|
||
|
|
||
|
def parse_lwvm(data, pageSize):
|
||
|
try:
|
||
|
hdr = LWVM_header.parse(data)
|
||
|
if hdr.type != LWVM_MAGIC:
|
||
|
print "LwVM magic mismatch"
|
||
|
return
|
||
|
tocheck = data[:44] + "\x00\x00\x00\x00" + data[48:0x1000]
|
||
|
check = crc32(tocheck) & 0xffffffff
|
||
|
if check != hdr.crc32:
|
||
|
return None
|
||
|
print "LwVM header CRC OK"
|
||
|
partitions = hdr.LWVM_partitionRecord[:hdr.numPartitions]
|
||
|
deviceSize=0
|
||
|
#XXX: HAAAAAAAX
|
||
|
for s in [8, 16, 32, 64, 128]:
|
||
|
if hdr.mediaSize < (s* 1024*1024*1024):
|
||
|
deviceSize = s
|
||
|
break
|
||
|
for i in xrange(len(hdr.chunks)):
|
||
|
if hdr.chunks[i] == 0x0:
|
||
|
lba0 = (i * deviceSize*1024*1024) / pageSize
|
||
|
partitions[0].first_lba = lba0
|
||
|
partitions[0].last_lba = lba0 + (partitions[0].end - partitions[0].begin) / pageSize
|
||
|
elif hdr.chunks[i] == 0x1000:
|
||
|
lbad = (i * deviceSize*1024*1024) / pageSize
|
||
|
partitions[1].first_lba = lbad
|
||
|
partitions[1].last_lba = lbad + (partitions[1].end - partitions[1].begin) / pageSize
|
||
|
return partitions
|
||
|
except:
|
||
|
return None
|
||
|
|