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)
Decodes existing AsciiString resources (strips NULL terminators, converts to text). NOT for string discovery - only processes already-identified AsciiString resources from StringsUnpacker.
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)
Finds all occurrences of a specified string pattern in binary data and replaces each occurrence with a replacement string. Handles multiple occurrences automatically and can work with NULL-terminated strings or raw byte patterns. Use for bulk string patching, renaming identifiers throughout a binary, changing URLs or domain names, updating configuration strings, replacing hardcoded paths, or modifying all instances of specific text. More efficient than manual individual replacements when the same change is needed in multiple locations.
By default, to_find will be replaced with the ASCII string specified in the config's
replace_with argument, encoded as bytes, with a null byte appended. To remove the null byte,
specify null_terminate = False in the config. If replace_with is larger than to_find, a
ModifierError will be raised, unless allow_overflow is True. Note that this has the
potential to overwrite important data, so only use allow_overflow = True if you know there is
extra space for the 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)
Patches a string at a specific offset in text resources, replacing the string at the exact offset with a new string. Unlike find-replace, this is offset-targeted for precise control. Use for targeted string replacement when you know the exact offset, patching specific string locations, modifying configuration strings at known positions, fixing specific text entries, or implementing precise string modifications. Useful when offset is known from analysis or when only one specific instance should be changed.
By default, data at offset will be patched with the ASCII string specified in the config's
string argument, encoded as bytes. To append a null byte to the string, specify
null_terminate = True in the config.
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)
Extracts NULL-terminated ASCII strings as separate child resources (AsciiString). Slow operation using Python regex. Use when you need strings as individual resources for hierarchical analysis. Alternative: StringsAnalyzer is much faster but returns flat dictionary. Not run by default.
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)