hacks/dump-imessages/iphone-dataprotection/python_scripts/nand/image.py

86 lines
3.4 KiB
Python

import os
import struct
import sys
"""
row-by-row dump
page = data + spare metadata + iokit return code + iokit return code 2
"""
class NANDImageFlat(object):
def __init__(self, filename, geometry):
flags = os.O_RDONLY
if sys.platform == "win32":
flags |= os.O_BINARY
self.fd = os.open(filename, flags)
self.nCEs = geometry["#ce"]
self.pageSize = geometry["#page-bytes"]
self.metaSize = geometry.get("meta-per-logical-page", 12)
self.dumpedPageSize = geometry.get("dumpedPageSize", self.pageSize + self.metaSize + 8)
self.hasIOKitStatus = True
if self.dumpedPageSize == self.pageSize + geometry["#spare-bytes"] or self.dumpedPageSize == self.pageSize + self.metaSize:
self.hasIOKitStatus = False
self.blankPage = "\xFF" * self.pageSize
self.blankSpare = "\xFF" * self.metaSize
self.imageSize = os.path.getsize(filename)
expectedSize = geometry["#ce"] * geometry["#ce-blocks"] * geometry["#block-pages"] * self.dumpedPageSize
if self.imageSize < expectedSize:
raise Exception("Error: image appears to be truncated, expected size=%d" % expectedSize)
print "Image size matches expected size, looks ok"
def _readPage(self, ce, page):
i = page * self.nCEs + ce
off = i * self.dumpedPageSize
os.lseek(self.fd, off, os.SEEK_SET)
return os.read(self.fd, self.dumpedPageSize)
def readPage(self, ce, page):
d = self._readPage(ce, page)
if not d or len(d) != self.dumpedPageSize:
return None,None
if self.hasIOKitStatus:
r1,r2 = struct.unpack("<LL", d[self.pageSize+self.metaSize:self.pageSize+self.metaSize+8])
if r1 != 0x0:
return None, None
data = d[:self.pageSize]
spare = d[self.pageSize:self.pageSize+self.metaSize]
if not self.hasIOKitStatus and data == self.blankPage and spare == self.blankSpare:
return None,None
return spare, data
"""
iEmu NAND format
one file for each CE, start with chip id (8 bytes) then pages
page = non-empty flag (1 byte) + data + spare metadata (12 bytes)
"""
class NANDImageSplitCEs(object):
def __init__(self, folder, geometry):
flags = os.O_RDONLY
if sys.platform == "win32":
flags |= os.O_BINARY
self.fds = []
self.nCEs = geometry["#ce"]
self.pageSize = geometry["#page-bytes"]
self.metaSize = 12
self.npages = 0
self.dumpedPageSize = 1 + self.pageSize + self.metaSize
for i in xrange(self.nCEs):
fd = os.open(folder + "/ce_%d.bin" % i, flags)
self.fds.append(fd)
self.npages += os.fstat(fd).st_size / self.dumpedPageSize
def _readPage(self, ce, page):
fd = self.fds[ce]
off = 8 + page * self.dumpedPageSize #skip chip id
os.lseek(fd, off, os.SEEK_SET)
return os.read(fd, self.dumpedPageSize)
def readPage(self, ce, page):
d = self._readPage(ce, page)
if not d or len(d) != self.dumpedPageSize:
return None,None
if d[0] != '1' and d[0] != '\x01':
return None,None
data = d[1:1+self.pageSize]
spare = d[1+self.pageSize:1+self.pageSize+self.metaSize]
return spare, data