Главная > прикладное, Программирование, системное > WinAPI: Смена серийного номера тома.

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

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

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

Поле/ФС FAT FAT32 NTFS
Метка тома 0x2B 0x47 ?
Файловая система 0x36 0x52 0x3
Серийный номер 0x27 0x43 0x48

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

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

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


HANDLE hD;

Начнем с описания функции 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() считывает в буфер данные из загрузочной области. В случае успеха возвращает "истину", иначе - "ложь".

И последняя функция 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(). В случае успеха возвращает "истину", иначе - "ложь".

Ну что, базовые функции мы реализовали, пора приступить и к завершающей стадии. Скинем на форму 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("Не указан диск или серийный номер!","Внимание");
}

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

Пожалуйста, оцените полезность и качество данной статьи. Одна звезда - плохо, 5 - хорошо.
1/5. Мы будем признательны, если вы напишете комментарий с причиной низкой оценки.2/5. Мы будем признательны, если вы напишете комментарий с причиной низкой оценки.3/5. Мы будем признательны, если вы напишете комментарий с причиной низкой оценки.4/5.5/5. (2 голосов, средний: 5,00 из 5)
Загрузка...
  1. Влад
    18 июля 2014 в 20:41 | #1

    Как с Вами связаться?

  2. lizz
    4 августа 2014 в 12:59 | #2

    @Влад
    В каких целях интересуетесь? :)

    Пишите в комментарии, если что-то дельное - я постараюсь передать автору статьи.

  3. Ruslan
    20 сентября 2015 в 22:11 | #3

    @ lizz
    А можно пример этого кода на делфи (паскаль)

  4. lizz
    15 февраля 2016 в 03:13 | #4

    @Ruslan

    Увы, но нет.

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