Enhance IDA script for IOExternalMethodDispatch structures:

- Added support for struct_type argument in create_external_method_dispatch_struct and format_external_method_array functions.
- Updated documentation for usage and structure formats.
- Improved handling of specific fields for IOExternalMethodDispatch2022.
This commit is contained in:
Karol Mazurek committed 2025-06-08 00:50:34 +02:00
1 parent bcc9f34241
commit 0f8df62d82
1 file changed
+79 -27
+79 -27
View File
@@ -1,46 +1,87 @@
"""
IDA script to format and analyze IOExternalMethodDispatch structures in iOS kernelcache.
Supports both IOExternalMethodDispatch (0x18 bytes) and IOExternalMethodDispatch2022 (0x28 bytes) formats.
Usage in IDA Python console:
format_external_method_array(0xFFFFFE0007DCDBD8, 16, 1) # For old format
format_external_method_array(0xFFFFFE0007DCDBD8, 16) # For 2022 format
Structure formats:
IOExternalMethodDispatch (0x18):
0x00 - function (ptr)
0x08 - checkScalarInputCount
0x0C - checkStructureInputSize
0x10 - checkScalarOutputCount
0x14 - checkStructureOutputSize
IOExternalMethodDispatch2022 (0x28):
[all fields from IOExternalMethodDispatch]
0x18 - allowAsync
0x20 - checkEntitlement (ptr)
"""
from idaapi import * from idaapi import *
import ida_bytes import ida_bytes
import idc import idc
import ida_name import ida_name
def create_external_method_dispatch_struct(): def create_external_method_dispatch_struct(struct_type=0):
sid = idc.get_struc_id("IOExternalMethodDispatch2022") """
Creates IDA structure for IOExternalMethodDispatch.
Args:
struct_type: 0 for IOExternalMethodDispatch2022 (0x28 bytes)
1 for IOExternalMethodDispatch (0x18 bytes)
Returns:
Structure ID or -1 on failure
"""
struct_name = f"IOExternalMethodDispatch{2022 if struct_type == 0 else ''}"
sid = idc.get_struc_id(struct_name)
if sid != -1: if sid != -1:
# Structure already exists
return sid return sid
sid = idc.add_struc(-1, "IOExternalMethodDispatch2022", 0) sid = idc.add_struc(-1, struct_name, 0)
if sid == -1: if sid == -1:
print("Failed to create structure") print("Failed to create structure")
return -1 return -1
# Define structure members # Common fields for both types
idc.add_struc_member(sid, "function", 0, ida_bytes.qword_flag(), -1, 8) idc.add_struc_member(sid, "function", 0, ida_bytes.qword_flag(), -1, 8)
idc.add_struc_member(sid, "checkScalarInputCount", 8, ida_bytes.dword_flag(), -1, 4) idc.add_struc_member(sid, "checkScalarInputCount", 8, ida_bytes.dword_flag(), -1, 4)
idc.add_struc_member(sid, "checkStructureInputSize", 0xC, ida_bytes.dword_flag(), -1, 4) idc.add_struc_member(sid, "checkStructureInputSize", 0xC, ida_bytes.dword_flag(), -1, 4)
idc.add_struc_member(sid, "checkScalarOutputCount", 0x10, ida_bytes.dword_flag(), -1, 4) idc.add_struc_member(sid, "checkScalarOutputCount", 0x10, ida_bytes.dword_flag(), -1, 4)
idc.add_struc_member(sid, "checkStructureOutputSize", 0x14, ida_bytes.dword_flag(), -1, 4) idc.add_struc_member(sid, "checkStructureOutputSize", 0x14, ida_bytes.dword_flag(), -1, 4)
idc.add_struc_member(sid, "allowAsync", 0x18, ida_bytes.byte_flag(), -1, 1)
# Align to pointer size for checkEntitlement if struct_type == 0:
idc.add_struc_member(sid, "checkEntitlement", 0x20, ida_bytes.qword_flag(), -1, 8) # Type 0 (2022) specific fields
idc.add_struc_member(sid, "allowAsync", 0x18, ida_bytes.byte_flag(), -1, 1)
# Align to pointer size for checkEntitlement
idc.add_struc_member(sid, "checkEntitlement", 0x20, ida_bytes.qword_flag(), -1, 8)
return sid return sid
def format_external_method_array(start_addr, count): def format_external_method_array(start_addr, count, struct_type=0):
# Create structure if it doesn't exist """
sid = create_external_method_dispatch_struct() Formats and analyzes an array of IOExternalMethodDispatch structures.
Args:
start_addr: Start address of the methods array
count: Number of entries to process
struct_type: 0 for IOExternalMethodDispatch2022 (default)
1 for IOExternalMethodDispatch
"""
sid = create_external_method_dispatch_struct(struct_type)
if sid == -1: if sid == -1:
return return
struct_size = 0x28 # Size of IOExternalMethodDispatch2022 struct_size = 0x28 if struct_type == 0 else 0x18
# Create array
for i in range(count): for i in range(count):
current_addr = start_addr + (i * struct_size) current_addr = start_addr + (i * struct_size)
# Create structure instance # Create structure instance
idc.create_struct(current_addr, struct_size, "IOExternalMethodDispatch2022") idc.create_struct(current_addr, struct_size, f"IOExternalMethodDispatch{2022 if struct_type == 0 else ''}")
# Get function pointer and try to get its name # Get function pointer and try to get its name
func_ptr = idc.get_qword(current_addr) func_ptr = idc.get_qword(current_addr)
if func_ptr != 0: if func_ptr != 0:
@@ -50,35 +91,46 @@ def format_external_method_array(start_addr, count):
else: else:
print(f"Entry {i}: Function = 0x{func_ptr:x}") print(f"Entry {i}: Function = 0x{func_ptr:x}")
# Get other fields # Get common fields
scalar_input = idc.get_wide_dword(current_addr + 8) scalar_input = idc.get_wide_dword(current_addr + 8)
struct_input = idc.get_wide_dword(current_addr + 0xC) struct_input = idc.get_wide_dword(current_addr + 0xC)
scalar_output = idc.get_wide_dword(current_addr + 0x10) scalar_output = idc.get_wide_dword(current_addr + 0x10)
struct_output = idc.get_wide_dword(current_addr + 0x14) struct_output = idc.get_wide_dword(current_addr + 0x14)
allow_async = idc.get_wide_byte(current_addr + 0x18)
entitlement = idc.get_qword(current_addr + 0x20)
print(f" ScalarInput: {scalar_input}") print(f" ScalarInput: {scalar_input}")
print(f" StructInput: {struct_input}") print(f" StructInput: {struct_input}")
print(f" ScalarOutput: {scalar_output}") print(f" ScalarOutput: {scalar_output}")
print(f" StructOutput: {struct_output}") print(f" StructOutput: {struct_output}")
print(f" AllowAsync: {allow_async}")
if entitlement != 0: if struct_type == 0:
ent_str = idc.get_strlit_contents(entitlement, -1, STRTYPE_C) # Type 0 (2022) specific fields
if ent_str: allow_async = idc.get_wide_byte(current_addr + 0x18)
print(f" Entitlement: {ent_str.decode('utf-8')}") entitlement = idc.get_qword(current_addr + 0x20)
print(f" AllowAsync: {allow_async}")
if entitlement != 0:
ent_str = idc.get_strlit_contents(entitlement, -1, STRTYPE_C)
if ent_str:
print(f" Entitlement: {ent_str.decode('utf-8')}")
print("") print("")
def main(): def main():
if len(idc.ARGV) != 3: if len(idc.ARGV) < 3:
print("Usage: format_externalmethods.py <start_address> <count>") print("Usage: format_externalmethods.py <start_address> <count> [type]")
print("Example: format_externalmethods.py 0xFFFFFE0007E1B118 10") print("In IDA: format_external_method_array(0xFFFFFE0007DCDBD8, 16, 1)")
print("Type: 0 = IOExternalMethodDispatch2022 (0x28 bytes)")
print(" 1 = IOExternalMethodDispatch (0x18 bytes)")
return return
start_addr = int(idc.ARGV[1], 16) start_addr = int(idc.ARGV[1], 16)
count = int(idc.ARGV[2]) count = int(idc.ARGV[2])
struct_type = int(idc.ARGV[3]) if len(idc.ARGV) > 3 else 0
format_external_method_array(start_addr, count) format_external_method_array(start_addr, count, struct_type)
if __name__ == '__main__': if __name__ == '__main__':
main() main()
# format_external_method_array(0xFFFFFE0007F647A0, 10)
# format_external_method_array(0xFFFFFE0007DCDBD8, 15, 1)