#include "precomp.h" // --------------------------------------------------------------------------- // [ÇïÆÛ ÇÔ¼ö] URB Àü¼Û ¹× ¸Þ¸ð¸® ÇØÁ¦ ·ÎÁ÷ (±âÁ¸ ÄÚµå À¯Áö) // --------------------------------------------------------------------------- NTSTATUS UDF_CallUSBDI(IN PDEVICE_OBJECT pDevObj, IN PVOID UrbEtc) { IO_STATUS_BLOCK IoStatus; KEVENT event; NTSTATUS status; PIRP Irp = NULL; PIO_STACK_LOCATION NextIrpStack = NULL; KeInitializeEvent(&event, NotificationEvent, FALSE); Irp = IoBuildDeviceIoControlRequest( IOCTL_INTERNAL_USB_SUBMIT_URB, pDevObj, NULL, 0, NULL, 0, TRUE, &event, &IoStatus); NextIrpStack = IoGetNextIrpStackLocation(Irp); NextIrpStack->Parameters.Others.Argument1 = UrbEtc; NextIrpStack->Parameters.Others.Argument2 = (PVOID)0; status = IoCallDriver(pDevObj, Irp); if (status == STATUS_PENDING) { status = KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL); status = IoStatus.Status; } return status; } PURB AllocUrb(USHORT Size) { PURB urb = ExAllocatePoolWithTag(NonPagedPool, Size, 'PURB'); if (urb) RtlZeroMemory(urb, Size); return urb; } VOID FreeUsbDeviceInfo(IN PUSB_PARSED_INFO pInfo) { if (!pInfo) return; if (pInfo->ManufacturerStr) ExFreePool(pInfo->ManufacturerStr); if (pInfo->ProductStr) ExFreePool(pInfo->ProductStr); if (pInfo->SerialNumberStr) ExFreePool(pInfo->SerialNumberStr); if (pInfo->ConfigDesc) ExFreePool(pInfo->ConfigDesc); ExFreePool(pInfo); } NTSTATUS GetUsbDeviceDescriptor(IN PDEVICE_OBJECT DeviceObject, OUT PUSB_DEVICE_DESCRIPTOR* ppDescriptor) { PURB urb = AllocUrb(sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST)); if (!urb) return STATUS_INSUFFICIENT_RESOURCES; PUSB_DEVICE_DESCRIPTOR descriptor = ExAllocatePoolWithTag(NonPagedPool, sizeof(USB_DEVICE_DESCRIPTOR), 'DST'); if (!descriptor) { ExFreePool(urb); return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory(descriptor, sizeof(USB_DEVICE_DESCRIPTOR)); UsbBuildGetDescriptorRequest(urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), USB_DEVICE_DESCRIPTOR_TYPE, 0, 0, descriptor, NULL, sizeof(USB_DEVICE_DESCRIPTOR), NULL); NTSTATUS status = UDF_CallUSBDI(DeviceObject, urb); if (!NT_SUCCESS(status)) { ExFreePool(descriptor); *ppDescriptor = NULL; } else { *ppDescriptor = descriptor; } ExFreePool(urb); return status; } NTSTATUS GetUsbStringDescriptor(IN PDEVICE_OBJECT DeviceObject, IN UCHAR Index, IN USHORT LangId, OUT PWCHAR* ppStringData) { if (Index == 0) return STATUS_INVALID_PARAMETER; PURB urb = AllocUrb(sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST)); if (!urb) return STATUS_INSUFFICIENT_RESOURCES; ULONG size = 256; PUSB_STRING_DESCRIPTOR pStrDesc = ExAllocatePoolWithTag(NonPagedPool, size, 'STR'); if (!pStrDesc) { ExFreePool(urb); return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory(pStrDesc, size); UsbBuildGetDescriptorRequest(urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), USB_STRING_DESCRIPTOR_TYPE, Index, LangId, pStrDesc, NULL, size, NULL); NTSTATUS status = UDF_CallUSBDI(DeviceObject, urb); if (NT_SUCCESS(status) && pStrDesc->bLength > 2) { ULONG strLenBytes = pStrDesc->bLength - 2; PWCHAR outBuf = ExAllocatePoolWithTag(NonPagedPool, strLenBytes + sizeof(WCHAR), 'STR2'); if (outBuf) { RtlZeroMemory(outBuf, strLenBytes + sizeof(WCHAR)); RtlCopyMemory(outBuf, pStrDesc->bString, strLenBytes); *ppStringData = outBuf; } else { status = STATUS_INSUFFICIENT_RESOURCES; } } else { *ppStringData = NULL; status = STATUS_UNSUCCESSFUL; } ExFreePool(pStrDesc); ExFreePool(urb); return status; } NTSTATUS GetUsbFullConfigDescriptor(IN PDEVICE_OBJECT DeviceObject, OUT PUSB_CONFIGURATION_DESCRIPTOR* ppConfigDesc) { PURB urb = AllocUrb(sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST)); if (!urb) return STATUS_INSUFFICIENT_RESOURCES; PUSB_CONFIGURATION_DESCRIPTOR pHeader = ExAllocatePoolWithTag(NonPagedPool, sizeof(USB_CONFIGURATION_DESCRIPTOR), 'CFG'); if (!pHeader) { ExFreePool(urb); return STATUS_INSUFFICIENT_RESOURCES; } UsbBuildGetDescriptorRequest(urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), USB_CONFIGURATION_DESCRIPTOR_TYPE, 0, 0, pHeader, NULL, sizeof(USB_CONFIGURATION_DESCRIPTOR), NULL); NTSTATUS status = UDF_CallUSBDI(DeviceObject, urb); if (!NT_SUCCESS(status)) { ExFreePool(pHeader); ExFreePool(urb); return status; } ULONG fullSize = pHeader->wTotalLength; ExFreePool(pHeader); PUSB_CONFIGURATION_DESCRIPTOR pFullDesc = ExAllocatePoolWithTag(NonPagedPool, fullSize, 'CFG'); if (!pFullDesc) { ExFreePool(urb); return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory(urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST)); UsbBuildGetDescriptorRequest(urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), USB_CONFIGURATION_DESCRIPTOR_TYPE, 0, 0, pFullDesc, NULL, fullSize, NULL); status = UDF_CallUSBDI(DeviceObject, urb); if (NT_SUCCESS(status)) { *ppConfigDesc = pFullDesc; } else { ExFreePool(pFullDesc); *ppConfigDesc = NULL; } ExFreePool(urb); return status; } NTSTATUS CollectUsbDeviceInfo( IN PDEVICE_OBJECT DeviceObject, OUT PUSB_PARSED_INFO* ppInfo ) { NTSTATUS status; PUSB_PARSED_INFO pInfo = NULL; PUSB_DEVICE_DESCRIPTOR pDevDesc = NULL; USHORT LangId = 0x0409; // English (US) *ppInfo = NULL; if (KeGetCurrentIrql() > APC_LEVEL) return STATUS_INVALID_DEVICE_STATE; pInfo = ExAllocatePoolWithTag(NonPagedPool, sizeof(USB_PARSED_INFO), 'INFO'); if (!pInfo) return STATUS_INSUFFICIENT_RESOURCES; RtlZeroMemory(pInfo, sizeof(USB_PARSED_INFO)); status = GetUsbDeviceDescriptor(DeviceObject, &pDevDesc); if (!NT_SUCCESS(status) || !pDevDesc) { FreeUsbDeviceInfo(pInfo); return status; } RtlCopyMemory(&pInfo->DeviceDesc, pDevDesc, sizeof(USB_DEVICE_DESCRIPTOR)); ExFreePool(pDevDesc); // String Descriptor ¼öÁý if (pInfo->DeviceDesc.iManufacturer) GetUsbStringDescriptor(DeviceObject, pInfo->DeviceDesc.iManufacturer, LangId, &pInfo->ManufacturerStr); if (pInfo->DeviceDesc.iProduct) GetUsbStringDescriptor(DeviceObject, pInfo->DeviceDesc.iProduct, LangId, &pInfo->ProductStr); if (pInfo->DeviceDesc.iSerialNumber) GetUsbStringDescriptor(DeviceObject, pInfo->DeviceDesc.iSerialNumber, LangId, &pInfo->SerialNumberStr); // Configuration Descriptor (Full) ¼öÁý ¹× ¿ø-ÆÐ½º ÆÄ½Ì status = GetUsbFullConfigDescriptor(DeviceObject, &pInfo->ConfigDesc); if (NT_SUCCESS(status) && pInfo->ConfigDesc) { pInfo->ConfigDescSize = pInfo->ConfigDesc->wTotalLength; PUCHAR pCurr = (PUCHAR)pInfo->ConfigDesc; PUCHAR pEnd = pCurr + pInfo->ConfigDescSize; LONG currentInterfaceIndex = -1; if (pCurr + sizeof(USB_CONFIGURATION_DESCRIPTOR) < pEnd) pCurr += ((PUSB_COMMON_DESCRIPTOR)pCurr)->bLength; KLogEx(DEBUG_TRACE_INFO, "[Configuration Descriptor] bNumInterfaces: 0x%X", pInfo->ConfigDesc->bNumInterfaces); while (pCurr < pEnd) { PUSB_COMMON_DESCRIPTOR pCommon = (PUSB_COMMON_DESCRIPTOR)pCurr; if (pCommon->bLength == 0 || pCurr + pCommon->bLength > pEnd) break; // ================================================================= // Interface Descriptor ÆÄ½Ì // ================================================================= if (pCommon->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE) { PUSB_INTERFACE_DESCRIPTOR pIntf = (PUSB_INTERFACE_DESCRIPTOR)pCommon; UCHAR cls = pIntf->bInterfaceClass; UCHAR subCls = pIntf->bInterfaceSubClass; UCHAR proto = pIntf->bInterfaceProtocol; KLogEx(DEBUG_TRACE_INFO, "[Interface Descriptor] bInterfaceNumber: 0x%X, bAlternateSetting: 0x%X, bNumEndpoints: 0x%X, bInterfaceClass: 0x%X, bInterfaceSubClass: 0x%X, bInterfaceProtocol: 0x%X", pIntf->bInterfaceNumber, pIntf->bAlternateSetting, pIntf->bNumEndpoints, pIntf->bInterfaceClass, pIntf->bInterfaceSubClass, pIntf->bInterfaceProtocol ); currentInterfaceIndex = pIntf->bInterfaceNumber; pInfo->FoundClassCount++; if (pInfo->FoundClassCount > 1) pInfo->IsCompositeDevice = TRUE; switch (cls) { case 0x01: pInfo->IsAudio = TRUE; break; case 0x02: pInfo->IsCDC = TRUE; break; case 0x06: case 0x0E: pInfo->IsImageOrVideo = TRUE; break; case 0x07: pInfo->IsPrinter = TRUE; break; case 0x08: pInfo->IsMassStorage = TRUE; break; case 0x09: pInfo->IsHub = TRUE; break; case 0x03: // HID (Űº¸µå, ¸¶¿ì½º, ±âŸ) if (subCls == 0x01) { if (proto == 0x01) pInfo->IsBootKeyboard = TRUE; else if (proto == 0x02) pInfo->IsBootMouse = TRUE; else pInfo->IsAbnormalHID = TRUE; } else if (subCls == 0x00) { pInfo->IsCustomHID = TRUE; } else { pInfo->IsAbnormalHID = TRUE; } if (!pInfo->IsBootKeyboard && !pInfo->IsBootMouse) { pInfo->OtherHidSubClass = subCls; pInfo->OtherHidProtocol = proto; } break; } } // ================================================================= // Endpoint Descriptor ÆÄ½Ì (BadUSB À§Çù ºÐ¼®¿ë) // ================================================================= else if (pCommon->bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE) { PUSB_ENDPOINT_DESCRIPTOR pEp = (PUSB_ENDPOINT_DESCRIPTOR)pCommon; UCHAR epType = pEp->bmAttributes & 0x03; // USB_ENDPOINT_TYPE_MASK KLogEx(DEBUG_TRACE_INFO, "[Endpoint Descriptor] bEndpointAddress: 0x%X, bmAttributes: 0x%X, wMaxPacketSize: 0x%X, bInterval: 0x%X\n", pEp->bEndpointAddress, pEp->bmAttributes, pEp->wMaxPacketSize, pEp->bInterval ); pInfo->TotalEndpoints++; if (epType == USB_ENDPOINT_TYPE_INTERRUPT) { pInfo->InterruptEndpoints++; } else if (epType == USB_ENDPOINT_TYPE_BULK) { pInfo->BulkEndpoints++; } } // ================================================================= // [C] HID Descriptor º°µµ º¸°ü (ÇÊ¿ä ½Ã Report ºÐ¼®¿ë) // ================================================================= else if (pCommon->bDescriptorType == USB_DESCRIPTOR_TYPE_HID) { PUSB_HID_DESCRIPTOR pHid = (PUSB_HID_DESCRIPTOR)pCommon; if (pInfo->HidInterfaceCount < MAX_HID_INTERFACES && currentInterfaceIndex >= 0) { ULONG idx = pInfo->HidInterfaceCount; pInfo->HidEntries[idx].InterfaceNumber = (UCHAR)currentInterfaceIndex; pInfo->HidEntries[idx].HidDesc = pHid; pInfo->HidInterfaceCount++; } } pCurr += pCommon->bLength; } // ================================================================= // [°á·Ð] ÃÖÁ¾ BadUSB ÈÞ¸®½ºÆ½ ÆÇº° (·çÇÁ Á¾·á ÈÄ) // ================================================================= // 1. Bulk¿Í Interrupt°¡ È¥¿ëµÇ¾ú´ÂÁö (¾ÆÀÌÆù, ÇÁ¸°ÅÍ µî º¹ÇÕÀåÄ¡ Ư¼º) if (pInfo->InterruptEndpoints > 0 && pInfo->BulkEndpoints > 0) { pInfo->HasMixedEndpoints = TRUE; } BOOLEAN hasHID = pInfo->IsBootKeyboard || pInfo->IsBootMouse; BOOLEAN hasBothHID = pInfo->IsBootKeyboard && pInfo->IsBootMouse; // 2. ÃÖÁ¾ ÆÇº° ·ÎÁ÷ (¾ÈÀüÇÑ ½ÅÇü ·ÎÁ÷ Àû¿ë) // Á¶°Ç: ÀڱⰡ Űº¸µå³ª ¸¶¿ì½º¶ó°í ÁÖÀåÇϴµ¥, ¾Æ·¡ Áß Çϳª¶óµµ ÇØ´çÇϸé BadUSB·Î Â÷´Ü! // - Űº¸µå¿Í ¸¶¿ì½º°¡ µ¿½Ã¿¡ Á¸Àç (ÇØÄ¿µéÀÌ ÀÚÁÖ ¾¸) // - ÀÎÅÍ·´Æ® ¿£µåÆ÷ÀÎÆ®°¡ 3°³ ÀÌ»óÀ¸·Î ºñÁ¤»óÀûÀ¸·Î ¸¹À½ // - ¿£µåÆ÷ÀÎÆ®°¡ ÀüÇô ¾øÀ½ (°¡Â¥ ÀåÄ¡) // - Űº¸µå¶ó¸é¼­ ´ë¿ë·® Àü¼Û¿ë BULK ¿£µåÆ÷ÀÎÆ®°¡ ¼¯¿© ÀÖÀ½ if (hasBothHID || (hasHID && (pInfo->InterruptEndpoints >= 3 || pInfo->TotalEndpoints == 0 || pInfo->HasMixedEndpoints))) { pInfo->IsBadUSB = TRUE; KLogEx(DEBUG_TRACE_ERROR, "[!!!] MALICIOUS BAD-USB DETECTED! (IntEps: %d, BulkEps: %d)\n", pInfo->InterruptEndpoints, pInfo->BulkEndpoints); } } else { pInfo->ConfigDesc = NULL; pInfo->ConfigDescSize = 0; } *ppInfo = pInfo; return STATUS_SUCCESS; } VOID PrintUsbParsedInfo(IN PUSB_PARSED_INFO pInfo) { if (!pInfo) { KLogEx(DEBUG_TRACE_ERROR, "[-] PrintUsbParsedInfo: pInfo is NULL\n"); return; } // HID Á¤º¸ Ãâ·Â if (pInfo->IsBootKeyboard) KLogEx(DEBUG_TRACE_INFO, " - IsBootKeyboard : TRUE\n"); if (pInfo->IsBootMouse) KLogEx(DEBUG_TRACE_INFO, " - IsBootMouse : TRUE\n"); if (pInfo->IsCustomHID) KLogEx(DEBUG_TRACE_INFO, " - IsCustomHID : TRUE\n"); if (pInfo->IsAbnormalHID) KLogEx(DEBUG_TRACE_INFO, " - IsAbnormalHID : TRUE\n"); // ±âŸ HIDÀÏ °æ¿ì¿¡¸¸ ¼­ºêŬ·¡½º¿Í ÇÁ·ÎÅäÄÝ °ªÀ» Ãâ·Â if (pInfo->IsCustomHID || pInfo->IsAbnormalHID) { KLogEx(DEBUG_TRACE_INFO, " > OtherHidSubClass : 0x%02X\n", pInfo->OtherHidSubClass); KLogEx(DEBUG_TRACE_INFO, " > OtherHidProtocol : 0x%02X\n", pInfo->OtherHidProtocol); } // µð¹ÙÀ̽º Ŭ·¡½º Á¤º¸ Ãâ·Â if (pInfo->IsMassStorage) KLogEx(DEBUG_TRACE_INFO, " - IsMassStorage : TRUE\n"); if (pInfo->IsAudio) KLogEx(DEBUG_TRACE_INFO, " - IsAudio : TRUE\n"); if (pInfo->IsPrinter) KLogEx(DEBUG_TRACE_INFO, " - IsPrinter : TRUE\n"); if (pInfo->IsImageOrVideo) KLogEx(DEBUG_TRACE_INFO, " - IsImageOrVideo : TRUE\n"); if (pInfo->IsHub) KLogEx(DEBUG_TRACE_INFO, " - IsHub : TRUE\n"); if (pInfo->IsCDC) KLogEx(DEBUG_TRACE_INFO, " - IsCDC : TRUE\n"); if (pInfo->IsCompositeDevice) KLogEx(DEBUG_TRACE_INFO, " - IsCompositeDevice : TRUE\n"); KLogEx(DEBUG_TRACE_INFO, " - FoundClassCount : %lu\n", pInfo->FoundClassCount); // 3. BadUSB ¹× ¿£µåÆ÷ÀÎÆ® Á¤º¸ Ãâ·Â KLogEx(DEBUG_TRACE_INFO, "\n[BadUSB & Endpoint Information]\n"); KLogEx(DEBUG_TRACE_INFO, " - TotalEndpoints : %lu\n", pInfo->TotalEndpoints); KLogEx(DEBUG_TRACE_INFO, " - InterruptEndpoints : %lu\n", pInfo->InterruptEndpoints); KLogEx(DEBUG_TRACE_INFO, " - BulkEndpoints : %lu\n", pInfo->BulkEndpoints); if (pInfo->HasMixedEndpoints) KLogEx(DEBUG_TRACE_INFO, " - HasMixedEndpoints : TRUE\n"); // BadUSB ŽÁö ¿©ºÎ´Â ´«¿¡ Àß ¶ç°Ô Ãâ·Â if (pInfo->IsBadUSB) { KLogEx(DEBUG_TRACE_INFO, " - IsBadUSB : *** TRUE (MALICIOUS DEVICE DETECTED!) ***\n"); } }