def do_ls(self, p): dirDict = self.volume.ls((self.curdir + "/" + p).replace("//","/")) if not dirDict: return for name in sorted(dirDict.keys()): size = "" protection_class = "" record = dirDict[name] if hasattr(record, "fileID"): size = sizeof_fmt(record.dataFork.logicalSize) cprotect = self.volume.getXattr(record.fileID, "com.apple.system.cprotect") if cprotect: protection_class = PROTECTION_CLASSES[struct.unpack("<L", cprotect[8:12])[0]] print "%s\t%s\t%s\t%s" % (name[:30].ljust(30), size.ljust(10), hfs_date(record.createDate), protection_class)
def _catalogFileCallback(self, data, usn, filter_): for k, v in carveBtreeNode(data, HFSPlusCatalogKey, HFSPlusCatalogData): if v.recordType != kHFSPlusFileRecord: continue if filter_ and not filter_(k, v): continue name = getString(k) #if not self.filterFileName(name): # continue h = hashlib.sha1(HFSPlusCatalogKey.build(k)).digest() if self.files.has_key(h): continue if not self.fileIds.has_key(v.data.fileID): print "Found deleted file record", v.data.fileID, name.encode( "utf-8"), "created", hfs_date(v.data.createDate) self.files[h] = (name, v, usn)
def readFileHax(self, filename, filerecord, filekeys): lba0 = self.first_lba + filerecord.dataFork.HFSPlusExtentDescriptor[ 0].startBlock filekey = None good_usn = None first_vpn = 0 first_usn = 0 hax = self.ftlhax print "%d versions for first lba" % len(hax.get(lba0, [])) for k in filekeys: for vpn in hax.get(lba0, []): s, ciphertext = self.nand.ftl.YAFTL_readPage(vpn, key=None, lpn=None) if not ciphertext: continue d = self.decryptFileBlock2(ciphertext, k, lba0, 0) #hexdump(d[:16]) if isDecryptedCorrectly(d): filekey = k first_vpn = vpn first_usn = good_usn = s.usn block = vpn / self.nand.ftl.vfl.pages_per_sublk break if not filekey: return False logicalSize = filerecord.dataFork.logicalSize missing_pages = 0 file_pages = [] lbns = [] for extent in self.volume.getAllExtents(filerecord.dataFork, filerecord.fileID): for bn in xrange(extent.startBlock, extent.startBlock + extent.blockCount): lbns.append(self.first_lba + bn) datas = {} usnblocksToLookAT = sorted( filter(lambda x: x >= good_usn, self.userblocks.keys()))[:5] print usnblocksToLookAT usnblocksToLookAT.insert(0, 0) first_block = True done = False for usn in usnblocksToLookAT: if first_block: bbtoc = self.getBBTOC(block) first_block = False else: bbtoc = self.getBBTOC(self.userblocks[usn]) for lbn in bbtoc.keys(): if not lbn in lbns: continue idx = lbns.index(lbn) s, ciphertext = self.nand.ftl.YAFTL_readPage(bbtoc[lbn], key=None, lpn=None) if not ciphertext: continue ciphertext = self.decryptFileBlock2(ciphertext, filekey, lbn, idx * self.pageSize) if idx == 0: if not isDecryptedCorrectly(ciphertext): continue datas[idx * self.pageSize] = (ciphertext, lbn - self.first_lba) #if idx == len(lbns): if len(datas) == len(lbns): done = True break if done: break cleartext = "" decrypt_offset = 0 for i in xrange(0, logicalSize, self.pageSize): if datas.has_key(i): ciphertext, lbn = datas[i] cleartext += ciphertext else: cleartext += self.blankPage missing_pages += 1 decrypt_offset += self.pageSize print "Recovered %d:%s %d missing pages, size %s, created %s, contentModDate %s" % \ (filerecord.fileID, filename.encode("utf-8"), missing_pages, sizeof_fmt(logicalSize), hfs_date(filerecord.createDate), hfs_date(filerecord.contentModDate)) filename = "%d_%d_%s" % (filerecord.fileID, first_usn, filename) if missing_pages == 0: filename = "OK_" + filename self.okfiles += 1 if True: #exactSize: cleartext = cleartext[:logicalSize] self.writeUndeletedFile(filename, cleartext) return True
def getFileAtUSN(self, filename, filerecord, filekey, usn, previousVersion=None, exactSize=True): missing_pages = 0 decrypt_offset = 0 file_pages = [] logicalSize = filerecord.dataFork.logicalSize for extent in self.volume.getAllExtents(filerecord.dataFork, filerecord.fileID): for bn in xrange(extent.startBlock, extent.startBlock + extent.blockCount): pn = self.pagesForLBN(bn).get(usn) #fail if pn: clear = self.decryptFileBlock(pn[-1], filekey, bn, decrypt_offset) file_pages.append(clear) elif previousVersion: file_pages.append(previousVersion[len(file_pages)]) else: file_pages.append(self.blankPage) missing_pages += 1 decrypt_offset += self.pageSize print "Recovered %d:%s %d missing pages, size %s, created %s, contentModDate %s" % \ (filerecord.fileID, filename.encode("utf-8"), missing_pages, sizeof_fmt(logicalSize), hfs_date(filerecord.createDate), hfs_date(filerecord.contentModDate)) filename = "%d_%d_%s" % (filerecord.fileID, usn, filename) if missing_pages == 0: filename = "OK_" + filename self.okfiles += 1 data = "".join(file_pages) if exactSize: data = data[:logicalSize] self.writeUndeletedFile(filename, data) return file_pages
def _catalogFileCallback(self, data, usn, filter_): for k,v in carveBtreeNode(data,HFSPlusCatalogKey, HFSPlusCatalogData): if v.recordType != kHFSPlusFileRecord: continue if filter_ and not filter_(k,v): continue name = getString(k) #if not self.filterFileName(name): # continue h = hashlib.sha1(HFSPlusCatalogKey.build(k)).digest() if self.files.has_key(h): continue if not self.fileIds.has_key(v.data.fileID): print "Found deleted file record", v.data.fileID, name.encode("utf-8"), "created", hfs_date(v.data.createDate) self.files[h] = (name,v, usn)
def readFileHax(self, filename, filerecord, filekeys): lba0 = self.first_lba + filerecord.dataFork.HFSPlusExtentDescriptor[0].startBlock filekey = None good_usn = None first_vpn = 0 first_usn = 0 hax = self.ftlhax print "%d versions for first lba" % len(hax.get(lba0, [])) for k in filekeys: for vpn in hax.get(lba0, []): s, ciphertext = self.nand.ftl.YAFTL_readPage(vpn, key=None, lpn=None) if not ciphertext: continue d = self.decryptFileBlock2(ciphertext, k, lba0, 0) #hexdump(d[:16]) if isDecryptedCorrectly(d): filekey = k first_vpn = vpn first_usn = good_usn = s.usn block = vpn / self.nand.ftl.vfl.pages_per_sublk break if not filekey: return False logicalSize = filerecord.dataFork.logicalSize missing_pages = 0 file_pages = [] lbns = [] for extent in self.volume.getAllExtents(filerecord.dataFork, filerecord.fileID): for bn in xrange(extent.startBlock, extent.startBlock + extent.blockCount): lbns.append(self.first_lba + bn) datas = {} usnblocksToLookAT = sorted(filter(lambda x: x >= good_usn, self.userblocks.keys()))[:5] print usnblocksToLookAT usnblocksToLookAT.insert(0, 0) first_block = True done = False for usn in usnblocksToLookAT: if first_block: bbtoc = self.getBBTOC(block) first_block = False else: bbtoc = self.getBBTOC(self.userblocks[usn]) for lbn in bbtoc.keys(): if not lbn in lbns: continue idx = lbns.index(lbn) s, ciphertext = self.nand.ftl.YAFTL_readPage(bbtoc[lbn], key=None, lpn=None) if not ciphertext: continue ciphertext = self.decryptFileBlock2(ciphertext, filekey, lbn, idx*self.pageSize) if idx == 0: if not isDecryptedCorrectly(ciphertext): continue datas[idx*self.pageSize] = (ciphertext, lbn - self.first_lba) #if idx == len(lbns): if len(datas) == len(lbns): done=True break if done: break cleartext = "" decrypt_offset = 0 for i in xrange(0,logicalSize, self.pageSize): if datas.has_key(i): ciphertext, lbn = datas[i] cleartext += ciphertext else: cleartext += self.blankPage missing_pages += 1 decrypt_offset += self.pageSize print "Recovered %d:%s %d missing pages, size %s, created %s, contentModDate %s" % \ (filerecord.fileID, filename.encode("utf-8"), missing_pages, sizeof_fmt(logicalSize), hfs_date(filerecord.createDate), hfs_date(filerecord.contentModDate)) filename = "%d_%d_%s" % (filerecord.fileID, first_usn, filename) if missing_pages == 0: filename = "OK_" + filename self.okfiles += 1 if True:#exactSize: cleartext = cleartext[:logicalSize] self.writeUndeletedFile(filename, cleartext) return True
def readFileHax(self, filename, filerecord, filekeys): lba0 = self.first_lba + filerecord.dataFork.HFSPlusExtentDescriptor[0].startBlock filekey = None good_usn = None first_usn = 0 lba0_versions = self.nand.ftl.findAllVersions(lba0) print "%d versions for first lba" % len(lba0_versions) for k in filekeys: for addr in lba0_versions: ciphertext = self.nand.ftl.readPage1(addr, key=None, lpn=lba0) if not ciphertext: continue d = self.decryptFileBlock2(ciphertext, k, lba0, 0) if isDecryptedCorrectly(d): hexdump(d[:16]) filekey = k weaveSeq = addr[0] break if not filekey: return False logicalSize = filerecord.dataFork.logicalSize missing_pages = 0 file_pages = [] lbns = [] for extent in self.volume.getAllExtents(filerecord.dataFork, filerecord.fileID): for bn in xrange(extent.startBlock, extent.startBlock + extent.blockCount): lbns.append(self.first_lba + bn) datas = {} first_block = True done = False for weaveSeq,lbn,ce,block,page in self.nand.ftl.findPagesInRange(weaveSeq, weaveSeq+50000): if not lbn in lbns: continue idx = lbns.index(lbn) ciphertext = self.nand.ftl.readPage1((weaveSeq,ce,block,page), key=None, lpn=lbn) if not ciphertext: continue ciphertext = self.decryptFileBlock2(ciphertext, filekey, lbn, idx*self.pageSize) if idx == 0: if not isDecryptedCorrectly(ciphertext): continue datas[idx*self.pageSize] = (ciphertext, lbn - self.first_lba) #if idx == len(lbns): if len(datas) == len(lbns): done=True break if done: break cleartext = "" decrypt_offset = 0 for i in xrange(0,logicalSize, self.pageSize): if datas.has_key(i): ciphertext, lbn = datas[i] cleartext += ciphertext else: cleartext += self.blankPage missing_pages += 1 decrypt_offset += self.pageSize print "Recovered %d:%s %d missing pages, size %s, created %s, contentModDate %s" % \ (filerecord.fileID, filename.encode("utf-8"), missing_pages, sizeof_fmt(logicalSize), hfs_date(filerecord.createDate), hfs_date(filerecord.contentModDate)) filename = "%d_%d_%s" % (filerecord.fileID, first_usn, filename) if missing_pages == 0: filename = "OK_" + filename self.okfiles += 1 if True:#exactSize: cleartext = cleartext[:logicalSize] self.writeUndeletedFile(filename, cleartext) return True