Автор сразу хочет оговориться: данный вариант, ввиду большого размера исходных файлов не подойдет для создания билдеров троев и прочей малвари (хотя кто как умудряется). В этой статье я покажу, как создать один единственный ехешник-билдер, который будет компилировать прогу пинговщик определенного 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
Поправь Ну и не плохо было бы, почистить список DCU. В идеале вообще, взять исходники системных модулей, и положив их рядом с проектом, почистить ненужные куски кода(а их там дохерища)
Поправил) Насчет списка DCU - там нет лишнего. Все файлы из этих требует dcc32.exe - проверено! Я не старался делать мегакрутой билдер. Я лишь хотел показать - билдер на дельфе возможен! Но твоя идея насчет исходников модулей - интересная) Готовый ехешник уменьшится в разы.
Я не всматривался в код, но где используется, например, модуль variants, я честно говоря не нашел... И он такой не один, по моим прикидкам(Dialogs,... Весь список вываливать лень)))) Хотя может где-то в необходимых модулях подтягиваются, не знаю) Нужно смотреть) Но в твоем(клиентском модуле) они вроде как не используются)
Да, я тоже удивился подгрузке, например, модуля Printers) Но без него не хочет компилиться, увы... Нужна чистка, конечно, но это очень, очень долго!
Как вариант, попользовать, что-то вроде, _http://www.peganza.com/products_icarus.htm Я его не тестировал, поэтому нужно быть аккуратным, по отзывам программа чистит(?) такие модули, как, ShareMem, XPMan и прочие)
Кто может помочь переделать под генератор вирусов ? Не за спасибо, разумеется. Пишите мне в вк vk.com/palcohol.manager