/* Benjamin DELPY `gentilkiwi` https://blog.gentilkiwi.com benjamin@gentilkiwi.com Licence : https://creativecommons.org/licenses/by/4.0/ */ #include "kull_m_rdm.h" BOOL rdm_get_version(HANDLE hFile, PSTR *version) { BOOL status = FALSE; BYTE *data, szData; if(rdm_send_receive(hFile, RDM_IOCTL_GET_VERSION, NULL, 0, &data, &szData)) { if(data) { if(*version = (PSTR) LocalAlloc(LPTR, szData + 1)) { RtlCopyMemory(*version, data, szData); status = TRUE; } LocalFree(data); } } return status; } BOOL rdm_send_receive(HANDLE hFile, BYTE ctl, LPCVOID in, BYTE szIn, LPBYTE *out, BYTE *szOut) { BOOL status = FALSE; BYTE i, crc, data[0x100] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 6 + szIn, 0x00, 0xaa, 0x00 /*addr*/, 1 + szIn, ctl, /* data[..], crc, 0xbb */}; USHORT bigSize; LPCWCHAR error; if(szIn <= 242) { if(szIn) RtlCopyMemory(data + 12, in, szIn); for(i = 0, crc = 0; i < (szIn + 2); i++) crc ^= data[10 + i]; data[12 + szIn] = crc; data[12 + szIn + 1] = 0xbb; kprintf(L">> "); kull_m_string_wprintf_hex(data, 14 + szIn, 1); kprintf(L"\n"); Sleep(RDM_SLEEP_BEFORE_SEND); if(HidD_SetFeature(hFile, data, sizeof(data))) { Sleep(RDM_SLEEP_BEFORE_RECV); if(HidD_GetFeature(hFile, data, sizeof(data))) { if(data[0] == 0x03) { bigSize = *(PUSHORT) (data + 6); if((bigSize >= 6) && (bigSize <= (242 + 6))) { kprintf(L"<< "); kull_m_string_wprintf_hex(data, bigSize + 8, 1); kprintf(L"\n"); szIn = (BYTE) (bigSize - 6); if(data[8] == 0xaa) { if((data[10] - 1) == szIn) { for(i = 0, crc = 0; i < (szIn + 2); i++) crc ^= data[10 + i]; if(crc == data[12 + szIn]) { if(data[12 + szIn + 1] = 0xbb) { switch(data[11]) { case 0x00: // command OK case 0xff: status = TRUE; if(out && szOut) { *out = NULL; *szOut = 0; if(szIn) { if(*out = (PBYTE) LocalAlloc(LPTR, szIn)) { RtlCopyMemory(*out, data + 12, szIn); *szOut = szIn; } else status = FALSE; } } error = NULL; break; case 0x01: // command failure if(szIn == 1) { switch(data[12]) { case 0x80: error = L"set OK"; break; case 0x81: error = L"set failure"; break; case 0x82: error = L"reader reply timeout"; break; case 0x83: error = L"card does not exist"; break; case 0x84: error = L"data response from the card"; break; case 0x85: error = L"format or parameter of the command"; break; case 0x87: error = L"unknown internal error"; break; case 0x8a: error = L"initVal process"; break; case 0x8b: error = L"wrong SNR during anticollision"; break; case 0x8c: error = L"authentication failure"; break; case 0x8f: error = L"reader received unknown command"; break; case 0x90: error = L"card does not support this command"; break; case 0x91: error = L"format of the command"; break; case 0x92: error = L"does not support option mode"; break; case 0x93: error = L"block does not exist"; break; case 0x94: error = L"object has been locked"; break; case 0x95: error = L"lock operation did not succeed"; break; case 0x96: error = L"operation did not succeed"; break; default: L"unknow error code!"; } PRINT_ERROR(L"Command failure: 0x%02x - %s\n", data[12], error); } else PRINT_ERROR(L"data size is not 1 when dealing when an error status (%hhu)\n", szIn); error = NULL; break; case 0x02: error = L"checksum"; break; case 0x03: error = L"not COM port selected"; break; case 0x04: error = L"timeout reply"; break; case 0x05: error = L"check sequence"; break; case 0x07: error = L"receive"; break; case 0x0a: error = L"parameter value out of range"; break; default: error = L"unknow error code!"; } if(error) PRINT_ERROR(L"Status failure: 0x%02x - %s\n", data[11], error); } else PRINT_ERROR(L"Bad China footer (0x%02x)\n", data[12 + szIn + 1]); } else PRINT_ERROR(L"Bad CRC (0x%02x -- 0x%02x)\n", crc, data[12 + szIn]); } else PRINT_ERROR(L"Bad HID size vs Data size (0x%02x -- 0x%02x)\n", szIn, data[10] - 1); } else PRINT_ERROR(L"Bad China header (0x%02x)\n", data[8]); } else PRINT_ERROR(L"Bad HID size (%hhu)\n", bigSize); } else PRINT_ERROR(L"Bad HID header (0x%02x)\n", data[0]); } else PRINT_ERROR_AUTO(L"HidD_GetFeature"); } else PRINT_ERROR_AUTO(L"HidD_SetFeature"); } else PRINT_ERROR(L"Size >= 242 (%hhu)\n", szIn); return status; } BOOL rdm_devices_get(PRDM_DEVICE *devices, DWORD *count) { PRDM_DEVICE *next = devices; GUID guidHid; HDEVINFO hDevInfo; SP_DEVICE_INTERFACE_DATA DeviceInterfaceData; BOOL enumStatus; DWORD enumIndex, dwRequired, id = 0; PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData; HANDLE deviceHandle; HIDD_ATTRIBUTES attributes; PHIDP_PREPARSED_DATA PreparsedData; NTSTATUS status; *next = NULL; HidD_GetHidGuid(&guidHid); hDevInfo = SetupDiGetClassDevs(&guidHid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); if(hDevInfo != INVALID_HANDLE_VALUE) { for(enumIndex = 0, enumStatus = TRUE; enumStatus; enumIndex++) { DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); if(enumStatus = SetupDiEnumDeviceInterfaces(hDevInfo, NULL, &guidHid, enumIndex, &DeviceInterfaceData)) { dwRequired = 0; if(!SetupDiGetDeviceInterfaceDetail(hDevInfo, &DeviceInterfaceData, NULL, 0, &dwRequired, NULL) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) { if(DeviceInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA) LocalAlloc(LPTR, dwRequired)) { DeviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); if(SetupDiGetDeviceInterfaceDetail(hDevInfo, &DeviceInterfaceData, DeviceInterfaceDetailData, dwRequired, &dwRequired, NULL)) { deviceHandle = CreateFile(DeviceInterfaceDetailData->DevicePath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if(deviceHandle != INVALID_HANDLE_VALUE) { attributes.Size = sizeof(HIDD_ATTRIBUTES); if(HidD_GetAttributes(deviceHandle, &attributes)) { if((attributes.VendorID == 0xffff) && (attributes.ProductID == 0x0035)) { if(*next = (PRDM_DEVICE) LocalAlloc(LPTR, sizeof(RDM_DEVICE))) { if(HidD_GetPreparsedData(deviceHandle, &PreparsedData)) { status = HidP_GetCaps(PreparsedData, &(*next)->hidCaps); if(!NT_SUCCESS(status)) PRINT_ERROR(L"HidP_GetCaps (%08x)\n", status); HidD_FreePreparsedData(PreparsedData); } (*next)->DevicePath = _wcsdup(DeviceInterfaceDetailData->DevicePath); (*next)->hidAttributes = attributes; (*next)->id = id; (*next)->hDevice = CreateFile(DeviceInterfaceDetailData->DevicePath, FILE_READ_DATA | FILE_WRITE_DATA, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if((*next)->hDevice && ((*next)->hDevice != INVALID_HANDLE_VALUE)) { next = &(*next)->next; id++; } else { if(GetLastError() != ERROR_ACCESS_DENIED) PRINT_ERROR_AUTO(L"CreateFile (hDevice)"); *next = (PRDM_DEVICE) LocalFree(*next); } } } } CloseHandle(deviceHandle); } else PRINT_ERROR_AUTO(L"CreateFile (deviceHandle)"); } LocalFree(DeviceInterfaceDetailData); } } } } SetupDiDestroyDeviceInfoList(hDevInfo); } else PRINT_ERROR_AUTO(L"SetupDiGetClassDevs"); if(count) *count = id; return (id > 0); } void rdm_devices_free(PRDM_DEVICE devices) { PRDM_DEVICE tmp; while(devices) { if(devices->hDevice) { CloseHandle(devices->hDevice); devices->hDevice = NULL; } if(devices->DevicePath) free(devices->DevicePath); tmp = devices->next; LocalFree(devices); devices = tmp; } }