Skip to content

lief_modifier.py

ofrak.core.elf.lief_modifier

LiefAddSectionModifer (Modifier)

modify(self, resource, config) async

Modify the given resource.

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

Parameters:

Name Type Description Default
resource Resource required
config LiefAddSectionModifierConfig

Optional config for modification. 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.

required
Source code in ofrak/core/elf/lief_modifier.py
async def modify(self, resource: Resource, config: LiefAddSectionModifierConfig):
    binary: Optional[lief.Binary] = lief.parse(await resource.get_data())
    if not binary or not isinstance(binary, lief.ELF.Binary):
        raise ValueError("Lief failed parsing binary.")
    section: lief.ELF.Section = lief.ELF.Section()
    section.name = config.name
    section.content = memoryview(bytearray(config.content))
    section.flags = config.flags
    binary.add(section)

    with tempfile.NamedTemporaryFile(delete_on_close=False) as temp_file:
        temp_file.close()
        binary.write(temp_file.name)
        with open(temp_file.name, "rb") as f_handle:
            new_data = f_handle.read()
    # replace all old content (old range) with new content from Lief
    resource.queue_patch(Range(0, await resource.get_data_length()), new_data)

LiefAddSectionModifierConfig (ComponentConfig) dataclass

LiefAddSectionModifierConfig(name: str, content: bytes, flags: int)

LiefAddSegmentConfig (ComponentConfig) dataclass

Config for the LiefAddSegmentModifier.

Attributes:

Name Type Description
virtual_address int

virtual address of the new segment

alignment int

alignment of the new segment

content List[int]

list of integers representing the raw bytes of the new segment

rwx_flags str

string representation of the new segment's R/W/X permissions

replace_note bool

replace the unused NOTE segment with the new segment, rather than adding a new segment. defaults to True, as adding a new segment may corrupt the ELF due to a LIEF bug.

physical_address Optional[int]

overwrite the default physical address (defaults to the virtual address)

LiefAddSegmentModifier (Modifier)

modify(self, resource, config) async

Modify the given resource.

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

Parameters:

Name Type Description Default
resource Resource required
config LiefAddSegmentConfig

Optional config for modification. 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.

required
Source code in ofrak/core/elf/lief_modifier.py
async def modify(self, resource: Resource, config: LiefAddSegmentConfig) -> None:
    binary: Optional[lief.Binary] = lief.parse(await resource.get_data())
    if not binary or not isinstance(binary, lief.ELF.Binary):
        raise ValueError("Lief failed parsing binary.")

    segment = lief.ELF.Segment()
    segment.type = lief.ELF.Segment.TYPE.LOAD
    segment.content = memoryview(bytearray(config.content))
    segment.alignment = config.alignment
    segment.virtual_address = config.virtual_address
    if config.physical_address is not None:
        segment.physical_address = config.physical_address
    if "r" in config.rwx_flags:
        segment.add(lief.ELF.Segment.FLAGS.R)
    if "w" in config.rwx_flags:
        segment.add(lief.ELF.Segment.FLAGS.W)
    if "x" in config.rwx_flags:
        segment.add(lief.ELF.Segment.FLAGS.X)

    if config.replace_note:
        # instead of adding a segment to the binary, replace a useless NOTE segment
        #   see https://github.com/lief-project/LIEF/issues/98
        #   and https://github.com/lief-project/LIEF/issues/143
        if not binary.has(lief.ELF.Segment.TYPE.NOTE):
            raise ValueError("Binary must have a NOTE section to add a new section")
        segment = binary.replace(segment, binary[lief.ELF.Segment.TYPE.NOTE])
        if config.physical_address is not None:
            segment.physical_address = config.physical_address
    else:
        _ = binary.add(segment)

    with tempfile.NamedTemporaryFile(delete_on_close=False) as temp_file:
        temp_file.close()
        binary.write(temp_file.name)
        with open(temp_file.name, "rb") as f_handle:
            new_data = f_handle.read()
    # replace all old content (old range) with new content from Lief
    resource.queue_patch(Range(0, await resource.get_data_length()), new_data)

LiefRemoveSectionModifier (Modifier)

modify(self, resource, config) async

Modify the given resource.

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

Parameters:

Name Type Description Default
resource Resource required
config LiefRemoveSectionModifierConfig

Optional config for modification. 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.

required
Source code in ofrak/core/elf/lief_modifier.py
async def modify(self, resource: Resource, config: LiefRemoveSectionModifierConfig):
    binary: Optional[lief.Binary] = lief.parse(await resource.get_data())
    if not binary or not isinstance(binary, lief.ELF.Binary):
        raise ValueError("Lief failed parsing binary.")
    section: lief.ELF.Section = binary.get_section(config.name)
    if section is None:
        raise AttributeError(f"No section with name {config.name}")
    binary.remove(section)

    with tempfile.NamedTemporaryFile(delete_on_close=False) as temp_file:
        temp_file.close()
        binary.write(temp_file.name)
        with open(temp_file.name, "rb") as f_handle:
            new_data = f_handle.read()
    # replace all old content (old range) with new content from Lief
    resource.queue_patch(Range(0, await resource.get_data_length()), new_data)

LiefRemoveSectionModifierConfig (ComponentConfig) dataclass

LiefRemoveSectionModifierConfig(name: str)