Hacking Question Payload loader for iOS?

Dread_Pirate_PJ

Well-Known Member
Newcomer
Joined
Feb 24, 2018
Messages
64
Trophies
0
Age
53
XP
178
Country
United States
I've gotten as far as making the packet and stuff.. The problem is I can't figure out how to "transfer I/O control" still.. None of the code posted on this thread works to transfer it.. I've made the code cross-platform for iOS and MacOS.. So it can be ran on MacOS and you can see.. Once it runs on MacOS, it'll run on iOS no problem and we'd be done :D

The code I have now is (entirely C++ for a reason):

USBDevice.hxx
Code:
//
//  USBDevice.h
//  iOUSB
//
//  Created by Brandon on 2018-05-28.
//  Copyright © 2018 XIO. All rights reserved.
//

extern "C" {
    #import <IOKit/IOKitLib.h>
    #import <IOKit/usb/IOUSBLib.h>
    #import <IOKit/IOCFPlugIn.h>
    #import <IOKit/IOMessage.h>
    #import <IOKit/IOBSD.h>
    #import <CoreFoundation/CoreFoundation.h>
}

#include <iostream>
#include <vector>

/// Allow formatting of C++ strings
template<typename... Args>
std::string string_format(const std::string& format, Args... args)
{
    size_t size = std::snprintf(nullptr, 0, format.c_str(), args...) + 1;
    std::unique_ptr<char[]> buf(new char[size]);
    std::snprintf(buf.get(), size, format.c_str(), args...);
    return std::string(buf.get(), buf.get() + size - 1);
}

/// Error Codes
extern std::string human_error_string(IOReturn errorCode);


/// Devices
class USBDevice
{
private:
    IOUSBDeviceInterface300** deviceInterface;
    IOUSBInterfaceInterface300** interface;
    io_object_t device;
 
    std::uint8_t controlPipeRef;
    std::uint8_t readPipeRef;
    std::uint8_t writePipeRef;
 
    /// Returns an arbitrary interface from a plugin interface
    void** GetInterface(io_object_t device, CFUUIDRef type, CFUUIDRef uuid);
 
    /// Get Device Property
    int GetProperty(std::string propertyName);
 
    /// Get String Descriptor
    std::string GetStringDescriptor(std::uint8_t index);
 
    /// Load Pipe Refs
    void GetPipeRefs();
 
public:
    USBDevice(io_object_t device);
    ~USBDevice();
 
    /// Properties
    std::string GetName();
    std::string GetClass();
    std::string GetPath();
    std::int32_t GetVendorID();
    std::int32_t GetProductID();
    std::string GetSerialNumber();
    std::string GetManufacturer();
    std::uint32_t GetLocationID();
 
    /// Debug Print an interface
    std::string PrintInterface();
 
    /// Get Max Packet Size for a pipe
    std::uint16_t GetMaxPipePacketSize(std::uint8_t pipeRef);
 
    /// Clear the pipe
    void ClearPipe(std::uint8_t pipeRef, std::uint32_t timeout);
 
    /// Open the Device Interface
    bool Open();
 
    /// Close the Device Interface
    void Close();
 
    /// Get Pipe Status
    kern_return_t GetPipeStatus(std::uint8_t pipeRef);
 
    /// Get Driver Version
    NumVersion GetDriverVersion();
 
    /// Get Control pipe reference
    std::uint8_t GetControlPipeRef();
 
    /// Get Read pipe reference
    std::uint8_t GetReadPipeRef();
 
    /// Get Write pipe reference
    std::uint8_t GetWritePipeRef();
 
    /// Read from the device
    int Read(std::uint8_t* buffer, std::size_t bufferSize);
 
    /// Read from the device asynchronously
    int ReadAsync(std::uint8_t* buffer, std::size_t bufferSize);
 
    /// Write to the device
    int Write(std::uint8_t* buffer, std::size_t bufferSize);
 
    /// Write to the device asynchronously
    int WriteAsync(std::uint8_t* buffer, std::size_t bufferSize);
 
    /// Send Device Request
    int SendDeviceRequest(int requesttype, int request, int value, int index, char *bytes, int size, int timeout = 0);
 
    /// Send I/O Control Request
    int SendControlRequest(int requesttype, int request, int value, int index, char *bytes, int size, int timeout = 0);
 
    /// Send Raw Request
    int SendRawRequest(IOUSBDevRequest *request);
 
    /// Send Raw I/O Control Request
    int SendRawControlRequest(IOUSBDevRequest *request, std::uint8_t pipeRef);
};

/// Device Manager
class USBDeviceManager
{
private:
    void* notificationRegistry;
 
public:
    USBDeviceManager();
    ~USBDeviceManager();
 
    std::vector<std::unique_ptr<USBDevice>> GetDevicesMatching(std::string service, int vendorId, int productId);
 
    void RegisterForDeviceNotifications(std::string service, int vendorId, int productId, void(*onDeviceAdded)(USBDevice *device), void(*onDeviceDisconnected)(USBDevice *device));
};

USBDevice.cxx:
Code:
//
//  USBDevice.m
//  iOUSB
//
//  Created by Brandon on 2018-05-28.
//  Copyright © 2018 XIO. All rights reserved.
//

#include "USBDevice.hxx"
#include <memory>

struct USBNotification
{
    USBDeviceManager* _this;
    IONotificationPortRef notificationPort;
    io_iterator_t deviceAddedIterator;
    io_iterator_t deviceRemovedIterator;
    io_object_t notification;
    CFRunLoopRef runLoop;
    void(*onDeviceAdded)(USBDevice *device);
    void(*onDeviceDisconnected)(USBDevice *device);
};

struct DeviceMessage
{
    USBDevice* _this;
    USBNotification* notification;
};

#pragma mark - Utilities

#define CFSAFERELEASE(ref) if (ref) CFRelease(ref)
void DeviceAdded(void *userInfo, io_iterator_t iterator);
void DeviceDisconnected(void *userInfo, io_iterator_t iterator);
void DeviceMessageReceived(void *userInfo, io_service_t service, natural_t messageType, void *messageArgument);

/// Converts IOKit errors to human readable strings.
std::string usb_human_error_string(IOReturn errorCode)
{
//    #define err_get_system(err) (((err)>>26)&0x3f)
//    #define err_get_sub(err) (((err)>>14)&0xfff)
//    #define err_get_code(err) ((err)&0x3fff)
 
    switch (errorCode) {
        case kIOUSBUnknownPipeErr:
            return string_format("Pipe Ref Not Recognized (%08x)", errorCode);
 
        case kIOUSBTooManyPipesErr:
            return string_format("Too Many Pipes (%08x)", errorCode);
 
        case kIOUSBNoAsyncPortErr:
            return string_format("No Async Port (%08x)", errorCode);
 
        case kIOUSBNotEnoughPipesErr:
            return string_format("Not Enough Pipes in Interface (%08x)", errorCode);
 
        case kIOUSBNotEnoughPowerErr:
            return string_format("Not Enough Power for Selected Configuration (%08x)", errorCode);
 
        case kIOUSBEndpointNotFound:
            return string_format("Endpoint Not Found (%08x)", errorCode);
 
        case kIOUSBConfigNotFound:
            return string_format("Configuration Not Found (%08x)", errorCode);
 
        case kIOUSBTransactionTimeout:
            return string_format("Transaction Timed Out (%08x)", errorCode);
 
        case kIOUSBTransactionReturned:
            return string_format("Transaction has been returned to the caller (%08x)", errorCode);
 
        case kIOUSBPipeStalled:
            return string_format("Pipe has stalled, Error needs to be cleared (%08x)", errorCode);
 
        case kIOUSBInterfaceNotFound:
            return string_format("Interface Ref Not Recognized (%08x)", errorCode);
 
        case kIOUSBLowLatencyBufferNotPreviouslyAllocated:
            return string_format("Attempted to use user land low latency isoc calls w/out calling PrepareBuffer (on the data buffer) first (%08x)", errorCode);
 
        case kIOUSBLowLatencyFrameListNotPreviouslyAllocated:
            return string_format("Attempted to use user land low latency isoc calls w/out calling PrepareBuffer (on the frame list) first (%08x)", errorCode);
 
        case kIOUSBHighSpeedSplitError:
            return string_format("Error to hub on high speed bus trying to do split transaction (%08x)", errorCode);
 
        case kIOUSBSyncRequestOnWLThread:
            return string_format("A synchronous USB request was made on the workloop thread (from a callback?).  Only async requests are permitted in that case (%08x)", errorCode);
 
        case kIOUSBDeviceTransferredToCompanion:
            return string_format("The device has been tranferred to another controller for enumeration (%08x)", errorCode);
 
        case kIOUSBClearPipeStallNotRecursive:
            return string_format("ClearPipeStall should not be called recursively (%08x)", errorCode);
 
        case kIOUSBDevicePortWasNotSuspended:
            return string_format("Port was not suspended (%08x)", errorCode);
 
        case kIOUSBEndpointCountExceeded:
            return string_format("The endpoint was not created because the controller cannot support more endpoints (%08x)", errorCode);
 
        case kIOUSBDeviceCountExceeded:
            return string_format("The device cannot be enumerated because the controller cannot support more devices (%08x)", errorCode);
 
        case kIOUSBStreamsNotSupported:
            return string_format("The request cannot be completed because the XHCI controller does not support streams (%08x)", errorCode);
 
        case kIOUSBInvalidSSEndpoint:
            return string_format("An endpoint found in a SuperSpeed device is invalid (usually because there is no Endpoint Companion Descriptor) (%08x)", errorCode);
 
        case kIOUSBTooManyTransactionsPending:
            return string_format("The transaction cannot be submitted because it would exceed the allowed number of pending transactions (%08x)", errorCode);
 
        default:
            return string_format("Error Code (%08x)\n-- System: (%02X), SubSystem: (%02X), Code: (%02X) ", errorCode, err_get_system(errorCode), err_get_sub(errorCode), err_get_code(errorCode));
    }
}

std::string human_error_string(IOReturn errorCode)
{
    switch (errorCode) {
        case kIOReturnSuccess:
            return string_format("Success (%08x)", errorCode);
 
        case kIOReturnError:
            return string_format("General Error (%08x)", errorCode);
 
        case kIOReturnNoMemory:
            return string_format("Cannot Allocate Memory (%08x)", errorCode);
 
        case kIOReturnNoResources:
            return string_format("Resource Shortage (%08x)", errorCode);
 
        case kIOReturnIPCError:
            return string_format("IPC Error (%08x)", errorCode);
 
        case kIOReturnNoDevice:
            return string_format("No Such Device (%08x)", errorCode);
 
        case kIOReturnNotPrivileged:
            return string_format("Insufficient Privileges (%08x)", errorCode);
 
        case kIOReturnBadArgument:
            return string_format("Invalid Argument (%08x)", errorCode);
 
        case kIOReturnLockedRead:
            return string_format("Device Read Locked (%08x)", errorCode);
 
        case kIOReturnLockedWrite:
            return string_format("Device Write Locked (%08x)", errorCode);
 
        case kIOReturnExclusiveAccess:
            return string_format("Exclusive Access and Device already opened (%08x)", errorCode);
 
        case kIOReturnBadMessageID:
            return string_format("Sent/Received Messages had different MSG_ID (%08x)", errorCode);
 
        case kIOReturnUnsupported:
            return string_format("Unsupported Function (%08x)", errorCode);
 
        case kIOReturnVMError:
            return string_format("Misc. VM Failure (%08x)", errorCode);
 
        case kIOReturnInternalError:
            return string_format("Internal Error (%08x)", errorCode);
 
        case kIOReturnIOError:
            return string_format("General I/O Error (%08x)", errorCode);
 
        case kIOReturnCannotLock:
            return string_format("Can't Acquire Lock (%08x)", errorCode);
 
        case kIOReturnNotOpen:
            return string_format("Device Not Open (%08x)", errorCode);
 
        case kIOReturnNotReadable:
            return string_format("Read Not Supported (%08x)", errorCode);
 
        case kIOReturnNotWritable:
            return string_format("Write Not Supported (%08x)", errorCode);
 
        case kIOReturnNotAligned:
            return string_format("Alignment Error (%08x)", errorCode);
 
        case kIOReturnBadMedia:
            return string_format("Media Error (%08x)", errorCode);
 
        case kIOReturnStillOpen:
            return string_format("Device(s) Still Open (%08x)", errorCode);
 
        case kIOReturnRLDError:
            return string_format("RLD Failure (%08x)", errorCode);
 
        case kIOReturnDMAError:
            return string_format("DMA Failure (%08x)", errorCode);
 
        case kIOReturnBusy:
            return string_format("Device Busy (%08x)", errorCode);
 
        case kIOReturnTimeout:
            return string_format("I/O Timeout (%08x)", errorCode);
 
        case kIOReturnOffline:
            return string_format("Device Offline (%08x)", errorCode);
 
        case kIOReturnNotReady:
            return string_format("Not Ready (%08x)", errorCode);
 
        case kIOReturnNotAttached:
            return string_format("Device Not Attached (%08x)", errorCode);
 
        case kIOReturnNoChannels:
            return string_format("No DMA Channels Left (%08x)", errorCode);
 
        case kIOReturnNoSpace:
            return string_format("No Space For Data (%08x)", errorCode);
 
        case kIOReturnPortExists:
            return string_format("Port Already Exists (%08x)", errorCode);
 
        case kIOReturnCannotWire:
            return string_format("Can't Write Down (%08x)", errorCode);
 
        case kIOReturnNoInterrupt:
            return string_format("No Interrupt Attached (%08x)", errorCode);
 
        case kIOReturnNoFrames:
            return string_format("No DMA Frames Enqueued (%08x)", errorCode);
 
        case kIOReturnMessageTooLarge:
            return string_format("Oversized MSG Received On Interrupt Port (%08x)", errorCode);
 
        case kIOReturnNotPermitted:
            return string_format("Not Permitted (%08x)", errorCode);
 
        case kIOReturnNoPower:
            return string_format("No Power To Device (%08x)", errorCode);
 
        case kIOReturnNoMedia:
            return string_format("Media Not Present (%08x)", errorCode);
 
        case kIOReturnUnformattedMedia:
            return string_format("Media Not Formatted (%08x)", errorCode);
 
        case kIOReturnUnsupportedMode:
            return string_format("No Such Mode (%08x)", errorCode);
 
        case kIOReturnUnderrun:
            return string_format("Buffer Underflow (%08x)", errorCode);
 
        case kIOReturnOverrun:
            return string_format("Buffer Overflow (%08x)", errorCode);
 
        case kIOReturnDeviceError:
            return string_format("The Device Is Not Working Properly! (%08x)", errorCode);
 
        case kIOReturnNoCompletion:
            return string_format("A Completion Routine Is Required (%08x)", errorCode);
 
        case kIOReturnAborted:
            return string_format("Operation Aborted (%08x)", errorCode);
 
        case kIOReturnNoBandwidth:
            return string_format("Bus Bandwidth Would Be Exceeded (%08x)", errorCode);
 
        case kIOReturnNotResponding:
            return string_format("Device Not Responding (%08x)", errorCode);
 
        case kIOReturnIsoTooOld:
            return string_format("ISOChronous I/O request for distance past! (%08x)", errorCode);
 
        case kIOReturnIsoTooNew:
            return string_format("ISOChronous I/O request for distant future! (%08x)", errorCode);
 
        case kIOReturnNotFound:
            return string_format("Data Not Found (%08x)", errorCode);
 
        case kIOReturnInvalid:
            return string_format("Should Never Be Seen(%08x)", errorCode);
 
        default:
            /// See here for more: https://developer.apple.com/library/content/qa/qa1075/_index.html
            return usb_human_error_string(errorCode);
    }
}


#pragma mark - Device Private
USBDevice::USBDevice(io_object_t device) : deviceInterface(nullptr), interface(nullptr), device(device), controlPipeRef(0x00), readPipeRef(0x01), writePipeRef(0x02)
{
    IOObjectRetain(device);
}

USBDevice::~USBDevice()
{
    Close();
    IOObjectRelease(device);
}

void** USBDevice::GetInterface(io_object_t device, CFUUIDRef type, CFUUIDRef uuid)
{
    /// Create a plugin interface for the service.
    IOCFPlugInInterface **plugInInterface = nullptr;
    SInt32 score = 0;
 
    kern_return_t kr = IOCreatePlugInInterfaceForService(device, type, kIOCFPlugInInterfaceID, &plugInInterface, &score);
 
    if ((kIOReturnSuccess != kr) || !plugInInterface)
    {
        std::cerr<<human_error_string(kr)<<"\n";
        return nullptr;
    }
 
    /// Get an interface from the plugin.. and release the plugin
    void **interface = nullptr;
    HRESULT res = (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(uuid), (LPVOID*) &interface);
    (*plugInInterface)->Release(plugInInterface);
 
    if (res || !interface)
    {
        return nullptr;
    }
    return interface;
}

int USBDevice::GetProperty(std::string propertyName)
{
    CFStringRef name = CFStringCreateWithCString(kCFAllocatorDefault, propertyName.c_str(), kCFStringEncodingUTF8);
    CFNumberRef number = (CFNumberRef)IORegistryEntryCreateCFProperty(device, name, kCFAllocatorDefault, 0);
 
    if (number)
    {
        int value = 0;
        CFNumberGetValue(number, kCFNumberSInt32Type, &value);
        CFSAFERELEASE(number);
        CFSAFERELEASE(name);
        return value;
    }
 
    CFSAFERELEASE(name);
    return -1;
}

std::string USBDevice::GetStringDescriptor(std::uint8_t index)
{
    std::uint8_t requestBuffer[256];
    IOUSBDevRequest request = {
        .bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice),
        .bRequest = kUSBRqGetDescriptor,
        .wValue = static_cast<std::uint16_t>((kUSBStringDesc << 8) | index),
        .wIndex = 0x409, //English
        .wLength = sizeof(requestBuffer),
        .pData = requestBuffer
    };
 
    kern_return_t kr = (*deviceInterface)->DeviceRequest(deviceInterface, &request);
    if (kr != KERN_SUCCESS)
    {
        std::cerr<<human_error_string(kr)<<"\n";
        return "";
    }
 
    CFStringRef descriptor = CFStringCreateWithBytes(kCFAllocatorDefault, &requestBuffer[2], requestBuffer[0] - 2, kCFStringEncodingUTF16LE, false);
 
    CFIndex length = CFStringGetLength(descriptor);
    CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1;
    std::string result(maxSize, '\0');
    CFStringGetCString(descriptor, &result[0], maxSize, kCFStringEncodingUTF8);
    CFSAFERELEASE(descriptor);
    return result;
}

void USBDevice::GetPipeRefs()
{
    controlPipeRef = 0x00;
    readPipeRef = 0x01;
    writePipeRef = 0x02;
 
    if (interface)
    {
        UInt8 interfaceNumEndpoints = 0;
        IOReturn err = (*interface)->GetNumEndpoints(interface, &interfaceNumEndpoints);
        if (err)
        {
            std::cerr<<human_error_string(err)<<"\n";
            return;
        }
 
        for (UInt8 ref = 1; ref <= interfaceNumEndpoints; ++ref)
        {
            UInt8 direction;
            UInt8 number;
            UInt8 transferType;
            UInt16 maxPacketSize;
            UInt8 interval;
 
            IOReturn kr = (*interface)->GetPipeProperties(interface, ref, &direction, &number, &transferType, &maxPacketSize, &interval);
 
            if (kr == kIOReturnSuccess)
            {
                if (transferType == kUSBControl)
                {
                    controlPipeRef = 0;
                }
                else if (transferType == kUSBBulk)
                {
                    if (direction == kUSBIn)
                    {
                        readPipeRef = ref;
                    }
                    else if (direction == kUSBOut)
                    {
                        writePipeRef = ref;
                    }
                }
            }
        }
    }
}

std::string USBDevice::GetName()
{
    io_string_t name = {0};
    kern_return_t kr = IORegistryEntryGetName(device, name);
    if (kr != KERN_SUCCESS)
    {
        std::cerr<<human_error_string(kr)<<"\n";
    }
    return std::string(name);
}

std::string USBDevice::GetClass()
{
    io_string_t name = {0};
    kern_return_t kr = IOObjectGetClass(device, name);
    if (kr != KERN_SUCCESS)
    {
        std::cerr<<human_error_string(kr)<<"\n";
    }
 
    return std::string(name);
}

std::string USBDevice::GetPath()
{
    io_string_t path = {0};
    kern_return_t kr = IORegistryEntryGetPath(device, kIOServicePlane, path);
    if (kr != KERN_SUCCESS)
    {
        std::cerr<<human_error_string(kr)<<"\n";
    }
 
    return std::string(path);
}

std::int32_t USBDevice::GetVendorID()
{
    return GetProperty(kUSBVendorID);
}

std::int32_t USBDevice::GetProductID()
{
    return GetProperty(kUSBProductID);
}

std::string USBDevice::GetSerialNumber()
{
    if (deviceInterface)
    {
        std::uint8_t index = 0;
        IOReturn kr = (*deviceInterface)->USBGetSerialNumberStringIndex(deviceInterface, &index);
        if (kr != kIOReturnSuccess)
        {
            std::cerr<<human_error_string(kr)<<"\n";
            return "";
        }
 
        return GetStringDescriptor(index);
    }
    return "";
}

std::string USBDevice::GetManufacturer()
{
    if (deviceInterface)
    {
        std::uint8_t index = 0;
        IOReturn kr = (*deviceInterface)->USBGetManufacturerStringIndex(deviceInterface, &index);
        if (kr != kIOReturnSuccess)
        {
            std::cerr<<human_error_string(kr)<<"\n";
            return "";
        }
 
        return GetStringDescriptor(index);
    }
    return "";
}

std::uint32_t USBDevice::GetLocationID()
{
    UInt32 locationID = -1;
    IOUSBDeviceInterface **deviceInterface = reinterpret_cast<IOUSBDeviceInterface **>(GetInterface(device, kIOUSBDeviceUserClientTypeID, kIOUSBDeviceInterfaceID));
    if (deviceInterface)
    {
        // Get the location ID from the USB Interface
        (*deviceInterface)->GetLocationID(deviceInterface, &locationID);
 
        // Cleanup
        (*deviceInterface)->Release(deviceInterface);
        deviceInterface = nil;
    }
 
    return locationID;
}

std::string USBDevice::PrintInterface()
{
    UInt8 interfaceNumEndpoints = 0;
    IOReturn err = (*interface)->GetNumEndpoints(interface, &interfaceNumEndpoints);
    if (err)
    {
        std::cerr<<human_error_string(err)<<"\n";
        return string_format("Unable to get number of endpoints (%08x)", err);
    }
 
    std::string output = string_format("Interface has %d endpoints\n", interfaceNumEndpoints);
 
    /// USUALLY..
    /// Index 0 = DeviceControl/ControlRequest.
    /// Index 1 = DeviceRead
    /// Index 2 = DeviceWrite
    for (UInt8 pipeRef = 1; pipeRef <= interfaceNumEndpoints; ++pipeRef)
    {
        UInt8 direction;
        UInt8 number;
        UInt8 transferType;
        UInt16 maxPacketSize;
        UInt8 interval;
 
        IOReturn kr = (*interface)->GetPipeProperties(interface, pipeRef, &direction, &number, &transferType, &maxPacketSize, &interval);
 
        if (kr != kIOReturnSuccess)
        {
            output += string_format("Unable to get properties of pipe %d (%08x)\n", pipeRef, kr);
        }
        else
        {
            std::string directions[] = {"Out", "In", "None", "Any"};
            std::string transferTypes[] = {"Control", "ISOC", "Bulk", "Interrupt", "Any"};
 
            output += string_format("Pipe: %d, Direction: %s, TransferType: %s, MaxPacketSize: %d\n", pipeRef, directions[direction].c_str(), transferTypes[transferType].c_str(), maxPacketSize);
        }
    }
 
    return output;
}

std::uint16_t USBDevice::GetMaxPipePacketSize(std::uint8_t pipeRef)
{
    UInt8 direction;
    UInt8 number;
    UInt8 transferType;
    UInt16 maxPacketSize;
    UInt8 interval;
 
    IOReturn kr = (*interface)->GetPipeProperties(interface, pipeRef, &direction, &number, &transferType, &maxPacketSize, &interval);
    if (kr != kIOReturnSuccess)
    {
        std::cerr<<human_error_string(kr)<<"\n";
        return 0;
    }
 
    return maxPacketSize;
}

void USBDevice::ClearPipe(std::uint8_t pipeRef, std::uint32_t timeout)
{
    uint16_t maxSize = GetMaxPipePacketSize(pipeRef);
    std::unique_ptr<char[]> readBuffer(new char[maxSize]);

    while(true)
    {
        std::uint32_t readSize = maxSize;
        bzero(readBuffer.get(), maxSize * sizeof(char));
        IOReturn kr = (*interface)->ReadPipeTO(interface, pipeRef, readBuffer.get(), (UInt32 *)&readSize, timeout, timeout);
        if (kr != kIOReturnSuccess)
        {
            std::cerr<<human_error_string(kr)<<"\n";
            break;
        }

        if (readSize == 0)
        {
            break;
        }
    }
 
    IOReturn kr = (*interface)->ClearPipeStallBothEnds(interface, pipeRef);
    if (kr)
    {
        std::cerr<<human_error_string(kr)<<"\n";
        return;
    }
}

bool USBDevice::Open()
{
    // Open the USB device for communication.
    deviceInterface = reinterpret_cast<IOUSBDeviceInterface300 **>(GetInterface(device, kIOUSBDeviceUserClientTypeID, kIOUSBDeviceInterfaceID300));
 
    if (deviceInterface)
    {
        kern_return_t kr = (*deviceInterface)->USBDeviceOpen(deviceInterface);
        if (kr != kIOReturnSuccess)
        {
            (*deviceInterface)->Release(deviceInterface);
            deviceInterface = nullptr;
 
            std::cerr<<human_error_string(kr)<<"\n";
            return false;
        }
 

        //Get the configuration..
        IOUSBConfigurationDescriptorPtr config;
        kr = (*deviceInterface)->GetConfigurationDescriptorPtr(deviceInterface, 0, &config);
        if (kr != kIOReturnSuccess)
        {
            (*deviceInterface)->USBDeviceClose(deviceInterface);
            (*deviceInterface)->Release(deviceInterface);
            deviceInterface = nullptr;
 
            std::cerr<<human_error_string(kr)<<"\n";
            return false;
        }
 
        //Set the configuration..
        (*deviceInterface)->SetConfiguration(deviceInterface, config->bConfigurationValue);
 
        //Find the USB interface..
        IOUSBFindInterfaceRequest interfaceRequest;
        interfaceRequest.bInterfaceClass = kIOUSBFindInterfaceDontCare;
        interfaceRequest.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
        interfaceRequest.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
        interfaceRequest.bAlternateSetting = kIOUSBFindInterfaceDontCare;
 
        //Get an interface iterator..
        io_iterator_t iterator;
        kr = (*deviceInterface)->CreateInterfaceIterator(deviceInterface, &interfaceRequest, &iterator);
        if (kr != kIOReturnSuccess)
        {
            (*deviceInterface)->USBDeviceClose(deviceInterface);
            (*deviceInterface)->Release(deviceInterface);
            deviceInterface = nullptr;
 
            std::cerr<<human_error_string(kr)<<"\n";
            return false;
        }
 
        //Get the device object
        io_object_t usbDevice = IOIteratorNext(iterator);
        if (!usbDevice)
        {
            IOObjectRelease(iterator);
            (*deviceInterface)->USBDeviceClose(deviceInterface);
            (*deviceInterface)->Release(deviceInterface);
            deviceInterface = nullptr;
            return false;
        }
 
        //Get a USB Interface
        interface = reinterpret_cast<IOUSBInterfaceInterface300 **>(GetInterface(usbDevice, kIOUSBInterfaceUserClientTypeID, kIOUSBInterfaceInterfaceID300));
 
        if (!interface)
        {
            IOObjectRelease(usbDevice);
            IOObjectRelease(iterator);
            (*deviceInterface)->USBDeviceClose(deviceInterface);
            (*deviceInterface)->Release(deviceInterface);
            deviceInterface = nullptr;
            return false;
        }


        kr = (*interface)->USBInterfaceOpen(interface);
        if (kr != kIOReturnSuccess)
        {
            (*interface)->Release(interface);
            interface = nullptr;
 
            IOObjectRelease(usbDevice);
            IOObjectRelease(iterator);
            (*deviceInterface)->USBDeviceClose(deviceInterface);
            (*deviceInterface)->Release(deviceInterface);
            deviceInterface = nullptr;
            return false;
        }
 
        //Load the pipe references
        GetPipeRefs();
 
        //Create Async Notifications
        //TODO: Release this event..
        CFRunLoopSourceRef asyncEventSource;
        kr = (*interface)->CreateInterfaceAsyncEventSource(interface, &asyncEventSource);
        CFRunLoopAddSource(CFRunLoopGetCurrent(), asyncEventSource, kCFRunLoopDefaultMode);
 
        IOObjectRelease(usbDevice);
        IOObjectRelease(iterator);
        return true;
    }
 
    return false;
}

void USBDevice::Close()
{
    if (interface)
    {
        (*interface)->USBInterfaceClose(interface);
        (*interface)->Release(interface);
        interface = nullptr;
    }
 
    if (deviceInterface)
    {
        (*deviceInterface)->USBDeviceClose(deviceInterface);
        (*deviceInterface)->Release(deviceInterface);
        deviceInterface = nullptr;
    }
}

kern_return_t USBDevice::GetPipeStatus(std::uint8_t pipeRef)
{
    if (interface)
    {
        return (*interface)->GetPipeStatus(interface, pipeRef);
    }
 
    return kIOReturnNotOpen;
}

NumVersion USBDevice::GetDriverVersion()
{
    if (interface)
    {
        NumVersion ioUSBLibVersion;
        NumVersion usbFamilyVersion;
        (*interface)->GetIOUSBLibVersion(interface, &ioUSBLibVersion, &usbFamilyVersion);
        return ioUSBLibVersion;
    }
 
    return NumVersion{0};
}

std::uint8_t USBDevice::GetControlPipeRef()
{
    return controlPipeRef;
}

std::uint8_t USBDevice::GetReadPipeRef()
{
    return readPipeRef;
}

std::uint8_t USBDevice::GetWritePipeRef()
{
    return writePipeRef;
}

void onReadAsync(void *refcon, IOReturn result, void *arg0)
{
 
}

void onWriteAsync(void *refcon, IOReturn result, void *arg0)
{
 
}

int USBDevice::Read(std::uint8_t* buffer, std::size_t bufferSize)
{
    if (interface)
    {
        UInt8 pipeRef = readPipeRef;
        UInt32 size = static_cast<UInt32>(bufferSize);
        kern_return_t res = (*interface)->ReadPipe(interface, pipeRef, buffer, &size);
        return res != kIOReturnSuccess ? -1 : static_cast<int>(size);
    }
    return -1;
}

int USBDevice::ReadAsync(std::uint8_t* buffer, std::size_t bufferSize)
{
    if (interface)
    {
        UInt8 pipeRef = readPipeRef;
        UInt32 size = static_cast<UInt32>(bufferSize);
        kern_return_t res = (*interface)->ReadPipeAsync(interface, pipeRef, buffer, size, onReadAsync, this);
        return res != kIOReturnSuccess ? -1 : static_cast<int>(size);
    }
    return -1;
}

int USBDevice::Write(uint8_t* buffer, size_t bufferSize)
{
    UInt8 pipeRef = writePipeRef;
    int packetSize = GetMaxPipePacketSize(pipeRef);
 
    size_t bytesWritten = 0;
    int bytesRemaining = static_cast<int>(bufferSize);
 
    auto internal_write = [&](std::uint8_t pipeRef, std::uint8_t* buffer, std::size_t bufferSize) {
        kern_return_t res = (*interface)->WritePipe(interface, pipeRef, buffer, static_cast<int>(bufferSize));
        return res != kIOReturnSuccess ? -1 : static_cast<int>(bufferSize);
    };
 
    while (bytesRemaining > 0)
    {
        size_t bytesToWrite = std::min(bytesRemaining, packetSize);
        auto retVal = internal_write(pipeRef, &buffer[bytesWritten], bytesToWrite);
        if (retVal < 0)
        {
            return retVal;
        }
        else if (retVal < static_cast<int>(bytesToWrite))
        {
            return static_cast<int>(bytesWritten) + retVal;
        }
 
        bytesWritten += retVal;
        bytesRemaining -= retVal;
    }
 
    return static_cast<int>(bytesWritten);
}

int USBDevice::WriteAsync(std::uint8_t* buffer, std::size_t bufferSize)
{
    UInt8 pipeRef = writePipeRef;
    int packetSize = GetMaxPipePacketSize(pipeRef);
 
    size_t bytesWritten = 0;
    int bytesRemaining = static_cast<int>(bufferSize);
 
    auto internal_write = [&](std::uint8_t pipeRef, std::uint8_t* buffer, std::size_t bufferSize) {
        kern_return_t res = (*interface)->WritePipeAsync(interface, pipeRef, buffer, static_cast<int>(bufferSize), onWriteAsync, this);
        return res != kIOReturnSuccess ? -1 : static_cast<int>(bufferSize);
    };
 
    while (bytesRemaining > 0)
    {
        size_t bytesToWrite = std::min(bytesRemaining, packetSize);
        auto retVal = internal_write(pipeRef, &buffer[bytesWritten], bytesToWrite);
        if (retVal < 0)
        {
            return retVal;
        }
        else if (retVal < static_cast<int>(bytesToWrite))
        {
            return static_cast<int>(bytesWritten) + retVal;
        }
 
        bytesWritten += retVal;
        bytesRemaining -= retVal;
    }
 
    return static_cast<int>(bytesWritten);
}

int USBDevice::SendDeviceRequest(int requesttype, int request, int value, int index, char *bytes, int size, int timeout)
{
    if (!deviceInterface)
    {
        return -1;
    }
 
    //If there's no timeout.. just send a regular request..
    if (timeout <= 0)
    {
        IOUSBDevRequest req;
        req.bmRequestType = requesttype;
        req.bRequest = request;
        req.wValue = value;
        req.wIndex = index;
        req.wLength = size;
        req.pData = bytes;
 
        kern_return_t result = (*deviceInterface)->DeviceRequest(deviceInterface, &req);
        return result != kIOReturnSuccess ? -1 : req.wLenDone; //Bytes Transferred..
    }
 
    //Send Timeout request..
    IOUSBDevRequestTO req;
    req.bmRequestType = requesttype;
    req.bRequest = request;
    req.wValue = value;
    req.wIndex = index;
    req.wLength = size;
    req.pData = bytes;
    req.completionTimeout = timeout;
 
    kern_return_t result = (*deviceInterface)->DeviceRequestTO(deviceInterface, &req);
    return result != kIOReturnSuccess ? -1 : req.wLenDone; //Bytes Transferred..
}

int USBDevice::SendControlRequest(int requesttype, int request, int value, int index, char *bytes, int size, int timeout)
{
    if (!interface)
    {
        return -1;
    }
 
    //If there's no timeout.. just send a regular request..
    if (timeout <= 0)
    {
        IOUSBDevRequest req;
        req.bmRequestType = requesttype;
        req.bRequest = request;
        req.wValue = value;
        req.wIndex = index;
        req.wLength = size;
        req.pData = bytes;
 
        kern_return_t result = (*interface)->ControlRequest(interface, controlPipeRef, &req);
        return result != kIOReturnSuccess ? -1 : req.wLenDone; //Bytes Transferred..
    }
 
    //Send Timeout request..
    IOUSBDevRequestTO req;
    req.bmRequestType = requesttype;
    req.bRequest = request;
    req.wValue = value;
    req.wIndex = index;
    req.wLength = size;
    req.pData = bytes;
    req.completionTimeout = timeout;
 
    kern_return_t result = (*interface)->ControlRequestTO(interface, controlPipeRef, &req);
    return result != kIOReturnSuccess ? -1 : req.wLenDone; //Bytes Transferred..
}

int USBDevice::SendRawRequest(IOUSBDevRequest *request)
{
    if (!deviceInterface)
    {
        return -1;
    }
    kern_return_t result = (*deviceInterface)->DeviceRequest(deviceInterface, request);
    return result != kIOReturnSuccess ? -1 : request->wLenDone; //Bytes Transferred..
}

int USBDevice::SendRawControlRequest(IOUSBDevRequest *request, std::uint8_t pipeRef)
{
    if (!interface)
    {
        return -1;
    }
    kern_return_t result = (*interface)->ControlRequest(interface, pipeRef, request);
    return result != kIOReturnSuccess ? -1 : request->wLenDone; //Bytes Transferred..
}

#pragma mark - USB Public

USBDeviceManager::USBDeviceManager() : notificationRegistry(nullptr)
{
}

USBDeviceManager::~USBDeviceManager()
{
    if (this->notificationRegistry)
    {
        USBNotification *notification = static_cast<USBNotification *>(this->notificationRegistry);
        delete notification;
    }
}

std::vector<std::unique_ptr<USBDevice>> USBDeviceManager::GetDevicesMatching(std::string service, int vendorId, int productId)
{
    io_iterator_t iter = 0;
 
    /// Find Matching Services
    CFMutableDictionaryRef matchingDict = IOServiceMatching(service.c_str());
    if (matchingDict == nil)
    {
        return std::vector<std::unique_ptr<USBDevice>> {};
    }
 
    /// Added VendorID and ProductID to query
    CFNumberRef numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vendorId);
    CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID), numberRef);
    CFRelease(numberRef);
 
    numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &productId);
    CFDictionarySetValue(matchingDict, CFSTR(kUSBProductID), numberRef);
    CFRelease(numberRef);
    numberRef = nullptr;
 
    /// Find devices matching the above criteria
    kern_return_t kr = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, &iter);
    if (kr != KERN_SUCCESS)
    {
        std::cerr<<human_error_string(kr)<<"\n";
        return std::vector<std::unique_ptr<USBDevice>> {};
    }
 
    /// Iterate over all devices
    io_service_t device = 0;
    std::vector<std::unique_ptr<USBDevice>> devices;
    while ((device = IOIteratorNext(iter)))
    {
        devices.push_back(std::unique_ptr<USBDevice>(new USBDevice(device)));
    }
 
    IOObjectRelease(iter);
    return devices;
}

void USBDeviceManager::RegisterForDeviceNotifications(std::string service, int vendorId, int productId, void(*onDeviceAdded)(USBDevice *device), void(*onDeviceDisconnected)(USBDevice *device))
{
    /// Find Matching Services
    CFMutableDictionaryRef matchingDict = IOServiceMatching(service.c_str());
    if (matchingDict == nil)
    {
        return;
    }
 
    /// Added VendorID and ProductID to query
    CFNumberRef numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vendorId);
    CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID), numberRef);
    CFRelease(numberRef);
 
    numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &productId);
    CFDictionarySetValue(matchingDict, CFSTR(kUSBProductID), numberRef);
    CFRelease(numberRef);
    numberRef = nullptr;
 
    // Setup notifications for when the device is available
    USBNotification *notificationInfo = new USBNotification();
    notificationInfo->_this = this;
    notificationInfo->onDeviceAdded = onDeviceAdded;
    notificationInfo->onDeviceDisconnected = onDeviceDisconnected;
    notificationInfo->notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
    notificationInfo->runLoop = CFRunLoopGetCurrent();
    notificationInfo->deviceAddedIterator = 0;
    notificationInfo->deviceRemovedIterator = 0;
    this->notificationRegistry = notificationInfo;
 
    CFRunLoopSourceRef runLoopSource = IONotificationPortGetRunLoopSource(notificationInfo->notificationPort);
    CFRunLoopAddSource(notificationInfo->runLoop, runLoopSource, kCFRunLoopDefaultMode);
 
    // Now set up a notification to be called when a device is matched and detached by I/O Kit.
    kern_return_t rc;
//    rc = IOServiceAddMatchingNotification(notificationInfo->notificationPort,
//                                          kIOTerminatedNotification,
//                                          matchingDict,
//                                          DeviceDisconnected,
//                                          notificationInfo, //userInfo
//                                          &notificationInfo->deviceRemovedIterator);
//
//    if (rc != kIOReturnSuccess)
//    {
//        IONotificationPortDestroy(notificationInfo->notificationPort);
//        delete notificationInfo;
//        std::cerr<<human_error_string(rc)<<"\n";
//        return;
//    }
 
    // Now set up a notification to be called when a device is matched and attached by I/O Kit.
    rc = IOServiceAddMatchingNotification(notificationInfo->notificationPort,
                                          kIOMatchedNotification,
                                          matchingDict,
                                          DeviceAdded,
                                          notificationInfo, //userInfo
                                          &notificationInfo->deviceAddedIterator);
 
    if (rc != kIOReturnSuccess)
    {
        IONotificationPortDestroy(notificationInfo->notificationPort);
        delete notificationInfo;
        std::cerr<<human_error_string(rc)<<"\n";
        return;
    }
 
//    DeviceDisconnected(notificationInfo, notificationInfo->deviceRemovedIterator);
    DeviceAdded(notificationInfo, notificationInfo->deviceAddedIterator);
}

// When a device has been plugged into the phone's serial port, this function will get called
void DeviceAdded(void *userInfo, io_iterator_t iterator)
{
    kern_return_t kr;
    io_service_t usbDevice;
 
    USBNotification *notificationInfo = static_cast<USBNotification *>(userInfo);
 
    // Iterate over all devices..
    while ((usbDevice = IOIteratorNext(iterator))) {
 
        DeviceMessage* notificationMessage = new DeviceMessage();
        notificationMessage->_this = new USBDevice(usbDevice);
        notificationMessage->notification = notificationInfo;
 
        if (notificationInfo->onDeviceAdded)
        {
            notificationInfo->onDeviceAdded(notificationMessage->_this);
        }
 
        // Register for Device Notifications.. IE: Disconnected Notification..
        kr = IOServiceAddInterestNotification(notificationInfo->notificationPort,
                                              usbDevice,
                                              kIOGeneralInterest,
                                              DeviceMessageReceived,
                                              notificationMessage, //userInfo
                                              &notificationInfo->notification);
        // Cleanup
        kr = IOObjectRelease(usbDevice);
    }
}

// When a device has been unplugged from the phone's serial port, this function will get called.
void DeviceDisconnected(void *userInfo, io_iterator_t iterator)
{
    USBNotification *notificationInfo = static_cast<USBNotification *>(userInfo);
    if (notificationInfo->onDeviceDisconnected)
    {
        notificationInfo->onDeviceDisconnected(nullptr);
    }
 
    // Cleanup
    IOObjectRelease(notificationInfo->notification);
    delete notificationInfo;
}

// When a device message has been received..
void DeviceMessageReceived(void* userInfo, io_service_t service, uint32_t messageType, void* messageArgument)
{
    DeviceMessage *message = static_cast<DeviceMessage *>(userInfo);
 
    // If it's the disconnect message, we need to cleanup..
    if (messageType == kIOMessageServiceIsTerminated)
    {
        if (message->notification && message->notification->onDeviceDisconnected)
        {
            message->notification->onDeviceDisconnected(message->_this);
        }
 
        // Cleanup
//        IOObjectRelease(message->notification->notificationPort);
        delete message;
    }
}


Then you use it for Nintendo Switch like:

main.mm:
Code:
//
//  main.m
//  USBLoader
//
//  Created by Brandon on 2018-05-30.
//  Copyright © 2018 XIO. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <IOKit/IOKitLib.h>
#import <IOKit/usb/IOUSBLib.h>
#import <IOKit/IOCFPlugIn.h>
#import <IOKit/IOMessage.h>
#import <IOKit/IOBSD.h>
#include <vector>
#include <iostream>
#include "USBDevice.hxx"

//Include some headers that read the fusee.bin and intermezzo and create the Fusee Gelee Payload..
#include "Fusee.h"

// Helper file to try to smash the stack..
#include "Smash.hpp"

//Nintendo Constants
#define kNintendoSwitchVendorID 0x0955
#define kNintendoSwitchProductID 0x7321

#pragma mark - Utilities

void displayStrings(std::vector<std::string> strings)
{
    for (std::string& str : strings)
    {
        std::cout<<str<<"\n";
    }
}

void displayStrings(NSArray<NSString *> *strings)
{
    for (NSString *str in strings)
    {
        NSLog(@"%@", str);
    }
}

void onDeviceAdded(USBDevice *device)
{
    if (!device->Open())
    {
        std::cerr<<"Cannot Open Device\n";
        return;
    }
 
    std::string manufacturer = device->GetManufacturer();
    std::string name = device->GetName();
    std::string clazz = device->GetClass();
    std::string path = device->GetPath();
    std::int32_t vendorId = device->GetVendorID();
    std::int32_t productId = device->GetProductID();
    std::uint32_t locationId = device->GetLocationID();
 
    displayStrings({
        "       Device Information",
        "-----------------------------------",
        string_format("Manufacturer: %s", manufacturer.c_str()),
        string_format("Name: %s", name.c_str()),
        string_format("Class: %s", clazz.c_str()),
        string_format("Path: %s", path.c_str()),
        string_format("VendorId: 0x%04X", vendorId),
        string_format("ProductId: 0x%04X", productId),
        string_format("LocationId: 0x%04X", locationId)
    });
 
    //device->ClearPipe(device->GetReadPipeRef(), 10);
    //device->ClearPipe(device->GetWritePipeRef(), 10);  //I don't have async event in the above class yet (it'll take a few lines of code to fix.. this function uses async read.. if changed to just read, it'll work).. in fact I think I can remove the read all together and just call clear stall.. - TODO: Brandon T investigate.
 
    uint8_t deviceId[0x10] = {0};
    if (device->Read(deviceId, sizeof(deviceId)) != sizeof(deviceId))
    {
        displayStrings({"Cannot Read Device-ID"});
        return;
    }
 
    std::cout<<"\n\n";
    std::string deviceSerialNumber = string_format("%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
                                                   (uint32_t)deviceId[0],
                                                   (uint32_t)deviceId[1],
                                                   (uint32_t)deviceId[2],
                                                   (uint32_t)deviceId[3],
                                                   (uint32_t)deviceId[4],
                                                   (uint32_t)deviceId[5],
                                                   (uint32_t)deviceId[6],
                                                   (uint32_t)deviceId[7],
                                                   (uint32_t)deviceId[8],
                                                   (uint32_t)deviceId[9],
                                                   (uint32_t)deviceId[10],
                                                   (uint32_t)deviceId[11],
                                                   (uint32_t)deviceId[12],
                                                   (uint32_t)deviceId[13],
                                                   (uint32_t)deviceId[14],
                                                   (uint32_t)deviceId[15]);
 
    displayStrings({
        string_format("Device Id: %s\n\n", deviceSerialNumber.c_str()),
        "Loading Payload"
    });
 
    auto payload = createRCMPayload(intermezzo, fusee);
 
    displayStrings({"Uploading Payload"});
    smash(device, payload);
 
    device->Close();
    return;
}

void onDeviceDisconnected(USBDevice *device)
{
    std::cout<<"Device Disconnected\n";
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        USBDeviceManager device;
        device.RegisterForDeviceNotifications("IOUSBHostDevice",
                                              kNintendoSwitchVendorID,
                                              kNintendoSwitchProductID,
                                              onDeviceAdded,
                                              onDeviceDisconnected);
        CFRunLoopRun();
    }
    return 0;
}


It uploads the payload successfully.. I just can't get it to freaking smash the damn stack.. grr.. Also, once you "read" the deviceId, the control of the device is switched so you CANNOT run the code again without restarting the device.. I tried libusb and it behaves the same way so it means the code above is working as it should.. I just have to figure out how to smash the stack and that's it.


Functions I added: "human_error_string" will print out any errors from IOKit as human readable strings =]
The USBDeviceManager will load all the devices that match the vendor and product. You will see when you plug in the switch, it will display:

y6fd2ID.png




Once I figure out how to "Transfer Control" after uploading the payload, I will post here or upload the code or something to the github.

I think we got fairly far.. just need the last step.. Btw, I tested the above on my iPhone 6S.. Same output. Still no control transfer..

Once you send the payload, you ask the Switch for the status with a control request with USB_REQ_GET_STATUS, with a ridiculously large length (0x7000). That is what smashes the stack. Check the last 5 lines of code of

https://github.com/DavidBuchanan314/fusee-nano/blob/master/src/exploit.c

and last 30 or so lines of

https://github.com/DavidBuchanan314/fusee-nano/blob/master/src/usb.c
 
Last edited by Dread_Pirate_PJ,
  • Like
Reactions: snoofly

JustBrandonT

Well-Known Member
Newcomer
Joined
Mar 11, 2018
Messages
75
Trophies
0
Age
34
XP
518
Country
Canada
I figured it out by writing a driver for OSX but for iOS, it only worked HALF the time (maybe I missed something).. In any case, I compiled libusb for iOS by modifying the OSTypes.h file and switching the project to compile for iphone-os release.

Then I wrote a wrapper around libusb that does the same stuff my OSX driver does to send control properly over the usb port.. There's no IOCTL for iOS and OSX usb port apparently..

So in any case.. I got it working on both platforms:

I'll upload what I have later and someone else can make it look pretty or add logs or w/e.. or I'll do it when I have time. For now, enjoy the video.. I gotta head out for a few :D

P.S. Sorry for the vertical vid. I was holding the my phone side-ways but I guess I screwed that up ={
 
Last edited by JustBrandonT,

Lil_SpazJoekp

Well-Known Member
Newcomer
Joined
Apr 11, 2018
Messages
89
Trophies
0
Age
27
XP
373
Country
United States
I figured it out by writing a driver for OSX but for iOS, it only worked HALF the time (maybe I missed something).. In any case, I compiled libusb for iOS by modifying the OSTypes.h file and switching the project to compile for iphone-os release.

Then I wrote a wrapper around libusb that does the same stuff my OSX driver does to send control properly over the usb port.. There's no IOCTL for iOS and OSX usb port apparently..

So in any case.. I got it working on both platforms:

I'll upload what I have later and someone else can make it look pretty or add logs or w/e.. or I'll do it when I have time. For now, enjoy the video.. I gotta head out for a few :D

P.S. Sorry for the vertical vid. I was holding the my phone side-ways but I guess I screwed that up ={

Awesome work! Can't wait to see the app. When you commit the changes, I will see what I can do to make it pretty!:D
 

metaljay

Well-Known Member
Member
Joined
Jan 10, 2012
Messages
466
Trophies
1
XP
1,901
Country
I figured it out by writing a driver for OSX but for iOS, it only worked HALF the time (maybe I missed something).. In any case, I compiled libusb for iOS by modifying the OSTypes.h file and switching the project to compile for iphone-os release.

Then I wrote a wrapper around libusb that does the same stuff my OSX driver does to send control properly over the usb port.. There's no IOCTL for iOS and OSX usb port apparently..

So in any case.. I got it working on both platforms:

I'll upload what I have later and someone else can make it look pretty or add logs or w/e.. or I'll do it when I have time. For now, enjoy the video.. I gotta head out for a few :D

P.S. Sorry for the vertical vid. I was holding the my phone side-ways but I guess I screwed that up ={

Excellent work bro!
 

Lil_SpazJoekp

Well-Known Member
Newcomer
Joined
Apr 11, 2018
Messages
89
Trophies
0
Age
27
XP
373
Country
United States
I figured it out by writing a driver for OSX but for iOS, it only worked HALF the time (maybe I missed something).. In any case, I compiled libusb for iOS by modifying the OSTypes.h file and switching the project to compile for iphone-os release.

Then I wrote a wrapper around libusb that does the same stuff my OSX driver does to send control properly over the usb port.. There's no IOCTL for iOS and OSX usb port apparently..

So in any case.. I got it working on both platforms:

I'll upload what I have later and someone else can make it look pretty or add logs or w/e.. or I'll do it when I have time. For now, enjoy the video.. I gotta head out for a few :D

P.S. Sorry for the vertical vid. I was holding the my phone side-ways but I guess I screwed that up ={

Okay. I have the ui mostly made. I'm just waiting on the code from you to start linking things together. This is starting to come together awesome. @Dread_Pirate_PJ have you made any progress?
 

JustBrandonT

Well-Known Member
Newcomer
Joined
Mar 11, 2018
Messages
75
Trophies
0
Age
34
XP
518
Country
Canada
I uploaded the code already. I have to put the code to generate a payload on the fly and that's all that's left. I redid the UI too.
Right now it loads the exploit from a .bin file and uploads it. I'd rather make it generate the exploit like all the others. Should take about 5 minutes or so to write.


https://github.com/Brandon-T/iOUSB/blob/master/iOSNXLauncher/NXLauncher.mm#L20

That's about it. I made it in such a way that you just have to provide an interface and it'd work with any 3rd party library. The code uses lib-usb OR Apple's IOKit. The IOKit is buggy so I disabled it for now and I just use lib-usb. All you have to do is compile it. I mean.. I can compile an ipa and release it I guess..

Again, I never tested it on an un-jailbroken iPhone. So don't go buying cables yet until I or someone else does test it. It's very likely that you'd have to jailbreak.
 
Last edited by JustBrandonT,

Lil_SpazJoekp

Well-Known Member
Newcomer
Joined
Apr 11, 2018
Messages
89
Trophies
0
Age
27
XP
373
Country
United States
I uploaded the code already. I have to put the code to generate a payload on the fly and that's all that's left. I redid the UI too.
Right now it loads the exploit from a .bin file and uploads it. I'd rather make it generate the exploit like all the others. Should take about 5 minutes or so to write.


https://github.com/Brandon-T/iOUSB/blob/master/iOSNXLauncher/NXLauncher.mm#L20

That's about it. I made it in such a way that you just have to provide an interface and it'd work with any 3rd party library. The code uses lib-usb OR Apple's IOKit. The IOKit is buggy so I disabled it for now and I just use lib-usb. All you have to do is compile it. I mean.. I can compile an ipa and release it I guess..

Again, I never tested it on an un-jailbroken iPhone. So don't go buying cables yet until I or someone else does test it. It's very likely that you'd have to jailbreak.
I’ll test it with my X on iOS 12 dev beta 1 tomorrow
 

Lil_SpazJoekp

Well-Known Member
Newcomer
Joined
Apr 11, 2018
Messages
89
Trophies
0
Age
27
XP
373
Country
United States
I uploaded the code already. I have to put the code to generate a payload on the fly and that's all that's left. I redid the UI too.
Right now it loads the exploit from a .bin file and uploads it. I'd rather make it generate the exploit like all the others. Should take about 5 minutes or so to write.


https://github.com/Brandon-T/iOUSB/blob/master/iOSNXLauncher/NXLauncher.mm#L20

That's about it. I made it in such a way that you just have to provide an interface and it'd work with any 3rd party library. The code uses lib-usb OR Apple's IOKit. The IOKit is buggy so I disabled it for now and I just use lib-usb. All you have to do is compile it. I mean.. I can compile an ipa and release it I guess..

Again, I never tested it on an un-jailbroken iPhone. So don't go buying cables yet until I or someone else does test it. It's very likely that you'd have to jailbreak.
Okay so I guess I'm either retarded or missing something. I keep getting an error saying that libusb/libusb.h is not found when running it. I found a libusb.h file here https://github.com/libusb/libusb added and still didn't work. Also I saw that libusb-1.0.0.dylib was missing so I used this here: https://github.com/qmk/qmk_flasher/blob/master/dfu/libusb-1.0.0.dylib added it and still still not running. Is there something I'm doing wrong or am I just retarded.
 

Dread_Pirate_PJ

Well-Known Member
Newcomer
Joined
Feb 24, 2018
Messages
64
Trophies
0
Age
53
XP
178
Country
United States
Okay so I guess I'm either retarded or missing something. I keep getting an error saying that libusb/libusb.h is not found when running it. I found a libusb.h file here https://github.com/libusb/libusb added and still didn't work. Also I saw that libusb-1.0.0.dylib was missing so I used this here: https://github.com/qmk/qmk_flasher/blob/master/dfu/libusb-1.0.0.dylib added it and still still not running. Is there something I'm doing wrong or am I just retarded.

The libusb-1.0.0.dylib has to be compiled for iOS. dylibs are used in Mac OS also, but a Mac OS compiled dylib won't work on an iOS device. You can't just grab it from some random Github project.

The easiest way is to git clone the libusb repo and change the Xcode project to build for iOS, then build it.

To fix the libusb/libusb.h issue, add the path of the libusb repo clone to Header prefix path in project settings.
 
Last edited by Dread_Pirate_PJ,

Lil_SpazJoekp

Well-Known Member
Newcomer
Joined
Apr 11, 2018
Messages
89
Trophies
0
Age
27
XP
373
Country
United States
The libusb-1.0.0.dylib has to be compiled for iOS. dylibs are used in Mac OS also, but a Mac OS compiled dylib won't work on an iOS device. You can't just grab it from some random Github project.

The easiest way is to git clone the libusb repo and change the Xcode project to build for iOS, then build it.

To fix the libusb/libusb.h issue, add the path of the libusb repo clone to Header prefix path in project settings.
Thats what I was just figuring out. I just didn't know what to do for building the libusb.
 

Dread_Pirate_PJ

Well-Known Member
Newcomer
Joined
Feb 24, 2018
Messages
64
Trophies
0
Age
53
XP
178
Country
United States
Thats what I was just figuring out. I just didn't know what to do for building the libusb.

To build libusb for iOS, find the Xcode project in libusb/Xcode, select the libusb target, and change the Build settings.

Base SDK - Latest iOS
Supported Platforms - iOS
Valid architectures - arm64 armv7 armv7s
 

Lil_SpazJoekp

Well-Known Member
Newcomer
Joined
Apr 11, 2018
Messages
89
Trophies
0
Age
27
XP
373
Country
United States
To build libusb for iOS, find the Xcode project in libusb/Xcode, select the libusb target, and change the Build settings.

Base SDK - Latest iOS
Supported Platforms - iOS
Valid architectures - arm64 armv7 armv7s
Okay here's what I have.
It builds successfully but I don't know where the file is spit out at.

Also, thank you for helping.:D
 

Attachments

  • Screen Shot 2018-06-08 at 6.44.09 PM.png
    Screen Shot 2018-06-08 at 6.44.09 PM.png
    75.3 KB · Views: 271

Dread_Pirate_PJ

Well-Known Member
Newcomer
Joined
Feb 24, 2018
Messages
64
Trophies
0
Age
53
XP
178
Country
United States
Okay here's what I have.
It builds successfully but I don't know where the file is spit out at.

Also, thank you for helping.:D

In the Xcode project, scroll all the way down to Products in the navigator (the file/group tree on the left). Listed under Products are the different things you can build. Right click on libusb-1.0.0.dylib and select "Show in Finder". Then you can copy and paste the file wherever you need.
 

Dread_Pirate_PJ

Well-Known Member
Newcomer
Joined
Feb 24, 2018
Messages
64
Trophies
0
Age
53
XP
178
Country
United States
I was able to successfully build the latest copy of the project, but it seems the app can't detect the Switch is in APX mode. Taping "Reload" does nothing.

I have a breakpoint in NXLauncher.mm line 41 and the devices array is empty.

Maybe I have a bad build. @JustBrandonT can you post your ipa?
 

GraFfiX420

Well-Known Member
Member
Joined
Oct 14, 2009
Messages
465
Trophies
1
XP
1,593
Country
United States
Never really worked with Xcode, wtf?? I'm simply trying to move some headers etc to be included in the project and am having issues, lots of stuff missing from IOKit that I find elsewhere on my mac.
 

datahoarder

Organized.
Member
Joined
Jul 7, 2007
Messages
567
Trophies
1
XP
749
Country
United States
It's hilarious to me to see the posts at the beginning of the thread that basically say - no: impossible - then argue about stock vs jailbroken iOS while still claiming it will never happen.. to skipping to the last page, within seven pages, and seeing that there is a functional payload being run from iOS. This is why people who don't know what they're talking about should probably stop commenting in the first place. Fantastic work @JustBrandonT.
 

Site & Scene News

Popular threads in this forum

General chit-chat
Help Users
  • No one is chatting at the moment.
    OctoAori20 @ OctoAori20: Nice nice-