Repository: mandiant/capa
File: capa/features/extractors/elf.py (Python)

Code before:

        self._parse(endian, bitness, symtab_buf)

    def _parse(self, endian: str, bitness: int, symtab_buf) -> None:
        """
        return the symbol's information in 
        the order specified by sys/elf32.h
        """
        for i in range(self.symnum):
            if bitness == 32:
                name, value, size, info, other, shndx = struct.unpack_from(endian+"IIIBBH", symtab_buf, i*self.entsize)
            elif bitness == 64:
                name, info, other, shndx, value, size = struct.unpack_from(endian+"IBBBQQ", symtab_buf, i*self.entsize)

            self.symbols.append((name, value, size, info, other, shndx))

    def fetch_str(self, offset) -> str:
        """
        fetch a symbol's name from symtab's
        associated strings' section (SHT_STRTAB)
        """
        for i in range(offset, self.strings_sz):
            if self.strings[i] == 0:
                return self.strings[offset:i].decode()

    def get_symbols(self) -> Tuple[int, int, int, int, int, int]:
        for symbol in self.symbols:
            yield symbol


def guess_os_from_osabi(elf) -> Optional[OS]:
    return elf.ei_osabi


def guess_os_from_ph_notes(elf) -> Optional[OS]:
    # search for PT_NOTE sections that specify an OS
    # for example, on Linux there is a GNU section with minimum kernel version
    PT_NOTE = 0x4
    for phdr in elf.program_headers:
        if phdr.type != PT_NOTE:
            continue

        note = PHNote(elf.endian, phdr.buf)

        if note.type_ != 1:
            # > The type field shall be 1.
            # Linux Standard Base Specification 1.2
            # ref: https://refspecs.linuxfoundation.org/LSB_1.2.0/gLSB/noteabitag.html
            continue

        if note.name == "Linux":

Review comment (suggestion):
would you please add a docstring comment describing what the return value is here? the type hints help, but im not sure how to interpret each integer

Code after:

        self._parse(endian, bitness, symtab_buf)

    def _parse(self, endian: str, bitness: int, symtab_buf: bytes) -> None:
        """
        return the symbol's information in 
        the order specified by sys/elf32.h
        """
        for i in range(self.symnum):
            if bitness == 32:
                name, value, size, info, other, shndx = struct.unpack_from(endian+"IIIBBH", symtab_buf, i*self.entsize)
            elif bitness == 64:
                name, info, other, shndx, value, size = struct.unpack_from(endian+"IBBBQQ", symtab_buf, i*self.entsize)

            self.symbols.append((name, value, size, info, other, shndx))

    def fetch_str(self, offset) -> str:
        """
        fetch a symbol's name from symtab's
        associated strings' section (SHT_STRTAB)
        """
        for i in range(offset, self.strings_sz):
            if self.strings[i] == 0:
                return self.strings[offset:i].decode()

    def get_symbols(self) -> Iterator[Tuple[int, int, int, int, int, int]]:
        """
        return a tuple: (name, value, size, info, other, shndx)
        for each symbol contained in the symbol table
        """
        for symbol in self.symbols:
            yield symbol


def guess_os_from_osabi(elf) -> Optional[OS]:
    return elf.ei_osabi


def guess_os_from_ph_notes(elf) -> Optional[OS]:
    # search for PT_NOTE sections that specify an OS
    # for example, on Linux there is a GNU section with minimum kernel version
    PT_NOTE = 0x4
    for phdr in elf.program_headers:
        if phdr.type != PT_NOTE:
            continue

        note = PHNote(elf.endian, phdr.buf)

        if note.type_ != 1:
            # > The type field shall be 1.
            # Linux Standard Base Specification 1.2