#include "precomp.h" #include #define _ALLOC_TAG 'kdqw' #define IOCTL_STORAGE_BASE FILE_DEVICE_MASS_STORAGE #define IOCTL_STORAGE_QUERY_PROPERTY CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS) // // struct // typedef enum _STORAGE_QUERY_TYPE { PropertyStandardQuery = 0, PropertyExistsQuery, PropertyMaskQuery, PropertyQueryMaxDefined } STORAGE_QUERY_TYPE, * PSTORAGE_QUERY_TYPE; typedef enum _STORAGE_PROPERTY_ID { StorageDeviceProperty = 0, StorageAdapterProperty, StorageDeviceIdProperty, StorageDeviceUniqueIdProperty, StorageDeviceWriteCacheProperty, StorageMiniportProperty, StorageAccessAlignmentProperty, StorageDeviceSeekPenaltyProperty, StorageDeviceTrimProperty, StorageDeviceWriteAggregationProperty } STORAGE_PROPERTY_ID, * PSTORAGE_PROPERTY_ID; typedef enum _STORAGE_BUS_TYPE { BusTypeUnknown = 0x00, BusTypeScsi, BusTypeAtapi, BusTypeAta, BusType1394, BusTypeSsa, BusTypeFibre, BusTypeUsb, BusTypeRAID, BusTypeiScsi, BusTypeSas, BusTypeSata, BusTypeSd, BusTypeMmc, BusTypeVirtual, BusTypeFileBackedVirtual, BusTypeMax, BusTypeMaxReserved = 0x7F } STORAGE_BUS_TYPE, * PSTORAGE_BUS_TYPE; typedef unsigned char BYTE; typedef struct _STORAGE_PROPERTY_QUERY { STORAGE_PROPERTY_ID PropertyId; STORAGE_QUERY_TYPE QueryType; unsigned char AdditionalParameters[1]; } STORAGE_PROPERTY_QUERY, * PSTORAGE_PROPERTY_QUERY; typedef struct _STORAGE_DEVICE_DESCRIPTOR { DWORD Version; DWORD Size; BYTE DeviceType; BYTE DeviceTypeModifier; BOOLEAN RemovableMedia; BOOLEAN CommandQueueing; DWORD VendorIdOffset; DWORD ProductIdOffset; DWORD ProductRevisionOffset; DWORD SerialNumberOffset; STORAGE_BUS_TYPE BusType; DWORD RawPropertiesLength; BYTE RawDeviceProperties[1]; } STORAGE_DEVICE_DESCRIPTOR, * PSTORAGE_DEVICE_DESCRIPTOR; NTSTATUS GetPhysicalDiskDeviceObject( __in PDEVICE_OBJECT VolumeDeviceObject, __out PDEVICE_OBJECT* PhysicalDiskDeviceObject ) { NTSTATUS status; PIRP Irp; KEVENT Event; IO_STATUS_BLOCK Iosb; PVOLUME_DISK_EXTENTS pDiskExtents = NULL; // ³Ë³ËÇÏ°Ô 4°³ Á¤µµÀÇ Extent °ø°£ È®º¸ ULONG extentsSize = sizeof(VOLUME_DISK_EXTENTS) + (sizeof(DISK_EXTENT) * 4); UNICODE_STRING physicalDiskName; WCHAR nameBuffer[64] = { 0 }; PFILE_OBJECT pFileObject = NULL; PDEVICE_OBJECT pDevObj = NULL; *PhysicalDiskDeviceObject = NULL; // 1. ¸Þ¸ð¸® ÇÒ´ç pDiskExtents = (PVOLUME_DISK_EXTENTS)ExAllocatePoolWithTag(NonPagedPool, extentsSize, 'dExt'); if (!pDiskExtents) return STATUS_INSUFFICIENT_RESOURCES; // ¸Þ¸ð¸® ÃʱâÈ­ (Áß¿ä) RtlZeroMemory(pDiskExtents, extentsSize); KeInitializeEvent(&Event, NotificationEvent, FALSE); Irp = IoBuildDeviceIoControlRequest( IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, VolumeDeviceObject, NULL, 0, pDiskExtents, extentsSize, FALSE, &Event, &Iosb ); if (!Irp) { ExFreePoolWithTag(pDiskExtents, 'dExt'); return STATUS_INSUFFICIENT_RESOURCES; } status = IoCallDriver(VolumeDeviceObject, Irp); if (status == STATUS_PENDING) { KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); status = Iosb.Status; } if (!NT_SUCCESS(status)) { ExFreePoolWithTag(pDiskExtents, 'dExt'); return status; } // [BSOD ¹æÁö ÇÙ½É] Extents °³¼ö È®ÀÎ! if (pDiskExtents->NumberOfDiskExtents == 0) { KLogEx(DEBUG_TRACE_INFO, "No Disk Extents found.\n"); ExFreePoolWithTag(pDiskExtents, 'dExt'); return STATUS_UNSUCCESSFUL; } __try { // 2. ¹°¸® µð½ºÅ© À̸§ »ý¼º ULONG diskNumber = pDiskExtents->Extents[0].DiskNumber; // ¾ÈÀüÇÑ ¹®ÀÚ¿­ ÇÔ¼ö »ç¿ë if (!NT_SUCCESS(RtlStringCbPrintfW(nameBuffer, sizeof(nameBuffer), L"\\Device\\Harddisk%u\\DR0", diskNumber))) { status = STATUS_BUFFER_OVERFLOW; __leave; } RtlInitUnicodeString(&physicalDiskName, nameBuffer); KLogEx(DEBUG_TRACE_INFO, "Trying to open: %S\n", nameBuffer); // 3. µð¹ÙÀ̽º Æ÷ÀÎÅÍ È¹µæ (°¡Àå À§ÇèÇÑ ±¸°£) // InstanceSetup¿¡¼­ ÀÌ È£ÃâÀÌ À§ÇèÇÒ ¼ö ÀÖÀ¸¹Ç·Î ½ÇÆÐ ½Ã Áï½Ã ºüÁ®³ª¿È status = IoGetDeviceObjectPointer( &physicalDiskName, FILE_READ_ATTRIBUTES, // ±ÇÇÑ ÃÖ¼ÒÈ­ &pFileObject, &pDevObj ); if (NT_SUCCESS(status)) { ObReferenceObject(pDevObj); // µð¹ÙÀ̽º °´Ã¼ ÂüÁ¶ ObDereferenceObject(pFileObject); // ÆÄÀÏ °´Ã¼ ´Ý±â *PhysicalDiskDeviceObject = pDevObj; } else { KLogEx(DEBUG_TRACE_ERROR, "IoGetDeviceObjectPointer Failed: 0x%x\n", status); } } __except (EXCEPTION_EXECUTE_HANDLER) { KLogEx(DEBUG_TRACE_ERROR, "Exception in GetPhysicalDiskDeviceObject\n"); status = STATUS_UNHANDLED_EXCEPTION; } ExFreePoolWithTag(pDiskExtents, 'dExt'); return status; } NTSTATUS QueryDeviceProperty( __in PDEVICE_OBJECT pDevice, __in DEVICE_REGISTRY_PROPERTY DevProperty, __out PVOID* ppBuffer, __out PULONG pResultLength ) { NTSTATUS status; PVOID pBuffer = NULL; ULONG BufferSize = 0; ASSERT(ARGUMENT_PRESENT(pDevice)); // sskim - 171122 Added. // FltGetDiskDeviceObject·Î ±¸ÇÑ pDevice´Â PDO¿©¼­ Verifier¿¡¼­ ÅÍÁü (FDO·Î °¡Á®¿À°Ô Ãß°¡) //pDevice = IoGetDeviceAttachmentBaseRef(pDevice); status = IoGetDeviceProperty( pDevice, DevProperty, BufferSize, NULL, &BufferSize ); if (NT_SUCCESS(status)) { return STATUS_NOT_SUPPORTED; } while (status == STATUS_BUFFER_TOO_SMALL) { pBuffer = ExAllocatePoolWithTag(PagedPool, BufferSize, _ALLOC_TAG); if (!pBuffer) { return STATUS_NO_MEMORY; } status = IoGetDeviceProperty( pDevice, DevProperty, BufferSize, pBuffer, &BufferSize ); if (NT_SUCCESS(status)) { *ppBuffer = pBuffer; *pResultLength = BufferSize; return status; } ExFreePool(pBuffer); pBuffer = NULL; } ASSERT(!pBuffer); return status; } //#define QUERY_BUFFER_SIZE 0x2000 //NTSTATUS SafeSetVolumContextParam(PUCHAR pucDest, DWORD dwSize, PUCHAR pucSrc, DWORD dwOffset) //{ // int size = 0; // PCHAR pszName = NULL; // // if (dwOffset == 0) // return STATUS_UNSUCCESSFUL; // // if (dwOffset >= dwSize) // return STATUS_UNSUCCESSFUL; // // if (dwOffset >= (QUERY_BUFFER_SIZE - 10)) // return STATUS_UNSUCCESSFUL; // // pszName = (char*)GetPtr(pucSrc, dwOffset); // size = (int)strlen(pszName); // // KLogEx(DEBUG_TRACE_INFO, "SafeSetVolumContextParam, size(%d)\n", size); // // if (size > VOLUME_DESCRIPTION_LENGTH) // { // size = VOLUME_DESCRIPTION_LENGTH - 1; // } // // RtlCopyMemory(pucDest, pszName, size); // return STATUS_SUCCESS; //} // ¸ÅÅ©·Î Á¤ÀÇ (¾ø´Ù¸é Ãß°¡ ÇÊ¿ä) #ifndef QUERY_BUFFER_SIZE #define QUERY_BUFFER_SIZE 0x2000 #endif // ¾ÈÀüÇÑ Æ÷ÀÎÅÍ °è»ê ¹× º¹»ç ÇÔ¼ö (´ë¹®ÀÚ º¯È¯ Æ÷ÇÔ) NTSTATUS SafeSetVolumContextParam( __in PUCHAR pucDest, // ´ë»ó ¹öÆÛ (Context ³» º¯¼ö) __in ULONG ulSrcTotalSize, // ¿øº» Àüü ¹öÆÛ Å©±â (pDesc->Size) __in PUCHAR pucSrcBase, // ¿øº» ¹öÆÛ ½ÃÀÛ ÁÖ¼Ò (pDesc) __in ULONG ulOffset // ¹®ÀÚ¿­ ¿ÀÇÁ¼Â ) { ULONG i = 0; PCHAR pSrcStr = NULL; // 1. ¿ÀÇÁ¼Â À¯È¿¼º °Ë»ç // ¿ÀÇÁ¼ÂÀÌ 0À̰ųª, ¿øº» ¹öÆÛ Å©±â¸¦ ¹þ¾î³ª¸é ½ÇÆÐ if (ulOffset == 0 || ulOffset >= ulSrcTotalSize) { // Á¤º¸°¡ ¾ø´Â °æ¿ìÀ̹ǷΠ¿¡·¯º¸´Ù´Â ´Ü¼øÈ÷ NULL ó¸®ÇÏ°í ¼º°ø ¸®ÅÏ if (pucDest) pucDest[0] = 0; return STATUS_SUCCESS; } // 2. ¹®ÀÚ¿­ ½ÃÀÛ Æ÷ÀÎÅÍ °è»ê pSrcStr = (PCHAR)(pucSrcBase + ulOffset); // 3. ¹®ÀÚ¿­ º¹»ç ¹× ´ë¹®ÀÚ º¯È¯ ·çÇÁ // Á¶°Ç: // A. ´ë»ó ¹öÆÛ Å©±â(VOLUME_DESCRIPTION_LENGTH - 1)¸¦ ³ÑÁö ¾ÊÀ» °Í // B. ¿øº» ¹öÆÛ ³¡(pucSrcBase + ulSrcTotalSize)À» ³ÑÁö ¾ÊÀ» °Í (Memory Access Violation ¹æÁö) // C. NULL ¹®ÀÚ¸¦ ¸¸³¯ ¶§±îÁö for (i = 0; i < VOLUME_DESCRIPTION_LENGTH - 1; i++) { // ¿øº» ¹öÆÛ ¹üÀ§ üũ (Overflow ¹æÁö) if ((ULONG_PTR)(pSrcStr + i) >= (ULONG_PTR)(pucSrcBase + ulSrcTotalSize)) break; // ¿øº» ¹®ÀÚ¿­ ³¡(NULL) üũ if (pSrcStr[i] == 0) break; // [¿äûÇϽбâ´É] ´ë¹®ÀÚ·Î º¯È¯ÇÏ¿© º¹»ç pucDest[i] = RtlUpperChar(pSrcStr[i]); } // 4. NULL Termination º¸Àå pucDest[i] = 0; KLogEx(DEBUG_TRACE_INFO, "Copied Length(%d), Content(%s)\n", i, pucDest); return STATUS_SUCCESS; } typedef struct _STORAGE_DEVICE_ID_DESCRIPTOR { ULONG Version; ULONG Size; ULONG NumberOfIdentifiers; UCHAR Identifiers[1]; // °¡º¯ ±æÀÌ ¹®ÀÚ¿­ ¹è¿­ } STORAGE_DEVICE_ID_DESCRIPTOR, * PSTORAGE_DEVICE_ID_DESCRIPTOR; NTSTATUS GetStorageDeviceId( __in PDEVICE_OBJECT DeviceObject, __out PWCHAR* OutInstanceId ) { NTSTATUS status = STATUS_SUCCESS; PIRP Irp; KEVENT Event; IO_STATUS_BLOCK Iosb; STORAGE_PROPERTY_QUERY PropQuery = { 0 }; PSTORAGE_DEVICE_ID_DESCRIPTOR pDesc = NULL; PVOID QueryBuffer = NULL; ULONG QuerySize = 1024; // ³Ë³ËÇÏ°Ô ÀâÀ½ *OutInstanceId = NULL; // 1. ¸Þ¸ð¸® ÇÒ´ç QueryBuffer = ExAllocatePoolWithTag(PagedPool, QuerySize, 'StoI'); if (!QueryBuffer) return STATUS_INSUFFICIENT_RESOURCES; RtlZeroMemory(QueryBuffer, QuerySize); // 2. Äõ¸® ¼³Á¤: StorageDeviceIdProperty (Áß¿ä!) PropQuery.PropertyId = StorageDeviceIdProperty; // enum °ª: 2 PropQuery.QueryType = PropertyStandardQuery; KeInitializeEvent(&Event, NotificationEvent, FALSE); // 3. IRP »ý¼º ¹× Àü¼Û Irp = IoBuildDeviceIoControlRequest( IOCTL_STORAGE_QUERY_PROPERTY, DeviceObject, &PropQuery, sizeof(PropQuery), QueryBuffer, QuerySize, FALSE, &Event, &Iosb ); if (!Irp) { ExFreePoolWithTag(QueryBuffer, 'StoI'); return STATUS_INSUFFICIENT_RESOURCES; } status = IoCallDriver(DeviceObject, Irp); if (status == STATUS_PENDING) { KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); status = Iosb.Status; } // 4. °á°ú ÆÄ½Ì if (NT_SUCCESS(status) && Iosb.Information > sizeof(STORAGE_DEVICE_ID_DESCRIPTOR)) { pDesc = (PSTORAGE_DEVICE_ID_DESCRIPTOR)QueryBuffer; if (pDesc->NumberOfIdentifiers > 0) { // Identifiers´Â Null·Î ±¸ºÐµÈ ANSI ¹®ÀÚ¿­µéÀÇ ¹è¿­ÀÔ´Ï´Ù. // ù ¹øÂ° ¹®ÀÚ¿­ÀÌ º¸Åë °¡Àå ±¸Ã¼ÀûÀÎ PnP ID (Hardware ID)ÀÔ´Ï´Ù. PCHAR pAnsiId = (PCHAR)pDesc->Identifiers; // ANSI String -> Unicode String º¯È¯ ÇÊ¿ä ANSI_STRING ansiStr; UNICODE_STRING uniStr; RtlInitAnsiString(&ansiStr, pAnsiId); status = RtlAnsiStringToUnicodeString(&uniStr, &ansiStr, TRUE); // TRUE: Allocate Memory if (NT_SUCCESS(status)) { // È£ÃâÀÚ¿¡°Ô Àü´Þ (È£ÃâÀÚ°¡ ³ªÁß¿¡ ExFreePool ÇØ¾ß ÇÔ) // RtlAnsiStringToUnicodeStringÀÌ ÇÒ´çÇÑ ¹öÆÛ´Â PagedPoolÀÔ´Ï´Ù. // ¿©±â¼­´Â È£ÃâÀÚ°¡ ÆíÇÏ°Ô ¾²µµ·Ï »õ ¹öÆÛ¿¡ º¹»çÇϰųª, uniStr.Buffer¸¦ ±×´ë·Î ÁÝ´Ï´Ù. // ¾ÈÀüÇÏ°Ô º¹»çº»À» ¸¸µé¾î ¸®ÅÏ (NonPagedPool ±ÇÀå ½Ã) ULONG uniSize = uniStr.Length + sizeof(WCHAR); PWCHAR pResult = ExAllocatePoolWithTag(NonPagedPool, uniSize, 'IDst'); if (pResult) { RtlZeroMemory(pResult, uniSize); RtlCopyMemory(pResult, uniStr.Buffer, uniStr.Length); *OutInstanceId = pResult; } RtlFreeUnicodeString(&uniStr); // Àӽà º¯È¯ ¹öÆÛ ÇØÁ¦ } } } ExFreePoolWithTag(QueryBuffer, 'StoI'); return status; } NTSTATUS GetStorageProperty( __in PDEVICE_OBJECT device_object, __in PVOLUME_CONTEXT pVolumeContext ) { PIRP Irp; KEVENT Event; NTSTATUS status = STATUS_SUCCESS; IO_STATUS_BLOCK Iosb; STORAGE_PROPERTY_QUERY PropQuery = { 0, }; PVOID QueryBuffer = NULL; ULONG QuerySize = QUERY_BUFFER_SIZE; PSTORAGE_DEVICE_DESCRIPTOR pDesc; //ULONG size = 0; __try { QueryBuffer = ExAllocatePoolWithTag(PagedPool, QuerySize, _ALLOC_TAG); if (!QueryBuffer) { status = STATUS_INSUFFICIENT_RESOURCES; __leave; } RtlZeroMemory(&PropQuery, sizeof(PropQuery)); RtlZeroMemory(QueryBuffer, QuerySize); PropQuery.PropertyId = StorageDeviceProperty; PropQuery.QueryType = PropertyStandardQuery; KeInitializeEvent(&Event, NotificationEvent, FALSE); Irp = IoBuildDeviceIoControlRequest( IOCTL_STORAGE_QUERY_PROPERTY, device_object, &PropQuery, sizeof(PropQuery), QueryBuffer, QuerySize, FALSE, &Event, &Iosb ); if (!Irp) { status = STATUS_INSUFFICIENT_RESOURCES; __leave; } status = IoCallDriver(device_object, Irp); if (status == STATUS_PENDING) { KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL ); status = Iosb.Status; } if (!NT_SUCCESS(status)) { __leave; } if (Iosb.Information < sizeof(STORAGE_DEVICE_DESCRIPTOR)) { status = STATUS_UNSUCCESSFUL; __leave; } pDesc = (PSTORAGE_DEVICE_DESCRIPTOR)QueryBuffer; if (!pDesc) __leave; if (pDesc->Size > Iosb.Information) { if (pDesc->Size > QuerySize) pDesc->Size = (ULONG)Iosb.Information; } KLogEx(DEBUG_TRACE_INFO, "Version(%x),Size(%x),DeviceType(%x),DeviceTypeModifier(%x)\n", pDesc->Version, pDesc->Size, pDesc->DeviceType, pDesc->DeviceTypeModifier); KLogEx(DEBUG_TRACE_INFO, "bustype(%d),Removal(%d),vidoffset(%x),pidoffset(%x)\n", pDesc->BusType, pDesc->RemovableMedia, pDesc->VendorIdOffset, pDesc->ProductIdOffset); KLogEx(DEBUG_TRACE_INFO, "ProductRevisionOffset(%d),SerialNumberOffset(%d)\n", pDesc->ProductRevisionOffset, pDesc->SerialNumberOffset); pVolumeContext->bustype = pDesc->BusType; SafeSetVolumContextParam(pVolumeContext->vendorid, pDesc->Size, (PUCHAR)pDesc, pDesc->VendorIdOffset); SafeSetVolumContextParam(pVolumeContext->productid, pDesc->Size, (PUCHAR)pDesc, pDesc->ProductIdOffset); SafeSetVolumContextParam(pVolumeContext->productrevisionlevel, pDesc->Size, (PUCHAR)pDesc, pDesc->ProductRevisionOffset); SafeSetVolumContextParam(pVolumeContext->vendorspecific, pDesc->Size, (PUCHAR)pDesc, pDesc->SerialNumberOffset); } __finally { if (QueryBuffer) { ExFreePoolWithTag(QueryBuffer, _ALLOC_TAG); QueryBuffer = NULL; } } return status; } NTSTATUS GetVolumeProperties( __in PCFLT_RELATED_OBJECTS FltObjects, __in PVOLUME_CONTEXT pVolumeContext ) { NTSTATUS status = STATUS_SUCCESS; PDEVICE_OBJECT pDevice = NULL; PVOID pBuffer = NULL; ULONG PropertySize = 0; PWCHAR pDeviceId = NULL; PDEVICE_OBJECT physicalDeviceObject = NULL; ASSERT(ARGUMENT_PRESENT(pVolumeContext)); __try { /*status = FltGetDiskDeviceObject(FltObjects->Volume, &pDevice); if (!NT_SUCCESS(status)) { pDevice = NULL; __leave; }*/ status = GetPhysicalDiskDeviceObject((PDEVICE_OBJECT)FltObjects->Volume, &pDevice); status = GetStorageProperty(pDevice, pVolumeContext); status = QueryDeviceProperty(pDevice, DevicePropertyRemovalPolicy, &pBuffer, &PropertySize); if (NT_SUCCESS(status)) { PDEVICE_REMOVAL_POLICY pRemovalPolicy = (PDEVICE_REMOVAL_POLICY)pBuffer; pVolumeContext->removalpolicy = *pRemovalPolicy; //pVolumeContext->device_object = pDevice; KLogEx(DEBUG_TRACE_INFO, " REMOVAL_POLICY pDevice(%p),removalpolicy(%d)\n", pDevice, pVolumeContext->removalpolicy); ExFreePoolWithTag(pBuffer, _ALLOC_TAG); pBuffer = NULL; } else { KLogEx(DEBUG_TRACE_INFO, "Query DevicePropertyRemovalPolicy Failed 0x%x\n", status); } status = QueryDeviceProperty(pDevice, DevicePropertyHardwareID, &pBuffer, &PropertySize); if (NT_SUCCESS(status)) { KLogEx(DEBUG_TRACE_INFO, "[PnP] Hardware ID: %S\n", pBuffer); ExFreePoolWithTag(pBuffer, _ALLOC_TAG); pBuffer = NULL; } else { KLogEx(DEBUG_TRACE_INFO, "Query DevicePropertyHardwareID Failed 0x%x\n", status); } status = GetStorageDeviceId(pDevice, &pDeviceId); if (NT_SUCCESS(status) && pDeviceId != NULL) { KLogEx(DEBUG_TRACE_INFO, "Found Device ID: %S\n", pDeviceId); // °á°ú ¿¹½Ã: "USB\VID_346D&PID_5678&REV_0100" // ¿©±â¼­ ¹®ÀÚ¿­ ÆÄ½ÌÇÏ¿© Á¤Ã¥ Àû¿ë ExFreePoolWithTag(pDeviceId, 'IDst'); } else { KLogEx(DEBUG_TRACE_INFO, "[IOCTL] Failed 0x%x. Trying PnP Query...\n", status); // ================================================================= // ½Ãµµ 2: PnP ¹æ½Ä (PDO¿¡°Ô ¿äû) - HardwareID / InstanceID // ================================================================= // IOCTLÀ» ó¸®ÇÏ´Â FDOÀÇ °¡Àå ¹Ø¹Ù´Ú(PDO)À» ±¸ÇÕ´Ï´Ù. physicalDeviceObject = IoGetDeviceAttachmentBaseRef(pDevice); if (physicalDeviceObject) { // PnP Äõ¸®´Â PDO¿¡°Ô ÇØ¾ß ÇÕ´Ï´Ù. // DevicePropertyHardwareID (¸®½ºÆ®) ¶Ç´Â DevicePropertyInstanceID (´ÜÀÏ) ½Ãµµ PWCHAR pHardwareId = NULL; // º¸Åë HardwareID°¡ °¡Àå È®½ÇÇÏ°Ô Á¤º¸(VID/PID)¸¦ ÁÝ´Ï´Ù. // HardwareID´Â MULTI_SZ Çü½ÄÀ̹ǷΠù ¹øÂ° ¹®ÀÚ¿­¸¸ ¾²¸é µË´Ï´Ù. status = QueryDeviceProperty(physicalDeviceObject, DevicePropertyHardwareID, &pHardwareId, &PropertySize); if (NT_SUCCESS(status) && pHardwareId) { KLogEx(DEBUG_TRACE_INFO, "[PnP] Hardware ID: %S\n", pHardwareId); ExFreePoolWithTag(pHardwareId, _ALLOC_TAG); } else { KLogEx(DEBUG_TRACE_INFO, "[PnP] Query DevicePropertyHardwareID Failed 0x%x\n", status); } ObDereferenceObject(physicalDeviceObject); } } status = STATUS_SUCCESS; } __finally { if (pDevice) ObDereferenceObject(pDevice); } return status; }