1. Теперь за форумную активность начисляются биткоины и другие криптоденьги. Подробнее.
    Скрыть объявление
  2. Появилась архивная версия форума arhiv.xaker.name, где собраны темы с 2007 по 2012 год.
    Скрыть объявление

Пишем Очень Чоткий Билдер на Delphi

Тема в разделе "Pascal/Delphi", создана пользователем Dr. MefistO, 21 май 2011.

  1. Dr. MefistO
    Dr. MefistO Крывіч Глобальный модератор
    Симпатии:
    123
    Автор сразу хочет оговориться:
    данный вариант, ввиду большого размера исходных файлов не подойдет для создания билдеров троев и прочей малвари (хотя кто как умудряется).

    В этой статье я покажу, как создать один единственный ехешник-билдер, который будет компилировать прогу пинговщик определенного ip-адреса, определенным кол-вом пакетов (все эти параметры будут указываться в билдере). Мы будем писать GUI-вариант со всякими галочками, кнопочками и прочими перделками. Но те кто захочет, могут в качестве домашнего задания сделать консольный вариант. Использоваться будет консольный компилятор dcc32.exe, который находится в папке Bin каталога с Delphi 7.

    Нам понадобится:
    • Delphi 7 для создания программ (советую Delphi 7 Lite);
    • Resource Builder (для вшивания файлов в ехе-шник);
    • DccUsing.pas - поможет в работе с dcc32.exe, не забудьте добавить его в файлы проекта билдера и в Uses;
    • Brain & Hands (спросите у Гугла).

    Итак, начнем мы с написания с шаблона ping-программы. Мы сделаем программу такой, чтобы она не показывала своего окна, а только выдавала в текстовик лог своей работы. Для того, чтобы создать тело проекта, откройте Дельфу (используем Delphi 7), нажмите File->New->Other...->Console Application.
    Сразу же можно сохранить весь проект: File->Save All, и укажем какую-нибудь папку. Я назвал проект test.dpr.

    Теперь, для того, чтобы программа не показывала своего окна, мы изменим APPTYPE с CONSOLE на GUI:
    Код:
    {$APPTYPE CONSOLE}
    Код:
    {$APPTYPE GUI}
    Объявим две константы: одну для адреса ресурса, который будем пинговать, а вторую - для количества пакетов, которые будем отсылать.
    Код:
    const
    ip='ipping';
    pac=5;
    ipping - это шаблон ip-адреса, который мы будем через билдер подменять - не стоит обращать на это внимания пока.
    В дальнейшем мы эти константы будем подменять на свои из билдера.
    Для того, чтобы получить вывод нашей проги в текстовый файл, воспользуемся функцией, найденной на просторах инета, и немного подредактированной:
    Код:
    procedure Dos2Win(CmdLine:String; OutMemo:TStringList);
    const BUFSIZE = 2000;
    var SecAttr    : TSecurityAttributes;
        hReadPipe,
        hWritePipe : THandle;
        StartupInfo: TStartUpInfo;
        ProcessInfo: TProcessInformation;
        Buffer     : Pchar;
        WaitReason,
        BytesRead  : DWord;
    begin
     
     with SecAttr do
     begin
       nlength              := SizeOf(TSecurityAttributes);
       binherithandle       := true;
       lpsecuritydescriptor := nil;
     end;
     // Creazione della pipe
     if Createpipe (hReadPipe, hWritePipe, @SecAttr, 0) then
     begin
       Buffer  := AllocMem(BUFSIZE + 1);    // Allochiamo un buffer di dimensioni BUFSIZE+1
       FillChar(StartupInfo, Sizeof(StartupInfo), #0);
       StartupInfo.cb          := SizeOf(StartupInfo);
       StartupInfo.hStdOutput  := hWritePipe;
       StartupInfo.hStdInput   := hReadPipe;
       StartupInfo.dwFlags     := STARTF_USESTDHANDLES +
                                  STARTF_USESHOWWINDOW;
       StartupInfo.wShowWindow := SW_HIDE;
     
       if CreateProcess(nil,
          PChar(CmdLine),
          @SecAttr,
          @SecAttr,
          true,
          NORMAL_PRIORITY_CLASS,
          nil,
          nil,
          StartupInfo,
          ProcessInfo) then
         begin
           // Attendiamo la fine dell'esecuzione del processo
           repeat
             WaitReason := WaitForSingleObject( ProcessInfo.hProcess,100);
             Application.ProcessMessages;
           until (WaitReason <> WAIT_TIMEOUT);
           // Leggiamo la pipe
           Repeat
             BytesRead := 0;
             // Leggiamo "BUFSIZE" bytes dalla pipe
             ReadFile(hReadPipe, Buffer[0], BUFSIZE, BytesRead, nil);
             // Convertiamo in una stringa "\0 terminated"
             Buffer[BytesRead]:= #0;
             // Convertiamo i caratteri da DOS ad ANSI
             OemToAnsi(Buffer,Buffer);
             // Scriviamo nell' "OutMemo" l'output ricevuto tramite pipe
             OutMemo.Text := OutMemo.text + String(Buffer);
           until (BytesRead < BUFSIZE);
         end;
       FreeMem(Buffer);
       CloseHandle(ProcessInfo.hProcess);
       CloseHandle(ProcessInfo.hThread);
       CloseHandle(hReadPipe);
       CloseHandle(hWritePipe);
     end;
    end;
    Как видим, это процедура выводит все в OutMemo:TStringList. Но у нас ведь нет еще его. Так что давайте объявим переменную, в которую и будем все выводить:
    Код:
    var
    mmoTemp: TStringList;
    Вы должны знать, что все переменные в консольном приложении объявляются до основного begin'а.
    Такс, переменная объявлена, теперь создадим в этой переменной объект TStringList. Этот код уже должен размещаться в основном теле Begin..End.:
    Код:
    mmoTemp:= TStringList.Create;
    Собственно, вызов процедуры вывода:
    Код:
    Dos2Win('ping.exe '+ip+' -n '+inttostr(pac), mmoTemp);
    Здесь мы вызываем стандартную утилиту винды: ping.exe, с ипником в константе ip, и количеством пакетов в константе pac.
    Итого пока получается команда: ping.exe ipping 5
    Теперь из этого mmoTemp сохраним текст в файл стандартной процедурой:
    Код:
    mmoTemp.SaveToFile(ExtractFileDir(ParamStr(0))+'\logout.log');
    ExtractFileDir(ParamStr(0)) - указывает путь к каталогу с программой.
    ...и очищаем память от объекта:
    Код:
    mmoTemp.free;
    Все, основной проект шаблона готов.
    Весь исходник шаблона (компилировать пока не нужно):
    Код:
    program testdpr;
    
    {$APPTYPE GUI}
    
    uses
      SysUtils, StdCtrls, Controls, Windows, Forms, Classes;
    
    const
      ip='ipping';
      pac=5;
    
    var
      mmoTemp: TStringList;
    
    procedure Dos2Win(CmdLine:String; OutMemo:TStringList);
    const BUFSIZE = 2000;
    var SecAttr    : TSecurityAttributes;
        hReadPipe,
        hWritePipe : THandle;
        StartupInfo: TStartUpInfo;
        ProcessInfo: TProcessInformation;
        Buffer     : Pchar;
        WaitReason,
        BytesRead  : DWord;
    begin
     
     with SecAttr do
     begin
       nlength              := SizeOf(TSecurityAttributes);
       binherithandle       := true;
       lpsecuritydescriptor := nil;
     end;
     // Creazione della pipe
     if Createpipe (hReadPipe, hWritePipe, @SecAttr, 0) then
     begin
       Buffer  := AllocMem(BUFSIZE + 1);    // Allochiamo un buffer di dimensioni BUFSIZE+1
       FillChar(StartupInfo, Sizeof(StartupInfo), #0);
       StartupInfo.cb          := SizeOf(StartupInfo);
       StartupInfo.hStdOutput  := hWritePipe;
       StartupInfo.hStdInput   := hReadPipe;
       StartupInfo.dwFlags     := STARTF_USESTDHANDLES +
                                  STARTF_USESHOWWINDOW;
       StartupInfo.wShowWindow := SW_HIDE;
     
       if CreateProcess(nil,
          PChar(CmdLine),
          @SecAttr,
          @SecAttr,
          true,
          NORMAL_PRIORITY_CLASS,
          nil,
          nil,
          StartupInfo,
          ProcessInfo) then
         begin
           // Attendiamo la fine dell'esecuzione del processo
           repeat
             WaitReason := WaitForSingleObject( ProcessInfo.hProcess,100);
             Application.ProcessMessages;
           until (WaitReason <> WAIT_TIMEOUT);
           // Leggiamo la pipe
           Repeat
             BytesRead := 0;
             // Leggiamo "BUFSIZE" bytes dalla pipe
             ReadFile(hReadPipe, Buffer[0], BUFSIZE, BytesRead, nil);
             // Convertiamo in una stringa "\0 terminated"
             Buffer[BytesRead]:= #0;
             // Convertiamo i caratteri da DOS ad ANSI
             OemToAnsi(Buffer,Buffer);
             // Scriviamo nell' "OutMemo" l'output ricevuto tramite pipe
             OutMemo.Text := OutMemo.text + String(Buffer);
           until (BytesRead < BUFSIZE);
         end;
       FreeMem(Buffer);
       CloseHandle(ProcessInfo.hProcess);
       CloseHandle(ProcessInfo.hThread);
       CloseHandle(hReadPipe);
       CloseHandle(hWritePipe);
     end;
    end;  
    
    begin
      { TODO -oUser -cConsole Main : Insert code here }
      mmoTemp:= TStringList.Create;
      Dos2Win('ping.exe '+ip+' -n '+inttostr(pac), mmoTemp);
      mmoTemp.SaveToFile(ExtractFileDir(ParamStr(0))+'\logout.log');
      mmoTemp.free;
    end.
    Часть вторая: написание основного билдера.
    Закрываем проект шаблона, и создаем новый проект: File->New->Application. Опять же сохраняем весь проект.
    На основную форму кинем два эдита (TEdit): в один мы будем писать адрес ресурса для пинга (edtIP), а во второй количество пакетов (edtPackets), затем кидаем кнопку для запуска построения файла из шаблона (btnBuild), и один Memo (mmoLog) для записи лога работы.

    Чтобы быть совсем уж чоткими поцыками, мы сделаем так, чтобы все необходимое извлекалось из ресурсов.
    Пропишем сначала процедуру для извлечения ресурса (в котором мы будем хранить исходник для компиляции) из файла:
    Код:
    procedure UnpackRes(const Name, FileName: string);
    var
      rsCode: TResourceStream;
    begin
      rsCode:= TResourceStream.Create(HInstance,Name,RT_RCDATA);
      rsCode.SaveToFile(FileName);
      rsCode.Free;
    end;
    В качестве Name мы будем передавать имя ресурса, а FileName - куда извлекать.

    Теперь нужно создать res-файл с исходником, который будет прикрепляться к билдеру. Для этого откроем Resource Builder. Откроем раздел RCDATA, нажмем на нем ПКМ и выберем Добавить. Появится окно выбора файла и ввода имени ресурса. Назовем ресурс CODE, и выберем dpr-файл того шаблона, что получился у нас в первой части. Теперь жмем меню Сервис->Компилировать, и сохраняем полученный файл в каталоге с исходником билдера (не шаблона!!!). Тип файла должен быть Resource Files, а расширение res. Файл назовем code.res. Все, RB можно закрывать.

    Для того, чтобы полученный файл ресурсов подключался к проекту, нужно прописать после:
    Код:
    {$R *.dfm}
    следующий код:
    Код:
    {$R code.res}
    Займемся написанием основного функционала.
    На кнопку btnBuild пропишем распаковку ресурсов из ехешника в каталог с программой под именем test.dpr:
    Код:
    UnpackRes('CODE', ExtractFileDir(ParamStr(0))+'\test.dpr');
    Все, шаблон распакован, но как же его изменять? Очень просто. Нам нужно загрузить этот шаблон во временный StringList. Назовем его mmoTemp, а затем через функцию StringReplace подменять участки кода:
    Код:
    var
      mmoTemp: TStringList;
      s,k: string;
    Теперь код считывания кода из распакованного ресурса, и загрузка его в переменную s (будем работать с текстом шаблона именно через эту переменную):
    Код:
      mmoTemp:=TStringList.Create;
      mmoTemp.LoadFromFile(ExtractFileDir(ParamStr(0))+'\test.dpr');
      s:=mmoTemp.Text;
      k:=StringReplace(s,'ipping',edtIP.text,[rfIgnoreCase]);
      s:=k;
      k:=StringReplace(s,'=5','='+edtPackets.text,[rfIgnoreCase]);
      s:=k;
      mmoTemp.Text:=k;
      mmoTemp.SaveToFile(ExtractFileDir(ParamStr(0))+'\test.dpr');
      mmoTemp.Free;
    Здесь мы создали StringList, загрузили в него файл шаблона, переменной s присвоили этот текст, заменили шаблон адреса ресурса введенным в эдит айпишником, затем заменили шаблон количества пакетов цифрой из эдита edtPackets. Потом сохранили изменения в распакованном шаблоне.

    Приступаем непосредственно к компиляции шаблона:
    Код:
    ExecDcc32(ExtractFileDir(ParamStr(0))+'\bin','-$D- -$L- -$Y- -O -H -Q -U"'+ExtractFileDir(ParamStr(0))+'\bin" -E"'+ExtractFileDir(ParamStr(0))+'"',ExtractFileDir(ParamStr(0))+'\test.dpr','logout.txt');
    Нихрена не понятно, да?) Сейчас разъясню.
    Первым параметром в процедуре ExecDcc32 передается папка с файлом dcc32.exe. У меня это папка bin в каталоге с ехешником билдера. Дальше идут ключи компилятора:
    Код:
    -$D- -$L- -$Y- -O -H -Q
    их лучше не трогайте, если не знаете, для чего они. Далее:
    Код:
    -U"'+ExtractFileDir(ParamStr(0))+'\bin"
    Здесь мы указываем путь к dcu файлам, необходимым для компиляции. Все нужное можно найти в папке Lib в каталоге с Дельфой. Что именно необходимо вы узнаете дальше.
    Дальше - каталог, в который будет сохраняться компилируемый ехешник шаблона:
    Код:
    -E"'+ExtractFileDir(ParamStr(0))+'"'
    У меня это каталог с билдером.
    Следующие два параметра:
    ExtractFileDir(ParamStr(0))+'\test.dpr' и 'logout.txt' указывают на распакованный из ресурсов код шаблона и файл лога его компиляции.

    Для того, чтобы следить за тем, что сделалось успешно, а что нет, нужно из файла лога компиляции загрузить текст в наш mmoLog. Для этого:
    Код:
    mmoLog.Lines.LoadFromFile('bin\logout.txt');
    Ну и напоследок перед компиляцией добавьте в Uses все необходимые библиотеки (у меня их может быть больше, но не обращайте внимания):
    Код:
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls, DccUsing, Grids, ValEdit, ExtCtrls, ComCtrls;
    С кодом компиляции покончено, а вот с самой компиляцией нет. Чуть ранее я говорил насчет dcu-файлов.
    Попробуйте сейчас скомпилировать проект. В логе будут появляться надписи, что, мол, не хватает какого-то dcu-файла, например: Dialogs.dcu. Вот их и нужно будет кидать в папку bin, к компилятору dcc32.exe. Итого, компилятор от меня потребовал добавить следующие файлы:
    [+] Файлы
    activex.dcu
    ActnList.dcu
    classes.dcu
    Clipbrd.dcu
    commctrl.dcu
    commdlg.dcu
    Consts.dcu
    contnrs.dcu
    Controls.dcu
    controls.res
    Dialogs.dcu
    dlgs.dcu
    ExtCtrls.dcu
    flatsb.dcu
    Forms.dcu
    Graphics.dcu
    helpintfs.dcu
    ImgList.dcu
    imm.dcu
    math.dcu
    Menus.dcu
    messages.dcu
    multimon.dcu
    Printers.dcu
    regstr.dcu
    RTLConsts.dcu
    shellapi.dcu
    shlobj.dcu
    StdActns.dcu
    StdCtrls.dcu
    strutils.dcu
    syncobjs.dcu
    SysConst.dcu
    SysInit.dcu
    System.dcu
    sysutils.dcu
    Themes.dcu
    Types.dcu
    typinfo.dcu
    UrlMon.dcu
    UxTheme.dcu
    variants.dcu
    varutils.dcu
    windows.dcu
    WinHelpViewer.dcu
    WinInet.dcu
    winspool.dcu
    [свернуть]

    Если все нормально, в каталоге с билдером создастся файл test.exe, который будет пинговать указанный вами ипник, и отправлять указанное количество пакетов.

    Ах, да! Можно после компиляции дописать удаление распакованного ресурса. А то вдруг кому-то захочется его прочитать?!=)
    Код:
    DeleteFile(ExtractFileDir(ParamStr(0))+'\test.exe');
    Ну и код для кнопки теста запуска:
    Код:
    WinExec(PAnsiChar(ExtractFileDir(ParamStr(0))+'\test.exe'),SW_HIDE);
    На этом все! "СТОП. А Как же ОДИН ехешник Билдера?"
    Здесь тоже все просто, только очень долго это все расписывать. Нужно по аналогии с шаблоном в ресурсах добавить еще и все dcu-файлы, компилятор туда же. И написать код для распаковки этого всего в папку Bin, которую перед распаковкой создавать, а после нее - удалять.

    Если что-то вам не понятно, прошу - спрашивайте! Постараюсь подсказать...
    З.Ы. Для защиты исходника можно его зашифровать, и зашифрованный уже зашивать в ресурсы. А потом, перед компиляцией расшифровывать. В своем проекте я использовал алгоритм проверки фокуса окна, т.е. если окно билдера на переднем фоне, то соурс распаковывается, и если фокус теряется - удаляю исходник. Но это уже оставляю на вашу фантазию))

    Вот вам готовый билдер со всеми прибамбасами:
    Hidden Content:
    **Hidden Content: To see this hidden content your post count must be 10 or greater.**
    Организовано:
    • защита исходника шифрованием;
    • удаление при потере фокуса;
    • поддержка параметров командной строки: dccbuilder.exe ipadress [packets exename]
    • если в каталоге с прогой есть файл set.ini с параметрами:
      Код:
      [BUILD]
      ip=192.168.1.1
      packets=666
      exename=out.exe
      
      происходит считывание из него параметров.
    Автор: Dr. MefistO
     
    Последнее редактирование: 21 май 2011
    21 май 2011
    2 пользователям это понравилось.
  2. ~|~евто|-|
    ~|~евто|-| Silentium Новичок
    Симпатии:
    162
    Поправь
    Ну и не плохо было бы, почистить список DCU.
    В идеале вообще, взять исходники системных модулей, и положив их рядом с проектом, почистить ненужные куски кода(а их там дохерища) :)
     
    21 май 2011
    1 человеку нравится это.
  3. Dr. MefistO
    Dr. MefistO Крывіч Глобальный модератор
    Симпатии:
    123
    Поправил)
    Насчет списка DCU - там нет лишнего. Все файлы из этих требует dcc32.exe - проверено!
    Я не старался делать мегакрутой билдер. Я лишь хотел показать - билдер на дельфе возможен! Но твоя идея насчет исходников модулей - интересная) Готовый ехешник уменьшится в разы.
     
    21 май 2011
  4. ~|~евто|-|
    ~|~евто|-| Silentium Новичок
    Симпатии:
    162
    Я не всматривался в код, но где используется, например, модуль variants, я честно говоря не нашел... И он такой не один, по моим прикидкам(Dialogs,... Весь список вываливать лень))))

    Хотя может где-то в необходимых модулях подтягиваются, не знаю) Нужно смотреть)
    Но в твоем(клиентском модуле) они вроде как не используются)
     
    Последнее редактирование: 21 май 2011
    21 май 2011
  5. Dr. MefistO
    Dr. MefistO Крывіч Глобальный модератор
    Симпатии:
    123
    Да, я тоже удивился подгрузке, например, модуля Printers)
    Но без него не хочет компилиться, увы... Нужна чистка, конечно, но это очень, очень долго!
     
    21 май 2011
  6. ~|~евто|-|
    ~|~евто|-| Silentium Новичок
    Симпатии:
    162
    Директивы условной компиляции, метод половинного деления и желание)
    Часа 1.5-2 с лихвой)
     
    21 май 2011
  7. ~|~евто|-|
    ~|~евто|-| Silentium Новичок
    Симпатии:
    162
    Как вариант, попользовать, что-то вроде, _http://www.peganza.com/products_icarus.htm

    Я его не тестировал, поэтому нужно быть аккуратным, по отзывам программа чистит(?) такие модули, как, ShareMem, XPMan и прочие)
     
    25 май 2011
    2 пользователям это понравилось.
  8. Nick100
    Nick100 Новичок
    Симпатии:
    0
    Кто может помочь переделать под генератор вирусов ? Не за спасибо, разумеется. Пишите мне в вк vk.com/palcohol.manager
     
    21 сен 2015

Поделиться этой страницей

Загрузка...