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;
}
Часто хочется оградить свою программу от несанкционированного использования. Для этого есть множество способов но все они естественно имеют не самую простую реализацию. Сегодня я расскажу как оградить вашу программу от использования на другом компьютере. Мы сделаем приложение которое будет привязываться к серийному номеру 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;
}