diff --git a/X. NU/custom/drivers/IOVerify.c b/X. NU/custom/drivers/IOVerify.c new file mode 100644 index 0000000..b9b4aeb --- /dev/null +++ b/X. NU/custom/drivers/IOVerify.c @@ -0,0 +1,289 @@ +/** + * @file IOVerify.c + * @brief Standalone tool for IOKit driver communication verification. + * clang IOVerify.c -o IOVerify -framework IOKit + * + * This tool, relevant to your work with IOKit and reverse engineering[5][7], allows for direct + * interaction with macOS IOKit drivers by sending structured data to specific methods. + * + * Usage: + * IOVerify -n (-m | -y ) [options] + * + * Options: + * -n : The class name of the IOKit service to target (required). + * -t : The connection type (user client type) to open. Default: 0. + * -m : The selector ID of the method to call. + * -y : Shorthand to specify method and buffer sizes. + * Format: "ID:[IN_SCA,IN_STR,OUT_SCA,OUT_STR]" + * Example: -y "0: [0, 96, 0, 96]" + * -p : A string to be used as the input buffer. + * -f : A file whose contents will be the input buffer. + * -b : A space-separated hex string for the input buffer (e.g., "00 11 22 aa"). + * -i : The size of the input structure buffer. + * -o : The size of the output structure buffer. + * -s : A 64-bit scalar input value (can be used multiple times). + * -S : The number of scalar output values. + */ + +#include +#include +#include +#include +#include +#include // For getopt +#include // For bool type +#include +#include // For mach_error_string + +// --- Structure Definitions --- + +typedef struct { + const char* driver_name; + uint64_t conn_type; + uint64_t method; + const char* payload; + const char* file_name; + uint64_t input_size; + uint64_t output_size; + uint64_t* scalar_input; + size_t scalar_in_size; + size_t scalar_out_size; + const char* byte_payload; +} verify_args_t; + +// --- Forward Declarations --- + +io_service_t find_driver_service(const char* driver_name); +io_connect_t get_driver_connection_handle(io_service_t service, const char* driver_name, uint32_t conn_type); +kern_return_t verify_driver_communication(const verify_args_t* args); +void print_usage(const char* prog_name); + +// --- Implementations --- + +void log_with_args(const char* format, ...) { + va_list args; + va_start(args, format); + vprintf(format, args); + va_end(args); + printf("\n"); +} + +void print_payload_hexdump(const unsigned char *data, size_t size) { + if (!data || size == 0) { + printf("[empty]\n"); + return; + } + for (size_t i = 0; i < size; ++i) { + printf("%02x ", data[i]); + if ((i + 1) % 16 == 0) printf("\n"); + } + if (size % 16 != 0) printf("\n"); +} + +void log_event_with_scalars(const char* event, const verify_args_t* args, kern_return_t result, const void* output_buffer, size_t output_size, const uint64_t* scalar_output, size_t scalar_out_size_actual, const void* input_buffer, size_t input_size) { + printf("\n--- [%s] Event Log ---\n", event); + printf("Driver: %s\n", args->driver_name); + printf("Connection Type: %llu\n", args->conn_type); + printf("Method Selector: %llu\n", args->method); + printf("Result: 0x%x (%s)\n", result, mach_error_string(result)); + + printf("\n--- Scalar I/O ---\n"); + printf("Scalar In Cnt: %zu\n", args->scalar_in_size); + if (args->scalar_in_size > 0 && args->scalar_input) { + printf("Scalar In: "); + for (size_t i = 0; i < args->scalar_in_size; ++i) printf("0x%llx ", args->scalar_input[i]); + printf("\n"); + } + printf("Scalar Out Cnt: %zu\n", scalar_out_size_actual); + if (scalar_out_size_actual > 0 && scalar_output) { + printf("Scalar Out: "); + for (size_t i = 0; i < scalar_out_size_actual; ++i) printf("0x%llx ", scalar_output[i]); + printf("\n"); + } + + printf("\n--- Structure I/O ---\n"); + printf("Input Size: %zu bytes\n", input_size); + printf("Input Data:\n"); + print_payload_hexdump(input_buffer, input_size); + + printf("\nOutput Size: %zu bytes\n", output_size); + printf("Output Data:\n"); + print_payload_hexdump(output_buffer, output_size); + printf("--- End of Log ---\n\n"); +} + +io_service_t find_driver_service(const char* driver_name) { + return IOServiceGetMatchingService(kIOMainPortDefault, IOServiceMatching(driver_name)); +} + +io_connect_t get_driver_connection_handle(io_service_t service, const char* driver_name, uint32_t conn_type) { + io_connect_t client = MACH_PORT_NULL; + kern_return_t kr = IOServiceOpen(service, mach_task_self(), conn_type, &client); + if (kr != KERN_SUCCESS) { + log_with_args("Failed to open connection for driver '%s' (type %u). Error: 0x%x (%s)", driver_name, conn_type, kr, mach_error_string(kr)); + return MACH_PORT_NULL; + } + return client; +} + +kern_return_t verify_driver_communication(const verify_args_t* args) { + if (!args || !args->driver_name) { + return KERN_INVALID_ARGUMENT; + } + + const io_service_t driver_service = find_driver_service(args->driver_name); + if (driver_service == MACH_PORT_NULL) { + log_with_args("Driver service '%s' not found.", args->driver_name); + return KERN_FAILURE; + } + + const io_connect_t client = get_driver_connection_handle(driver_service, args->driver_name, args->conn_type); + if (client == MACH_PORT_NULL) { + IOObjectRelease(driver_service); + return KERN_FAILURE; + } + + void* input_buffer = NULL; + size_t input_size = args->input_size; + if (args->file_name) { + FILE* file = fopen(args->file_name, "rb"); + if (file) { + fseek(file, 0, SEEK_END); + input_size = ftell(file); + fseek(file, 0, SEEK_SET); + input_buffer = calloc(1, input_size); + if (input_buffer) fread(input_buffer, 1, input_size, file); + fclose(file); + } + } else if (args->byte_payload) { + char* bp_copy = strdup(args->byte_payload); + char* p = bp_copy; + size_t count = 0; + while (*p) { + if (*p != ' ' && (p == bp_copy || *(p-1) == ' ')) count++; + p++; + } + input_size = count; + input_buffer = calloc(1, input_size); + p = bp_copy; + size_t idx = 0; + while(idx < input_size) { + char* next; + ((unsigned char*)input_buffer)[idx++] = (unsigned char)strtol(p, &next, 16); + p = next; + while(*p == ' ') p++; + } + free(bp_copy); + } else if (args->payload) { + input_size = strlen(args->payload); + input_buffer = calloc(1, input_size + 1); + if (input_buffer) memcpy(input_buffer, args->payload, input_size); + } else if (input_size > 0) { + input_buffer = calloc(1, input_size); + } + + size_t scalar_output_count = args->scalar_out_size; + uint64_t* scalar_output = (scalar_output_count > 0) ? calloc(scalar_output_count, sizeof(uint64_t)) : NULL; + size_t output_size = args->output_size; + void* output_buffer = (output_size > 0) ? calloc(1, output_size) : NULL; + + uint32_t scalar_output_count_32 = scalar_output_count; + kern_return_t result = IOConnectCallMethod(client, args->method, args->scalar_input, args->scalar_in_size, input_buffer, input_size, scalar_output, &scalar_output_count_32, output_buffer, &output_size); + + log_event_with_scalars("VERIFY", args, result, output_buffer, output_size, scalar_output, scalar_output_count_32, input_buffer, input_size); + + free(input_buffer); + free(output_buffer); + free(scalar_output); + IOServiceClose(client); + IOObjectRelease(driver_service); + return result; +} + +void print_usage(const char* prog_name) { + printf("Usage: %s -n (-m | -y ) [options]\n", prog_name); + printf("Options:\n"); + printf(" -n Target driver class name (required).\n"); + printf(" -t Connection type (default: 0).\n"); + printf(" -m Method selector ID.\n"); + printf(" -y Specify method and buffer sizes in one string.\n"); + printf(" Format: \"ID: [IN_SCA, IN_STR, OUT_SCA, OUT_STR]\"\n"); + printf(" Example: -y \"0: [0, 96, 0, 96]\"\n"); + printf(" -p Payload as a string.\n"); + printf(" -f File path for payload.\n"); + printf(" -b Space-separated hex string payload.\n"); + printf(" -i Input buffer size (ignored if -y is used).\n"); + printf(" -o Output buffer size (ignored if -y is used).\n"); + printf(" -s Scalar input (uint64_t). Can be specified multiple times.\n"); + printf(" -S Scalar output count (ignored if -y is used).\n"); + printf(" -h Show this help message.\n"); +} + +int main(int argc, char *argv[]) { + verify_args_t args = {0}; + int opt; + uint64_t scalar_inputs[16] = {0}; + size_t scalar_input_idx = 0; + bool method_is_set = false; + bool y_flag_used = false; + + while ((opt = getopt(argc, argv, "hn:t:m:p:f:b:i:o:s:S:y:")) != -1) { + switch (opt) { + case 'h': print_usage(argv[0]); return 0; + case 'n': args.driver_name = optarg; break; + case 't': args.conn_type = strtoull(optarg, NULL, 0); break; + case 'm': args.method = strtoull(optarg, NULL, 0); method_is_set = true; break; + case 'y': { + y_flag_used = true; + unsigned long long m, si, is, so, os; + int items = sscanf(optarg, "%llu : [ %llu , %llu , %llu , %llu ]", &m, &si, &is, &so, &os); + if (items == 5) { + args.method = m; + args.scalar_in_size = si; + args.input_size = is; + args.scalar_out_size = so; + args.output_size = os; + method_is_set = true; + } else { + fprintf(stderr, "Error: Invalid format for -y. Use 'ID: [sc_in, st_in, sc_out, st_out]'.\n"); + return 1; + } + break; + } + case 'p': args.payload = optarg; break; + case 'f': args.file_name = optarg; break; + case 'b': args.byte_payload = optarg; break; + case 'i': if (!y_flag_used) args.input_size = strtoull(optarg, NULL, 0); break; + case 'o': if (!y_flag_used) args.output_size = strtoull(optarg, NULL, 0); break; + case 's': + if (scalar_input_idx < 16) scalar_inputs[scalar_input_idx++] = strtoull(optarg, NULL, 0); + else fprintf(stderr, "Exceeded maximum of 16 scalar inputs.\n"); + break; + case 'S': if (!y_flag_used) args.scalar_out_size = strtoull(optarg, NULL, 0); break; + default: print_usage(argv[0]); return 1; + } + } + + if (!args.driver_name || !method_is_set) { + fprintf(stderr, "Error: Driver name (-n) and method ID (-m or -y) are required.\n"); + print_usage(argv[0]); + return 1; + } + + if (y_flag_used) { + if (scalar_input_idx > args.scalar_in_size) { + fprintf(stderr, "Warning: More scalars via -s (%zu) than in -y (%zu). Extra values ignored.\n", scalar_input_idx, args.scalar_in_size); + } else if (scalar_input_idx < args.scalar_in_size) { + fprintf(stderr, "Warning: Fewer scalars via -s (%zu) than in -y (%zu). Remaining values zeroed.\n", scalar_input_idx, args.scalar_in_size); + } + } else { + args.scalar_in_size = scalar_input_idx; + } + + args.scalar_input = scalar_inputs; + + printf("Starting verification for driver: %s\n", args.driver_name); + verify_driver_communication(&args); + + return 0; +}