#!/usr/bin/env python3 """Static ELF/PE/Mach-O layout, dependency, symbol and disassembly inventory.""" import argparse from collections import Counter import gzip import hashlib import json from pathlib import Path import platform import re import shutil import struct import subprocess from analyze_qvm import write_json, write_rows MAGICS = {b'\x7fELF': 'ELF', b'MZ': 'PE', b'\xcf\xfa\xed\xfe': 'Mach-O'} def take(data, offset, length): if offset < 0 or length < 0 or offset+length > len(data): raise ValueError('out-of-file structure') return data[offset:offset+length] def unpack(fmt, data, offset): return struct.unpack(fmt, take(data, offset, struct.calcsize(fmt))) def cstring(data, offset): if not 0 <= offset < len(data): raise ValueError('invalid string offset') end = data.find(b'\0', offset) if end < 0: raise ValueError('unterminated string') return data[offset:end].decode('utf-8', errors='backslashreplace') def elf(data): if data[4] not in (1, 2) or data[5] != 1: raise ValueError('only little-endian ELF32/64 supported') bits = 64 if data[4] == 2 else 32 h = unpack('> 4, 'visibility': other & 3, 'undefined': section == 0, 'table': name}) if typ in (4, 9): relocations.append({'section': name, 'entry_bytes': entsize, 'count': size//entsize if entsize else None}) interpreter = None for i in range(phcount): at = phoff+i*phsize ph = unpack(' 1 and directories[1]['rva_or_security_file_offset']: at = rva_offset(directories[1]['rva_or_security_file_offset']) for _ in range(4096): desc = unpack(' commands_end: raise ValueError('invalid Mach-O load command') commands.append({'command': hex(cmd), 'file_offset': at, 'bytes': size}) command = take(data, at, size) if cmd == 0x19: _, _, seg, va, vsize, off, length, maxprot, initprot, count, _ = unpack('