diff --git a/dissect/executable/elf/c_elf.pyi b/dissect/executable/elf/c_elf.pyi new file mode 100644 index 0000000..f2e4487 --- /dev/null +++ b/dissect/executable/elf/c_elf.pyi @@ -0,0 +1,920 @@ +# Generated by cstruct-stubgen +from typing import BinaryIO, Literal, TypeAlias, overload + +import dissect.cstruct as __cs__ + +class _c_common_elf(__cs__.cstruct): + PT_LOOS: Literal[1610612736] = ... + PT_HIOS: Literal[1879048191] = ... + PT_LOPROC: Literal[1879048192] = ... + PT_HIPROC: Literal[2147483647] = ... + PT_GNU_EH_FRAME: Literal[1685382480] = ... + PT_GNU_STACK: Literal[1685382481] = ... + PN_XNUM: Literal[65535] = ... + ET_LOPROC: Literal[65280] = ... + ET_HIPROC: Literal[65535] = ... + DT_NULL: Literal[0] = ... + DT_NEEDED: Literal[1] = ... + DT_PLTRELSZ: Literal[2] = ... + DT_PLTGOT: Literal[3] = ... + DT_HASH: Literal[4] = ... + DT_STRTAB: Literal[5] = ... + DT_SYMTAB: Literal[6] = ... + DT_RELA: Literal[7] = ... + DT_RELASZ: Literal[8] = ... + DT_RELAENT: Literal[9] = ... + DT_STRSZ: Literal[10] = ... + DT_SYMENT: Literal[11] = ... + DT_INIT: Literal[12] = ... + DT_FINI: Literal[13] = ... + DT_SONAME: Literal[14] = ... + DT_RPATH: Literal[15] = ... + DT_SYMBOLIC: Literal[16] = ... + DT_REL: Literal[17] = ... + DT_RELSZ: Literal[18] = ... + DT_RELENT: Literal[19] = ... + DT_PLTREL: Literal[20] = ... + DT_DEBUG: Literal[21] = ... + DT_TEXTREL: Literal[22] = ... + DT_JMPREL: Literal[23] = ... + DT_ENCODING: Literal[32] = ... + OLD_DT_LOOS: Literal[1610612736] = ... + DT_LOOS: Literal[1610612749] = ... + DT_HIOS: Literal[1879044096] = ... + DT_VALRNGLO: Literal[1879047424] = ... + DT_VALRNGHI: Literal[1879047679] = ... + DT_ADDRRNGLO: Literal[1879047680] = ... + DT_ADDRRNGHI: Literal[1879047935] = ... + DT_VERSYM: Literal[1879048176] = ... + DT_RELACOUNT: Literal[1879048185] = ... + DT_RELCOUNT: Literal[1879048186] = ... + DT_FLAGS_1: Literal[1879048187] = ... + DT_VERDEF: Literal[1879048188] = ... + DT_VERDEFNUM: Literal[1879048189] = ... + DT_VERNEED: Literal[1879048190] = ... + DT_VERNEEDNUM: Literal[1879048191] = ... + OLD_DT_HIOS: Literal[1879048191] = ... + DT_LOPROC: Literal[1879048192] = ... + DT_HIPROC: Literal[2147483647] = ... + EI_NIDENT: Literal[16] = ... + EI_MAG0: Literal[0] = ... + EI_MAG1: Literal[1] = ... + EI_MAG2: Literal[2] = ... + EI_MAG3: Literal[3] = ... + EI_CLASS: Literal[4] = ... + EI_DATA: Literal[5] = ... + EI_VERSION: Literal[6] = ... + EI_OSABI: Literal[7] = ... + EI_PAD: Literal[8] = ... + ELFMAG0: Literal[127] = ... + ELFMAG1: Literal["E"] = ... + ELFMAG2: Literal["L"] = ... + ELFMAG3: Literal["F"] = ... + ELFMAG: Literal[b"\x7fELF"] = ... + SELFMAG: Literal[4] = ... + ELFCLASSNONE: Literal[0] = ... + ELFCLASS32: Literal[1] = ... + ELFCLASS64: Literal[2] = ... + ELFCLASSNUM: Literal[3] = ... + ELFDATANONE: Literal[0] = ... + ELFDATA2LSB: Literal[1] = ... + ELFDATA2MSB: Literal[2] = ... + EV_NONE: Literal[0] = ... + EV_CURRENT: Literal[1] = ... + EV_NUM: Literal[2] = ... + ELFOSABI_NONE: Literal[0] = ... + ELFOSABI_LINUX: Literal[3] = ... + NT_PRSTATUS: Literal[1] = ... + NT_PRFPREG: Literal[2] = ... + NT_PRPSINFO: Literal[3] = ... + NT_TASKSTRUCT: Literal[4] = ... + NT_AUXV: Literal[6] = ... + NT_SIGINFO: Literal[1397311305] = ... + NT_FILE: Literal[1179208773] = ... + NT_PRXFPREG: Literal[1189489535] = ... + NT_PPC_VMX: Literal[256] = ... + NT_PPC_SPE: Literal[257] = ... + NT_PPC_VSX: Literal[258] = ... + NT_PPC_TAR: Literal[259] = ... + NT_PPC_PPR: Literal[260] = ... + NT_PPC_DSCR: Literal[261] = ... + NT_PPC_EBB: Literal[262] = ... + NT_PPC_PMU: Literal[263] = ... + NT_PPC_TM_CGPR: Literal[264] = ... + NT_PPC_TM_CFPR: Literal[265] = ... + NT_PPC_TM_CVMX: Literal[266] = ... + NT_PPC_TM_CVSX: Literal[267] = ... + NT_PPC_TM_SPR: Literal[268] = ... + NT_PPC_TM_CTAR: Literal[269] = ... + NT_PPC_TM_CPPR: Literal[270] = ... + NT_PPC_TM_CDSCR: Literal[271] = ... + NT_PPC_PKEY: Literal[272] = ... + NT_386_TLS: Literal[512] = ... + NT_386_IOPERM: Literal[513] = ... + NT_X86_XSTATE: Literal[514] = ... + NT_S390_HIGH_GPRS: Literal[768] = ... + NT_S390_TIMER: Literal[769] = ... + NT_S390_TODCMP: Literal[770] = ... + NT_S390_TODPREG: Literal[771] = ... + NT_S390_CTRS: Literal[772] = ... + NT_S390_PREFIX: Literal[773] = ... + NT_S390_LAST_BREAK: Literal[774] = ... + NT_S390_SYSTEM_CALL: Literal[775] = ... + NT_S390_TDB: Literal[776] = ... + NT_S390_VXRS_LOW: Literal[777] = ... + NT_S390_VXRS_HIGH: Literal[778] = ... + NT_S390_GS_CB: Literal[779] = ... + NT_S390_GS_BC: Literal[780] = ... + NT_S390_RI_CB: Literal[781] = ... + NT_ARM_VFP: Literal[1024] = ... + NT_ARM_TLS: Literal[1025] = ... + NT_ARM_HW_BREAK: Literal[1026] = ... + NT_ARM_HW_WATCH: Literal[1027] = ... + NT_ARM_SYSTEM_CALL: Literal[1028] = ... + NT_ARM_SVE: Literal[1029] = ... + NT_ARC_V2: Literal[1536] = ... + NT_VMCOREDD: Literal[1792] = ... + NT_MIPS_DSP: Literal[2048] = ... + NT_MIPS_FP_MODE: Literal[2049] = ... + class PT(__cs__.Enum): + NULL = ... + LOAD = ... + DYNAMIC = ... + INTERP = ... + NOTE = ... + SHLIB = ... + PHDR = ... + TLS = ... + + class Elf_Type(__cs__.Enum): + ET_NONE = ... + ET_REL = ... + ET_EXEC = ... + ET_DYN = ... + ET_CORE = ... + + class STB(__cs__.Enum): + LOCAL = ... + GLOBAL = ... + WEAK = ... + + class STT(__cs__.Enum): + NOTYPE = ... + OBJECT = ... + FUNC = ... + SECTION = ... + FILE = ... + COMMON = ... + TLS = ... + + class STV(__cs__.Enum): + DEFAULT = ... + INTERNAL = ... + HIDDEN = ... + PROTECTED = ... + + class PF(__cs__.Flag): + R = ... + W = ... + X = ... + + class SHT(__cs__.Enum): + NULL = ... + PROGBITS = ... + SYMTAB = ... + STRTAB = ... + RELA = ... + HASH = ... + DYNAMIC = ... + NOTE = ... + NOBITS = ... + REL = ... + SHLIB = ... + DYNSYM = ... + NUM = ... + + class SHN(__cs__.Enum): + UNDEF = ... + LOPROC = ... + HIPROC = ... + LIVEPATCH = ... + ABS = ... + COMMON = ... + HIRESERVE = ... + +# Technically `c_common_elf` is an instance of `_c_common_elf`, but then we can't use it in type hints +c_common_elf: TypeAlias = _c_common_elf + +class _c_elf_32(__cs__.cstruct): + PT_LOOS: Literal[1610612736] = ... + PT_HIOS: Literal[1879048191] = ... + PT_LOPROC: Literal[1879048192] = ... + PT_HIPROC: Literal[2147483647] = ... + PT_GNU_EH_FRAME: Literal[1685382480] = ... + PT_GNU_STACK: Literal[1685382481] = ... + PN_XNUM: Literal[65535] = ... + ET_LOPROC: Literal[65280] = ... + ET_HIPROC: Literal[65535] = ... + DT_NULL: Literal[0] = ... + DT_NEEDED: Literal[1] = ... + DT_PLTRELSZ: Literal[2] = ... + DT_PLTGOT: Literal[3] = ... + DT_HASH: Literal[4] = ... + DT_STRTAB: Literal[5] = ... + DT_SYMTAB: Literal[6] = ... + DT_RELA: Literal[7] = ... + DT_RELASZ: Literal[8] = ... + DT_RELAENT: Literal[9] = ... + DT_STRSZ: Literal[10] = ... + DT_SYMENT: Literal[11] = ... + DT_INIT: Literal[12] = ... + DT_FINI: Literal[13] = ... + DT_SONAME: Literal[14] = ... + DT_RPATH: Literal[15] = ... + DT_SYMBOLIC: Literal[16] = ... + DT_REL: Literal[17] = ... + DT_RELSZ: Literal[18] = ... + DT_RELENT: Literal[19] = ... + DT_PLTREL: Literal[20] = ... + DT_DEBUG: Literal[21] = ... + DT_TEXTREL: Literal[22] = ... + DT_JMPREL: Literal[23] = ... + DT_ENCODING: Literal[32] = ... + OLD_DT_LOOS: Literal[1610612736] = ... + DT_LOOS: Literal[1610612749] = ... + DT_HIOS: Literal[1879044096] = ... + DT_VALRNGLO: Literal[1879047424] = ... + DT_VALRNGHI: Literal[1879047679] = ... + DT_ADDRRNGLO: Literal[1879047680] = ... + DT_ADDRRNGHI: Literal[1879047935] = ... + DT_VERSYM: Literal[1879048176] = ... + DT_RELACOUNT: Literal[1879048185] = ... + DT_RELCOUNT: Literal[1879048186] = ... + DT_FLAGS_1: Literal[1879048187] = ... + DT_VERDEF: Literal[1879048188] = ... + DT_VERDEFNUM: Literal[1879048189] = ... + DT_VERNEED: Literal[1879048190] = ... + DT_VERNEEDNUM: Literal[1879048191] = ... + OLD_DT_HIOS: Literal[1879048191] = ... + DT_LOPROC: Literal[1879048192] = ... + DT_HIPROC: Literal[2147483647] = ... + EI_NIDENT: Literal[16] = ... + EI_MAG0: Literal[0] = ... + EI_MAG1: Literal[1] = ... + EI_MAG2: Literal[2] = ... + EI_MAG3: Literal[3] = ... + EI_CLASS: Literal[4] = ... + EI_DATA: Literal[5] = ... + EI_VERSION: Literal[6] = ... + EI_OSABI: Literal[7] = ... + EI_PAD: Literal[8] = ... + ELFMAG0: Literal[127] = ... + ELFMAG1: Literal["E"] = ... + ELFMAG2: Literal["L"] = ... + ELFMAG3: Literal["F"] = ... + ELFMAG: Literal[b"\x7fELF"] = ... + SELFMAG: Literal[4] = ... + ELFCLASSNONE: Literal[0] = ... + ELFCLASS32: Literal[1] = ... + ELFCLASS64: Literal[2] = ... + ELFCLASSNUM: Literal[3] = ... + ELFDATANONE: Literal[0] = ... + ELFDATA2LSB: Literal[1] = ... + ELFDATA2MSB: Literal[2] = ... + EV_NONE: Literal[0] = ... + EV_CURRENT: Literal[1] = ... + EV_NUM: Literal[2] = ... + ELFOSABI_NONE: Literal[0] = ... + ELFOSABI_LINUX: Literal[3] = ... + NT_PRSTATUS: Literal[1] = ... + NT_PRFPREG: Literal[2] = ... + NT_PRPSINFO: Literal[3] = ... + NT_TASKSTRUCT: Literal[4] = ... + NT_AUXV: Literal[6] = ... + NT_SIGINFO: Literal[1397311305] = ... + NT_FILE: Literal[1179208773] = ... + NT_PRXFPREG: Literal[1189489535] = ... + NT_PPC_VMX: Literal[256] = ... + NT_PPC_SPE: Literal[257] = ... + NT_PPC_VSX: Literal[258] = ... + NT_PPC_TAR: Literal[259] = ... + NT_PPC_PPR: Literal[260] = ... + NT_PPC_DSCR: Literal[261] = ... + NT_PPC_EBB: Literal[262] = ... + NT_PPC_PMU: Literal[263] = ... + NT_PPC_TM_CGPR: Literal[264] = ... + NT_PPC_TM_CFPR: Literal[265] = ... + NT_PPC_TM_CVMX: Literal[266] = ... + NT_PPC_TM_CVSX: Literal[267] = ... + NT_PPC_TM_SPR: Literal[268] = ... + NT_PPC_TM_CTAR: Literal[269] = ... + NT_PPC_TM_CPPR: Literal[270] = ... + NT_PPC_TM_CDSCR: Literal[271] = ... + NT_PPC_PKEY: Literal[272] = ... + NT_386_TLS: Literal[512] = ... + NT_386_IOPERM: Literal[513] = ... + NT_X86_XSTATE: Literal[514] = ... + NT_S390_HIGH_GPRS: Literal[768] = ... + NT_S390_TIMER: Literal[769] = ... + NT_S390_TODCMP: Literal[770] = ... + NT_S390_TODPREG: Literal[771] = ... + NT_S390_CTRS: Literal[772] = ... + NT_S390_PREFIX: Literal[773] = ... + NT_S390_LAST_BREAK: Literal[774] = ... + NT_S390_SYSTEM_CALL: Literal[775] = ... + NT_S390_TDB: Literal[776] = ... + NT_S390_VXRS_LOW: Literal[777] = ... + NT_S390_VXRS_HIGH: Literal[778] = ... + NT_S390_GS_CB: Literal[779] = ... + NT_S390_GS_BC: Literal[780] = ... + NT_S390_RI_CB: Literal[781] = ... + NT_ARM_VFP: Literal[1024] = ... + NT_ARM_TLS: Literal[1025] = ... + NT_ARM_HW_BREAK: Literal[1026] = ... + NT_ARM_HW_WATCH: Literal[1027] = ... + NT_ARM_SYSTEM_CALL: Literal[1028] = ... + NT_ARM_SVE: Literal[1029] = ... + NT_ARC_V2: Literal[1536] = ... + NT_VMCOREDD: Literal[1792] = ... + NT_MIPS_DSP: Literal[2048] = ... + NT_MIPS_FP_MODE: Literal[2049] = ... + class PT(__cs__.Enum): + NULL = ... + LOAD = ... + DYNAMIC = ... + INTERP = ... + NOTE = ... + SHLIB = ... + PHDR = ... + TLS = ... + + class Elf_Type(__cs__.Enum): + ET_NONE = ... + ET_REL = ... + ET_EXEC = ... + ET_DYN = ... + ET_CORE = ... + + class STB(__cs__.Enum): + LOCAL = ... + GLOBAL = ... + WEAK = ... + + class STT(__cs__.Enum): + NOTYPE = ... + OBJECT = ... + FUNC = ... + SECTION = ... + FILE = ... + COMMON = ... + TLS = ... + + class STV(__cs__.Enum): + DEFAULT = ... + INTERNAL = ... + HIDDEN = ... + PROTECTED = ... + + class PF(__cs__.Flag): + R = ... + W = ... + X = ... + + class SHT(__cs__.Enum): + NULL = ... + PROGBITS = ... + SYMTAB = ... + STRTAB = ... + RELA = ... + HASH = ... + DYNAMIC = ... + NOTE = ... + NOBITS = ... + REL = ... + SHLIB = ... + DYNSYM = ... + NUM = ... + + class SHN(__cs__.Enum): + UNDEF = ... + LOPROC = ... + HIPROC = ... + LIVEPATCH = ... + ABS = ... + COMMON = ... + HIRESERVE = ... + + Elf32_Addr: TypeAlias = _c_elf_32.uint32 + Elf32_Half: TypeAlias = _c_elf_32.uint16 + Elf32_Off: TypeAlias = _c_elf_32.uint32 + Elf32_Sword: TypeAlias = _c_elf_32.int32 + Elf32_Word: TypeAlias = _c_elf_32.uint32 + class Rel(__cs__.Structure): + r_offset: _c_elf_32.uint32 + r_info: _c_elf_32.uint32 + @overload + def __init__(self, r_offset: _c_elf_32.uint32 | None = ..., r_info: _c_elf_32.uint32 | None = ...): ... + @overload + def __init__(self, fh: bytes | memoryview | bytearray | BinaryIO, /): ... + + class Rela(__cs__.Structure): + r_offset: _c_elf_32.uint32 + r_info: _c_elf_32.uint32 + r_addend: _c_elf_32.int32 + @overload + def __init__( + self, + r_offset: _c_elf_32.uint32 | None = ..., + r_info: _c_elf_32.uint32 | None = ..., + r_addend: _c_elf_32.int32 | None = ..., + ): ... + @overload + def __init__(self, fh: bytes | memoryview | bytearray | BinaryIO, /): ... + + class Sym(__cs__.Structure): + st_name: _c_elf_32.uint32 + st_value: _c_elf_32.uint32 + st_size: _c_elf_32.uint32 + st_info: _c_elf_32.char + st_other: _c_elf_32.char + st_shndx: _c_elf_32.uint16 + @overload + def __init__( + self, + st_name: _c_elf_32.uint32 | None = ..., + st_value: _c_elf_32.uint32 | None = ..., + st_size: _c_elf_32.uint32 | None = ..., + st_info: _c_elf_32.char | None = ..., + st_other: _c_elf_32.char | None = ..., + st_shndx: _c_elf_32.uint16 | None = ..., + ): ... + @overload + def __init__(self, fh: bytes | memoryview | bytearray | BinaryIO, /): ... + + class Ehdr(__cs__.Structure): + e_ident: __cs__.CharArray + e_type: _c_elf_32.Elf_Type + e_machine: _c_elf_32.uint16 + e_version: _c_elf_32.uint32 + e_entry: _c_elf_32.uint32 + e_phoff: _c_elf_32.uint32 + e_shoff: _c_elf_32.uint32 + e_flags: _c_elf_32.uint32 + e_ehsize: _c_elf_32.uint16 + e_phentsize: _c_elf_32.uint16 + e_phnum: _c_elf_32.uint16 + e_shentsize: _c_elf_32.uint16 + e_shnum: _c_elf_32.uint16 + e_shstrndx: _c_elf_32.uint16 + @overload + def __init__( + self, + e_ident: __cs__.CharArray | None = ..., + e_type: _c_elf_32.Elf_Type | None = ..., + e_machine: _c_elf_32.uint16 | None = ..., + e_version: _c_elf_32.uint32 | None = ..., + e_entry: _c_elf_32.uint32 | None = ..., + e_phoff: _c_elf_32.uint32 | None = ..., + e_shoff: _c_elf_32.uint32 | None = ..., + e_flags: _c_elf_32.uint32 | None = ..., + e_ehsize: _c_elf_32.uint16 | None = ..., + e_phentsize: _c_elf_32.uint16 | None = ..., + e_phnum: _c_elf_32.uint16 | None = ..., + e_shentsize: _c_elf_32.uint16 | None = ..., + e_shnum: _c_elf_32.uint16 | None = ..., + e_shstrndx: _c_elf_32.uint16 | None = ..., + ): ... + @overload + def __init__(self, fh: bytes | memoryview | bytearray | BinaryIO, /): ... + + class Phdr(__cs__.Structure): + p_type: _c_elf_32.PT + p_offset: _c_elf_32.uint32 + p_vaddr: _c_elf_32.uint32 + p_paddr: _c_elf_32.uint32 + p_filesz: _c_elf_32.uint32 + p_memsz: _c_elf_32.uint32 + p_flags: _c_elf_32.PF + p_align: _c_elf_32.uint32 + @overload + def __init__( + self, + p_type: _c_elf_32.PT | None = ..., + p_offset: _c_elf_32.uint32 | None = ..., + p_vaddr: _c_elf_32.uint32 | None = ..., + p_paddr: _c_elf_32.uint32 | None = ..., + p_filesz: _c_elf_32.uint32 | None = ..., + p_memsz: _c_elf_32.uint32 | None = ..., + p_flags: _c_elf_32.PF | None = ..., + p_align: _c_elf_32.uint32 | None = ..., + ): ... + @overload + def __init__(self, fh: bytes | memoryview | bytearray | BinaryIO, /): ... + + class Shdr(__cs__.Structure): + sh_name: _c_elf_32.uint32 + sh_type: _c_elf_32.SHT + sh_flags: _c_elf_32.uint32 + sh_addr: _c_elf_32.uint32 + sh_offset: _c_elf_32.uint32 + sh_size: _c_elf_32.uint32 + sh_link: _c_elf_32.uint32 + sh_info: _c_elf_32.uint32 + sh_addralign: _c_elf_32.uint32 + sh_entsize: _c_elf_32.uint32 + @overload + def __init__( + self, + sh_name: _c_elf_32.uint32 | None = ..., + sh_type: _c_elf_32.SHT | None = ..., + sh_flags: _c_elf_32.uint32 | None = ..., + sh_addr: _c_elf_32.uint32 | None = ..., + sh_offset: _c_elf_32.uint32 | None = ..., + sh_size: _c_elf_32.uint32 | None = ..., + sh_link: _c_elf_32.uint32 | None = ..., + sh_info: _c_elf_32.uint32 | None = ..., + sh_addralign: _c_elf_32.uint32 | None = ..., + sh_entsize: _c_elf_32.uint32 | None = ..., + ): ... + @overload + def __init__(self, fh: bytes | memoryview | bytearray | BinaryIO, /): ... + + class Nhdr(__cs__.Structure): + n_namesz: _c_elf_32.uint32 + n_descsz: _c_elf_32.uint32 + n_type: _c_elf_32.uint32 + @overload + def __init__( + self, + n_namesz: _c_elf_32.uint32 | None = ..., + n_descsz: _c_elf_32.uint32 | None = ..., + n_type: _c_elf_32.uint32 | None = ..., + ): ... + @overload + def __init__(self, fh: bytes | memoryview | bytearray | BinaryIO, /): ... + +# Technically `c_elf_32` is an instance of `_c_elf_32`, but then we can't use it in type hints +c_elf_32: TypeAlias = _c_elf_32 + +class _c_elf_64(__cs__.cstruct): + PT_LOOS: Literal[1610612736] = ... + PT_HIOS: Literal[1879048191] = ... + PT_LOPROC: Literal[1879048192] = ... + PT_HIPROC: Literal[2147483647] = ... + PT_GNU_EH_FRAME: Literal[1685382480] = ... + PT_GNU_STACK: Literal[1685382481] = ... + PN_XNUM: Literal[65535] = ... + ET_LOPROC: Literal[65280] = ... + ET_HIPROC: Literal[65535] = ... + DT_NULL: Literal[0] = ... + DT_NEEDED: Literal[1] = ... + DT_PLTRELSZ: Literal[2] = ... + DT_PLTGOT: Literal[3] = ... + DT_HASH: Literal[4] = ... + DT_STRTAB: Literal[5] = ... + DT_SYMTAB: Literal[6] = ... + DT_RELA: Literal[7] = ... + DT_RELASZ: Literal[8] = ... + DT_RELAENT: Literal[9] = ... + DT_STRSZ: Literal[10] = ... + DT_SYMENT: Literal[11] = ... + DT_INIT: Literal[12] = ... + DT_FINI: Literal[13] = ... + DT_SONAME: Literal[14] = ... + DT_RPATH: Literal[15] = ... + DT_SYMBOLIC: Literal[16] = ... + DT_REL: Literal[17] = ... + DT_RELSZ: Literal[18] = ... + DT_RELENT: Literal[19] = ... + DT_PLTREL: Literal[20] = ... + DT_DEBUG: Literal[21] = ... + DT_TEXTREL: Literal[22] = ... + DT_JMPREL: Literal[23] = ... + DT_ENCODING: Literal[32] = ... + OLD_DT_LOOS: Literal[1610612736] = ... + DT_LOOS: Literal[1610612749] = ... + DT_HIOS: Literal[1879044096] = ... + DT_VALRNGLO: Literal[1879047424] = ... + DT_VALRNGHI: Literal[1879047679] = ... + DT_ADDRRNGLO: Literal[1879047680] = ... + DT_ADDRRNGHI: Literal[1879047935] = ... + DT_VERSYM: Literal[1879048176] = ... + DT_RELACOUNT: Literal[1879048185] = ... + DT_RELCOUNT: Literal[1879048186] = ... + DT_FLAGS_1: Literal[1879048187] = ... + DT_VERDEF: Literal[1879048188] = ... + DT_VERDEFNUM: Literal[1879048189] = ... + DT_VERNEED: Literal[1879048190] = ... + DT_VERNEEDNUM: Literal[1879048191] = ... + OLD_DT_HIOS: Literal[1879048191] = ... + DT_LOPROC: Literal[1879048192] = ... + DT_HIPROC: Literal[2147483647] = ... + EI_NIDENT: Literal[16] = ... + EI_MAG0: Literal[0] = ... + EI_MAG1: Literal[1] = ... + EI_MAG2: Literal[2] = ... + EI_MAG3: Literal[3] = ... + EI_CLASS: Literal[4] = ... + EI_DATA: Literal[5] = ... + EI_VERSION: Literal[6] = ... + EI_OSABI: Literal[7] = ... + EI_PAD: Literal[8] = ... + ELFMAG0: Literal[127] = ... + ELFMAG1: Literal["E"] = ... + ELFMAG2: Literal["L"] = ... + ELFMAG3: Literal["F"] = ... + ELFMAG: Literal[b"\x7fELF"] = ... + SELFMAG: Literal[4] = ... + ELFCLASSNONE: Literal[0] = ... + ELFCLASS32: Literal[1] = ... + ELFCLASS64: Literal[2] = ... + ELFCLASSNUM: Literal[3] = ... + ELFDATANONE: Literal[0] = ... + ELFDATA2LSB: Literal[1] = ... + ELFDATA2MSB: Literal[2] = ... + EV_NONE: Literal[0] = ... + EV_CURRENT: Literal[1] = ... + EV_NUM: Literal[2] = ... + ELFOSABI_NONE: Literal[0] = ... + ELFOSABI_LINUX: Literal[3] = ... + NT_PRSTATUS: Literal[1] = ... + NT_PRFPREG: Literal[2] = ... + NT_PRPSINFO: Literal[3] = ... + NT_TASKSTRUCT: Literal[4] = ... + NT_AUXV: Literal[6] = ... + NT_SIGINFO: Literal[1397311305] = ... + NT_FILE: Literal[1179208773] = ... + NT_PRXFPREG: Literal[1189489535] = ... + NT_PPC_VMX: Literal[256] = ... + NT_PPC_SPE: Literal[257] = ... + NT_PPC_VSX: Literal[258] = ... + NT_PPC_TAR: Literal[259] = ... + NT_PPC_PPR: Literal[260] = ... + NT_PPC_DSCR: Literal[261] = ... + NT_PPC_EBB: Literal[262] = ... + NT_PPC_PMU: Literal[263] = ... + NT_PPC_TM_CGPR: Literal[264] = ... + NT_PPC_TM_CFPR: Literal[265] = ... + NT_PPC_TM_CVMX: Literal[266] = ... + NT_PPC_TM_CVSX: Literal[267] = ... + NT_PPC_TM_SPR: Literal[268] = ... + NT_PPC_TM_CTAR: Literal[269] = ... + NT_PPC_TM_CPPR: Literal[270] = ... + NT_PPC_TM_CDSCR: Literal[271] = ... + NT_PPC_PKEY: Literal[272] = ... + NT_386_TLS: Literal[512] = ... + NT_386_IOPERM: Literal[513] = ... + NT_X86_XSTATE: Literal[514] = ... + NT_S390_HIGH_GPRS: Literal[768] = ... + NT_S390_TIMER: Literal[769] = ... + NT_S390_TODCMP: Literal[770] = ... + NT_S390_TODPREG: Literal[771] = ... + NT_S390_CTRS: Literal[772] = ... + NT_S390_PREFIX: Literal[773] = ... + NT_S390_LAST_BREAK: Literal[774] = ... + NT_S390_SYSTEM_CALL: Literal[775] = ... + NT_S390_TDB: Literal[776] = ... + NT_S390_VXRS_LOW: Literal[777] = ... + NT_S390_VXRS_HIGH: Literal[778] = ... + NT_S390_GS_CB: Literal[779] = ... + NT_S390_GS_BC: Literal[780] = ... + NT_S390_RI_CB: Literal[781] = ... + NT_ARM_VFP: Literal[1024] = ... + NT_ARM_TLS: Literal[1025] = ... + NT_ARM_HW_BREAK: Literal[1026] = ... + NT_ARM_HW_WATCH: Literal[1027] = ... + NT_ARM_SYSTEM_CALL: Literal[1028] = ... + NT_ARM_SVE: Literal[1029] = ... + NT_ARC_V2: Literal[1536] = ... + NT_VMCOREDD: Literal[1792] = ... + NT_MIPS_DSP: Literal[2048] = ... + NT_MIPS_FP_MODE: Literal[2049] = ... + class PT(__cs__.Enum): + NULL = ... + LOAD = ... + DYNAMIC = ... + INTERP = ... + NOTE = ... + SHLIB = ... + PHDR = ... + TLS = ... + + class Elf_Type(__cs__.Enum): + ET_NONE = ... + ET_REL = ... + ET_EXEC = ... + ET_DYN = ... + ET_CORE = ... + + class STB(__cs__.Enum): + LOCAL = ... + GLOBAL = ... + WEAK = ... + + class STT(__cs__.Enum): + NOTYPE = ... + OBJECT = ... + FUNC = ... + SECTION = ... + FILE = ... + COMMON = ... + TLS = ... + + class STV(__cs__.Enum): + DEFAULT = ... + INTERNAL = ... + HIDDEN = ... + PROTECTED = ... + + class PF(__cs__.Flag): + R = ... + W = ... + X = ... + + class SHT(__cs__.Enum): + NULL = ... + PROGBITS = ... + SYMTAB = ... + STRTAB = ... + RELA = ... + HASH = ... + DYNAMIC = ... + NOTE = ... + NOBITS = ... + REL = ... + SHLIB = ... + DYNSYM = ... + NUM = ... + + class SHN(__cs__.Enum): + UNDEF = ... + LOPROC = ... + HIPROC = ... + LIVEPATCH = ... + ABS = ... + COMMON = ... + HIRESERVE = ... + + Elf64_Addr: TypeAlias = _c_elf_64.uint64 + Elf64_Half: TypeAlias = _c_elf_64.uint16 + Elf64_SHalf: TypeAlias = _c_elf_64.int16 + Elf64_Off: TypeAlias = _c_elf_64.uint64 + Elf64_Sword: TypeAlias = _c_elf_64.int32 + Elf64_Word: TypeAlias = _c_elf_64.uint32 + Elf64_Xword: TypeAlias = _c_elf_64.uint64 + Elf64_Sxword: TypeAlias = _c_elf_64.int64 + class Rel(__cs__.Structure): + r_offset: _c_elf_64.uint64 + r_info: _c_elf_64.uint64 + @overload + def __init__(self, r_offset: _c_elf_64.uint64 | None = ..., r_info: _c_elf_64.uint64 | None = ...): ... + @overload + def __init__(self, fh: bytes | memoryview | bytearray | BinaryIO, /): ... + + class Rela(__cs__.Structure): + r_offset: _c_elf_64.uint64 + r_info: _c_elf_64.uint64 + r_addend: _c_elf_64.int64 + @overload + def __init__( + self, + r_offset: _c_elf_64.uint64 | None = ..., + r_info: _c_elf_64.uint64 | None = ..., + r_addend: _c_elf_64.int64 | None = ..., + ): ... + @overload + def __init__(self, fh: bytes | memoryview | bytearray | BinaryIO, /): ... + + class Sym(__cs__.Structure): + st_name: _c_elf_64.uint32 + st_info: _c_elf_64.char + st_other: _c_elf_64.char + st_shndx: _c_elf_64.uint16 + st_value: _c_elf_64.uint64 + st_size: _c_elf_64.uint64 + @overload + def __init__( + self, + st_name: _c_elf_64.uint32 | None = ..., + st_info: _c_elf_64.char | None = ..., + st_other: _c_elf_64.char | None = ..., + st_shndx: _c_elf_64.uint16 | None = ..., + st_value: _c_elf_64.uint64 | None = ..., + st_size: _c_elf_64.uint64 | None = ..., + ): ... + @overload + def __init__(self, fh: bytes | memoryview | bytearray | BinaryIO, /): ... + + class Ehdr(__cs__.Structure): + e_ident: __cs__.CharArray + e_type: _c_elf_64.Elf_Type + e_machine: _c_elf_64.uint16 + e_version: _c_elf_64.uint32 + e_entry: _c_elf_64.uint64 + e_phoff: _c_elf_64.uint64 + e_shoff: _c_elf_64.uint64 + e_flags: _c_elf_64.uint32 + e_ehsize: _c_elf_64.uint16 + e_phentsize: _c_elf_64.uint16 + e_phnum: _c_elf_64.uint16 + e_shentsize: _c_elf_64.uint16 + e_shnum: _c_elf_64.uint16 + e_shstrndx: _c_elf_64.uint16 + @overload + def __init__( + self, + e_ident: __cs__.CharArray | None = ..., + e_type: _c_elf_64.Elf_Type | None = ..., + e_machine: _c_elf_64.uint16 | None = ..., + e_version: _c_elf_64.uint32 | None = ..., + e_entry: _c_elf_64.uint64 | None = ..., + e_phoff: _c_elf_64.uint64 | None = ..., + e_shoff: _c_elf_64.uint64 | None = ..., + e_flags: _c_elf_64.uint32 | None = ..., + e_ehsize: _c_elf_64.uint16 | None = ..., + e_phentsize: _c_elf_64.uint16 | None = ..., + e_phnum: _c_elf_64.uint16 | None = ..., + e_shentsize: _c_elf_64.uint16 | None = ..., + e_shnum: _c_elf_64.uint16 | None = ..., + e_shstrndx: _c_elf_64.uint16 | None = ..., + ): ... + @overload + def __init__(self, fh: bytes | memoryview | bytearray | BinaryIO, /): ... + + class Phdr(__cs__.Structure): + p_type: _c_elf_64.PT + p_flags: _c_elf_64.PF + p_offset: _c_elf_64.uint64 + p_vaddr: _c_elf_64.uint64 + p_paddr: _c_elf_64.uint64 + p_filesz: _c_elf_64.uint64 + p_memsz: _c_elf_64.uint64 + p_align: _c_elf_64.uint64 + @overload + def __init__( + self, + p_type: _c_elf_64.PT | None = ..., + p_flags: _c_elf_64.PF | None = ..., + p_offset: _c_elf_64.uint64 | None = ..., + p_vaddr: _c_elf_64.uint64 | None = ..., + p_paddr: _c_elf_64.uint64 | None = ..., + p_filesz: _c_elf_64.uint64 | None = ..., + p_memsz: _c_elf_64.uint64 | None = ..., + p_align: _c_elf_64.uint64 | None = ..., + ): ... + @overload + def __init__(self, fh: bytes | memoryview | bytearray | BinaryIO, /): ... + + class Shdr(__cs__.Structure): + sh_name: _c_elf_64.uint32 + sh_type: _c_elf_64.SHT + sh_flags: _c_elf_64.uint64 + sh_addr: _c_elf_64.uint64 + sh_offset: _c_elf_64.uint64 + sh_size: _c_elf_64.uint64 + sh_link: _c_elf_64.uint32 + sh_info: _c_elf_64.uint32 + sh_addralign: _c_elf_64.uint64 + sh_entsize: _c_elf_64.uint64 + @overload + def __init__( + self, + sh_name: _c_elf_64.uint32 | None = ..., + sh_type: _c_elf_64.SHT | None = ..., + sh_flags: _c_elf_64.uint64 | None = ..., + sh_addr: _c_elf_64.uint64 | None = ..., + sh_offset: _c_elf_64.uint64 | None = ..., + sh_size: _c_elf_64.uint64 | None = ..., + sh_link: _c_elf_64.uint32 | None = ..., + sh_info: _c_elf_64.uint32 | None = ..., + sh_addralign: _c_elf_64.uint64 | None = ..., + sh_entsize: _c_elf_64.uint64 | None = ..., + ): ... + @overload + def __init__(self, fh: bytes | memoryview | bytearray | BinaryIO, /): ... + + class Nhdr(__cs__.Structure): + n_namesz: _c_elf_64.uint32 + n_descsz: _c_elf_64.uint32 + n_type: _c_elf_64.uint32 + @overload + def __init__( + self, + n_namesz: _c_elf_64.uint32 | None = ..., + n_descsz: _c_elf_64.uint32 | None = ..., + n_type: _c_elf_64.uint32 | None = ..., + ): ... + @overload + def __init__(self, fh: bytes | memoryview | bytearray | BinaryIO, /): ... + +# Technically `c_elf_64` is an instance of `_c_elf_64`, but then we can't use it in type hints +c_elf_64: TypeAlias = _c_elf_64 + +PT: TypeAlias = c_common_elf.PT +Elf_Type: TypeAlias = c_common_elf.Elf_Type +STB: TypeAlias = c_common_elf.STB +STT: TypeAlias = c_common_elf.STT +STV: TypeAlias = c_common_elf.STV +PF: TypeAlias = c_common_elf.PF +SHN: TypeAlias = c_common_elf.SHN +SHT: TypeAlias = c_common_elf.SHT diff --git a/dissect/executable/elf/tools/__init__.py b/dissect/executable/elf/tools/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/dissect/executable/elf/tools/loader.py b/dissect/executable/elf/tools/loader.py new file mode 100644 index 0000000..33dacef --- /dev/null +++ b/dissect/executable/elf/tools/loader.py @@ -0,0 +1,380 @@ +from __future__ import annotations + +import argparse +import ctypes +import ctypes.util +import enum +import json +import logging +import os +import platform +import random +import struct +import sys +from io import BytesIO +from pathlib import Path +from typing import TYPE_CHECKING, Any, BinaryIO + +from dissect.executable.elf.c_elf import PF, PT +from dissect.executable.elf.elf import ELF + +if TYPE_CHECKING: + from collections.abc import Callable + + from dissect.executable.elf.elf import Segment + +log = logging.getLogger(__name__) +log.setLevel(os.getenv("DISSECT_LOG_EXECUTABLE", "CRITICAL")) + + +class PROT(enum.IntFlag): + READ = 0x1 + WRITE = 0x2 + EXEC = 0x4 + + @classmethod + def from_PF(cls, flags: PF) -> PROT: + mapping = { + PF.R: PROT.READ, + PF.X: PROT.EXEC, + PF.W: PROT.WRITE, + } + + result = 0 + for pf, prot in mapping.items(): + if flags & pf: + result |= prot + + return result + + +class MAP(enum.IntFlag): + SHARED = 0x01 + PRIVATE = 0x02 + FIXED = 0x10 + ANONYMOUS = 0x20 + + +class AT(enum.IntEnum): + NULL = 0 + IGNORE = 1 + EXECFD = 2 + PHDR = 3 + PHENT = 4 + PHNUM = 5 + PAGESZ = 6 + BASE = 7 + FLAGS = 8 + ENTRY = 9 + NOTELF = 10 + UID = 11 + EUID = 12 + GID = 13 + EGID = 14 + PLATFORM = 15 + HWCAP = 16 + CLKTCK = 17 + SECURE = 23 + BASE_PLATFORM = 24 + RANDOM = 25 + EXECFN = 31 + SYSINFO = 32 + SYSINFO_EHDR = 33 + + +PAGE_SIZE = 4096 +ALIGN = PAGE_SIZE - 1 + + +libc = None +loader = None + + +def _setup_libc(path: str | None = None) -> None: + """Set up the libc functions. + + Args: + path: The optional path to the libc library to use. + """ + path = path or ctypes.util.find_library("c") + if path is None: + raise ValueError("Unable to find path to libc") + + global libc + if libc is not None: + return + + libc = ctypes.CDLL(path, use_errno=True) + + libc.mmap.argtypes = [ + # addr + ctypes.c_size_t, + # length + ctypes.c_size_t, + # prot + ctypes.c_int, + # flags + ctypes.c_int, + # fd + ctypes.c_int, + # offset + ctypes.c_size_t, + ] + libc.mmap.restype = ctypes.c_size_t + + libc.mprotect.argtypes = [ + # addr + ctypes.c_size_t, + # len + ctypes.c_size_t, + # prot + ctypes.c_int, + ] + libc.mprotect.restype = ctypes.c_int + + libc.getauxval.argtypes = [ + # type + ctypes.c_ulong + ] + libc.getauxval.restype = ctypes.c_size_t + + if log.level <= logging.DEBUG: + libc.mmap = _ctype_log(libc.mmap) + libc.mprotect = _ctype_log(libc.mprotect) + libc.getauxval = _ctype_log(libc.getauxval) + + +def _setup_loader() -> None: + """Set up the loader function.""" + global loader + if loader is not None: + return + + machine = platform.machine() + if machine == "x86_64": + asm = bytes.fromhex( + # rdi = pointer to initial stack + # rsi = size of stack + # rdx = entry point + # + # Reserve space for the stack and align it + " 48 29 f4" # sub rsp, rsi + "48 83 e4 f0" # and rsp, 0fffffffffffffff0h + # Copy the stack over (dst=rdi, src=rsi, count=rcx) + " 48 89 f1" # mov rcx, rsi + " 48 89 fe" # mov rsi, rdi + " 48 89 e7" # mov rdi, rsp + " fc" # cld + " f3 a4" # rep movsb + # Jump to the entry point + " ff e2" # jmp rdx + " f4" # hlt + ) + elif machine == "aarch64": + asm = bytes.fromhex( + # x0 = pointer to initial stack + # x1 = size of stack + # x2 = entry point + # + # Reserve space for the stack and align it + "eb 63 21 cb" # sub x11, sp, x1 + "6b ed 7c 92" # and x11, x11, #~0xF + "7f 01 00 91" # mov sp, x11 + # Copy the stack over (dst=x3, src=x0, count=x1) + "e3 03 00 91" # mov x3, sp + "a1 00 00 b4" # loop: cbz x1, end + "06 14 40 38" # ldrb w6, [x0], #1 + "66 14 00 38" # strb w6, [x3], #1 + "21 04 00 f1" # subs x1, x1, #1 + "81 ff ff 54" # b.ne loop + # Jump to the entry point + "40 00 1f d6" # end: br x2 + ) + else: + raise NotImplementedError(f"Unsupported architecture: {machine}") + + buf = libc.mmap(0, len(asm), PROT.WRITE, MAP.PRIVATE | MAP.ANONYMOUS, -1, 0) + ptr = ctypes.cast(buf, ctypes.POINTER(ctypes.c_char * len(asm))) + ptr.contents[:] = asm + libc.mprotect(buf, len(asm), PROT.READ | PROT.EXEC) + + loader = ctypes.cast( + buf, + ctypes.CFUNCTYPE( + ctypes.c_void_p, + ctypes.c_char_p, + ctypes.c_size_t, + ctypes.c_size_t, + ), + ) + + if log.level <= logging.DEBUG: + loader = _ctype_log(loader) + + +def _ctype_log(function: Callable) -> Callable: + def fmt(arg: Any) -> str: + if isinstance(arg, enum.Enum): + return f"{arg.__class__.__name__}_{arg.name}" + if isinstance(arg, int): + return hex(arg) + return repr(arg) + + def wrapper(*args, **kwargs) -> Any: + result = function(*args, **kwargs) + arg_str = ", ".join(f"{fmt(arg)}" for arg in args) + log.debug("%s(%s) -> %s", function.__name__, arg_str, fmt(result)) + return result + + return wrapper + + +def load( + path: Path, argv: list[str] | None = None, envp: dict[str, str] | None = None, *, libc: str | None = None +) -> None: + """Load an ELF executable into memory and execute it. + + Args: + path: The path to the ELF executable to load. + argv: The arguments to pass to the executable. + envp: The environment variables to pass to the executable. + libc: The optional path to the libc library to use. + """ + if os.name != "posix" and sys.platform != "darwin": + raise TypeError("This loader only supports POSIX systems") + + _setup_libc(libc) + _setup_loader() + + argv = argv or [] + envp = envp or {} + + with path.open("rb") as fh: + elf = ELF(fh) + + if elf.dynamic: + raise NotImplementedError("Dynamic loading is not yet implemented, only static executables are supported") + + segments = elf.segments.by_type(PT.LOAD) + base = truncate(min([s.virtual_address for s in segments])) + + for segment in segments: + map_segment(segment, MAP.FIXED | MAP.PRIVATE | MAP.ANONYMOUS) + + stack = create_stack(elf, base, argv, envp) + loader(stack, len(stack), elf.header.e_entry) + + +def map_segment(segment: Segment, flags: MAP) -> None: + """Map segment to memory. + + Args: + segment: The segment to map. + flags: The flags to pass to mmap. + """ + alignment = segment.alignment - 1 + + offset = segment.virtual_address & alignment + start = truncate(segment.virtual_address, alignment) + size = round(segment.memory_size + offset, alignment) + + pointer = libc.mmap(start, size, PROT.WRITE, flags, -1, 0) + + if pointer == 0xFFFF_FFFF_FFFF_FFFF: + raise ValueError("mmap failed to allocate memory.") + + ptr = ctypes.cast(pointer, ctypes.POINTER(ctypes.c_char * size)) + ptr.contents[offset : offset + segment.size] = segment.data + + pflags = PROT.from_PF(segment.flags) + libc.mprotect(pointer, size, pflags) + + +def create_stack(elf: ELF, base: int, argv: list[str], envp: dict[str, str]) -> bytes: + """Create the initial process stack for the executable. + + The stack is created according to the System V AMD64 ABI specification, which can be found here: + https://refspecs.linuxfoundation.org/elf/x86_64-abi-0.99.pdf + + Args: + elf: The ELF executable to create the stack for. + base: The base address of the executable. + argv: The arguments to pass to the executable. + envp: The environment variables to pass to the executable. + """ + stack = BytesIO() + + stack.write(struct.pack(" None: + """Copy auxiliary value from the host process to the stack.""" + write_aux(fh, type, ctypes.c_uint64(libc.getauxval(type))) + + +def write_aux(fh: BinaryIO, type: AT, value: bytes) -> None: + """Write auxiliary value to the stack.""" + fh.write(struct.pack(" int: + """Truncate value to alignment.""" + return value & ~(align) + + +def round(value: int, align: int = ALIGN) -> int: + """Round value up to alignment.""" + return truncate(value + align, align) + + +def main() -> None: + parser = argparse.ArgumentParser() + parser.add_argument("path", type=Path, help="the ELF executable to load") + parser.add_argument("--libc", type=str, help="the path of the libc library to use") + parser.add_argument( + "--env", "-e", type=json.loads, default=None, help="environment variables to pass to the executable" + ) + parser.add_argument("-v", "--verbose", action="store_true", help="enable verbose logging") + args, rest = parser.parse_known_args() + + if args.verbose: + logging.basicConfig(format="%(asctime)s %(levelname)s %(message)s") + log.setLevel(logging.DEBUG) + + arguments = [args.path.name, *rest] + load(args.path, arguments, args.env, libc=args.libc) + + +if __name__ == "__main__": + main() diff --git a/tests/_data/elf/hello_world-aarch64-static.bin b/tests/_data/elf/hello_world-aarch64-static.bin new file mode 100755 index 0000000..463ad79 Binary files /dev/null and b/tests/_data/elf/hello_world-aarch64-static.bin differ diff --git a/tests/_data/elf/hello_world-aarch64-stripped.bin b/tests/_data/elf/hello_world-aarch64-stripped.bin new file mode 100755 index 0000000..18a70d8 Binary files /dev/null and b/tests/_data/elf/hello_world-aarch64-stripped.bin differ diff --git a/tests/_data/elf/hello_world-aarch64.bin b/tests/_data/elf/hello_world-aarch64.bin new file mode 100755 index 0000000..d9a5362 Binary files /dev/null and b/tests/_data/elf/hello_world-aarch64.bin differ diff --git a/tests/_data/elf/hello_world-x86_64-static.bin b/tests/_data/elf/hello_world-x86_64-static.bin new file mode 100755 index 0000000..53bee91 Binary files /dev/null and b/tests/_data/elf/hello_world-x86_64-static.bin differ diff --git a/tests/_data/elf/hello_world.stripped.out b/tests/_data/elf/hello_world-x86_64-stripped.bin similarity index 64% rename from tests/_data/elf/hello_world.stripped.out rename to tests/_data/elf/hello_world-x86_64-stripped.bin index 3cbb41b..7084a5d 100755 Binary files a/tests/_data/elf/hello_world.stripped.out and b/tests/_data/elf/hello_world-x86_64-stripped.bin differ diff --git a/tests/_data/elf/hello_world.out b/tests/_data/elf/hello_world-x86_64.bin similarity index 56% rename from tests/_data/elf/hello_world.out rename to tests/_data/elf/hello_world-x86_64.bin index 9d3d0c0..f589c17 100755 Binary files a/tests/_data/elf/hello_world.out and b/tests/_data/elf/hello_world-x86_64.bin differ diff --git a/tests/_data/elf/hello_world.c b/tests/_data/elf/hello_world.c new file mode 100644 index 0000000..6edcb3f --- /dev/null +++ b/tests/_data/elf/hello_world.c @@ -0,0 +1,7 @@ +// gcc hello_world.c -Wl,-Ttext-segment=0x1000000 [-static] -o hello_world.bin +#include + +int main() { + setbuf(stdout, NULL); + printf("Kusjes van SRT <3\n"); +} diff --git a/tests/elf/test_dump.py b/tests/elf/test_dump.py index de47d67..be90510 100644 --- a/tests/elf/test_dump.py +++ b/tests/elf/test_dump.py @@ -15,8 +15,8 @@ @pytest.mark.parametrize( "path", [ - "_data/elf/hello_world.out", - "_data/elf/hello_world.stripped.out", + "_data/elf/hello_world-x86_64.bin", + "_data/elf/hello_world-x86_64-stripped.bin", ], ) def test_dump(path: str, tmp_path: Path) -> None: diff --git a/tests/elf/tools/__init__.py b/tests/elf/tools/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/elf/tools/test_loader.py b/tests/elf/tools/test_loader.py new file mode 100644 index 0000000..c37a840 --- /dev/null +++ b/tests/elf/tools/test_loader.py @@ -0,0 +1,24 @@ +from __future__ import annotations + +import os +import platform +import subprocess +import sys + +import pytest + +from tests._utils import absolute_path + + +@pytest.mark.skipif(os.name != "posix" and sys.platform != "darwin", reason="Loader only supports POSIX systems") +@pytest.mark.skipif( + platform.machine() not in ("x86_64", "aarch64"), reason="Loader only supports x86_64 and aarch64 architectures" +) +def test_loader() -> None: + """Test that the loader can load a simple ELF binary.""" + path = absolute_path(f"_data/elf/hello_world-{platform.machine()}-static.bin") + + # Run the loader in a subprocess to avoid affecting the test runner process + # The loader currently does not clean up after itself and will segfault + result = subprocess.run([sys.executable, "-m", "dissect.executable.elf.tools.loader", path], capture_output=True) + assert result.stdout == b"Kusjes van SRT <3\n"