diff --git a/QualcommWireless/QualcommWireless.cpp b/QualcommWireless/QualcommWireless.cpp index a2f9b3b..af9377a 100644 --- a/QualcommWireless/QualcommWireless.cpp +++ b/QualcommWireless/QualcommWireless.cpp @@ -9,6 +9,88 @@ #define super IOService OSDefineMetaClassAndStructors(QualcommWireless, IOService) +struct HciCommandHdr { + uint16_t opcode; + uint8_t len; +} __attribute__((packed)); + +#define MAX_HCI_BUF_LEN 255 +#define HCI_OP_RESET 0x0c03 +#define HCI_OP_LE_SET_SCAN_PARAM 0x200B +#define HCI_OP_LE_SET_SCAN_ENABLE 0x200C + +static const uint8_t sRandomAddressHci[9] = {0x05, 0x20, 0x06, 0x48, 0x1B, 0x7F, 0x3C, 0xF2, 0xEC}; + +typedef IOReturn (*DeviceRequestInternalFn)(IOUSBHostDevice *that, IOService *forClient, StandardUSB::DeviceRequest &request, void *rawBuffer, IOMemoryDescriptor *descriptorBuffer, uint32_t &bytesTransferred, IOUSBHostCompletion *completion, uint32_t completionTimeoutMs); + +static DeviceRequestInternalFn sOrigDeviceRequest = nullptr; +static void **sOrigVtablePtr = nullptr; +static bool sRandomAddressInit = false; +static void *sShadowVtable[512] = {0}; +static size_t sDeviceRequestVtableIndex = 0; + +struct DeviceRequestAccessor : public IOUSBHostDevice { + static size_t getVtableIndex() { + typedef IOReturn (IOUSBHostDevice::*Fn)(IOService*, StandardUSB::DeviceRequest&, void*, IOMemoryDescriptor*, uint32_t&, IOUSBHostCompletion*, uint32_t); + Fn fn = &DeviceRequestAccessor::deviceRequest; + uintptr_t ptrVal = *(uintptr_t *)&fn; + if (ptrVal & 1) { + return (ptrVal - 1) / sizeof(void *); + } + return 0; + } +}; + +static IOReturn hookDeviceRequest(IOUSBHostDevice *that, IOService *forClient, StandardUSB::DeviceRequest &request, void *rawBuffer, IOMemoryDescriptor *descriptorBuffer, uint32_t &bytesTransferred, IOUSBHostCompletion *completion, uint32_t completionTimeoutMs) { + HciCommandHdr *hdr = nullptr; + char hciBuf[MAX_HCI_BUF_LEN] = {0}; + + if (rawBuffer == nullptr) { + if (descriptorBuffer != nullptr) { + descriptorBuffer->prepare(kIODirectionOut); + if (descriptorBuffer->getLength() > 0) { + descriptorBuffer->readBytes(0, hciBuf, (descriptorBuffer->getLength() < MAX_HCI_BUF_LEN) ? descriptorBuffer->getLength() : MAX_HCI_BUF_LEN); + } + descriptorBuffer->complete(kIODirectionOut); + } + hdr = (HciCommandHdr *)hciBuf; + } else { + hdr = (HciCommandHdr *)rawBuffer; + } + + if (hdr) { + if (hdr->opcode == HCI_OP_RESET) { + sRandomAddressInit = false; + } else if (hdr->opcode == HCI_OP_LE_SET_SCAN_PARAM) { + if (!sRandomAddressInit && sOrigDeviceRequest) { + StandardUSB::DeviceRequest randReq; + randReq.bmRequestType = makeDeviceRequestbmRequestType(kRequestDirectionOut, kRequestTypeClass, kRequestRecipientInterface); + randReq.bRequest = 0; + randReq.wIndex = 0; + randReq.wValue = 0; + randReq.wLength = sizeof(sRandomAddressHci); + uint32_t randLen = sizeof(sRandomAddressHci); + + IOBufferMemoryDescriptor *randDesc = IOBufferMemoryDescriptor::withBytes(sRandomAddressHci, sizeof(sRandomAddressHci), kIODirectionOut); + if (randDesc) { + randDesc->prepare(kIODirectionOut); + sOrigDeviceRequest(that, forClient, randReq, nullptr, randDesc, randLen, nullptr, 2000); + randDesc->complete(kIODirectionOut); + randDesc->release(); + } + sRandomAddressInit = true; + IOLog("QualcommWireless: [PATCH] Intercepte LE_SET_SCAN_PARAM -> adresse aleatoire LE injectee au vol !\n"); + } + } + } + + if (!sOrigDeviceRequest) { + return kIOReturnNotReady; + } + + return sOrigDeviceRequest(that, forClient, request, rawBuffer, descriptorBuffer, bytesTransferred, completion, completionTimeoutMs); +} + bool QualcommWireless::init(OSDictionary *dictionary) { if (!super::init(dictionary)) return false; fDevice = nullptr; @@ -406,6 +488,23 @@ bool QualcommWireless::start(IOService *provider) { OSSafeReleaseNULL(intfIter); } + // 4. Installation du hook shadow vtable sur fDevice pour intercepter les requêtes HCI au vol (ex: scan LE) + sDeviceRequestVtableIndex = DeviceRequestAccessor::getVtableIndex(); + if (sDeviceRequestVtableIndex > 0 && sDeviceRequestVtableIndex < 512) { + void **origVtable = *(void ***)fDevice; + if (origVtable && !sOrigDeviceRequest) { + memcpy(sShadowVtable, origVtable, sizeof(sShadowVtable)); + sOrigVtablePtr = origVtable; + sOrigDeviceRequest = (DeviceRequestInternalFn)origVtable[sDeviceRequestVtableIndex]; + sShadowVtable[sDeviceRequestVtableIndex] = (void *)hookDeviceRequest; + *(void ***)fDevice = sShadowVtable; + IOLog("QualcommWireless: Hook shadow vtable installe avec succes (index=%zu, fn=%p) !\n", + sDeviceRequestVtableIndex, (void *)sOrigDeviceRequest); + } + } else { + IOLog("QualcommWireless: Index vtable invalide (%zu).\n", sDeviceRequestVtableIndex); + } + // Délai de 150ms avant de relâcher l'accès exclusif pour garantir que bluetoothd // trouve le contrôleur dans un état parfaitement calme et stabilisé au démarrage. IOSleep(150); @@ -421,6 +520,15 @@ bool QualcommWireless::start(IOService *provider) { void QualcommWireless::stop(IOService *provider) { IOLog("QualcommWireless: Arret du service.\n"); + if (fDevice && sOrigVtablePtr) { + void **currentVtable = *(void ***)fDevice; + if (currentVtable == sShadowVtable) { + *(void ***)fDevice = sOrigVtablePtr; + sOrigVtablePtr = nullptr; + sOrigDeviceRequest = nullptr; + } + } + if (fInterface) { if (fInterface->isOpen(this)) { fInterface->close(this);