From b0439e72208038f546ad2230df5178edc3cd47f6 Mon Sep 17 00:00:00 2001 From: Karol Mazurek Date: Mon, 9 Jun 2025 01:38:54 +0200 Subject: [PATCH] Add trace_ioserviceopen.py script to trace IOServiceOpen calls in LLDB --- X. NU/custom/drivers/trace_ioserviceopen.py | 109 ++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 X. NU/custom/drivers/trace_ioserviceopen.py diff --git a/X. NU/custom/drivers/trace_ioserviceopen.py b/X. NU/custom/drivers/trace_ioserviceopen.py new file mode 100644 index 0000000..2362121 --- /dev/null +++ b/X. NU/custom/drivers/trace_ioserviceopen.py @@ -0,0 +1,109 @@ +""" +trace_ioserviceopen.py + +Trace IOServiceOpen calls in a target process using LLDB Python scripting to get Service Names and User Client types. + +How to use: + 1. In LLDB, import this script: + (lldb) command script import trace_ioserviceopen.py + + 2. Start tracing with: + (lldb) setup_ioserviceopen --executable_path EXE_PATH -- [args...] + or + (lldb) setup_ioserviceopen --pid PID + +What it does: + - Sets a breakpoint on IOServiceOpen. + - On every call, prints: + - PID + - Executable path + - IOService name + - Type + - Does not stop or break execution; output is continuous and non-intrusive. + +""" + +import lldb +import shlex + +def ioserviceopen_trace_hook(frame, bp_loc, dict): + # Get target and process objects from the current frame + target = frame.GetThread().GetProcess().GetTarget() + process = frame.GetThread().GetProcess() + pid = process.GetProcessID() + # Get the main module (executable) path + module = target.GetModuleAtIndex(0) + exe_path = module.GetFileSpec().fullpath or "unknown" + # x0 holds the IOService pointer, x2 holds the type argument + service = frame.FindRegister("x0").GetValueAsUnsigned() + type_val = frame.FindRegister("x2").GetValueAsUnsigned() + + # Try to resolve the IOService name using IORegistryEntryGetName. + # This only works if the symbol is available and the process is not restricted. + name_str = f"0x{service:x}" + try: + # Evaluate an expression in the target to call IORegistryEntryGetName. + # This is safe if the symbol is present and the process allows it. + expr = ( + 'char name[128] = {0}; ' + 'extern int IORegistryEntryGetName(void*, char*); ' + f'IORegistryEntryGetName((void*){service}, name); ' + 'name' + ) + val = frame.EvaluateExpression(expr) + if val.IsValid() and val.GetSummary(): + s = val.GetSummary().strip('"') + if s and not s.startswith('0x'): + name_str = s + except Exception: + # If anything fails, just show the pointer value + pass + + print(f"\nPID: {pid}\nEXE PATH: {exe_path}\nSERVICE: {name_str}\nTYPE: {type_val}\n") + # Returning False tells LLDB to auto-continue without stopping at the breakpoint + return False + +def setup_ioserviceopen(debugger, command, result, internal_dict): + args = shlex.split(command) + executable_path = None + pid = None + program_args = [] + i = 0 + # Parse command-line arguments for executable path, pid, and any program arguments + while i < len(args): + if args[i] == "--executable_path" and i + 1 < len(args): + executable_path = args[i + 1] + i += 2 + elif args[i] == "--pid" and i + 1 < len(args): + pid = args[i + 1] + i += 2 + elif args[i] == "--" and i + 1 < len(args): + program_args = args[i + 1:] + break + else: + i += 1 + + if executable_path and pid: + print("Error: Specify either --executable_path or --pid", file=result) + return + if not executable_path and not pid: + print("Error: Specify --executable_path or --pid", file=result) + return + + # Set up the target and breakpoint, and ensure auto-continue is enabled + if executable_path: + debugger.HandleCommand(f'target create "{executable_path}"') + bp = debugger.GetSelectedTarget().BreakpointCreateByName("IOServiceOpen") + bp.SetScriptCallbackFunction("trace_ioserviceopen.ioserviceopen_trace_hook") + bp.SetAutoContinue(True) + debugger.HandleCommand(f'process launch -- {" ".join(shlex.quote(arg) for arg in program_args)}') + elif pid: + debugger.HandleCommand(f'process attach --pid {pid}') + bp = debugger.GetSelectedTarget().BreakpointCreateByName("IOServiceOpen") + bp.SetScriptCallbackFunction("trace_ioserviceopen.ioserviceopen_trace_hook") + bp.SetAutoContinue(True) + debugger.HandleCommand('continue') + +def __lldb_init_module(debugger, internal_dict): + # Register the setup command with LLDB + debugger.HandleCommand('command script add -f trace_ioserviceopen.setup_ioserviceopen setup_ioserviceopen') \ No newline at end of file