В предыдущей статье мы рассказывали про скрытую запись с веб-камеры на C#. Сегодня поговорим про получение информации о подключенных устройствах на C#.
Еще по теме: Программа для прослушки помещения на C#
Получение информации о подключенных устройствах на C#
К целевому компьютеру могут быть подключены разные устройства: флешки, телефоны, мышки, клавиатуры. Для работы с устройствами существует целый класс API.
Например, великий Павел Йосифович в своей книге Windows 10 System Programming Part 1 на странице 540 демонстрирует функцию DisplayDevices(). С ее помощью возможно перечислить подключенные устройства.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
#define INITGUID #include <string> #include <vector> #include <wiaintfc.h> #include <Windows.h> #include <SetupAPI.h> #include <Wiaintfc.h> #include <Ntddvdeo.h> #include <initguid.h> #include <Usbiodef.h> #include <devpkey.h> #include <Ntddkbd.h> #include <ntddmou.h> #include <ntddvdeo.h> #include <locale> #pragma comment(lib, "SetupAPI.lib") struct DeviceInfo { std::wstring SymbolicLink; std::wstring FriendlyName; }; void DisplayDevices(const std::vector<DeviceInfo>& devices, const char* name) { printf("%s\n%s\n", name, std::string(::strlen(name), '-').c_str()); for (auto& di : devices) { printf("Symbolic link: %ws\n", di.SymbolicLink.c_str()); printf(" Name: %ws\n", di.FriendlyName.c_str()); auto hDevice = ::CreateFile(di.SymbolicLink.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); if (hDevice == INVALID_HANDLE_VALUE) printf(" Failed to open device (%d)\n", ::GetLastError()); else { printf(" Device opened successfully!\n"); ::CloseHandle(hDevice); } } printf("\n"); } std::vector<DeviceInfo> EnumDevices(const GUID& guid) { std::vector<DeviceInfo> devices; auto hInfoSet = ::SetupDiGetClassDevs(&guid, nullptr, nullptr, DIGCF_PRESENT | DIGCF_INTERFACEDEVICE); if (hInfoSet == INVALID_HANDLE_VALUE) return devices; devices.reserve(4); SP_INTERFACE_DEVICE_DATA data = { sizeof(data) }; PSP_INTERFACE_DEVICE_DETAIL_DATA DevDetail; SP_DEVINFO_DATA ddata = { sizeof(ddata) }; BYTE buffer[1 << 12]; DWORD dw; for (DWORD i = 0; ; i++) { if (!::SetupDiEnumDeviceInterfaces(hInfoSet, nullptr, &guid, i, &data)) { dw = GetLastError(); break; } ULONG needed, l; ::SetupDiGetDeviceInterfaceDetail(hInfoSet, &data, NULL, 0, &needed, 0); l = needed; DevDetail = (SP_DEVICE_INTERFACE_DETAIL_DATA*)GlobalAlloc(GPTR, l + 4); DevDetail->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA); if (::SetupDiGetDeviceInterfaceDetail(hInfoSet, &data, DevDetail, l, &needed, &ddata)) { DeviceInfo info; info.SymbolicLink = DevDetail->DevicePath; if (::SetupDiGetDeviceRegistryProperty(hInfoSet, &ddata, SPDRP_DEVICEDESC, nullptr, buffer, sizeof(buffer), nullptr)) info.FriendlyName = (WCHAR*)buffer; devices.push_back(std::move(info)); } dw = GetLastError(); } ::SetupDiDestroyDeviceInfoList(hInfoSet); return devices; } int main() { setlocale(LC_ALL, ""); auto devices = EnumDevices(GUID_DEVINTERFACE_IMAGE); DisplayDevices(devices, "Image"); DisplayDevices(EnumDevices(GUID_DEVINTERFACE_MONITOR), "Monitor"); DisplayDevices(EnumDevices(GUID_DEVINTERFACE_DISPLAY_ADAPTER),"Display Adapter"); DisplayDevices(EnumDevices(GUID_DEVINTERFACE_DISK), "Disk"); DisplayDevices(EnumDevices(GUID_DEVINTERFACE_KEYBOARD), "keyboard"); DisplayDevices(EnumDevices(GUID_DEVINTERFACE_USB_DEVICE), "usb"); DisplayDevices(EnumDevices(GUID_DEVINTERFACE_MOUSE), "mouse"); return 0; } |
Что уж тут говорить, для одной только батареи в Windows есть отдельный API — GetSystemPowerStatus().
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#include <iostream> #include <Windows.h> #include <locale> int main() { setlocale(LC_ALL, ""); SYSTEM_POWER_STATUS sps; if (GetSystemPowerStatus(&sps)) { int batteryLifePercent = sps.BatteryLifePercent; if (batteryLifePercent != 255) { std::cout << "Текущий заряд батареи: " << batteryLifePercent << "%" << std::endl; } else { std::cout << "Заряд батареи неизвестен." << std::endl; } } else { std::cout << "Не удалось получить информацию о состоянии питания." << std::endl; } return 0; } |
Кстати, можно злоупотреблять Windows Power Management API: реализовать необычный метод персиста, при котором наш код будет исполняться при включении или отключения дисплея. Подробно можно почитать в этом ресерче VXUG.
Если опускаться чуть ниже, то основное взаимодействие с любым устройством происходит через API DeviceIoControl().
1 2 3 4 5 6 7 8 9 |
BOOL DeviceIoControl( _In_ HANDLE hDevice, _In_ DWORD dwIoControlCode, _In_ LPVOID lpInBuffer, _In_ DWORD nInBufferSize, _Out_ LPVOID lpOutBuffer, _In_ DWORD nOutBufferSize, _Out_opt_ LPDWORD lpBytesReturned, _Inout_opt_ LPOVERLAPPED lpOverlapped); |
Затык может произойти уже на втором аргументе — dwIoControlCode. Для каждого устройства могут быть установлены собственные управляющие коды, что несколько усложняет процесс разработки.
Тем не менее существует несколько средств, которые помогут разобраться с устройствами по API. Рекомендую обратить внимание на DevCon. Это полноценная большая программа, которая позволяет извлекать информацию об устройствах и управлять ими.
Впрочем, для слежения нам достаточно лишь вовремя получать информацию о подключении устройства. Из C# в таком случае проще обращаться к WMI. Я так сделал в проекте USB-Monitor.
Там на помощь пришел WqlEventQuery, с ним мы можем зарегистрировать колбэк, который будет вызван при подключении нового USB-устройства.
Дальше дело за малым — нужно, исходя из поля Service, определить, какое устройство вставили. В случае флешки будет строка USBSTOR, затем нужно конвертировать название физического диска ( \\.\PHYSICALDRIVE) в привычную букву ( E:), а потом просто вывести содержимое папки, чтобы увидеть интересные файлы на флешке.
На C++ можно обрабатывать различные сообщения WM_DEVICE, но для этого требуется создавать оконное приложение, что нам не очень подходит.
Спасибо, Михаил!
ПОЛЕЗНЫЕ ССЫЛКИ:
- Как написать кейлоггер на C#
- Как взломать приложение на C# созданное в Xamarin
- Программы для анализа истории подключения флешек