92 lines
3.2 KiB
Python
92 lines
3.2 KiB
Python
CHUNK = 128*512 # 64KB
|
|
LV_START = 5120000*512
|
|
BSIZE = 4096
|
|
|
|
# Block 5251104, virtual byte = 5251104 * 4096 = 21508521984
|
|
# group=65638, chunk_idx=4, intra=0
|
|
|
|
# Physical layout: each group of 5 virtual chunks occupies
|
|
# 5*CHUNK bytes on the physical disk (md0)
|
|
# group 65638 starts at:
|
|
group = 65638
|
|
group_phys_start = LV_START + group * 5 * CHUNK
|
|
print(f'Group {group} physical start: {group_phys_start}')
|
|
print()
|
|
|
|
import struct
|
|
|
|
with open('/dev/md0','rb') as f:
|
|
# Read all 5 chunks of this group
|
|
f.seek(group_phys_start)
|
|
all_chunks = f.read(5*CHUNK)
|
|
|
|
for ci in range(5):
|
|
chunk = all_chunks[ci*CHUNK:(ci+1)*CHUNK]
|
|
nonzero = sum(1 for b in chunk if b != 0)
|
|
# Try first 32 bytes as directory
|
|
ino = struct.unpack_from('<I', chunk, 0)[0]
|
|
rec = struct.unpack_from('<H', chunk, 4)[0]
|
|
nl = chunk[6]
|
|
ft = chunk[7]
|
|
print(f'Chunk {ci}: nonzero={nonzero}/{CHUNK}', end='')
|
|
if 10 < ino < 500_000_000 and 8 <= rec <= 256 and 0 < nl < 32 and ft in (1,2,7):
|
|
name = chunk[8:8+nl].decode('utf-8',errors='replace')
|
|
print(f' POSSIBLE DIR: inode={ino} name={name!r}', end='')
|
|
print()
|
|
|
|
# The data chunks (0-3) map to virtual chunks as follows:
|
|
# Our translation: virtual chunk N -> physical chunk N (for N<4)
|
|
# So physical chunks 0,1,2,3 = virtual chunks 0,1,2,3
|
|
# And physical chunk 4 = the metadata chunk we skip
|
|
|
|
# But what if our anchor points were right (FAT32 and LV)
|
|
# yet the internal mapping within the LV is different?
|
|
# What if the PERC uses a different chunk as metadata inside the LV?
|
|
|
|
# Our two anchors:
|
|
# FAT32 VBR at PERC virtual 2048 -> md0 sector 1664
|
|
# LV start at PERC virtual 6400000 -> md0 sector 5120000
|
|
|
|
# These are BEFORE the LV. Inside the LV, could the chunk order differ?
|
|
# What if inside the LV the metadata chunk is chunk 0, not chunk 4?
|
|
|
|
# Test: read chunk 0 of group 65638 as directory
|
|
chunk0 = all_chunks[0:CHUNK]
|
|
print()
|
|
print('Chunk 0 as directory:')
|
|
off = 0
|
|
while off < BSIZE-8:
|
|
ino = struct.unpack_from('<I', chunk0, off)[0]
|
|
rec_len = struct.unpack_from('<H', chunk0, off+4)[0]
|
|
name_len= chunk0[off+6]
|
|
ftype = chunk0[off+7]
|
|
if rec_len < 8: break
|
|
if ino > 0 and name_len > 0:
|
|
name = chunk0[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
|
|
|
|
# Test each chunk as potential /var directory
|
|
print()
|
|
for ci in range(5):
|
|
chunk = all_chunks[ci*CHUNK:(ci+1)*CHUNK]
|
|
off = 0
|
|
entries = []
|
|
while off < BSIZE-8:
|
|
ino = struct.unpack_from('<I', chunk, off)[0]
|
|
rec_len = struct.unpack_from('<H', chunk, off+4)[0]
|
|
name_len= chunk[off+6]
|
|
ftype = chunk[off+7]
|
|
if rec_len < 8: break
|
|
if 10 < ino < 500_000_000 and name_len > 0 and ftype in (1,2,7):
|
|
name = chunk[off+8:off+8+name_len].decode('utf-8',errors='replace')
|
|
if name.isprintable():
|
|
entries.append((ino, name, ftype))
|
|
off += rec_len
|
|
if entries:
|
|
print(f'Chunk {ci} has {len(entries)} directory entries:')
|
|
for ino, name, ftype in entries[:5]:
|
|
tname = {1:'file',2:'dir',7:'link'}.get(ftype,'?')
|
|
print(f' {tname} inode={ino} {name!r}')
|