Skip to content

strings.py

ofrak.core.strings

AsciiString (ResourceView) dataclass

Resource representing a C-style, NULL-terminated string of ASCII characters. The text string is not NULL-terminated.

AsciiStringAnalyzer (Analyzer)

Extract the decoded string from a C-style, NULL-terminated string of ASCII characters.

analyze(self, resource, config) 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 None

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.

required

Returns:

Type Description
AsciiString

The analysis results

Source code in ofrak/core/strings.py
async def analyze(self, resource: Resource, config: None) -> AsciiString:
    raw_without_null_byte = (await resource.get_data()).rstrip(b"\x00")
    return AsciiString(raw_without_null_byte.decode("ascii"))

StringFindReplaceConfig (ComponentConfig) dataclass

Attributes:

Name Type Description
to_find str

the string to search for

replace_with str

the string to pass in

null_terminate bool

add a null terminator to the replacement if True

allow_overflow bool

allow the replace string to overflow the found string if True

StringFindReplaceModifier (Modifier)

Find and replace all instances of a given string with a replacement string.

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 StringFindReplaceConfig

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/strings.py
async def modify(self, resource: Resource, config: StringFindReplaceConfig) -> None:
    to_find = config.to_find.encode("utf-8")
    replace_with = config.replace_with.encode("utf-8") + (
        b"\x00" if config.null_terminate and config.replace_with[-1] != "\x00" else b""
    )
    if not config.allow_overflow and len(replace_with) > len(to_find):
        raise ModifierError(
            f"Original string is longer than the new string ({len(to_find)} < "
            f"{len(replace_with)})! Set config.allow_overflow = True to override this error. "
            f"If you expect that the string to replace is null-terminated, then an overflow "
            f"of one byte when config.null_terminate = True will not have any effect."
        )
    for offset in await resource.search_data(to_find):
        await resource.run(BinaryPatchModifier, BinaryPatchConfig(offset, replace_with))

StringPatchingConfig (ComponentConfig) dataclass

Dataclass required to apply a string patch with StringPatchingModifier. The configuration describes the offset where the patch is to be applied, and the string to patch in.

Attributes:

Name Type Description
offset int

the offset at which to apply the patch

string str

the string to patch in

StringPatchingModifier (Modifier)

Patch a string in a resource at a given offset, based on the provided configuration.

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 StringPatchingConfig

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/strings.py
async def modify(self, resource: Resource, config: StringPatchingConfig):
    new_data = config.string.encode("utf-8")
    if config.null_terminate:
        new_data += b"\x00"
    patch_config = BinaryPatchConfig(config.offset, new_data)
    await resource.run(BinaryPatchModifier, patch_config)

StringsUnpacker (Unpacker)

Unpack NULL-terminated strings of printable ASCII characters.

unpack(self, resource, config) async

Unpack the given resource.

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

Parameters:

Name Type Description Default
resource Resource

The resource that is being unpacked

required
config None

Optional config for unpacking. 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/strings.py
async def unpack(self, resource: Resource, config: None) -> None:
    if resource.get_data_id() is None:
        return
    if resource.has_tag(CodeRegion):
        # code is less likely to have strings so more likely to have false positives
        pattern = self.LONG_STRING_PATTERN
    else:
        pattern = self.SHORT_STRING_PATTERN

    children = [
        resource.create_child_from_view(
            AsciiString(string.rstrip(b"\x00").decode("ascii")),
            data_range=Range.from_size(offset, len(string)),
        )
        for offset, string in await resource.search_data(pattern)
    ]

    await asyncio.gather(*children)