mimikatz/modules/kull_m_busylight.c

364 lines
12 KiB
C

/* Benjamin DELPY `gentilkiwi`
http://blog.gentilkiwi.com
benjamin@gentilkiwi.com
Licence : https://creativecommons.org/licenses/by/4.0/
*/
#include "kull_m_busylight.h"
const BUSYLIGHT_DEVICE_ID KULL_M_BUSYLIGHT_CATALOG[] = {
{0x27bb, 0x3bca, BUSYLIGHT_CAP_LIGHT | BUSYLIGHT_CAP_SOUND | BUSYLIGHT_CAP_JINGLE_CLIPS, L"Busylight Lync model (with bootloader)"},
{0x27bb, 0x3bcb, BUSYLIGHT_CAP_LIGHT | BUSYLIGHT_CAP_SOUND, L"Busylight UC model"},
{0x27bb, 0x3bcc, BUSYLIGHT_CAP_INPUTEVENT, L"kuandoBOX"},
{0x27bb, 0x3bcd, BUSYLIGHT_CAP_LIGHT | BUSYLIGHT_CAP_SOUND | BUSYLIGHT_CAP_JINGLE_CLIPS, L"Busylight Omega model"},
{0x04d8, 0xf848, BUSYLIGHT_CAP_LIGHT | BUSYLIGHT_CAP_SOUND, L"Busylight Lync model (Microchip Id)"},
{0x0bf8, 0x1020, BUSYLIGHT_CAP_LIGHT, L"Fujitsu MMM2"},
};
const BUSYLIGHT_COLOR
BUSYLIGHT_COLOR_OFF = {0, 0, 0},
BUSYLIGHT_COLOR_RED = {100, 0, 0},
BUSYLIGHT_COLOR_ORANGE = {100, 50, 0},
BUSYLIGHT_COLOR_YELLOW = {100, 100, 0},
BUSYLIGHT_COLOR_CHARTREUSE_GREEN = {50, 100, 0},
BUSYLIGHT_COLOR_GREEN = {0, 100, 0},
BUSYLIGHT_COLOR_SPRING_GREEN = {0, 100, 50},
BUSYLIGHT_COLOR_CYAN = {0, 100, 100},
BUSYLIGHT_COLOR_AZURE = {0, 50, 100},
BUSYLIGHT_COLOR_BLUE = {0, 0, 100},
BUSYLIGHT_COLOR_VIOLET = {50, 0, 100},
BUSYLIGHT_COLOR_MAGENTA = {100, 0, 100},
BUSYLIGHT_COLOR_ROSE = {100, 0, 50},
BUSYLIGHT_COLOR_WHITE = {100, 100, 100}
;
PCBUSYLIGHT_DEVICE_ID kull_m_busylight_devices_getIdFromAttributes(PHIDD_ATTRIBUTES attributes)
{
DWORD i;
if(attributes)
for(i = 0; i < ARRAYSIZE(KULL_M_BUSYLIGHT_CATALOG); i++)
if((KULL_M_BUSYLIGHT_CATALOG[i].Vid == attributes->VendorID) && (KULL_M_BUSYLIGHT_CATALOG[i].Pid == attributes->ProductID))
return &KULL_M_BUSYLIGHT_CATALOG[i];
return NULL;
}
BOOL kull_m_busylight_devices_get(PBUSYLIGHT_DEVICE *devices, DWORD *count, DWORD mask, BOOL bAutoThread)
{
PBUSYLIGHT_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;
PCBUSYLIGHT_DEVICE_ID deviceId;
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(deviceId = kull_m_busylight_devices_getIdFromAttributes(&attributes))
{
if((deviceId->Capabilities & mask) == mask)
{
if(*next = (PBUSYLIGHT_DEVICE) LocalAlloc(LPTR, sizeof(BUSYLIGHT_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)->deviceId = deviceId;
(*next)->dpi.box_sensivity = 4;
(*next)->dpi.box_timeout = 4;
(*next)->dpi.box_triggertime = 85;
(*next)->id = id;
(*next)->hBusy = CreateFile(DeviceInterfaceDetailData->DevicePath, FILE_READ_DATA | FILE_WRITE_DATA, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if((*next)->hBusy && ((*next)->hBusy != INVALID_HANDLE_VALUE))
{
if(bAutoThread)
{
(*next)->dKeepAliveThread = 5000;
if((*next)->hKeepAliveThread = CreateThread(NULL, 0, kull_m_busylight_keepAliveThread, *next, 0, NULL))
{
next = &(*next)->next;
id++;
}
else
{
PRINT_ERROR_AUTO(L"CreateThread (hKeepAliveThread)");
CloseHandle((*next)->hBusy);
LocalFree(*next);
}
}
else
{
next = &(*next)->next;
id++;
}
}
else
{
PRINT_ERROR_AUTO(L"CreateFile (hBusy)");
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 kull_m_busylight_devices_free(PBUSYLIGHT_DEVICE devices, BOOL instantOff)
{
PBUSYLIGHT_DEVICE tmp;
while(devices)
{
if(devices->hBusy)
{
if(instantOff && (devices->hBusy != INVALID_HANDLE_VALUE))
kull_m_busylight_request_send_off(devices, FALSE);
CloseHandle(devices->hBusy);
devices->hBusy = NULL;
}
devices->dKeepAliveThread = 0;
if(devices->hKeepAliveThread)
{
TerminateThread(devices->hKeepAliveThread, ERROR_SUCCESS);
devices->hKeepAliveThread = NULL;
}
devices->dWorkerThread = 0;
if(devices->hWorkerThread)
{
TerminateThread(devices->hWorkerThread, ERROR_SUCCESS);
devices->hWorkerThread = NULL;
}
if(devices->DevicePath)
free(devices->DevicePath);
tmp = devices->next;
LocalFree(devices);
devices = tmp;
}
}
BOOL kull_m_busylight_request_create(PCBUSYLIGHT_COMMAND_STEP commands, DWORD count, PBYTE *data, DWORD *size)
{
BOOL status = FALSE;
DWORD i;
USHORT sum;
*size = BUSYLIGHT_OUTPUT_REPORT_SIZE;
if(*data = (PBYTE) LocalAlloc(LPTR, *size))
{
if(count >=7)
PRINT_ERROR(L"count=%u (max is 7)\n", count);
for(i = 0; i < min(count, 7); i++)
{
(*data)[i * 8 + 1] = (commands[i].NextStep & 0xf0) ? commands[i].NextStep : (commands[i].NextStep | 0x10);
(*data)[i * 8 + 2] = commands[i].RepeatInterval;
// TODO avoid color (or not ?)
(*data)[i * 8 + 3] = commands[i].color.red;
(*data)[i * 8 + 4] = commands[i].color.green;
(*data)[i * 8 + 5] = commands[i].color.blue;
(*data)[i * 8 + 6] = commands[i].OnTimeSteps;
(*data)[i * 8 + 7] = commands[i].OffTimeSteps;
(*data)[i * 8 + 8] = commands[i].AudioByte;
}
(*data)[57] = 4;
(*data)[58] = 4;
(*data)[59] = 85;
(*data)[60] = (*data)[61] = (*data)[62] = 0xff;
for(i = 1, sum = 0; i < (*size - 2); i++)
sum += (*data)[i];
(*data)[63] = (BYTE) (sum / 256);
(*data)[64] = (BYTE) (sum % 256);
status = TRUE; // TODO add checks
if(!status)
{
*data = (PBYTE) LocalFree(*data);
*size = 0;
}
}
return status;
}
BOOL kull_m_busylight_device_send_raw(PBUSYLIGHT_DEVICE device, LPCVOID request, DWORD size)
{
BOOL status = FALSE;
DWORD writed;
if(device && device->hBusy && (device->hBusy != INVALID_HANDLE_VALUE))
{
if(size <= device->hidCaps.OutputReportByteLength)
{
status = WriteFile(device->hBusy, request, size, &writed, NULL);
if(!status)
PRINT_ERROR(L"[device %u] WriteFile (0x%08x)\n", device->id, GetLastError());
}
else PRINT_ERROR(L"[device %u] Size is not valide (siz = %u, max = %u)\n", device->id, size, device->hidCaps.OutputReportByteLength);
}
else PRINT_ERROR(L"[device %u] Invalid Device/Busy Handle\n", device->id);
return status;
}
BOOL kull_m_busylight_device_read_raw(PBUSYLIGHT_DEVICE device, LPVOID *data, DWORD *size)
{
BOOL status = FALSE;
DWORD toRead;
if(device && device->hBusy && (device->hBusy != INVALID_HANDLE_VALUE))
{
toRead = device->hidCaps.InputReportByteLength;
if(*data = LocalAlloc(LPTR, toRead))
{
status = ReadFile(device->hBusy, *data, toRead, size, NULL);
if(!status || (status && (*size != toRead)))
{
if(!status)
PRINT_ERROR(L"[device %u] ReadFile (0x%08x)\n", device->id, GetLastError());
else
PRINT_ERROR(L"[device %u] %u byte(s) readed, %u wanted\n", *size, toRead);
*data = LocalFree(*data);
*size = 0;
}
}
}
else PRINT_ERROR(L"[device %u] Invalid Device/Busy Handle\n", device->id);
return status;
}
DWORD WINAPI kull_m_busylight_keepAliveThread(LPVOID lpThreadParameter)
{
PBUSYLIGHT_DEVICE device = (PBUSYLIGHT_DEVICE) lpThreadParameter;
while(device && device->hKeepAliveThread && device->dKeepAliveThread && device->hBusy)
{
if(kull_m_busylight_request_send_keepalive(device, FALSE))
Sleep(device->dKeepAliveThread);
else
{
CloseHandle(device->hBusy);
device->hBusy = NULL;
device->dKeepAliveThread = 0;
device->hKeepAliveThread = NULL;
break;
}
};
return ERROR_SUCCESS;
}
BOOL kull_m_busylight_device_read_infos(PBUSYLIGHT_DEVICE device, BUSYLIGHT_INFO *info)
{
BOOL status = FALSE;
LPBYTE data;
DWORD size;
if(kull_m_busylight_request_send_keepalive(device, FALSE))
{
if(kull_m_busylight_device_read_raw(device, (LPVOID *) &data, &size))
{
RtlZeroMemory(info, sizeof(BUSYLIGHT_INFO));
if(status = !data[0])
{
info->status = data[1];
RtlCopyMemory(info->ProductId, data + 2, 3);
RtlCopyMemory(info->CostumerId, data + 5, 8);
RtlCopyMemory(info->Model, data + 13, 4);
RtlCopyMemory(info->Serial, data + 17, 8);
RtlCopyMemory(info->Mfg_ID, data + 25, 8);
RtlCopyMemory(info->Mfg_Date, data + 33, 8);
RtlCopyMemory(info->swrelease, data + 41, 6);
}
else PRINT_ERROR(L"[device %u] data[0] is not NULL (0x%02x)\n", data[0]);
LocalFree(data);
}
}
return status;
}
BOOL kull_m_busylight_request_send(PBUSYLIGHT_DEVICE device, PCBUSYLIGHT_COMMAND_STEP commands, DWORD count, BOOL all)
{
BOOL status = FALSE;
PBUSYLIGHT_DEVICE cur;
LPBYTE data;
DWORD size;
if(status = kull_m_busylight_request_create(commands, count, &data, &size))
{
for(cur = device; cur; cur = all ? cur->next : NULL)
status &= kull_m_busylight_device_send_raw(cur, data, size);
LocalFree(data);
}
return status;
}
BOOL kull_m_busylight_request_send_keepalive(PBUSYLIGHT_DEVICE device, BOOL all)
{
BUSYLIGHT_COMMAND_STEP mdl = {0x8f, 0, {0, 0, 0}, 0, 0, 0};
return kull_m_busylight_request_send(device, &mdl, 1, all);
}
BOOL kull_m_busylight_request_send_off(PBUSYLIGHT_DEVICE device, BOOL all)
{
PBUSYLIGHT_DEVICE cur;
BUSYLIGHT_COMMAND_STEP mdl = {0, 0, {0, 0, 0}, 0, 0, BUSYLIGHT_MEDIA_MUTE};
for(cur = device; cur; cur = all ? cur->next : NULL)
{
cur->dWorkerThread = 0;
if(cur->hWorkerThread)
{
TerminateThread(cur->hWorkerThread, ERROR_SUCCESS);
cur->hWorkerThread = NULL;
}
}
return kull_m_busylight_request_send(device, &mdl, 1, all);
}
BOOL kull_m_busylight_request_single_send(PBUSYLIGHT_DEVICE device, const BUSYLIGHT_COLOR * color, BYTE sound, BYTE volume, BOOL all)
{
BUSYLIGHT_COMMAND_STEP mdl = {0, 0, {color->red, color->green, color->blue}, 0, 0, BUSYLIGHT_MEDIA(sound, volume)};
return kull_m_busylight_request_send(device, &mdl, 1, all);
}