PDA

Просмотр полной версии : [Руководство] Простейшая привязка приложения к железу


Ivan_32
09.02.2009, 06:43
Немного теории:
Часто хочется оградить свою программу от несанкционированного использования. Для этого есть множество способов но все они естественно имеют не самую простую реализацию. Сегодня я расскажу как оградить вашу программу от использования на другом компьютере. Мы сделаем приложение которое будет привязываться к серийному номеру HDD. В первой части мы напишем программу которая будет показывать серийный номер HDD - его можно будет использовать во второй(защищаемой) программе.

Итак приступим. Самый простой способ получить серийный номер винчестера это функция GetVolumeInfromation:
BOOL WINAPI GetVolumeInformation(
1. __in_opt LPCTSTR lpRootPathName,
2. __out LPTSTR lpVolumeNameBuffer,
3. __in DWORD nVolumeNameSize,
4. __out_opt LPDWORD lpVolumeSerialNumber,
5. __out_opt LPDWORD lpMaximumComponentLength,
6. __out_opt LPDWORD lpFileSystemFlags,
7. __out LPTSTR lpFileSystemNameBuffer,
8. __in DWORD nFileSystemNameSize
);

Как видно из предварительного кода, все выходные параметры, опциональны. (об это свидетельствует пометка __out_opt).
Пройдемся по параметрам:
1. Путь к сканируемому диску.
2. Буфер в который будет возвращено имя диска.
3. Максимальный размер этого буфера.
4. Вот это то что нам надо - серийный номер HDD.
5. Максимальная длина имени файла для данной файловой системы.
6. Это двойное слово на само деле что то вроде флагового регистра, каждый бит в нем что то означает.
7. Буфер для имени файловой системы.
8. Длина этого буфера.

Теперь осталось только приступить к написанию программы.
Поскольку уроки по написанию оконных программ под Win32 уже есть, тут я не буду детализировать объяснения, только добавлю свои примечания.

Начнем:


#include "stdafx.h"
#include <stdio.h>

LRESULT WINAPI mainProc(HWND,UINT,WPARAM,LPARAM);
BOOL InitializeControls(HWND);
DWORD GetHDDSerial();

#define bGetSN 1000
static HWND hBGetSN;

#define eSN 1001
static HWND hESN;

Stdio.h содержит нужную нам функцию для работы со строками - sprintf ([Ссылки могут видеть только зарегистрированные и активированные пользователи])

StdAfx.h это файл поставляемый вместе с проектом, в нем записан следующий код:

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

Ничего примечательного.

mainProc - функция обработки сообщений.

InitializeControls - срабатывает на событие WM_CREATE и создает все нужные контролы.

GetHDDSerial - функция говорит сама за себя, ее код мы рассмотрим позже.

Ну а дальше идут дескрипторы окон и их идентификаторы:
hESN - идентификатор eSN - текстовое поле.
hBGetSN - идентификатор bGetSN - кнопка.

Перейдем к функции WinMain:

int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
HWND hMain;

hMain=CreateWindowEx(0,WC_DIALOG,"HDD SN",\
WS_VISIBLE|WS_SYSMENU,CW_USEDEFAULT,CW_USEDEFAULT, \
165,85,0,0,0,0);
if(!hMain)return 0;

SetWindowLong(hMain,DWL_DLGPROC,(long)mainProc);
SendMessageA(hMain,WM_CREATE,0,0);

while(GetMessageA(&msg,0,0,0)!=NULL)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}

Опять же ничего примечательного, только добавлена проверка на создание окна. Если hMain равно 0 - приложение завершится. Маловероятно что такое может произойти но все же, такие конструкции что то вроде этикета для кода.

Функция обработки сообщений mainProc:
LRESULT WINAPI mainProc(HWND hWnd,UINT message,WPARAM wp,LPARAM lp)
{
switch(message)
{
case WM_COMMAND:
{
switch(wp)
{
case bGetSN:
{
char szBuff[260];
sprintf(szBuff,"HDDSN: %u",GetHDDSerial());
SetWindowText(hESN,szBuff);
}break;
}
}break;
case WM_CREATE:
{
InitializeControls(hWnd);
}break;
case WM_CLOSE:
{
PostQuitMessage(0);
}break;
}
return 0;
}
Как видно из кода, при срабатывания события нажатия на нашу кнопку, вызывается функция получения серийного номера HDD, номер записывается в строку и текст в нашем текстовом поле заменяется на тот что находится в szBuff.

При сообщение WM_CREATE срабатывает функция создания контролов. В остальном все обыденно.

Функция InitializeControls:

BOOL InitializeControls(HWND hWnd)
{
hESN=CreateWindowEx(0,"edit",0,WS_VISIBLE|WS_CHILD|WS_BORDER,5,5,150,20,hWnd,( HMENU)eSN,0,0);
if(!hESN)return FALSE;

hBGetSN=CreateWindowEx(0,"button","Get Serial Number",WS_VISIBLE|WS_CHILD,5,30,150,25,hWnd,(HMENU)bGetS N,0,0);
if(!hBGetSN)return FALSE;

return TRUE;
}

Добавлены проверки на создание контролов в остальном все опять же обыденно.

Ну и наконец виновник торжества - функция GetHDDSerial:

DWORD GetHDDSerial()
{
DWORD serialNumber;
GetVolumeInformation("%SystemDrive%",0,0,&serialNumber,0,0,0,0);
return serialNumber;
}

Константа %SystemDrive% это такая общая для всей системы ссылка на диск на котором установлена ОС. Допустим установлен у вас Windows на диске С:\ оно и подставит вместо нее путь C:\.

Скомпилируйте и узнайте серийный номер своего HDD - он вам понадобится для следующей части.


Защищенная программа:
Ну а теперь напишем и защищенную программу. Функция WinMain идентична использованной нами в предыдущей программе. Та же участь постигла и функцию GetHDDSerial. Приведу только код функции обработки сообщений.

Функция mainProc:

static DWORD SN=0;//Замените ноль на ваш серийный номер.
LRESULT WINAPI mainProc(HWND hWnd,UINT message,WPARAM wp,LPARAM lp)
{
switch(message)
{
case WM_CREATE:
{
if(GetHDDSerial()!=SN)
PostQuitMessage(0);
CreateWindowEx(0,"static","Program started!",WS_VISIBLE|SS_CENTER|WS_CHILD,10,10,100,30,hWnd,0 ,0,0);
}break;
case WM_CLOSE:
{
PostQuitMessage(0);
}break;
}
return 0;
}

Как видно из кода, при инициализации формы(тоесть при сообщение WM_CREATE происходит проверка серийного номера винчастера, если проверка неудачна то приложение просто закрывается. При успешной проверке на форме создается надпись.


Вот собственно и все. В заключение приведу исходники обоих программ.


#include "stdafx.h"
#include <stdio.h>

LRESULT WINAPI mainProc(HWND,UINT,WPARAM,LPARAM);
BOOL InitializeControls(HWND);
DWORD GetHDDSerial();

#define bGetSN 1000
static HWND hBGetSN;

#define eSN 1001
static HWND hESN;

int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
HWND hMain;

hMain=CreateWindowEx(0,WC_DIALOG,"HDD SN",\
WS_VISIBLE|WS_SYSMENU,CW_USEDEFAULT,CW_USEDEFAULT, \
165,85,0,0,0,0);
if(!hMain)return 0;

SetWindowLong(hMain,DWL_DLGPROC,(long)mainProc);
SendMessageA(hMain,WM_CREATE,0,0);

while(GetMessageA(&msg,0,0,0)!=NULL)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT WINAPI mainProc(HWND hWnd,UINT message,WPARAM wp,LPARAM lp)
{
switch(message)
{
case WM_COMMAND:
{
switch(wp)
{
case bGetSN:
{
char szBuff[260];
sprintf(szBuff,"HDDSN: %u",GetHDDSerial());
SetWindowText(hESN,szBuff);
}break;
}
}break;
case WM_CREATE:
{
InitializeControls(hWnd);
}break;
case WM_CLOSE:
{
PostQuitMessage(0);
}break;
}
return 0;
}
BOOL InitializeControls(HWND hWnd)
{
hESN=CreateWindowEx(0,"edit",0,WS_VISIBLE|WS_CHILD|WS_BORDER,5,5,150,20,hWnd,( HMENU)eSN,0,0);
if(!hESN)return FALSE;

hBGetSN=CreateWindowEx(0,"button","Get Serial Number",WS_VISIBLE|WS_CHILD,5,30,150,25,hWnd,(HMENU)bGetS N,0,0);
if(!hBGetSN)return FALSE;

return TRUE;
}
DWORD GetHDDSerial()
{
DWORD serialNumber;
GetVolumeInformation("%SystemDrive%",0,0,&serialNumber,0,0,0,0);
return serialNumber;
}



#include "stdafx.h"
LRESULT WINAPI mainProc(HWND,UINT,WPARAM,LPARAM);
DWORD GetHDDSerial();
static DWORD SN=0;
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
HWND hMain;

hMain=CreateWindowEx(0,WC_DIALOG,"Program",\
WS_VISIBLE|WS_SYSMENU,CW_USEDEFAULT,CW_USEDEFAULT, \
115,80,0,0,0,0);
if(!hMain)return 0;

SetWindowLong(hMain,DWL_DLGPROC,(long)mainProc);
SendMessageA(hMain,WM_CREATE,0,0);

while(GetMessageA(&msg,0,0,0)!=NULL)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}

LRESULT WINAPI mainProc(HWND hWnd,UINT message,WPARAM wp,LPARAM lp)
{
switch(message)
{
case WM_CREATE:
{
if(GetHDDSerial()!=SN)
PostQuitMessage(0);
CreateWindowEx(0,"static","Program started!",WS_VISIBLE|SS_CENTER|WS_CHILD,10,10,100,30,hWnd,0 ,0,0);
}break;
case WM_CLOSE:
{
PostQuitMessage(0);
}break;
}
return 0;
}

DWORD GetHDDSerial()
{
DWORD serialNumber;
GetVolumeInformation("%SystemDrive%",0,0,&serialNumber,0,0,0,0);
return serialNumber;
}

ANTIBLANK
27.03.2011, 14:02
Это самый простой? о_0

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

doctor_flasher
15.05.2011, 18:14
Стоит отметить, что этот способ бесполезен чуть менее, чем полностью, ибо даже новичку не составит труда после часа чтений мануалов найти правильный HardwareID. И (ИМХО) не стоило засорять код длиииинными вызовами апи для создания форм и тп. - проще было бы с использованием всех плюшек вижуал студио сделать для примера - было бы строк 10 кода

Тигрь
17.05.2011, 07:56
Что касается способо то конечно обойти легко, и я тут на форуме об этом писал. А что касается вин апи, не заметил как раздел называется?

doctor_flasher
31.05.2011, 10:14
Ну не весь же код на ВинАпи ;) я когда начинал кодить, с ума сходил, всматриваясь на большооооой такой код других людей (где, в принципе, для сабжа статьи требовалось не более 30 строк). Ну не знаю короче - просто свое сраное мнение высказал =)

doctor_flasher
14.06.2011, 12:14
Russian_Zarj, хэндлы окон (hWnd). Там нечего рассказывать, в принципе, - это просто идентификаторы окон. Ну, чтоб система могла с ними нормально общаться. Вот. Гугл же.

gum_classis
19.06.2011, 19:06
Подскажите легко ломается ? собираюсь сервис открыть и думаю кряки всегда и всюду будут ?

Муха_
19.06.2011, 19:33
Ломается легко кряков будет куча

doctor_flasher
07.08.2011, 20:03
это что самый простой ?
Самый простой. Там большая часть кода - создание формы и тп. Для защиты нужна непосредственно функция GetVolumeInformation

zAvratos
29.10.2011, 13:06
у меня не получилось привязать ..мини прогу..делал всё по инструкции!

_ziza_
23.03.2012, 23:40
это заблуждение.
GetVolumeInformation возвращает серийный номер тома.
Который легко меняется на любой тк не привязан к железу (записан в первых секторах).
И может сменится после форматирования

Вот вам первоисточник
[Ссылки могут видеть только зарегистрированные и активированные пользователи](v=vs.85).aspx

Vandal91
19.04.2012, 04:18
Попробовал привязать к самой простой проге - не работает. Тема еще актуальна или это моя ошибка?

[Na`Vi]DendI
19.08.2012, 00:45
Возможно ли написать dll-ку и юзать на c# ? Слышал что все хорошие привязки,защиты написаны на асме но юзаются в других языках.

avi2011class
30.03.2013, 13:53
А какая функция дает серийник процессора? не подскажете? Понимаю, что не в тему.

Dinmaite[Work]
01.04.2013, 15:58
Автор уже давно не пользуется ресурсом.

Вы пишите, что именно, не получилось.

FoX-DO
03.04.2013, 17:22
У меня вообще написало, что "серийник" - 1

avi2011class
22.04.2013, 21:42
У меня выдает серийник жесткого диска 1, но цифр маловато мне кажется((. Подскажите, сколько цифр должно быть.