PDA

View Full Version : یک روش برای نوشتن قفل نرم افزاری



SalarSoft
جمعه 02 مرداد 1383, 07:30 صبح
به نظر من یکی از بهترین روش ها استفاده تواما از چنیدین روش قفل گذاری می باشد , که در زیر توضیح داده می شود.

یکی از روش هایی که مدت هاست که مرسوم است استفاده از ریجستری است. البته این روش به تنهایی قادر به تامین امنیت برنامه نمی باشد.
در این روش اطلاعات کاربر و رمز ورود و سایر مشخصات مورد نیاز در قسمتی از ریجستری که دور از ذهن باشد به صورت کد شده نوشته می شود. لازم به ذکر است که یکی از ضعف های این روش این است که با استفاده از یک برنامه مانیتورینگ پی به محل ذخیره سازی اطلاعات برد.

یکی دیگر از روش ها نوشتن اطلاعات و مشخصات به صورت کد شده و به صورت یک رکورد در آخر یک فایل.
این فایل می تواند یک فایل DLL باشد یا هر فایلی ولی فایل DLL ترجیه داده می شود. این روش نسبت به استفاده از ریجستری از امنیت بیشتری برخوردار است ولی باز هم کافی نیست.

اما... یکی از بهترین روش ها استفاده از دو روش مذکور به طور همزمان است.

اطلاعات کاربر و اطلاعات برنامه در یک رکورد قرار گرفته و این رکورد می تواند در درون ریجستری و در آخر یک یا چندین فایل مختلف قرار گیرد.

البته به علت طولانی شدن مبحث (و... :? ) فقط روش نوشتن رکورد های ثبت در آخر فایل در زیر توضیح داده شده است!

برای مثال رکوردی مانند این:

TProgTrial=Packed Record
fWinVer:integer ;
fProgVer:integer ;
fRemindTime:TDateTime;
fLastUse:TDateTime;
fTrial:Boolean;
fUserName:string[30];
fUsedDays:cardinal;
end;
TProgAccess=Packed Record
fWinVer:integer ;
fProgVer:integer ;
fUserName:string[30];
fRegistered:Boolean;
fRegTime:TDateTime;
end;
رکورد اولی یعنی TProgTrial زمانی توسط برنامه نوشته می شه که برنامه زمان دار یا همان Trial است. بعد از هر روز یک عدد به مقدار fUsedDays افزوده می شود و مقدار fTrial هم true است.علت استفاده از fTrial هم در پایین توضیح داده شده است.

رکورد دومی یعنی TProgAccess هم زمانی نوشته می شود که برنامه توسط کاربر به ثبت رسیده باشد. یعنی کاربر کد ثبت را به درستی وارد کرده و برنامه به طور کامل در اختیار او قرار می گیرد.

نکته ای که در اینجا مهم است نحوه خواندن رکورد های فوق از آخر فایل است. برای تعیین محل خواندن اطلاعات باید اندازه فایل را منهای اندازه رکورد کرد تا محل خواندن اطلاعات مشخص شود.
مثال زیر این نکته را در خط 18 نشان می دهد. البته مثال زیر مربوط به رکورد TProgTrial است:

Function GetFileTrial(fName:String):TProgTrial;
var
fFileStream:TFileStream;
begin
try
If not FileExists(fName) then begin
Result.fWinVer:=0;
Result.fProgVer:=0;
Result.fRemindTime:=0;
Result.fTrial:=false;
Result.fUserName:='';
Result.fUsedDays:=999999;
Result.fLastUse:=0;
exit;
end;
fFileStream:=TFileStream.Create(fName,fmOpenRead or fmShareDenyWrite);
try
fFileStream.Seek(fFileStream.Size-SizeOf(TProgTrial),soBeginning);
fFileStream.ReadBuffer(result,sizeOf(TProgTrial));
finally
fFileStream.Free;
end;
Result.fWinVer:=(Result.fWinVer);
Result.fprogVer:=((Result.fProgVer));
Result.fUserName:=((Result.fUserName));
except
end;
end;
و این مثال TProgAccess :

Function GetFileAccess(fName:String):TProgAccess;
var
fFileStream:TFileStream;
begin
try
If not FileExists(fName) then begin
Result.fWinVer:=0;
Result.fprogVer:=0;
Result.fRegTime:=0;
Result.fRegistered:=false;
Result.fUserName:='';
exit;
end;
fFileStream:=TFileStream.Create(fName,fmOpenRead or fmShareDenyWrite);
try
fFileStream.Seek(-sizeOf(TProgAccess),soEnd);
fFileStream.ReadBuffer(result,sizeOf(TProgAccess)) ;
finally
fFileStream.free;
end;
Result.fWinVer:=((Result.fWinVer));
Result.fprogVer:=((Result.fprogVer));
Result.fUserName:=TrimRight((Result.fUserName));

except
end;
end;
و نکته دیگر اینکه باید صحت رکوردها مورد بررسی قرار گیرد. یعنی با اطلاعات برنامه تطابق داده شود. کد های زیر این مطلب را نشان می دهند:

const
sVersion=1;
sRemindUserName='SalarSoftwares';

function AccessFile(fName: String): Boolean;
var
fProgReg:TProgAccess;
Major,Minor:Cardinal;
begin
try
result:=false;
Major := (DWORD(LOBYTE(LOWORD(GetVersion))));
Minor := (DWORD(HIBYTE(LOWORD(GetVersion))));
fProgReg:=GetFileAccess(fName);
If fProgReg.fRegistered then
result:=true;
If (fProgReg.fWinVer)<>(Major+Minor) then
Result:=false;
If fProgReg.fprogVer<>sVersion then
result:=false;
Except
Result:=false;
end;
end;

function TimedFile(fName: String): Boolean;
var
fprogRemind:TProgTrial;
Major,Minor:Cardinal;
begin
Result:=false;
try
Major := (DWORD(LOBYTE(LOWORD(GetVersion))));
Minor := (DWORD(HIBYTE(LOWORD(GetVersion))));
fprogRemind:=GetFileTrial(fName);
If fprogRemind.fTrial then
result:=true;
If fprogRemind.fUserName=sRemindUserName then
result:=true;
If (fprogRemind.fWinVer)<>(Major+Minor) then
Result:=false;
If fprogRemind.fprogVer<>sVersion then
result:=false;
Except
Result:=false;
end;
end;

و نکته دیگر اینکه حتما باید در هنگام خواندن رکوردها هر دوی این رکوردها(یعنی TProgAccess و TProgTrial ) با هم خوانده شود. علت کار این است که برای تشخیص اینکه برنامه به ثبت رسیده یا Trial است لازم می باشد.
کدهای زیر این مطلب را نشان می دهند:

type
TAccessMode=(amNone,amTimed,amFullAccess,amError);
function GetAccessMode(filename:Tfilename): TAccessMode;
var
fret1,fret2:Boolean;
begin
try
Result:=amError;
fret1:=AccessFile(filename) ;
fret2:=TrialFile(filename) ;
//fret3:=AccessReg(sRegAddr); //Define with self
//fret4:=TrialReg(sRegAddr); //Define with self
If fret2 then
Result:=amTimed;
If fret1 then
Result:=amFullAccess;
If (fret1 and fret2)then //error when fret1=fret2=true
Result:=amError;
If not (fret1 or fret2) then
Result:=amNone;
except
Result:=amError;
end;
end;
در این کد GetAccessMode نوع دسترسی شما به فایل را نشان می دهد:
amNone: یعنی هیچ کاری بر روی فایل انجام نگرفته است و نه به ثبت رسیده و نه Trial است.
amTimed: یعنی فایل trial است.
amFullAccess: یعنی فایل به طور کامل و درست به ثبت رسیده است.
amError: یعنی اشکالی در ثبت فایل وجود دارد و برنامه نباید به کار خود ادامه دهد.

وآخرین نکته در این مبحث نحوه نوشتن رکورد ها در فایل است. به کد های زیر دقت فرمایید.


function SetAccessFile(fName:String;fUser: String): Boolean;
var
Hfile:file;
fBReg:TprogAccess;
Major,Minor:Cardinal;
begin
try
AssignFile(Hfile,fname);
reset(Hfile,1);
try
seek(Hfile,Filesize(Hfile)-SizeOf(TprogAccess));
blockread(Hfile,fBReg,sizeOf(fBReg));
If fBReg.fprogVer<>sVersion then
seek(Hfile,Filesize(Hfile){-SizeOf(TprogAccess)});
Major := (DWORD(LOBYTE(LOWORD(GetVersion))));
Minor := (DWORD(HIBYTE(LOWORD(GetVersion))));
//GetVersionEx(OsVer);
fBReg.fWinVer:=(Major)+(Minor);
fBReg.fprogVer:=(sVersion);
fBReg.fRegTime:=now;
fBReg.fRegistered:=True;
fBReg.fUserName:=(fUser);
blockwrite(Hfile,fBReg,sizeOf(fBReg));
finally
closeFile(Hfile);
Result:=true;
end;
except
Result:=false;
end;
end;

Function GetShortFilename(Const FileName:TFileName):TFilename;
var
Buffer:Array[0..Max_Path-1] of char;
begin
SetString(Result,Buffer,GetShortPathName(Pchar(Fil ename),Buffer,Max_Path-1));
Result:=lowerCase(Result);
end;

function SetTimedFile(fName: String;fRemindTime,fLastUse:TDateTime;UsedDays:Car dinal): Boolean;
var
hfile:file;
fBRemind:TProgTrial;
Major,Minor:Cardinal;
begin
try
Result:=true;
fname:=GetShortFilename(fname);
If not fileexists(fname) then exit;
AssignFile(hfile,(fname));
reset(hfile,1);
try
seek(hfile,Filesize(hfile)-SizeOf(TProgTrial));
blockread(hfile,fBRemind,sizeOf(fBRemind));
If fBRemind.fprogVer<>sVersion then
begin
seek(hfile,Filesize(hfile){-SizeOf(TprogTimed)});
end
else
begin
seek(hfile,Filesize(hfile)-SizeOf(TProgTrial));
end;
Major := (DWORD(LOBYTE(LOWORD(GetVersion))));
Minor := (DWORD(HIBYTE(LOWORD(GetVersion))));
//GetVersionEx(OsVer);
fBRemind.fLastUse:=fLastUse;
fBRemind.fRemindTime:=fRemindTime;
fBRemind.fWinVer:=(Major)+(Minor);
fBRemind.fprogVer:=(sVersion);
fBRemind.fTrial:=true;
fBRemind.fUserName:=(sRemindUserName);
fBRemind.fUsedDays:=UsedDays;
blockwrite(hfile,fBRemind,sizeOf(fBRemind));
Result:=true;
finally
closeFile(hfile);
end;
except
Result:=false;
end;
end;

و برای راحتی کار شما عزیزان من یک نسخه از فایل این قفل را در سایت می گذارم.
پیشاپیش از پیشنهادات و انتقادات شما عزیزان تشکر می کنم. :flower:

iranboy
سه شنبه 06 مرداد 1383, 11:24 صبح
good

nasr
سه شنبه 06 مرداد 1383, 23:32 عصر
دستت درد نکنه :flower:

ali643
پنج شنبه 08 مرداد 1383, 05:50 صبح
دستت درد نکنه
اگه می تونی یه مثال برای برنامه های database اینجا ردیف کن
مرسی

SalarSoft
پنج شنبه 08 مرداد 1383, 09:29 صبح
برای فایلهای Database نمیشه از این روش استفاده کرد (یعنی صحیح نیست).

توصیه من اینه که فقط با فایل های اجرایی که آخرشون اهمیت نداره چی باشه استفاده کنین.

مانند فایل اجرایی که آخرش در دلفی با کاراکتر 0# پر میشه. یا فایل های dll , exe ,scr و ...