Skip to content

Instantly share code, notes, and snippets.

@aerosoul94
Created February 19, 2020 00:48
Show Gist options
  • Save aerosoul94/a9af1d6c0dbaeaa52f1808c44082c87f to your computer and use it in GitHub Desktop.
Save aerosoul94/a9af1d6c0dbaeaa52f1808c44082c87f to your computer and use it in GitHub Desktop.
Dump FIOS cache files
from datetime import datetime
import struct
import os
class CacheDescriptor(object):
DESCRIPTOR_FMT = ">QQQQII16s456x"
def __init__(self, f):
(self.accessDate,
self.modificationDate,
self.creationDate,
self.offset,
self.dataLength,
self.flags,
self.md5) = \
struct.unpack(self.DESCRIPTOR_FMT,
f.read(struct.calcsize(self.DESCRIPTOR_FMT)))
def isnull(self):
if not all(c == '\0' for c in self.md5):
return False
return True
def _print(self):
print("accessDate: %s" %
datetime.utcfromtimestamp(self.accessDate // 1000000000))
print("modificationDate: %s" %
datetime.utcfromtimestamp(self.modificationDate // 1000000000))
print("creationDate: %s" %
datetime.utcfromtimestamp(self.creationDate // 1000000000))
print("offset: %#x" % self.offset)
print("dataLength: %#x" % self.dataLength)
print("flags: %#x" % self.flags)
print("md5: %s" % self.md5.encode("hex"))
class CacheHeader(object):
FILE_HEADER_FMT = ">8sQHHHHII?7sI468x"
CACHE_SIGNATURE = b"fioscach"
def __init__(self, f):
(self.signature,
self.discId,
self.version,
self.headerSize,
self.descriptorSize,
self.pathMax,
self.numBlocks,
self.blockSize,
self.singleFile,
self.reserved,
self.knownFlags) = \
struct.unpack(self.FILE_HEADER_FMT,
f.read(struct.calcsize(self.FILE_HEADER_FMT)))
if self.signature != self.CACHE_SIGNATURE:
raise ValueError("Invalid signature!")
def _print(self):
print("signature: %s" % self.signature)
print("discId: %i" % self.discId)
print("version: %i" % self.version)
print("headerSize: %#x" % self.headerSize)
print("descriptorSize: %#x" % self.descriptorSize)
print("pathMax: %i" % self.pathMax)
print("numBlocks: %i" % self.numBlocks)
print("blockSize: %#x" % self.blockSize)
print("singleFile: %s" % self.singleFile)
print("knownFlags: %#x" % self.knownFlags)
class CacheFile(object):
def __init__(self, f):
self._file = f
self._header = None
self._descriptors = []
self._header = CacheHeader(f)
self.parse()
def parse(self):
pass
@property
def header(self):
return self._header
@property
def descriptors(self):
return self._descriptors
class CacheIndex(CacheFile):
def parse(self):
for _ in range(self._header.numBlocks):
descriptor = CacheDescriptor(self._file)
if not descriptor.isnull():
self._descriptors.append(descriptor)
class CacheData(CacheFile):
def dump(self, f, desc):
print("%#x" % self._file.tell())
pad = self._header.blockSize - desc.dataLength
data = self._file.read(desc.dataLength)
self._file.seek(pad, 1)
f.seek(desc.offset)
f.write(data)
class CacheDumper(object):
def __init__(self, idx, dat):
self.idxf = open(idx, 'rb')
self.datf = open(dat, 'rb')
self.index = CacheIndex(self.idxf)
self.data = CacheData(self.datf)
root = "./recovered"
if not os.path.exists(root):
os.mkdir(root)
for descriptor in self.index.descriptors:
with open(root + "/" + descriptor.md5.hex(), 'ab') as tmpf:
print("%#x (offset %#x, len %#x)" % \
(self.data._file.tell(), descriptor.offset, descriptor.dataLength))
self.data.dump(tmpf, descriptor)
tmpf.flush()
self.idxf.close()
self.datf.close()
CacheDumper('cache.idx', 'cache.dat')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment