А ещё кейлогер туда можно засунуть и пароли его банковские подглядеть.
Мда…
Ну зачем уж в крайности впадать :)
Всё-таки привязка к «железу» — довольно перспективное направление, вы довольно хорошо показали его применение помимо лицензирования.
И как получение уникального ID работает в скопированной виртуалке? Или защита такой надёжности не требуется?
На счет виртуальных машин. Проверял в VirtualBox — система отдавала почему-то ноль, либо выбрасывала исключение, сейчас уже не помню какое. А вот в vmWare все работало нормально.
К сожалению только винда, в линуксе данный метод не работает. Я под обычным пользователем так и не смог добраться до системной информации
До какой именно?
Я в одном проекте делал: ОС, MAC сетевых адаптеров, модель диска. Не достучался только до серийного номера диска (через ioctl) и BIOS
Не достучался только до серийного номера диска (через ioctl)

ioctl не нужен, вполне отдается через sysfs обычному пользователю: см., например, /sys/bus/scsi/devices/0:0:0:0/wwid


и BIOS

Если речь про DMI, то да, там обычно нужен либо доступ к /dev/mem, либо к чему-нибудь в районе /sys/firmware/dmi — и там тоже все только для root.

вот спасибо про
/sys/bus/scsi/devices/0:0:0:0/wwid

я через sysfs как раз получаю модель диска, но вот серийный номер… тогда не нашёл такого параметра
Спасибо, буду пробовать
Хотел получить серийник матери и диска. Под виндой использовал WMI а в линукс версии так и не добрался

В 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 контроллерами уже "геморройнее"...

Я делаю портативную программу, запускаемую даже с флешки. И естественно без рута. Но спасибо, попробую.
Как бороться со злонамеренной отправкой миллиона рандомных записей?
HMAC подпись?
Да, есть такая дыра, на практике я использовал шифрование отправляемых данных (aes). На стороне сервера расшифровывал, проверял, если все ОК, то только тогда закидывал в БД.
В чём проблема вытащить ключ из программы и самим шифровать всё что вздумается и отправлять на сервер?
Для этого ее нужно будет дизассемблировать, а потом рыться в IL коде. От нефик делать желающих немного найдется. Хотя… По крайней мере, я ничего другого не придумал…
Уже давно есть декомпиляторы и деобфускаторы, с которыми можно смотреть С# (конечно код далеко не всегда идентичен оригиналу). Посмотрите на ILSpy, dnSpy (мне больше всего он нравится), dotPeek.
Из деобфускаторов наверное de4dot
Подозреваю, тут надо бояться не этого, а того, что на сервере пользовательский ввод никак не фильтруется и при должной сноровке любой желающий может получить неограниченный доступ к БД.
Пользуемся CSharpAnalytics. Позволяет отправлять данные в google analytics и потом смотреть красивые отчеты — количество онлайн, среднее время работы, ошибки, счетчики, переходы между окнами.
Статистика как на обычном сайте. Отличие в том что на обычном сайте — вставил код трекинга в футер и все. А программе под винду нужно на каждое событие добавить код трекинга.
Спасибо за идею, посмотрю!
Идея претендует на большую полноту, так как предусматривает готовый сервер сбора статистики.
Почему-то сразу подумал про гугло-аналитику. Они позволяют отслеживать что угодно, можно хоть входящих в магазин людей считать при желании.

По сути, какая-то специальная библиотека не требуется. Достаточно отправлять collect запросы со своим UA. Не знаю правда как обезопасить себя от подделки запросов, но наверное что-то есть в доках аналитики. Ну на крайняк можно подписывать, заворачивать на свой сервер и оттуда уже в аналитику. Скрипт на PHP на пять строчек по сути.

ProcessorID не явзяется уникальным идентификатором экземпляра устройства, и даже у разных моделей может совпадать. Готовый UUID рекомендуют брать у Win32_ComputerSystemProduct (говорят интернеты).

Я бы сделал автообновление (проверка на наличие их при работе) — и считал бы загрузки таких обновлений.
Можете назвать меня привередой, но если уж пишете реальный код в примерах, то соблюдайте хотябы минимальную гигиену- у вас в C# коде нету ни одного вызова Dispose или использования using, причем вы открываете кучу unmanaged дескрипторов. Я уже не говорю про пустые catch и ваш весьма сомнительный подход к управлению потоками.
Согласен с замечанием, вот так будет правильнее:
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 «железа». А на счет потока не совсем понял, что там не так.
Во первых пустые кетчи это не красиво. Во вторых, в общих чертах вы пытаетесь сгенерировать хеш оборудования, и то что вы просто пропускаете ошибки не обрабатывая увеличивет количество коллизий. По управлению потоком — вы стартуете поток в Registration(). А где возможность его остановить? А где обработка ThreadAbortException?
И кстати по самой теме статьи — NetworkInterface.GetAllNetworkInterfaces() .Where(_ => _.OperationalStatus == OperationalStatus.Up).Select( _ => _.GetPhysicalAddress().ToString())
Согласен, код неидеален, но он и не является закрытым. Любой может взять его за основу, доработать и убрать ошибки.
Спасибо за критику.
Всё это здорово, но только в одном случае — если программу выпустят в сеть. А в общем случае никто условный калькулятор или блокнот туда не пустит в принципе. Более того, если такое приложение вдруг полезет в сеть без очевидной для пользователя нужды, это плохо скажется на его репутации.
Только полноправные пользователи могут оставлять комментарии.
Войдите, пожалуйста.