Skip to content

Instantly share code, notes, and snippets.

@BlueFalconHD
Created February 9, 2025 21:19
Show Gist options
  • Save BlueFalconHD/f50339a00ef39659bc1c9dc11d53f1b5 to your computer and use it in GitHub Desktop.
Save BlueFalconHD/f50339a00ef39659bc1c9dc11d53f1b5 to your computer and use it in GitHub Desktop.
DYLD Extracted Shared Cache CFString offset fixer
import idc
import idaapi
import idautils
import ida_auto
import re
import random
# CFString structure offsets
OFFSET_ISA = 0x0 # pointer to isa
OFFSET_INFO = 0x8 # info pointer
OFFSET_DATA = 0x10 # pointer to the string data (thing fixed)
OFFSET_LENGTH = 0x18 # length of the string
SUBTRACT_VAL = 0x20000000000000 # set this to the value prepended to the actual address in the list of cfstrings, for me it was 0x20000000000000
ADD_VAL = 0x180000000 # set this to base address of DYLD shared cache.
# Maximum allowed length for new names
MAX_NAME_LENGTH = 20
def unique_name(base, addr, max_length=MAX_NAME_LENGTH):
"""
Ensure the name is unique. If the base name is already in use
(and not by the current address), append a suffix of an underscore and
three random digits, adjusting so that the final length does not exceed max_length.
"""
if len(base) > max_length:
base = base[:max_length]
new_name = base
while idc.get_name_ea_simple(new_name) != idc.BADADDR and idc.get_name_ea_simple(new_name) != addr:
suffix = "_%03d" % random.randint(0, 999)
if len(base) + len(suffix) > max_length:
new_name = base[:max_length - len(suffix)] + suffix
else:
new_name = base + suffix
return new_name
def fix_cfstring(addr):
"""
Fixes the CFString structure at 'addr':
- Patches the data pointer.
- Reads the string content.
- Renames the structure to "cf<content>" (limited to 20 characters, unique).
"""
# 1. Read the original data pointer.
data_field_addr = addr + OFFSET_DATA
orig_data_ptr = idc.get_qword(data_field_addr)
if orig_data_ptr is None:
print("Failed to read data pointer at 0x{:X}".format(data_field_addr))
return
# 2. Calculate the corrected pointer.
corrected_ptr = orig_data_ptr - SUBTRACT_VAL + ADD_VAL
# 3. Patch the data field.
idc.patch_qword(data_field_addr, corrected_ptr)
# 4. Read the length field.
length_field_addr = addr + OFFSET_LENGTH
length = idc.get_qword(length_field_addr)
if length is None or length <= 0:
print("Invalid length at 0x{:X}".format(length_field_addr))
string_content = ""
else:
# 5. Read the string bytes from the corrected pointer.
string_bytes = idc.get_bytes(corrected_ptr, length)
if string_bytes is None:
print("Unable to read bytes at 0x{:X}".format(corrected_ptr))
string_content = ""
else:
try:
# Assume UTF-8 encoding (change if needed)
string_content = string_bytes.decode('utf-8', errors='replace')
except Exception as e:
print("Decoding error at 0x{:X}: {}".format(corrected_ptr, e))
string_content = ""
# 6. Build a base name from the string content.
# Replace non-alphanumeric characters with underscores.
sanitized = re.sub(r'\W+', '_', string_content).strip('_')
if not sanitized:
sanitized = "_unknown"
new_name_base = "cf" + sanitized
# 7. Limit the name to MAX_NAME_LENGTH characters.
new_name_base = new_name_base[:MAX_NAME_LENGTH]
unique_new_name = unique_name(new_name_base, addr, MAX_NAME_LENGTH)
# 8. Rename the CFString instance.
idc.set_name(addr, unique_new_name, idc.SN_NOWARN)
print("CFString at 0x{:X}: data pointer 0x{:X} -> 0x{:X}, length 0x{:X}, renamed to '{}'".format(
addr, orig_data_ptr, corrected_ptr, length, unique_new_name))
def main():
"""
Process all __cfstring segments:
- Fix each CFString structure.
- Record modified address ranges.
- Trigger reanalysis on modified ranges to update cross-references.
"""
modified_ranges = []
for seg_ea in idautils.Segments():
seg_name = idc.get_segm_name(seg_ea)
if seg_name.startswith("__cfstring"):
print("Processing segment: {}".format(seg_name))
seg_end = idc.get_segm_end(seg_ea)
ea = seg_ea
# Process each CFString structure (assuming size 0x20 bytes)
while ea < seg_end:
fix_cfstring(ea)
modified_ranges.append((ea, ea + 0x20))
ea += 0x20
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment