71 lines
2.6 KiB
Python
71 lines
2.6 KiB
Python
import struct
|
|
|
|
CHUNK = 128*512
|
|
LV_START = 5120000*512
|
|
BSIZE = 4096
|
|
|
|
# Search for /var directory block by looking for its known contents
|
|
# /var should contain: lib, log, cache, spool, tmp, www, etc.
|
|
# inode 1310721 with links=15 means 15 entries
|
|
|
|
# The directory block must contain entry for 'lib' pointing to a valid inode
|
|
# Let's search all of md0 for a 4KB block containing 'lib' as a dir entry
|
|
# where the parent context suggests it's /var
|
|
|
|
targets = [b'log', b'cache', b'spool', b'backups', b'mail']
|
|
|
|
print('Searching for /var directory block...')
|
|
print('Looking for block containing multiple /var subdirectory names')
|
|
|
|
chunk_size = 32*1024*1024
|
|
offset = LV_START # start from filesystem area
|
|
|
|
found_blocks = {}
|
|
|
|
with open('/dev/md0','rb') as f:
|
|
f.seek(0,2)
|
|
disk_size = f.tell()
|
|
|
|
f.seek(offset)
|
|
pos = offset
|
|
while pos < disk_size:
|
|
data = f.read(min(chunk_size, disk_size-pos))
|
|
if not data: break
|
|
|
|
# Look for blocks containing multiple target strings
|
|
for blk_off in range(0, len(data)-BSIZE, BSIZE):
|
|
block = data[blk_off:blk_off+BSIZE]
|
|
matches = sum(1 for t in targets if t in block)
|
|
if matches >= 2:
|
|
abs_byte = pos + blk_off
|
|
# Verify as directory block
|
|
entries = []
|
|
off = 0
|
|
while off < BSIZE-8:
|
|
ino = struct.unpack_from('<I', block, off)[0]
|
|
rec_len = struct.unpack_from('<H', block, off+4)[0]
|
|
name_len= block[off+6]
|
|
ftype = block[off+7]
|
|
if rec_len < 8: break
|
|
if (10 < ino < 500_000_000 and
|
|
0 < name_len <= rec_len-8 and
|
|
ftype in (1,2,7) and
|
|
rec_len % 4 == 0):
|
|
name = block[off+8:off+8+name_len].decode('utf-8',errors='replace')
|
|
if name.isprintable():
|
|
entries.append((ino,name,ftype))
|
|
off += rec_len
|
|
|
|
if len(entries) >= 3:
|
|
abs_block = (abs_byte - LV_START) // BSIZE
|
|
print(f'Candidate at md0 byte {abs_byte} '
|
|
f'(block {abs_block}):')
|
|
for ino,name,ftype in entries[:10]:
|
|
tname={1:\"file\",2:\"dir\",7:\"link\"}.get(ftype,'?')
|
|
print(f' {tname} inode={ino} {name!r}')
|
|
print()
|
|
|
|
pos += chunk_size
|
|
if pos % (10*1024**3) == 0:
|
|
print(f' Scanned {pos//1024**3}GB...', flush=True)
|