Comments 31
Мда…
Насколько я понял программа получает какой-то уникальный ID железа, типа материнской платы или даже нескольких устройств. А разве эти данные нельзя как-то перехватить или даже перезаписать, как MAC-адрес?
Я в одном проекте делал: ОС, MAC сетевых адаптеров, модель диска. Не достучался только до серийного номера диска (через ioctl) и BIOS
Не достучался только до серийного номера диска (через ioctl)
ioctl не нужен, вполне отдается через sysfs обычному пользователю: см., например, /sys/bus/scsi/devices/0:0:0:0/wwid
и BIOS
Если речь про DMI, то да, там обычно нужен либо доступ к /dev/mem, либо к чему-нибудь в районе /sys/firmware/dmi — и там тоже все только для root.
В Linux посмотрите ветку /sys/class/dmi/id/
Но наиболее надежный product_uuid обычно
-r--------. 1 root root 4096 Oct 9 13:31 /sys/class/dmi/id/product_uuid
Но имейте в виду, что хоть обычный пользователь и не будет этим заниматься, но подделать все эти ID не сильно сложно: изменив оригинальный образ BIOS и прошить его.
Серийник диска получить тоже реально. Для обычных SATA легче всего, но вот со всякими SAS, NVMe, хитрыми RAID контроллерами уже "геморройнее"...
Статистика как на обычном сайте. Отличие в том что на обычном сайте — вставил код трекинга в футер и все. А программе под винду нужно на каждое событие добавить код трекинга.
Идея претендует на большую полноту, так как предусматривает готовый сервер сбора статистики.
По сути, какая-то специальная библиотека не требуется. Достаточно отправлять collect запросы со своим UA. Не знаю правда как обезопасить себя от подделки запросов, но наверное что-то есть в доках аналитики. Ну на крайняк можно подписывать, заворачивать на свой сервер и оттуда уже в аналитику. Скрипт на PHP на пять строчек по сути.
ProcessorID
не явзяется уникальным идентификатором экземпляра устройства, и даже у разных моделей может совпадать. Готовый UUID
рекомендуют брать у Win32_ComputerSystemProduct
(говорят интернеты).
using (ManagementObjectSearcher mos = new ManagementObjectSearcher())
{
// Процессор
mos.Query = new ObjectQuery("Select * From Win32_processor");
foreach (ManagementObject mo in mos.Get())
{
try
{
CPUid = mo["ProcessorID"].ToString();
}
catch { }
}
// Материнская плата
mos.Query = new ObjectQuery("SELECT * FROM Win32_BaseBoard");
foreach (ManagementObject mo in mos.Get())
{
try
{
MtbId = mo["SerialNumber"].ToString();
}
catch { }
}
// Жесткий диск
ManagementObject dsk = new ManagementObject(@"win32_logicaldisk.deviceid=""C:""");
try
{
DiskId = dsk["VolumeSerialNumber"].ToString();
}
catch { }
finally
{
dsk.Dispose();
}
}
На счет пустых catch — они нужны только для того что бы не вылетало сообщение о необработанном исключении, в случае если не удается определить id «железа». А на счет потока не совсем понял, что там не так.
И кстати по самой теме статьи — NetworkInterface.GetAllNetworkInterfaces() .Where(_ => _.OperationalStatus == OperationalStatus.Up).Select( _ => _.GetPhysicalAddress().ToString())
Счетчик копий программы или сбор статистики об использовании