67 lines
2.3 KiB
Python
67 lines
2.3 KiB
Python
CHUNK = 128*512
|
|
LV_START = 5120000*512
|
|
BSIZE = 4096
|
|
|
|
# Block 5251104 falls in:
|
|
# virt_byte = 5251104 * 4096 = 21508521984
|
|
# group=65638, chunk_idx=4, intra=0
|
|
|
|
# The physical location of this metadata chunk:
|
|
group = 65638
|
|
phys_meta = LV_START + group*5*CHUNK + 4*CHUNK
|
|
print(f'Metadata chunk physical byte: {phys_meta}')
|
|
|
|
# Read the full 64KB metadata chunk
|
|
with open('/dev/md0','rb') as f:
|
|
f.seek(phys_meta)
|
|
meta = f.read(CHUNK)
|
|
|
|
nonzero = sum(1 for b in meta if b != 0)
|
|
print(f'Nonzero bytes: {nonzero}/{CHUNK}')
|
|
print()
|
|
|
|
# Earlier we found that metadata chunks store 512 bytes per sector
|
|
# of the 4 adjacent data chunks = 128 sectors * 4 chunks = 512 entries
|
|
# But what if SOME of those 512-byte slots contain filesystem data
|
|
# instead of PERC metadata?
|
|
|
|
# The /var dir block should be 4096 bytes
|
|
# Could it be stored in 8 consecutive 512-byte slots?
|
|
# Let's look for directory signatures in the metadata chunk
|
|
|
|
import struct
|
|
|
|
# Search for directory entry signature: valid inode + rec_len + name_len
|
|
print('Searching for directory entries in metadata chunk...')
|
|
for off in range(0, CHUNK-8, 4):
|
|
ino = struct.unpack_from('<I', meta, off)[0]
|
|
rec_len = struct.unpack_from('<H', meta, off+4)[0]
|
|
name_len= meta[off+6]
|
|
ftype = meta[off+7]
|
|
if (10 < ino < 500_000_000 and
|
|
8 <= rec_len <= 256 and
|
|
0 < name_len <= rec_len-8 and
|
|
ftype in (1,2,7) and
|
|
rec_len % 4 == 0):
|
|
name = meta[off+8:off+8+name_len].decode('utf-8',errors='replace')
|
|
if name.isprintable() and len(name) == name_len:
|
|
print(f' offset {off}: inode={ino} rec_len={rec_len} '
|
|
f'name={name!r} ftype={ftype}')
|
|
|
|
# Also check: does the metadata chunk contain the filesystem data
|
|
# at a fixed offset? e.g. first 4096 bytes = filesystem data block?
|
|
print()
|
|
print('First 4096 bytes as directory:')
|
|
off = 0
|
|
while off < 4096-8:
|
|
ino = struct.unpack_from('<I', meta, off)[0]
|
|
rec_len = struct.unpack_from('<H', meta, off+4)[0]
|
|
name_len= meta[off+6]
|
|
ftype = meta[off+7]
|
|
if rec_len < 8: break
|
|
if ino > 0 and name_len > 0:
|
|
name = meta[off+8:off+8+name_len].decode('utf-8',errors='replace')
|
|
tname = {1:'file',2:'dir',7:'link'}.get(ftype,'?')
|
|
print(f' {tname} inode={ino} {name!r}')
|
|
off += rec_len
|