Skip to content

analyzer.py

ofrak.core.elf.analyzer

ElfBasicHeaderAttributesAnalyzer (Analyzer)

Deserialize the ElfBasicHeader, which contains the first 7 fields of the ELF header. These fields are all endianness- & word-size-agnostic, and in fact define the endianness and word size for the remainder of the header.

The remaining fields are deserialized as part of the ElfHeader. See "ELF header (Ehdr)" in https://man7.org/linux/man-pages/man5/elf.5.html for details.

analyze(self, resource, config=None) async

Analyze a resource for to extract specific ResourceAttributes.

Users should not call this method directly; rather, they should run Resource.run or Resource.analyze.

Parameters:

Name Type Description Default
resource Resource

The resource that is being analyzed

required
config

Optional config for analyzing. If an implementation provides a default, this default will always be used when config would otherwise be None. Note that a copy of the default config will be passed, so the default config values cannot be modified persistently by a component run.

None

Returns:

Type Description
ElfBasicHeader

The analysis results

Source code in ofrak/core/elf/analyzer.py
async def analyze(self, resource: Resource, config=None) -> ElfBasicHeader:
    tmp = await resource.get_data()
    deserializer = BinaryDeserializer(io.BytesIO(tmp))
    (
        ei_magic,
        ei_class,
        ei_data,
        ei_version,
        ei_osabi,
        ei_abiversion,
        ei_pad,
    ) = deserializer.unpack_multiple("4sBBBBB7s")
    assert ei_magic == b"\x7fELF"
    return ElfBasicHeader(
        ei_magic, ei_class, ei_data, ei_version, ei_osabi, ei_abiversion, ei_pad
    )

ElfDynamicSectionAnalyzer (Analyzer)

If an object file participates in dynamic linking, its program header table will have an element of type PT_DYNAMIC. This segment contains the .dynamic section.

Descriptions of the Dynamic Table entries may be found herein: https://docs.oracle.com/cd/E19683-01/817-3677/chapter6-42444/index.html

analyze(self, resource, config=None) async

Analyze a resource for to extract specific ResourceAttributes.

Users should not call this method directly; rather, they should run Resource.run or Resource.analyze.

Parameters:

Name Type Description Default
resource Resource

The resource that is being analyzed

required
config

Optional config for analyzing. If an implementation provides a default, this default will always be used when config would otherwise be None. Note that a copy of the default config will be passed, so the default config values cannot be modified persistently by a component run.

None

Returns:

Type Description
ElfDynamicEntry

The analysis results

Source code in ofrak/core/elf/analyzer.py
async def analyze(self, resource: Resource, config=None) -> ElfDynamicEntry:
    deserializer = await _create_deserializer(resource)
    return self.deserialize(deserializer)

ElfHeaderAttributesAnalyzer (Analyzer)

Deserialize the ElfHeader, which contains all of the ELF header fields except the first 7. The first 7 fields are deserialized as part of the ElfBasicHeader.

analyze(self, resource, config=None) async

Analyze a resource for to extract specific ResourceAttributes.

Users should not call this method directly; rather, they should run Resource.run or Resource.analyze.

Parameters:

Name Type Description Default
resource Resource

The resource that is being analyzed

required
config

Optional config for analyzing. If an implementation provides a default, this default will always be used when config would otherwise be None. Note that a copy of the default config will be passed, so the default config values cannot be modified persistently by a component run.

None

Returns:

Type Description
ElfHeader

The analysis results

Source code in ofrak/core/elf/analyzer.py
async def analyze(self, resource: Resource, config=None) -> ElfHeader:
    deserializer = await _create_deserializer(resource)
    return self.deserialize(deserializer)

ElfPointerAnalyzer (Analyzer)

analyze(self, resource, config=None) async

Analyze a resource for to extract specific ResourceAttributes.

Users should not call this method directly; rather, they should run Resource.run or Resource.analyze.

Parameters:

Name Type Description Default
resource Resource

The resource that is being analyzed

required
config

Optional config for analyzing. If an implementation provides a default, this default will always be used when config would otherwise be None. Note that a copy of the default config will be passed, so the default config values cannot be modified persistently by a component run.

None

Returns:

Type Description
ElfVirtualAddress

The analysis results

Source code in ofrak/core/elf/analyzer.py
async def analyze(self, resource: Resource, config=None) -> ElfVirtualAddress:
    deserializer = await _create_deserializer(resource)
    return self.deserialize(deserializer)

ElfPointerArraySectionAnalyzer (Analyzer)

analyze(self, resource, config=None) async

Analyze a resource for to extract specific ResourceAttributes.

Users should not call this method directly; rather, they should run Resource.run or Resource.analyze.

Parameters:

Name Type Description Default
resource Resource

The resource that is being analyzed

required
config

Optional config for analyzing. If an implementation provides a default, this default will always be used when config would otherwise be None. Note that a copy of the default config will be passed, so the default config values cannot be modified persistently by a component run.

None

Returns:

Type Description
ElfPointerArraySection

The analysis results

Source code in ofrak/core/elf/analyzer.py
async def analyze(self, resource: Resource, config=None) -> ElfPointerArraySection:
    unnamed_section = await resource.view_as(UnanalyzedElfSection)
    section_header = await unnamed_section.get_header()
    elf_r = await unnamed_section.get_elf()
    elf_basic_header = await elf_r.get_basic_header()
    num_pointers = section_header.sh_size // elf_basic_header.get_bitwidth().value // 8  # bits
    return ElfPointerArraySection(
        section_index=section_header.section_index, num_pointers=num_pointers
    )

ElfProgramAttributesAnalyzer (Analyzer)

Analyze the ProgramAttributes of an ELF, which are part of the information stored in the ELF header.

analyze(self, resource, config=None) async

Analyze a resource for to extract specific ResourceAttributes.

Users should not call this method directly; rather, they should run Resource.run or Resource.analyze.

Parameters:

Name Type Description Default
resource Resource

The resource that is being analyzed

required
config Optional[ofrak.model.component_model.ComponentConfig]

Optional config for analyzing. If an implementation provides a default, this default will always be used when config would otherwise be None. Note that a copy of the default config will be passed, so the default config values cannot be modified persistently by a component run.

None

Returns:

Type Description
ProgramAttributes

The analysis results

Source code in ofrak/core/elf/analyzer.py
async def analyze(
    self, resource: Resource, config: Optional[ComponentConfig] = None
) -> ProgramAttributes:
    elf_header = await resource.get_only_descendant_as_view(
        ElfHeader, r_filter=ResourceFilter.with_tags(ElfHeader)
    )
    elf_basic_header = await resource.get_only_descendant_as_view(
        ElfBasicHeader, r_filter=ResourceFilter.with_tags(ElfBasicHeader)
    )

    return ProgramAttributes(
        elf_header.get_isa(),
        None,
        elf_basic_header.get_bitwidth(),
        elf_basic_header.get_endianness(),
        None,
    )

ElfProgramHeaderAttributesAnalyzer (Analyzer)

Deserialize an ElfProgramHeader.

analyze(self, resource, config=None) async

Analyze a resource for to extract specific ResourceAttributes.

Users should not call this method directly; rather, they should run Resource.run or Resource.analyze.

Parameters:

Name Type Description Default
resource Resource

The resource that is being analyzed

required
config

Optional config for analyzing. If an implementation provides a default, this default will always be used when config would otherwise be None. Note that a copy of the default config will be passed, so the default config values cannot be modified persistently by a component run.

None

Returns:

Type Description
ElfProgramHeader

The analysis results

Source code in ofrak/core/elf/analyzer.py
async def analyze(self, resource: Resource, config=None) -> ElfProgramHeader:
    segment_structure = await resource.view_as(ElfSegmentStructure)
    deserializer = await _create_deserializer(resource)
    return self.deserialize(deserializer, segment_structure.segment_index)

ElfRelaAnalyzer (Analyzer)

Deserialize an ElfRelaEntry, an entry in a rela.* table.

http://sourceware.org/git/?p=glibc.git;a=blob_plain;f=elf/elf.h

analyze(self, resource, config=None) async

Analyze a resource for to extract specific ResourceAttributes.

Users should not call this method directly; rather, they should run Resource.run or Resource.analyze.

Parameters:

Name Type Description Default
resource Resource

The resource that is being analyzed

required
config

Optional config for analyzing. If an implementation provides a default, this default will always be used when config would otherwise be None. Note that a copy of the default config will be passed, so the default config values cannot be modified persistently by a component run.

None

Returns:

Type Description
ElfRelaEntry

The analysis results

Source code in ofrak/core/elf/analyzer.py
async def analyze(self, resource: Resource, config=None) -> ElfRelaEntry:
    deserializer = await _create_deserializer(resource)
    return self.deserialize(deserializer)

ElfSectionHeaderAttributesAnalyzer (Analyzer)

Deserialize an ElfSectionHeader.

analyze(self, resource, config=None) async

Analyze a resource for to extract specific ResourceAttributes.

Users should not call this method directly; rather, they should run Resource.run or Resource.analyze.

Parameters:

Name Type Description Default
resource Resource

The resource that is being analyzed

required
config

Optional config for analyzing. If an implementation provides a default, this default will always be used when config would otherwise be None. Note that a copy of the default config will be passed, so the default config values cannot be modified persistently by a component run.

None

Returns:

Type Description
ElfSectionHeader

The analysis results

Source code in ofrak/core/elf/analyzer.py
async def analyze(self, resource: Resource, config=None) -> ElfSectionHeader:
    section_structure = await resource.view_as(ElfSectionStructure)
    deserializer = await _create_deserializer(resource)
    return self.deserialize(deserializer, section_structure.section_index)

ElfSectionNameAnalyzer (Analyzer)

Get the name of an ELF section. ELF section names are stored as null-terminated strings in dedicated string section, and each ELF section header's sh_name field is an offset in this section.

analyze(self, resource, config=None) async

Analyze a resource for to extract specific ResourceAttributes.

Users should not call this method directly; rather, they should run Resource.run or Resource.analyze.

Parameters:

Name Type Description Default
resource Resource

The resource that is being analyzed

required
config

Optional config for analyzing. If an implementation provides a default, this default will always be used when config would otherwise be None. Note that a copy of the default config will be passed, so the default config values cannot be modified persistently by a component run.

None

Returns:

Type Description
ElfSection

The analysis results

Source code in ofrak/core/elf/analyzer.py
async def analyze(self, resource: Resource, config=None) -> ElfSection:
    unnamed_section = await resource.view_as(UnanalyzedElfSection)
    section_header = await unnamed_section.get_header()
    elf_r = await unnamed_section.get_elf()
    string_section = await elf_r.get_section_name_string_section()
    try:
        string_section_data = await string_section.resource.get_data(
            Range(section_header.sh_name, Range.MAX)
        )
        name_string_end = string_section_data.find(b"\x00")
        raw_section_name = await string_section.resource.get_data(
            Range(section_header.sh_name, section_header.sh_name + name_string_end)
        )
        section_name = raw_section_name.decode("ascii")
    except ValueError:
        LOGGER.info("String section is empty! Using '<no-strings>' as section name")
        section_name = "<no-strings>"  # This is what readelf returns in this situation
    return ElfSection(
        section_index=section_header.section_index,
        name=section_name,
        virtual_address=section_header.sh_addr,
        size=section_header.sh_size,
    )

ElfSectionStructureIndexAnalyzer (Analyzer)

analyze(self, resource, config=None) async

Analyze a resource for to extract specific ResourceAttributes.

Users should not call this method directly; rather, they should run Resource.run or Resource.analyze.

Parameters:

Name Type Description Default
resource Resource

The resource that is being analyzed

required
config

Optional config for analyzing. If an implementation provides a default, this default will always be used when config would otherwise be None. Note that a copy of the default config will be passed, so the default config values cannot be modified persistently by a component run.

None

Returns:

Type Description
ElfSectionStructure

The analysis results

Source code in ofrak/core/elf/analyzer.py
async def analyze(self, resource: Resource, config=None) -> ElfSectionStructure:
    elf = await resource.get_only_ancestor_as_view(Elf, ResourceFilter.with_tags(Elf))
    elf_header = await elf.get_header()
    resource_start_offset = (await resource.get_data_range_within_parent()).start

    if resource.has_tag(ElfSectionHeader):
        segment_index = _calculate_elf_index(
            entry_offset=resource_start_offset,
            table_offset=elf_header.e_shoff,
            table_entry_size=elf_header.e_shentsize,
        )

        return ElfSectionStructure(segment_index)
    elif resource.has_tag(ElfSection):
        for section_header in await elf.get_section_headers():
            if section_header.sh_offset == resource_start_offset:
                return ElfSectionStructure(section_header.section_index)
        raise ValueError(
            f"No header found for section starting at offset {hex(resource_start_offset)}"
        )
    else:
        raise TypeError(f"Resource did not have expected tags {ElfSectionHeader.__name__}")

ElfSegmentAnalyzer (Analyzer)

Analyze an ElfSegment.

analyze(self, resource, config=None) async

Analyze a resource for to extract specific ResourceAttributes.

Users should not call this method directly; rather, they should run Resource.run or Resource.analyze.

Parameters:

Name Type Description Default
resource Resource

The resource that is being analyzed

required
config

Optional config for analyzing. If an implementation provides a default, this default will always be used when config would otherwise be None. Note that a copy of the default config will be passed, so the default config values cannot be modified persistently by a component run.

None

Returns:

Type Description
ElfSegment

The analysis results

Source code in ofrak/core/elf/analyzer.py
async def analyze(self, resource: Resource, config=None) -> ElfSegment:
    unnamed_segment = await resource.view_as(UnanalyzedElfSegment)
    segment_header = await unnamed_segment.get_header()
    return ElfSegment(
        segment_index=segment_header.segment_index,
        virtual_address=segment_header.p_vaddr,
        size=segment_header.p_memsz,
    )

ElfSegmentStructureIndexAnalyzer (Analyzer)

analyze(self, resource, config=None) async

Analyze a resource for to extract specific ResourceAttributes.

Users should not call this method directly; rather, they should run Resource.run or Resource.analyze.

Parameters:

Name Type Description Default
resource Resource

The resource that is being analyzed

required
config

Optional config for analyzing. If an implementation provides a default, this default will always be used when config would otherwise be None. Note that a copy of the default config will be passed, so the default config values cannot be modified persistently by a component run.

None

Returns:

Type Description
ElfSegmentStructure

The analysis results

Source code in ofrak/core/elf/analyzer.py
async def analyze(self, resource: Resource, config=None) -> ElfSegmentStructure:
    elf = await resource.get_only_ancestor_as_view(Elf, ResourceFilter.with_tags(Elf))
    elf_header = await elf.get_header()

    if resource.has_tag(ElfProgramHeader):
        segment_index = _calculate_elf_index(
            entry_offset=(await resource.get_data_range_within_parent()).start,
            table_offset=elf_header.e_phoff,
            table_entry_size=elf_header.e_phentsize,
        )

        return ElfSegmentStructure(segment_index)
    else:
        raise TypeError(f"Resource did not have expected tags {ElfProgramHeader.__name__}")

ElfSymbolAttributesAnalyzer (Analyzer)

Deserialize an ElfSymbol, an entry in the ELF symbol table.

analyze(self, resource, config=None) async

Analyze a resource for to extract specific ResourceAttributes.

Users should not call this method directly; rather, they should run Resource.run or Resource.analyze.

Parameters:

Name Type Description Default
resource Resource

The resource that is being analyzed

required
config

Optional config for analyzing. If an implementation provides a default, this default will always be used when config would otherwise be None. Note that a copy of the default config will be passed, so the default config values cannot be modified persistently by a component run.

None

Returns:

Type Description
ElfSymbol

The analysis results

Source code in ofrak/core/elf/analyzer.py
async def analyze(self, resource: Resource, config=None) -> ElfSymbol:
    symbol_structure = await resource.view_as(ElfSymbolStructure)
    deserializer = await _create_deserializer(resource)

    return self.deserialize(deserializer, symbol_structure.symbol_index)

ElfSymbolStructureIndexAnalyzer (Analyzer)

analyze(self, resource, config=None) async

Analyze a resource for to extract specific ResourceAttributes.

Users should not call this method directly; rather, they should run Resource.run or Resource.analyze.

Parameters:

Name Type Description Default
resource Resource

The resource that is being analyzed

required
config

Optional config for analyzing. If an implementation provides a default, this default will always be used when config would otherwise be None. Note that a copy of the default config will be passed, so the default config values cannot be modified persistently by a component run.

None

Returns:

Type Description
ElfSymbolStructure

The analysis results

Source code in ofrak/core/elf/analyzer.py
async def analyze(self, resource: Resource, config=None) -> ElfSymbolStructure:
    elf = await resource.get_only_ancestor_as_view(Elf, ResourceFilter(tags=(Elf,)))
    deserializer = await _create_deserializer(resource)
    symbol_index = _calculate_elf_index(
        entry_offset=(await resource.get_data_range_within_parent()).start,
        # The entry offset is from the section start, not the ELF start. Match that
        table_offset=0,
        table_entry_size=24 if deserializer.get_word_size() == 8 else 16,
    )

    return ElfSymbolStructure(symbol_index)

_calculate_elf_index(entry_offset, table_offset, table_entry_size) private

Helper for calculating index of an entry in a table. entry_offset and table_offset should be relative to the same point, such as the start of the ELF.

Source code in ofrak/core/elf/analyzer.py
def _calculate_elf_index(
    entry_offset: int,
    table_offset: int,
    table_entry_size: int,
) -> int:
    """
    Helper for calculating index of an entry in a table. `entry_offset` and `table_offset` should
    be relative to the same point, such as the start of the ELF.
    """
    entry_offset_in_table = entry_offset - table_offset
    if 0 > entry_offset_in_table:
        raise ValueError(
            f"Elf structure "
            f"{hex(entry_offset)} bytes into the ELF cannot be in "
            f"the table which starts {hex(table_offset)} bytes in"
        )
    if 0 != (entry_offset_in_table % table_entry_size):
        raise ValueError(
            f"Elf structure is {hex(entry_offset_in_table)} bytes into the table which starts at "
            f"{hex(table_offset)}, which does not divide evenly into a table entry size of "
            f"{hex(table_entry_size)}"
        )
    return int(entry_offset_in_table / table_entry_size)