Initial remote commit
This commit is contained in:
107
misc_tools/digging.py
Normal file
107
misc_tools/digging.py
Normal file
@@ -0,0 +1,107 @@
|
||||
import struct
|
||||
|
||||
CHUNK = 128*512
|
||||
LV_START = 5120000*512
|
||||
BSIZE = 4096
|
||||
IPG = 8192
|
||||
|
||||
def read_virt(virt_byte, length):
|
||||
result = bytearray(length)
|
||||
pos = virt_byte
|
||||
remaining = length
|
||||
with open('/dev/md0','rb') as f:
|
||||
while remaining > 0:
|
||||
group = pos // (5*CHUNK)
|
||||
in_group = pos % (5*CHUNK)
|
||||
chunk_idx = in_group // CHUNK
|
||||
intra = in_group % CHUNK
|
||||
seg_len = min(CHUNK-intra, remaining)
|
||||
dst_off = pos - virt_byte
|
||||
if chunk_idx != 4:
|
||||
phys = LV_START + group*4*CHUNK + chunk_idx*CHUNK + intra
|
||||
f.seek(phys)
|
||||
data = f.read(seg_len)
|
||||
result[dst_off:dst_off+len(data)] = data
|
||||
pos += seg_len
|
||||
remaining -= seg_len
|
||||
return bytes(result)
|
||||
|
||||
# Cache GDT
|
||||
print('Loading full GDT...')
|
||||
NUM_GROUPS = 35728
|
||||
gdt_data = read_virt(BSIZE, NUM_GROUPS*64)
|
||||
print(f'GDT loaded: {len(gdt_data)} bytes')
|
||||
|
||||
def get_inode_table_block(group):
|
||||
entry = gdt_data[group*64:(group+1)*64]
|
||||
it_lo = struct.unpack_from('<I', entry, 8)[0]
|
||||
it_hi = struct.unpack_from('<I', entry, 40)[0]
|
||||
return (it_hi<<32)|it_lo
|
||||
|
||||
def read_inode(inode_num):
|
||||
group = (inode_num-1)//IPG
|
||||
idx = (inode_num-1)%IPG
|
||||
it_block = get_inode_table_block(group)
|
||||
return read_virt(it_block*BSIZE + idx*256, 256)
|
||||
|
||||
def get_extents(inode_data):
|
||||
blocks = []
|
||||
if struct.unpack_from('<H', inode_data, 40)[0] != 0xf30a:
|
||||
return blocks
|
||||
entries = struct.unpack_from('<H', inode_data, 42)[0]
|
||||
depth = struct.unpack_from('<H', inode_data, 46)[0]
|
||||
if depth == 0:
|
||||
for i in range(min(entries,4)):
|
||||
off = 52+i*12
|
||||
ee_len = struct.unpack_from('<H', inode_data, off+4)[0]
|
||||
ee_hi = struct.unpack_from('<H', inode_data, off+6)[0]
|
||||
ee_lo = struct.unpack_from('<I', inode_data, off+8)[0]
|
||||
start = (ee_hi<<32)|ee_lo
|
||||
if ee_len > 1024: continue
|
||||
for b in range(min(ee_len,8)):
|
||||
blocks.append(start+b)
|
||||
return blocks
|
||||
|
||||
def list_dir(inode_num):
|
||||
inode_data = read_inode(inode_num)
|
||||
mode = struct.unpack_from('<H', inode_data, 0)[0]
|
||||
if (mode&0xf000) != 0x4000:
|
||||
return []
|
||||
entries = []
|
||||
for blk in get_extents(inode_data):
|
||||
blk_data = read_virt(blk*BSIZE, BSIZE)
|
||||
off = 0
|
||||
while off < BSIZE-8:
|
||||
ino = struct.unpack_from('<I', blk_data, off)[0]
|
||||
rec_len = struct.unpack_from('<H', blk_data, off+4)[0]
|
||||
name_len= blk_data[off+6]
|
||||
ftype = blk_data[off+7]
|
||||
if rec_len < 8: break
|
||||
if ino > 0 and name_len > 0:
|
||||
name = blk_data[off+8:off+8+name_len].decode('utf-8',errors='replace')
|
||||
if name not in ('.','..'):
|
||||
entries.append((ino, name, ftype))
|
||||
off += rec_len
|
||||
return entries
|
||||
|
||||
# Walk tree from /var
|
||||
print()
|
||||
print('=== /var (inode 1310721) ===')
|
||||
for ino, name, ftype in list_dir(1310721):
|
||||
tname = {1:'file',2:'dir',7:'link'}.get(ftype,'?')
|
||||
print(f' {tname:4s} inode={ino:10d} {name!r}')
|
||||
|
||||
print()
|
||||
for ino, name, ftype in list_dir(1310721):
|
||||
if name == 'lib':
|
||||
print(f'=== /var/lib (inode {ino}) ===')
|
||||
for i2,n2,f2 in list_dir(ino):
|
||||
tname = {1:'file',2:'dir',7:'link'}.get(f2,'?')
|
||||
print(f' {tname:4s} inode={i2:10d} {n2!r}')
|
||||
|
||||
for i2,n2,f2 in list_dir(ino):
|
||||
if n2 == 'pterodactyl':
|
||||
print(f'\n=== /var/lib/pterodactyl (inode {i2}) ===')
|
||||
for i3,n3,f3 in list_dir(i2):
|
||||
tname = {1:'file',2:'dir',7:'link'}.get(f3,'?')
|
||||
print(f' {tname:4s} inode={i3:10d} {n3!r}')
|
||||
Reference in New Issue
Block a user