Узнать серийный номер флешки

Delphi

Как-то встала передо мной задача – написать программу-сторож, позволяющую использовать только разрешенные USB-флешки на определенных компьютерах. Привязку решил делать к серийному номеру, а так же VID и PID флешки (Vendor ID и Part ID), что в общем случае можно считать уникальной информацией.

Я сейчас не рассматриваю способы перепрошивки флешек под произвольный VID, PID, Serial, это всё можно сделать, подобрав соответствующую утилитку под производителя контроллера.

Итак, нависла задача узнать всю нужную информацию. Сейчас я не буду рассматривать разработку целого приложения, покажу лишь основную функцию. Буду даже рад, если кто-то поможет доработать программу. Да и сам я буду постоянно улучшать и модернизировать этот код.

Итак, для выбора данных воспользуемся моим любимым WMI (Windows Management Instrumentation). Почему оно мне нравится? Да потому что все работает “из коробки”, не нужно устанавливать дополнительные программы и компоненты и есть множество классов.

Вот видео по теме:

Как работать с технологией – посмотрите по тегам WMI, WMIC, а я повествую дальше.

Выковыривать данные будет из строки идентификатора устройства, которая выглядит как-то так:

USB\VID_152D&PID_2329\0FD2ACBFFFFF

В этой строке есть VID, PID и серийный номер после второй косой черты.

Важно не перепутать серийный номер флешки и серийный номер тома. Последний (можно получить командой dir) меняется при форматировании флешки и никак не годится для уникальной идентификации.

Механизм получения серийного номера флешки

Теперь задача – получить строку эту.

Средствами WMI мы получаем эту информацию из класса Win32_usbhub, объявленного в пространстве \\root\cimv2

Итак, запускаем командную строку, там программу wmic.

wmic
wmic

Пишем там команду выбора поля DeviceID из класса Win32_usbhub. Забегая вперед скажу, что выдастся много устройств (корневые концентраторы, мышь и т.д.,) поэтому я сразу напишу фильтр по запоминающим устройствам.

wmic:root\cli>path win32_usbhub Where (Caption="Запоминающее устройство для USB") get DeviceID

wmic path get where
wmic path get where

Вот и получили наши заветные строки. Парсить их придется уже другими средствами.

Кстати, вот наработка на Delphi, кому-то может это пригодится.


unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ComCtrls, StdCtrls;
type
TForm1 = class(TForm)
lst1: TListBox;
btn1: TButton;
procedure btn1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses ActiveX, ComObj;
procedure TForm1.btn1Click(Sender: TObject);
Var Enumerator: IEnumVariant;
WbemLocator, WbemServices, WbemObjectSet: Variant;
Properties: IEnumVariant;
Property_, System: OleVariant;
j: LongWord;
sProperty: string;
VID,PID,Serial: ShortString;
begin
lst1.Clear;
WbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
WbemServices := WbemLocator.ConnectServer;
WbemObjectSet := WbemServices.InstancesOf('Win32_usbhub');
Enumerator := IEnumVariant(TVarData(WbemObjectSet._NewEnum).VDispatch);
try
while Enumerator.Next(1, System, j) = S_OK do
try
try
if (System.Caption <> 'Запоминающее устройство для USB') then Continue;
except end;
Properties := IEnumVariant(TVarData(System.Properties_._NewEnum).VDispatch);
while Properties.Next(1, Property_, j) = S_OK do
begin
sProperty := VarToStr(Property_.Value);
if (Property_.Name = 'DeviceID') then
begin
VID := Copy(sProperty, Pos('VID_',sProperty)+4,4);
PID := Copy(sProperty, Pos('PID_',sProperty)+4,4);
Serial := Copy(sProperty, Pos('PID_',sProperty)+9,Length(sProperty)-Pos('PID_',sProperty)+10);
if ((Pos('\',Serial) > 0)) then
Begin
Serial := Copy(Serial,Pos('\',Serial)+1,Length(Serial)-Pos('\',Serial));
end;
lst1.Items.Add('VID: '+ VID + ' PID: ' + PID + ' SERIAL: ' + Serial);
end;
end;
except end;
except end;
end;
end.

Код, конечно, грубоват, но собран на коленке. Главное – работает. Пользуйтесь, если нужно:

Delphi
Delphi

Скачать проект с исполняемым файлом можно по ссылке

Таким образом, используя WMI мы получили серийный номер флешки, а так же дополнительную информацию в виде VID и PID.

А можно ли как-нибудь изменить серийный номер флешки?

Да, можно. Есть программы-прошивальщики (под каждый чип своя программа), которые можно использовать для изменения серийного номера и VID PID идентификаторов. Например, для чипов Alcor я использую Alcor Change Vid Pid Rework.

Смена серийного номера флешки
Смена серийного номера флешки
Смена серийного номера флешки
Смена серийного номера флешки
Смена серийного номера флешки
Смена серийного номера флешки

Сменить серийный номер флешки несложно. Подключаем флешку, выбираем её в порту в списке. Нажимаем Setup (открывается окно на фотках выше) вводит нужные VID PID и SN и жмём кнопку START. Флешка готова через секунду с новым серийным номером.

Кстати, я уже писал ранее, как можно отформатировать флешку в ntfs – это может оказаться полезным!

Друзья! Вступайте в нашу группу Вконтакте, чтобы не пропустить новые статьи! Хотите сказать спасибо? Ставьте Like, делайте репост! Это лучшая награда для меня от вас! Так я узнаю о том, что статьи подобного рода вам интересны и пишу чаще и с большим энтузиазмом!

Также, подписывайтесь на наш канал в YouTube! Видео выкладываются весьма регулярно и будет здорово увидеть что-то одним из первых!

Интересно? Поделись с другом
Litl-Admin.ru

Comments:

Comments: 9
  1. valentino

    А почему при определении серийного номера флешки в первом варианте вставляются символы & ?
    Таким образом у меня МТС-модем определился. А серийный номер обычных флешек определяется на ура!

  2. litladmin (author)

    Всё правильно! Вот такие сложные серийные номера с идентификаторами вендора – у сложных устройств. С флешками и дисками такого не возникнет.

  3. litladmin (author)

    Узнал у знающих ребят. Если в серийном номере тома второй символ & то это динамический серийник, не постоянный. После перезагрузки системы будет определяться уже другой, так что построить нормальную систему мониторинга серийников не получится.
    Выход – перешивать флешку с постоянным номером. Скоро протестирую, если что – напишу статью!

  4. dr_nil

    а как мне внутри указанного кода еще и размер узнать?
    вопрос в том, что надо проставить соответствие DeviceID и его размера

  5. litladmin (author)

    В этом коде никак. Но можно воспользоваться дополнительно другим WMI классом. win32_diskdrive
    Для сравнения, выполните команду в командной строке с вставленной флешкой:
    > wmic path win32_diskdrive get pnpdeviceid, size

    Увидите похожую строку серийного номера, а так же размер в байтах.
    Нужно только выделить серийный номер, найти его в одной из этих строк, а так же выдать размер в байтах (предварительно пересчитать, например в МБ).

  6. Actek

    Здравствуйте, не могли бы вы мне подсказать, я повесил вашу функцию на событие WM_DEVICECHANGE, а точнее на сообщение DBT_DEVICEARRIVAL,то есть когда флешку только вставили мне нужно сразу узнать её серийный номер, в итоге выскакивает ошибка
    “Не удается выполнить исходящий вызов, так как приложение обрабатывает входящий синхронный вызов.”
    Задержка на 5 секунд спасает, но, может, как-то можно исправить эту ошибку?
    Заранее Спасибо.

    1. litladmin (author)

      @Actek, Было бы интересно полный код посмотреть. На самом деле помочь вам может статья https://litl-admin.ru/skripting/sozdaem-potrebitel-sobytij-wmi.html где я делал потребитель событий на установку нового USB устройства.

      1. Actek

        @litladmin, Вот код:
        procedure DEVICECHANGE(var Msg: TMessage); message WM_DEVICECHANGE;

        procedure TForm1.DEVICECHANGE(var Msg: TMessage);
        var
        Enumerator: IEnumVariant;
        WbemLocator, WbemServices, WbemObjectSet : Variant;
        Properties : IEnumVariant;
        Property1, System : OleVariant;
        j : LongWord;
        sProperty : string;
        Vid, Pid, Serial : ShortString;
        begin
        case Msg.WParam of
        DBT_DEVICEARRIVAL:
        begin
        Label1.Caption := 'Flash change';

        WbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
        WbemServices:= WbemLocator.ConnectServer;
        WbemObjectSet:= WbemServices.InstancesOf('Win32_usbhub');
        Enumerator := IEnumVariant(TVarData(WbemObjectSet._NewEnum).VDispatch);
        try
        while Enumerator.Next(1, System, j) = S_OK do
        try
        try
        if (System.Caption 'Запоминающее устройство для USB') then Continue;
        except end;
        Properties:= IEnumVariant(TVarData(System.Properties_._NewEnum).VDispatch);
        while Properties.Next(1, Property1, j) = S_OK do
        begin
        sProperty := VarToStr(Property1.Value);
        if(Property1.Name = 'DeviceID') then
        begin
        VID := Copy(sProperty, Pos('VID_', sProperty)+4,4);
        PID := Copy(sProperty, Pos('PID_', sProperty)+4,4);
        Serial := Copy(sProperty, Pos('PID_', sProperty)+9, Length(sProperty)-Pos('PID_', sProperty)+10);
        if ((Pos('\', Serial)>0)) then
        begin
        Serial:=Copy(Serial, Pos('\' ,Serial)+1, Length(Serial)-Pos('\', Serial));
        end;
        lst1.Items.Add('Vid: '+VID + ' Pid: '+PID+ ' Serial: '+ Serial);
        end;
        end;
        except end;
        except end;

        end;
        end;
        end;

        За статью спасибо, постараюсь разобраться.

Leave a Reply