این مطالب از سایت http://barnamenevis.org استفاده شدن و مطالب مال آقای "دنیای دلفی " هستش که با احترام به ایشون و درج ... مطالب و میذارم چون واقعا مفیدا و بسیار بدرد بخور !!! پس فرصت و از دست ندین !!

اين مطالبي را كه مي نويسم شامل تجربيات بنده در مورد نوشتن رويه هاي محافظت از نرم افزارهاي تحت ويندوز مي باشد :
‌‍{ممكن است خيلي ساده باشه ولي خيلي روش كار و فكر كردم}
1- اگر اسمبلي يك مقداري سردر بياريد بسيار مفيد است
2-برنامه هاي وجود دارد كه به راحتي فانكشنها و پروسيجر هاي شما را غير فعال و حتي مسير اجرا شدن آنها را تغيير مي دهند . حتي بدون يك خط كدنويسي مانند :PE Explorer و Resource Tuner كه توي اين كار بسيار حرفه اي عمل مي كنند . حتي مي تونند برنامه هاي نوشته شده با VB.NET را فرمهايشان را نيز نشان دهند .
گروهي از كركرهاي ساده (تازه كار)كه از اسمبلي خبر ندارند با استفاده از اين برنامه هاي برنامه هاي شما را حداقل مي توانيد تغيير ليبل دهند . پس براي جلوگيري از شناسايي توابع بايد چه راهي را اتخاذ كرد ؟
جواب : شما نبايد در زمان طراحي فرم از اشياء استفاده كنيد بايد آنها را در هنگام اجرا بسازيد (Run Time) . شما نبايد در رويداد OnCreate فرم توابع بررسي قفل يا اطلاعات نويسنده را بنويسيد . يك تابع تعريف مي نمائيد .

کد:
  public
    { Public declarations }
    procedure FirstTestLock(Sender: TObject);
  end;
ببينيد چون مي خواهيم در بخش ديگري اين تابع را صدا بزنيم آن را نبايد در بخش Private تعريف نمود و طبق كد پايين اين تابع را صدا مي زنيم .

کد:
 
program Project1;
uses
  Forms,
  Unit1 in 'Unit1.pas' {Form1};
{$R *.res}
begin
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Form1.FirstTestLock(nil);
  Application.Run;
end.
حالا بايد اشياء ي را كه مي خواهيم بسازيم درون تابع مربوطه توليد كنيم . به كد زير توجه كنيد براي ساختن يك تايمر است و مقدار دهي به تايمر كه چه كدي را بايد اجرا نمايد :

اين فرامين را در تابع تعريف شده مي نويسيم :

کد:
 
procedure TForm1.FirstTestLock(Sender: TObject);
 var
   Timer1: TTimer;
begin
    Try
     Timer1 := TTimer.Create(self);
     Timer1.Interval:=60000;
     Timer1.Enabled:=True;
     Timer1.OnTimer:=OnTimerActive1;
.
.
.
حالا بايد تابع OnTimerActive1 تعريف كنيم دقيقا در مكاني كه مشخص مي كنم :


کد:
 
  private
    { Private declarations }
    procedure OnTimerActive1(Sender: TObject);

.
.
.

حالا در مكاني دلخواه كدهاي اين تايمر را مي نويسيم :

کد:
procedure TForm1.OnTimerActive1(Sender: TObject);
begin
با استفاده از توابع موجود حجم و Crc32 فايل را بدست آوريد

حجم فايل را درون يك فايل به صورت كد شده يا در رجيستري ذخيره نمائيد
Crc را نيز همين طور حالا بررسي كنيد كه آيا حجم يا سي آر سي فايل تغيير نموده يا خير كه اگر تغيير نموده بود برنامه را Halt و مي توانيد دهن ويندوز را هم بكنيد در غير اين صورت .

حالا اگر كركر از Loader استفاده كرده باشد كه دهن ما ... است . براي رفع تا حدودي اين مشكل مي توانيد از يكي از شماره سريالهاي منحصر بفرد سيستم مانند هارد ديسك استفاده كنيد كه به صورت كد شده در فايل بانك اطلاعاتي يا رجيستري ذخيره و با شماره فعلي سيستم مقايسه كنيد . چون اين فرامين در داخل يك تايمر هستند مي توانيد حتي اگر برنامه با لودر اجرا شده باشد (معمولا حجم و CRC تغيير نمي كند) باعث بسته شدن برنامه و ساير كارهاي شويد .

نكته بسيار مهم رشته ها هستند شما تحت هيچ شرايطي رشته ها را لخت ()رها نكنيد
يعني آنها را مستقيم در برنامه ننويسيد :
پيشنهاد : شما مي توانيد در بيرون برنامه رشته را كد كنيد (مثلا :استفاده از خاصيت AESEncrypt مربوط به IceLicense) حالا در برنامه آنها را دي كد كنيد (مثلا : با استفاده از AESDecrypt مربوط به IceLicense ) ولي يك مشكل وجود دارد آن هم استفاده از كليد براي دي كد كردن است كه شما مجبور هستيد آن را در برنامه به صورت يك رشته وارد كنيد .
راه حل : شما مي توانيد : كليد را به اين صورت بنويسيد

کد:
PChar(Char(72)+Char(104)+Char(125))
اين كار باعث مي شود كه كليد فقط RunTime ظاهر شود . و در حالت عادي در فايل اجراي شما قابل ديدن نباشد . اين باعث مي شود كه تا حدي وضعيت رشته ها در برنامه مستحكم شود . البته تا حدي

حالا بهتره توي تايمر يه مقداري حال ديباگر ها را هم بگيريم البته تا حدي :
با استفاده از :

کد:
 
var
  Task:HWND;

    Task:=FindWindow(Pchar(IceLicense1.AESDecrypt('wdwUZkYwdwZawd',PChar(Char(51)+Char(95)+Char(50)),nil));
    PostMessage(Task,WM_CLOSE,0,0);
wdwUZkYwdwZawd : كد كلمه OlyDbg است
کد:
PChar(Char(51)+Char(95)+Char(50))

كليد تبديل كد به OlyDbg است .

البته تايمري كه اين كار و كارهاي ديگر را مي كند با همان روش بالا ايجاد و نيم ثانيه به نيم ثانيه اجرا شود .
اين جوري هم يكم كركرهاي تازه كار را آره ...



كليه روشهاي فوق قابل دور زدن و روئيت هستند فقط براي بالا بردن امنيت استفاده مي شوند .

البته يه كاري ديگه هم مي شه كرد كه من انجام دادم هنوز كه هنوزه كسي نتونسته Crack Me من را بيشتر از 50 درصد كرك كنند . البته اون 50 درصد بعدي خيلي مهم تره چون مجوز اجراي برنامه رو در گام اخر ميده اگر نتونستند كرك كنند اون را هم مي گم .

بخش دوم آموزش محافظت از نرم افزارها در مقابل كركينگ:

شايد براي شما اين سوال پيش بيايد كه چگونه بايد CRC و حجم يك فايل را بدست آورد :
روش بدست آوردن CRC16 , CRC32 , Size با استفاده از كامپوننت زير

با استفاده از تابع زير مي توانيد موارد مورد نياز خود را بدست آوريد
کد:
   Error32  :  WORD;
   FileBytes:  TInteger8;
   CRC32File :  LongWord;

CalcFileCRC32 (Application.ExeName, CRC32File, FileBytes, Error32);
روش ديگر براي بدست آوردن حجم فايل برنامه :

کد:
function GetFSize(Handle: THandle): Int64;
  var
    i64: record
      LoDWord: LongWord;
      HiDWord: LongWord;
    end;
  begin
    i64.LoDWord := GetFileSize(Handle, @i64.HiDWord);
    if (i64.LoDWord = MAXDWORD) and (GetLastError <> 0) then
      Result := 0
    else
      Result := PInt64(@i64)^;
  end;



  Stream:TFileStream;
 FSize2:int64;


    Stream := nil;
    try
      Stream := TFileStream.Create(Application.ExeName,
                                   fmOpenRead or fmShareDenyNone);

      Fsize2:=GetFSize(Stream.Handle);
    finally
      Stream.Free;
    end;
شما مي توانيد براي امنيت بيشتر در صورت عدم شرايط مجاز اقدام به خودزني و حذف فايل اجرايي كنيد فايل براي انجام اين جنايت ضميمه شده است .

با استفاده از تابع

کد:
Deleteexe;
پايان قسمت دوم
فایل های ضمیمه
نوع فایل: rar crc32.rar (3.9 کیلوبایت, 24 دیدار)
نوع فایل: rar DelExe.rar (622 بایت, 21 دیدار)

 

بخش سوم امنيت نرم افزارهاي (پيشرفته):
اين روش بسيار كارآمد و تقريبا مي توان گفت تا وقتي كه كد اصلي (Decode) لو نرفته برنامه شما تا 99% ايمن و به راحتي قابل انتشار در بازار حتي بازار جهاني است .
گوش فرا دهيد :
در برنامه هاي تجاري مي توان گفت كه 100% وجود بانك اطلاعاتي الزامي است (Sql Sever,Oracle , MySql ,DBISAM) و نكته مهمي كه وجود دارد برقراي ارتباط با بانك اطلاعتي است (Connect To Database) پس يكي از گزينه هاي مهم برنامه اتصال به بانك اطلاعاتي است .
در صورتي كه شما بخشي از كدهاي مهم برنامه را كه براي اجراي برنامه وجودشان حياتي است را محافظت كنيد مي توانيد گام مؤثري را در مقابله با كركرها برداريد .
كركرها در حالت طبيعي و نرمال پس از UnPack برنامه مي توانيد شرطها و كيسها و حلقه ها را شناسايي و عملكرد آنها را تغيير يا غيرفعال كنند . يك تايمر يا يك تابع را با يك Nop يا عكس كردن عملش آن را غير فعال و اصطلاحاٌ آن را كرك كنند . اما اگر حلقه For يا Case يا Connect به بانك اطلاعاتي وجود داشته باشد .
بله مي خوام برم بعد از اين مقدمه كوتاه روي اصل ماجرا .
خوب اگر ما بتوانيم كدهاي برنامه را بعد از مرحله Design و توليد فايل اجرايي تغيير دهيم ديگر كسي نمي تواند كدهاي ما را تغيير و آنها را Crack كند . البته غيير ممكن نيست ولي بسيار مشكل و به شانس بسيار زيادي بستگي دارد .
خوب پس براي اجراي كدهاي تغيير پيدا كرده چه كاري مي توان انجام داد . بايد با استفاده از الگوريتم عكس عمل كد در زمان اجرا (Run Time) كدهاي Encrypt شده را در حافظه Decrypt نمود .

بسياري از پروتكتورهاي معرف اين امكان مهم را ارائه و پشتيباني مي كنند كه ما به راحتي از آن به دليل (شايد بلد نبود نحوه استفاده يا عدم مطالعه Help) ناشناخته استفاده نمي كنيم .

من براي مثال نحوه انجام اين كار را با Protector & Packer SVKP 1.44 توضيح مي دهم .

در پكيجهاي ابزارهاي Packer و Protector معمولا دو فايل با نامهاي مشخص وجود دارد كه براي اين مجموعه به نامهاي delphi_svkp_block_begin.inc و delphi_svkp_block_end.inc فايل اول حاوي اطلاعات و كدهاي اسمبلي زير است :

کد:
asm DB $EB,$7F,$EB,$00,$99,$AA,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $EB,$7F,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;

و فايل دوم حاوي كدهاي زير است :

کد:
asm DB $EB,$7F,$EB,$00,$BB,$CC,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $EB,$7F,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;
asm DB $90,$90,$90,$90,$90,$90,$90,$90,$90,$90 end;


اين كدها قرار است قبل و بعد از فرامين كليدي و مهم ما كه در بالا به يكي از مهمترين آنها اشاره شد قرار مي گيرند .

با فرض اينكه اين دو فايل در پوشه include قرار داشته باشند به اين نحو استفاده مي شوند :

کد:
unit main;

interface

procedure Start;

implementation

uses
  Registry,
  Classes,
  Windows,
  SysUtils,
  special;

var
  RegMessage : String;
// This procedure will encrypted and it will decrypted only if user have correct registration key
procedure ActionForRegisteredUsers;
begin
    {$I include\delphi_svkp_block_begin.inc}
    RegMessage := 'Registered version!';
    MessageBox(0,PChar (RegMessage),'',0);
    {$I include\delphi_svkp_block_end.inc}
end;

procedure Start;
begin
  try

// this code will decrypted before using and after use removed
// tip: This type of blocks is very good use in initialize part of program
// (load DLL(s), initialize data, fill some special variables and etc.)
    {$I include\delphi_svkp_block_type2_begin.inc}
    RegMessage := 'Encryption blocks example';
    {$I include\delphi_svkp_block_type2_end.inc}

// This code will decrypted before using and encrypted again after use
    {$I include\delphi_svkp_block_type1_begin.inc}
    MessageBox(0,PChar (RegMessage),'',0);
    ActionForRegisteredUsers; //this procedure is only for registered users
    {$I include\delphi_svkp_block_type1_end.inc}
  except
  end;
end;
end.

در كد بالا از يك Uses به نام special استفاده شده است كه ممكن است براي شما سوال پيش بيايد كه اين فايل چيست . معمولا Protectorها علاوه بر تغييراتي كه برروي فايل اجرايي انجام مي دهند يك سري كدهاي سودمند براي مقابله با Debugger ها و ساير سيستمهاي نفوذي مي نويسند كه با توجه به نوع زبان برنامه نويسي قابل استفاده است . كه در اينجا با استفاده از اين فايل كه در اصل براي استفاده از يك Dll كه همراه package پروتكتور عرضه شده استفاده شده است . عدم استفاده از اين فايل اشكالي در سيستمي حفاظتي از كدها نمي كند . فقط جهت افزايش امنيت است .


حالا براي اينكه بتوان كدها را حفاظت نمود پس از توليد فايل اجرايي شما بايد به وسيله پروتكتور فايل را محافظت كنيد . در هنگامي كه پروتكتور در حال تغيير موقعيت احضار توابع و رويه ها است . وقتي به كدهاي ما رسيد :

کد:
procedure ActionForRegisteredUsers;
begin
    {$I include\delphi_svkp_block_begin.inc}
    RegMessage := 'Registered version!';
    MessageBox(0,PChar (RegMessage),'',0);
    {$I include\delphi_svkp_block_end.inc}
end;

اطلاعات موجود در فايل هاي مشخص شده را با اطلاعات كد هاي ما و يك سري كد كه با ااگوريتم RSA توليد مي شود تركيب مي نمايد . و باعث تغيير فيزيكي محتواي فايل اجرايي مي شود . يا اصطلاحاْ به نوعي محتواي فايل را خراب مي كند .

حالا براي اجراي برنامه به صورت صحيح و رجيستر شده حتما نياز به كد فعال سازي جهت Decrypt شدن اطلاعات خراب شده در فايل اجرايي برنامه است كه اين فايل توسط پروتكتور توليد مي شود .

كه در اين مثال SVKP فايل را به نام regkey.key توليد مي كند كه حاوي كد فعال سازي و بازسازي اطلاعات تخريب شده در زمان اجراست است.

به يك نمونه از محتواي اين فايل توجه كنيد :

کد:
-----BEGIN RSA PUBLIC KEY-----
AAG/aAN0uqBYL7SxnMqOHJouq3Yhz2nV3KW6pfhDQ29qbIlFRJWrYni8fVTud9Gli5rJft
jAYy/pf0Ee2aKcD2t+j6+y2pweECBTfOjVwBw9bmFWTOchMBG8b7xzh3wZ+6S/2/QeYILI
0Gmop/wuCrZzm3MkekGSRspC2v2R8dtgDl3ZGsHwMYpmOqWnNSrpxzeanGAS4D3iUyo50H
tVKGOHqba96HD4yG5G+suc3tZObR1rJveXpCU9WLCFltVxkXhpDYQFr7XhEJTi3H9TEfJ1
coH8MQla3j1vwPLtyVD4hpeyyOHJ5qbTyLXmyjavIouaOBOSZBYlLi332qLiPI4DAQADA
-----END RSA PUBLIC KEY-----

در صورتي كه اين فايل وجود داشته باشد برنامه اجرا و در غير اين صورت امكان اجراي برنامه وجود نخواهد داشت .

براي پيدا كردن اين كد بايد به روش سعي و خطا عمل كرد مانند روش پيدا كردن رمز فايلهاي RAR يا Zip يا از روش نقل قول (Fh_prg) : (Bruteforce) مي توان استفاده نمود كه كار بسيار وقت گير و مشكلي است .

البته من براي اين كار از پروتكتورها استفاده نمي كنم . من در برنامه ها از كامپوننت SecureCode استفاده مي كنم . به دليل كپي رايت از ارائه اين كامپوننت در اينجا شرمنده هستم

البته اگر فايل رجيستر را ارائه دهيد و سيستم امنيني برنامه شما پايين باشد به راحتي مي توان با مثلا OLLY آن را dump كرد و از آنجايي كه فايل به صورت صحيح در Ram لود شده است اين محدوديت از بين مي رود .

از دوستان تقاضا مي شود كه الگوريتمهاي antidebug خود دريغ نكنند . با همكاري و هم فكري هم ميشه سد بسيار بسيار بزرگي در مقابل كركرها ايجاد نمود .
از دوستان كركر كلاه سفبد تقاضا مي شود از الگوريتمهاي ضد ديباگ و مشكل ساز براي كركها بگذارند .

خب مي خوام ابزاري رو معرفي كنم كه رايگان و بسيار قدرتمند است براي كد كردن رشته ها در دلفي يا اصطلاحا مخفي كردن آنها اين ابزار بسيار مفيد براي كركرها تازه كار و كار كركرهاي حرفه اي را بسيار مشكل در پيدا كردن و شناسايي رشته هاي برنامه ها شما مي كند .

دقت كنيد : نام اين مجموعه
Delphi Strings Killer (DSKiller) مي باشد . شما به صورت عادي برنامه را نوشته و كليه رشته ها را در برنامه تعريف مي كنيد سپس برنامه DSKiller را اجرا و فايل pas خود را مثلا اگر نامش unit1.pas باشد را open مي كنيد در فايل رشته ها را تعريف كرده ايد . حالا فايل شما باز شده و كليه رشته هاي شما ظاهر مي شود آنهايي را كه مي خواهيد كد كنيد را انتخاب و كليد كد شدن را بزنيد .
من يك مثال قبل از كد و يكي بعد از كد براي شما مي زنم

قبل از كد شدن :

کد:
 
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
    if edit1.Text='HiProgrammer' then
     showmessage('Hoooooooooooooo')
end;
end.



بعد از كد شدن : (كركر)


کد:
 
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
const
  dbs: array [0..26] of Byte= (
    $78,$EB,$94,$6C,$AC,$D9,$B6,$27,$F4,$A2,$CE,$21,$78,$ED,$0E,$29,
    $0D,$39,$6C,$6C,$80,$BC,$F4,$82,$D8,$80,$D4
  );

function dcf(aBegPos, aLength: Integer): string;
var tmp: string;
    i, endPos: Integer;
    MyKey: word;
begin
  MyKey:= 12345;
  SetLength(Result, aLength);
  tmp:= '';
  endPos:= aBegPos+ aLength -1;
  for i:= aBegPos to endPos do
    tmp:= tmp+ Chr(dbs[i]);
  for i:= 1 to Length(tmp) do
  begin
    Result[i]:= Char(Byte(tmp[i]) xor (MyKey shr 8));
    MyKey:= (Byte(tmp[i])+ MyKey)* 52845+ 22719;
  end;
end;
 
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
    if edit1.Text=dcf(0 ,12) then
     showmessage(dcf(12 ,15))
end;
end.

خوب اميد وارم كه استفاده كرده باشيد .
ما هرچه داريم رو مي كنيم . منتظر دارايهاي شما هم هستيم .

فایل های ضمیمه
نوع فایل: rar StringKiller.rar