Рейтинг@Mail.ru

WinAPI: Смена серийного номера тома.


В статье «WinAPI: Определение типа носителя и его серийного номера» я показывал простой пример как реализовать защиту программ путем привязки к железу. Но все бы хорошо, да только бывают моменты, когда просто необходимо «отвязаться» от железки. С такой проблемой столкнулся sansan. Собственно, благодаря ему и была написана эта статья.

Ну а теперь от слов к делу. Вся информация для корректной работы накопителя хранится в его загрузочной области. Нас будет интересовать используемая файловая система, от которой зависит расположения нужных байт относительно начала загрузочной области. Поэтому основная наша задача — это определить тип файловой системы, и сместившись на нужный адрес, переписать значение серийного номера. Всё просто ;). Изучим таблицу.
Таблица:

Поле/ФС FAT FAT32 NTFS
Метка тома 0x2B 0×47 ?
Файловая система 0×36 0×52 0×3
Серийный номер 0×27 0×43 0×48

В приведенной таблице показаны основные файловые системы и соответствующие для них смещения. Оперируя этой информацией мы и будем реализовывать нашу программу. Нам необходимо реализовать следующие функции:

  • DiskOpen — открыть диск
  • DiskClose — закрыть диск
  • ReadSector — прочитать сектор
  • WriteSector — записать сектор

Реализовывать нашу программу мы будем С++ под семейство Windows NT. В частности, в среде разработки С++ Builder 6. Нам понадобиться глобальная переменная, в которой будем хранить указатель на используемый диск:

HANDLE hD;

Начнем c описания функции DiskOpen():

bool DiskOpen(char *vol) {   char szDrive[10];   sprintf(szDrive, "\\\\.\\%c:", vol[0]);   hD = CreateFile(     szDrive,     GENERIC_READ | GENERIC_WRITE,     FILE_SHARE_READ | FILE_SHARE_WRITE,     NULL,     OPEN_EXISTING,     0,     NULL);   return hD != INVALID_HANDLE_VALUE; }

Данной функции в качестве параметра передаётся буква диска, которому нужно сменить серийный номер. С помощью API-функции CreateFile(), мы получаем указатель на диск (подробней о CreateFile можно прочитать в статье «WinAPI: Работа с файлами (основные функции)«). В случае успеха возвращает «истину», иначе — «ложь».

Далее опишем функцию DiskClose():

void DiskClose() {   if (hD != INVALID_HANDLE_VALUE)     CloseHandle(hD); }

Эта функция достаточно простая, она освобождает используемый указатель на диск.

Следующая функция ReadSector():

bool ReadSector (DWORD sector, char *Buffer, int sectorSize) {   DWORD read = 0;   if (SetFilePointer(hD, sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)     return false;   if (!ReadFile(hD, Buffer, sectorSize, &read, NULL))     return false;   return true; }

Эта функция уже посложней. Исользует 3 параметра:

  • первый — указатель на диск.
  • второй — буфер, куда будут записаны данные, считанные из загрузочной области.
  • третий — размер загрузочной области, а следовательно и буфера.

Функция переводит указатель смещения в файле на нужную позицию с помощью API-функции SetFilePointer(), а потом с помощью ReadFile() считывает в буфер данные из загрузочной области (подробней о ReadFile() можно прочитать в статье «WinAPI: Работа с файлами (основные функции)«). В случае успеха возвращает «истину», иначе — «ложь».

И последняя функция WriteSector():

bool WriteSector(DWORD sector, char *Buffer, int sectorSize) {   DWORD wrote = 0;   if (SetFilePointer(hD, sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)     return false;   if (!WriteFile(hD, Buffer, sectorSize, &wrote, NULL))     return false;   return true; }

Эта функция аналогична предыдущей. Только вместо API-функции ReadFile() используется WriteFile() (подробней о WriteFile() можно прочитать в статье «WinAPI: Работа с файлами (основные функции)«). В случае успеха возвращает «истину», иначе — «ложь».

Ну что, базовые функции мы реализовали, пора приступить и к завершающей стадии. Скинем на форму 1 кнопку, 1 поле ввода (сюда будем вводить новый серийный номер), и 1 ComboBox (определим выбор основных букв дисков). И для кнопки опишем следующий код:

void __fastcall TForm1::Button1Click(TObject *Sender) { //проверяем не пусты ли необходимые поля   if ((ComboBox1->Text !="") && (Edit1->Text !=""))   {     DWORD newSerial = StrToInt(Edit1->Text);     const max_pbsi = 3; //определяем структуру для сигнатуры загрузочной области     struct partial_boot_sector_info     {       LPSTR Fs; // название файловой системы       DWORD FsOffs; // смещение системного имени в загрузочной области       DWORD SerialOffs; // смещение серийного номера в загрузочной области     }; //описываем часто используемые сигнатуры     partial_boot_sector_info pbsi[max_pbsi] =     {      {"FAT32", 0x52, 0x43},      {"FAT",   0x36, 0x27},      {"NTFS",  0x03, 0x48}     }; //инициализируем необходимые переменные     TCHAR Drive[12]={0};     char Sector[512];     DWORD i;     sprintf(Drive, "%s:\\", ComboBox1->Text);    //открываем диск     if (!DiskOpen(Drive))     {//если ошибка - оповещаем пользователя и выходим из процедуры       Application->MessageBoxA("Невозможно открыть диск!","Ошибка");       return;     }   // читаем загрузочную область     if (!ReadSector(0, Sector,512))     {       Application->MessageBoxA("Невозможно считать данные","Ошибка");       return;     }   // посик сигнатуры загрузочной области     for (i=0;i= max_pbsi)     {       Application->MessageBoxA("Невозможно сменить номер для этой файловой системы!","Ошибка");       return;     }   // меняем номер     *(PDWORD)(Sector+pbsi[i].SerialOffs) = newSerial;   // записываем в загрузочную область     if (!WriteSector(0, Sector,512))     {       Application->MessageBoxA("Невозможно записать на диск!","Ошибка");       return;     }     DiskClose();     Application->MessageBoxA("Серийный номер успешно изменен! Необходимо перезагрузить компьютер.","Внимание");   }else      Application->MessageBoxA("Не указан диск или серийный номер!","Внимание"); }

Если Вы меняете серийный номер тома флешки, то компьютер перезагружать не обязательно, достаточно отключить и заново подключить флешку. В других случаях результат буде виден только после перезагрузки. На этом всё, замечания и вопросы можете высказать на форуме. Спасибо за внимание! ;)

Рабочий пример скачать.

Рекомендуемые статьи для прочтения:
WinAPI: Работа с файлами (основные функции).
WinAPI: Определение типа носителя и его серийного номера.

прикладное, Программирование, системное ,

Пожалуйста, оцените полезность и качество данной статьи. Одна звезда - плохо, 5 - хорошо.
1 звезда2 звезды3 звезды4 звезды5 звёзд (5 голосов, средний: 4,80 из 5)
Loading ... Loading ...

  1. Пока что нет комментариев.
  1. Пока что нет уведомлений.
*