Авторитетный
Зарегистрирован: 06.03.2010
Группа: Модераторы
Сообщений: 265
Статус: Offline
|
Предисловие
данная статья не была заранее подготовленной, идея ее написать появилась у меня сегодня после того как увидел один пост на форуме и вспомнил как с друзьями мы убирали привязку у программ друг друга статья написано как можно более понятно, так как большинство посетителей нашего форума новички в программировании, и прошу не серчать за излишнюю подробность думаю вам будет интересно почитать 
на форуме один из посетителей сделал прозьбу о том как сделать привязку программке 
итак начнем, первое правда что мне пришлось сделать это скачать дэлфи, так как, увы, давно на нем не писал, а наш ресурс узко специализированн 
после того как устанавили дэлфи нужна программка которую мы будем привязывать 
и мы ее пишем
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Edit1: TEdit;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage(Edit1.text);
end;
end.

дальше нам нужна программка которая скажет нам наш HardID , на который мы будем привязывать, в данном примере будем привязывать к ID логического диска, правда да, оно при переустановке системы меняется, но все же, пойдет 
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Edit1: TEdit;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
VSNum, dw1, dw2: DWORD;
szTemp: array[0..MAX_PATH] of char;
begin
GetWindowsDirectory(szTemp,MAX_PATH);
GetVolumeInformation(PAnsiChar(szTemp[0]+':\'), nil, 0, @VSNum, dw1, dw2, nil, 0);
Edit1.Text := IntToHex(VSNum,16);
end;
end.

суть привязки в том что бы просто сравнить прописанный в проге HardID с HardID на запущенной системе и если ID не совпадают, то завершить программу
пишем процедуру которая будет это делать 
procedure pegging(); // спасибо гуглу за перевод
var
myID:DWORD;
VSNum, dw1, dw2: DWORD;
szTemp: array[0..MAX_PATH] of char;
begin
myID := $003C7FD842;
GetWindowsDirectory(szTemp,MAX_PATH);
GetVolumeInformation(PAnsiChar(szTemp[0]+':\'), nil, 0, @VSNum, dw1, dw2, nil, 0);
if( VSNum <> myID) then
begin
TerminateProcess(GetCurrentProcess(), 0);
end;
end;
вызываем ее при запуске программы
procedure TForm1.FormCreate(Sender: TObject);
begin
pegging();
end;
в итоге если мы запустим программу на другом компьютере она завершится
но не все так хорошо насколько кажется, ведь если сделать такую привязку в реальном программном продукте, то привязку очень быстро уберут 
если мы откроем наш ехе файл дэбагерром(например OllyDbg) , то сможем легко найти импорт функции TerminateProcess и увидить где он вызывается

дальше если взглянуть выше по коду будет видно прыжок, а точнее условный переход на вызов TerminateProcess
CMP EBX,DWORD PTR SS:[EBP-4]
JE SHORT crack.00453882
сразу становится понятно что это сравнение нашего ключа с ключем на локальной систем, если ключ подходит, то продолжается выполнение программы, если же нет, то программа завершается
прыжок происходит командой JE , для того что бы убрать привязку достаточно лишь изменить условие перехода на обратное, а т.е JE поменять на JNZ(или JNE)

для того что бы усложнить поиск нужного участка кода, который отвечает за проверку на HardID можно избавится от вызова TerminateProcess, например
procedure pegging();
var
myID:DWORD;
VSNum, dw1, dw2: DWORD;
szTemp: array[0..MAX_PATH] of char;
begin
myID := $003C7FD822;
GetWindowsDirectory(szTemp,MAX_PATH);
GetVolumeInformation(PAnsiChar(szTemp[0]+':\'), nil, 0, @VSNum, dw1, dw2, nil, 0);
asm
mov eax,myID
mov ebx,dw2
sub eax,VSNum
push offset @metka
add esp,eax
ret
@metka:
end;
end;
в данном примере отсутствует даже сравнение как таковое, здесь все происходит так,в регистр eax записывается ID с которым нужно сравнивать(айди компьютера на котором программа должна запустится)
в регист ebx заносится ID локального компьютера
дальше считается разница между eax b ebx (между первым и вторым ID) , и результат записывается в eax, в итоге если первый и второй ID равны то в eax окажется ноль, иначе какое то число
дальше в стек заносится адрес метки завершения привязки и к регистру esp добавляется значение регистра eax, и получается если eax не равен нулю то работа программы будет нарушена, и дальше при выполнении команды ret программа вызовет исключение, ошибку, а если в eax будет 0 то программа как работала так и будет работать
в данном коде можно даже убрать все что идет после add esp,eax , и привязка все равно будет работать
такую привязку будет чу чуть сложнее найти и вылечить, но все равно возможно, для большего усложнения ее обнаружения можно убрать GetVolumeInformation из импортов и сделать поиск адреса функции через GetProcAddr 
но все равно это не даст надежной защиты и программу можно будет взломать в течении пары часов
по моему самым лучшим способом привязать программу это совместить привязку и крипт, что бы для того что бы найти код привязки его и весь остальной код программы нужно было бы еще расшифровать, а этот процесс достаточно долгий для пошагового выполнения вручную
|