Имеется задача: нужно объединить два *.exe файла в один так, чтобы при
открытии
этого файла запускались обе программы. Я написал программу, использующую
TFileStream, которая записывает один файл в конец другого. Однако при
открытии этого "составного" файла стартует только та программа, которая
находится в голове файла. На сколько я понимаю, при открытии файла
создается процесс и его первичный поток, который представляет первую
программу, а так как вторая программа никак не связана с первой, то она
и не запускается. Так вот, как все-таки запустить ее? Вызвать ее из
первой как еще один поток? Нужно заметить, что меня не устраивает такой
вариант, что первая программа копирует из этого составного файла тело
второй программы в другое место на жестком диске. Буду искренне рад
увидеть примеры ;)
Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице. Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.
20-02-2005 12:03
Высылаю вам статью по этой теме!
Я тоже работаю над такой програмой только я програмирую на Си.
На этот сайт попал случайно, случайно нашол и эту статью которая возможно вам пригодится. Если что получится вышлите пожалуста ехе файл на мыло а то у меня сейчас Delfi нет. Буду также очень благодарен тем хто поможет перевести текст этой проги на СИ.
Как сделать Joiner и недостатки VisualBasic.
Part. #1
Каждый человек, который когда-либо сталкивался с использованием трояном знает что таит в себе это загадочное слово Joiner. Для несведущих объясню, Joiner - это программа, которая позволяет склеить два файла в один исполняемый. А это очень нужная процедура! Объясню на примере: кодер пишет небольшую утилу на VisualBasic, а всем кто когда-либо писал на этом "замечательном" языке должно быть известно, код которые компилит среда является т.н. р-кодом, а он в свою очередь представляет собой закодированные инструкции программы. Исполняемый файл, который получается в результате компиляции является всего лишь интерпретатором р-кода с добавлением кода программы. А весь код который который необходим для работы приложений (отображение формы, рисование контролов и т.д.) содержится в т.н виртуальных машинах, эти файлы жизненно необходимы для работы любой программы на VB. За счет того что все функции зашиты в такие вир-машины удалось значительно снизить размер исполняемого файла программы. Но так ли эффективен этот метод?
Давай рассмотрим простейшую программу на VB…При запуске среды тебе предлагают создать новый проект, выбираем Стандартный-ЕХЕ, после этого будет образован новый проект. Его уже можно запустить на выполнение, нажав клавишу F5. Программа будет выполненна очень быстро, т.к. не будет выполнена процедура компиляции и сборки програмы, как напримет в Delphi. Теперь выберим пункт меня Файл-Создать Ехе, и сохраним его например на рабочий стол. После компиляции на рабочем столе (или в папке куда сохранили) появится файл с расширение ехе, это и есть интерпретатор р-кода. Его размер будет около 14 кб (значение может варьироваться в зависимости от версии языка, например в версиии VB 1.0 он будет размером около 4 кб). Аналогичная программа на Delphi созданная с помощью Vcl будет размером под 300 кб! В чем же причина? А причина как вы уже наверно догадались кроется в использовании вир-машины посмотрим же на ее размер….а находится она по умолчанию в катологе %WinDir%\System (или %WinDir%\System32 в случае линейки НТ) и называется vbrun***.dll для версий языка 1.00-4.00 и msvbvm**.dll для версий 5.0-6.0, гже *** - номер версии языка. Смотрим размер файла и …… о боже! Его размер около 1 Мб! И этот файл необходимо таскать с собой чтоб иметь возможность запустить свою прогу на компе где он отстутсвует! А такскать его за собой, сами понимаете, доволно накладно, особенно если распространять программу вы собираетесь через интернет… Есть конечно выход из сложившейся ситуации, можно сделать для своей программы инсталлятор и распространять уже его, не опасаясь того что у конечного пользователя может не оказаться необходимых файлов. Но делать инсталятор для небольшой программы это по-моему излишество, т.к. вы придется отдать за сдрасте 200-30кб… Вот тут к вам на помощь придет программа джойнер, которая позволит вам сделать из программ на VB что-нибудь более приличное, мы просто возмем и склеим программу и вир-машину в один исполняемый файл, у которого мы также сможем установить иконку…если я Вас заинтересовал, то читайте далее….
Принцип действия
Принцип действия этой программы до безобразия прост! Берутся два файла и записываются после небольшой программы-загрузчика (принцип работы загрузчика мы рассмотрим позже), также записываются размеры этих файлов, зачем - сами потом увидите… Весь код будет оформлен на языке Delphi, в случае необходимости он может быть с легкостью перенесен на другой язык программирование, конечно кроме VB ;)
Сначала лепим на форме много рычагов и кнопок! У меня там валяются 2 - поля ввода, 1 - OpenDialog, 1 - SaveDialog и 4 - кнопки. В полях ввода мы будем отображать имена файлов для склейки. Теперь напишем код для кнопок которые будут отображать эти имена:
-----
type Info = record //Объявляем запись с информацией о файлах
File1Size : Int64; //Размер первого файла
File2Size : Int64; //Размер второго файла
File1ext : string[6]; //Расширение первого файла
File2ext : string[6]; //Расширение второго файла
end;
var Infos : Info;
//Этот код открывает первый файл
procedure TForm1.Button1Click(Sender: TObject);
begin
if OpenDialog1.Execute then Edit1.Text:=OpenDialog1.FileName;
end;
//Этот код открывает второй файл
procedure TForm1.Button2Click(Sender: TObject);
begin
if OpenDialog1.Execute then Edit2.Text:=OpenDialog1.FileName;
end;
//По нажатию этой кнопки мы будем выходить из программы :)
procedure TForm1.Button3Click(Sender: TObject);
begin
Close;
end;
//Сдесь будет находиться весь основной код, который
//осуществляет склеивание файлов
procedure TForm1.Button4Click(Sender: TObject);
var
F1, //Первый файл
F2, //Второй файл
F4, //Загрузчик
F5, //Результат
F6 : TFileStream; //Файл с инфой
F3 : File of Info;
begin
//Если файлы не заданы, то выйти из процедуры
if Edit1.text='' then Exit;
if Edit2.text='' then Exit;
//Открываем склеиваемые файлы
F1:=TFileStream.Сreate(Edit1.Text,fmOpenRead);
F2:=TFileStream.Сreate(Edit2.Text,fmOpenRead);
//Открываем загрузчик
F4:=TFileStream.Сreate(ExtractFilePath(Application.ExeName)+'Loader.exe',fmOpenRead);
//Создаем результирующий файл
F5:=TFileStream.Сreate(ExtractFilePath(Application.ExeName)+'result.exe',fmOpenWrite or fmCreate);
//Заносим в запись инфу о наших файлах
Infos.File1Size:=F1.Size;
Infos.File2Size:=F2.Size;
Infos.File1Ext:=ExtractFileExt(Edit1.Text);
Infos.File2Ext:=ExtractFileExt(Edit2.Text);
//Заносим в запись инфу о наших файлах
AssignFile(F3,ExtractFilePath(Application.ExeName)+'info.dat');
Rewrite(F3);
Write(F3, Infos);
CloseFile(F3);
//Открываем этот файл
F6:=TFileStream.create(ExtractFilePath(Application.ExeName)+'info.dat', fmOpenRead);
//Копируем в исходный файл загрузчик
F5.CopyFrom(F4,F4.Size);
//Копируем iервый файл
F5.CopyFrom(F1,F1.Size);
//Копируем второй файл
F5.CopyFrom(F2,F2.Size);
//Копируем файл с информацией
F5.CopyFrom(F6,F6.Size);
//Закрываем все открытые файлы
F1.Free;
F2.Free;
F4.Free;
F5.Free;
F6.Free;
//Удаляем файл с информациией, т.к. он нам больше ненужен
DeleteFile(PChar(ExtractFilePath(Application.ExeName)+'Info.dat'));
end;
Это весь код! Правда несложно! Если же ты че-то непонял смотри коментарии и исходник. Теперь нам нужно сделать Загрузчик который будет извлекать и запускать склеенные файлы. Принцим его работы также прост: сначала он переписывает себя во временный каталог. Потом мы извлекаем из конца файла инфу. Потом читаем размеры файлов из заголовка. Переходим в позицию после Загрузчика и читаем первый файл длиной, которая записана в заголовке, и сохраняем его на диск, потом переходим в позицию длина Загрузчика+длина первого файла и читаем оотуда второй файл, который также сохраняем на диск. Остается просто запустить эти файлы, предварительно удалив ненужный мусор, который мы создали ;) Вот код Загрузчика:
program Loader;
uses Windows, Classes, SysUtils, ShellAPI;
type
dm = record
File1Size : Int64;
File2Size : Int64;
File1Ext : String[6];
File2Ext : String[6];
end;
{$R *.res}
const
LoaderSize = 53248; //размер упаковщика (После компиляции проверь и измени!!!)
HeaderSize = 32; //размер заголовка
var
F1, //Первый файл
F2, //Второй файл
F3, //Заголовочный файл
F4 : TFileStream; //Главный файл
d : Dm;
f : file of dm;
//---------- Вырезано из Avl ----------//
function TempDir:String;
var
Buf:array[0..MAX_PATH] of Char;
begin
GetTempPath(MAX_PATH+1, @buf);
Result := buf;
end;
//---------- Вырезано из Avl ----------//
begin
//Копируем наш файл в другое место
CopyFile(PChar(ParamStr(0)), PChar(TempDir+'temp.dat'), True);
//Открываем наш файл
F4:=TFileStream.Create(TempDir+'temp.dat',fmOpenRead);
F4.Seek(F4.Size-HeaderSize,0);
//извлекаем заголовочный файл с размерами файлов в нутри нашего файла %)
F3:=TFileStream.Create(TempDir+'Header.dat',fmOpenWrite or fmCreate);
F3.CopyFrom(F4,HeaderSize);
F3.Free;
AssignFile(f,TempDir+'Header.dat');//Открываем файл
reset(f); //заголовка
Read(F,d); //и читаем из него
Closefile(F); //наши данные
F4.Seek(LoaderSize,0); //переходим в позицию после упаковщика
//сохраняем 1-ый файл на диске
F1:=TFileStream.Create(TempDir+'file1'+d.File1Ext,fmOpenWrite or fmCreate);
F1.CopyFrom(F4,d.File1Size);
F1.Free;
//переходим в позицию после упаковщика + размер первого файла
F4.Seek(LoaderSize+d.File1Size,0);
//сохраняем 2-ой файл на диске
F2:=TFileStream.create(TempDir+'file2'+d.File1Ext,fmOpenWrite or fmCreate);
F2.CopyFrom(F4,d.File2Size);
F2.Free;
//Закоываем конечный файл
F4.Free;
//Удаляем мусор
DeleteFile(PChar(TempDir+'temp.dat'));
DeleteFile(PChar(TempDir+'Header.dat'));
//Запускаем файлы
ShellExecute(0,'open',PChar(TempDir+'file1'+d.File1Ext),'','',SW_NORMAL);
ShellExecute(0,'open',PChar(TempDir+'file2'+d.File1Ext),'','',SW_NORMAL);
end.
Ну как вам Загрузчик? Ведь тоже ОЧЕНЬ просто! А теперь я хочу заострить ваше внимание на константе LoaderSize эта константа содержит размер Загрузчика в байтах, после того как вы скомпилируете Загрузчик посмотрите его размер и впишите его в значение этой константы и перекомпилируйте снова, т.к. без этого он не будет работать!!! ВСЕ! Теперь вы можете склеивать файлы!!! И напоследок: размер Загрузчика получился довольно большой, чтобы уменьшить его раза в два можно сжать его например Upx или AsPack. Желаю вам удачного склеивания!
Я тут подумал и решил, что продолжу эту тему ;) В одной из следующих статей я раскажу как можно сделать загрузчик меньше 10 кил. и как сделать чтобы Джойнер представлял из себя один файл, а Загрузчик был зашит в тело ехе!
Можно толко пофантазировать следующим образом: весь файл "ляжет" в память, а потом найти сигнатуру и смещение для входа и "прыгнуть" (JMP) туда на асме. Интересно что получится...
Для того чтобы запускать программы по очереди, и чтобы удалять с диска после их закрытия, можно воспользоваться возможностями, предоставляемыми коммандными файлами (файлы типа *.bat). Я также использовал упаковщик SuperGlue32 (спасибо Sportster'у за ссылку - очень полезная программка). Первой в списке (в окне "СуперКлея") следует первая программа, потом вторая, и в конце - *.bat файл. Там же устанавливаешь параметры запуска: первые два файла не запускать, а лишь сохранять (распаковывать) на диске (установка Store), а третий (*.bat файл) - запускать (установка Run). Также можно установить запуск *.bat файла в скрытом режиме (установка Hidden), чтобы не открывалось сопуствуещее командным файлам черное окно. Содержимое *.bat файла будет примерно таковым:
start /wait program1.exe
start /wait program2.exe
del program1.exe
del program2.exe
cls
Команда start с параметром /wait запускает указанную программу и ждет ее закрытия, после чего передает управление следующей команде *.bat файла (если ввести start /? в коммандной строке, будут указаны все параметры команды start).
После запуска упакованного файла, произойдет распаковывание всех трех файлов и запуск *.bat файла. Этот файл запустит первую программу. После ее закрытия будет запущена вторая программа. После закрытия второй программы, будут удалены обе программы с диска. Естественно, файлы можно удалять и после закрытия каждой программы в отдельности (жаль нельзя удалять программу сразу после ее запуска, так как Windows не разрешает стирать файл программы до ее закрытия). Однако *.bat файл не будет удален (он ведь не может сам себя удалить).
Команда cls в конце обеспечит автоматическое закрытие черного окна *.bat файла после его завершения (даже если *.bat файл запускается скрытно, лучше оставить эту строку, чтобы программа закрылась до конца).
А насчет запуска программ НЕ из файлов на диске, я не представляю, как это сделать.
Нашел недавно еще одну подобную программу объединяющую два файла
и запускающую их по очереди: SuperGlue32 by BaNZaY.
Нашел здесь: http://bonza.narod.ru
Может у кого нибудь есть ее исходники? Очень надо!!!
P.S. Может все таки кто нибудь знает принцип построения
exe-компрессоров или может дать ссылку на архив документации
по этому вопросу? Жду ответов тут или на мыло!
Здравствуйте я вот уже несколько недель бьюсь над проблемой склейки двух файлов и у меня таже проблема
Joiner и другие деревянные изделия ничем помочь не могут они запускают оба файла сразу.
Если вы нашли то что искали напишите мне буду очень признателе.
volkov-b@yandex.ru, volkov-b@rambler.ru
Я пробовал такое делать и нечего хорошего не добился.
Единственое как уменя работеает это:
-сливаю два файла программно
-выполняется та которая первая
-первая же прога у меня отцепляла от себя вторую в определённый
каталог и запускала.
Только так.
Таким образо можно соединить хоть 10 файлов но будет выполнятся
только первый. А затем он разединит от общего все и будет их запускать.
Joiner by Crash - это копия (почти) широко известной Joiner by Blade. Все там устроено просто. В начале
файла идет распаковщик, а затем программы. При запуске распаковщик КОПИРУЕТ из тела файла программы
в другое место на диске и запускает их с помощью CreateProcess() или ShellExecute(). Мне бы хотелось
запускать эти программы БЕЗ копирования. Размер склеиваемых программ может достигать скажем 5 МБ и
заниматься копированием этих программ ну никак не хочется. Да и казалось бы зачем? Ведь они и так уже
загружены в памяти!! Мне говорили на ассемблере возможно такое сделать, но я его не знаю ;) Неужели на
Delphi такого сделать нельзя?
Да, посмотрел на MJ... Он делает именно так, тупо и просто: создаёт во временном
каталоге два exe'шника, соответствующих упакованным файлам и запускает их.
А Joiner by crash я так и не понял, что это за зверь... Судя по исходникам --
что-то подобное.
Есть такой сайт "Мастера Дельфи"
DELPHI.mastak.ru
Поищи там вот это -
Joiner by crash
Программа, которая пакует 2 файла в один,
и когда запускаешь упакованыый файл,
то запускаются ранее упакованые 2 файла.
Там же можно скачать и исходники
Можно попробовать объединить две проги в одну, объединив и все их управляющие
структуры... Было бы интересно, я поковыряюсь. Но вряд ли это быстро. Так
что попробуй готовые решения поискать.
Естесственно первая программа в исходниках, то есть это должна быть моя программа. втрой идет
чужая программа. она может быть вполне приличных размеров, скажем 1-5 МБ.
К сожалению я не представляю как работают упаковщики exe'шников. Программы должны исполняться
одна за другой. Сначала запускается первая программа (та, что в начале файла), заканчивает свою работу и
запускается вторая программа. Я даже примерно не представляю как это можно сделать :( Мне бы идейку или
примерчик ;)
А чем плох вариант с двумя отдельными exe'шниками? Вообще говоря, структура
PE-файла (частный случай -- виндомые exe, dll и пр.) не предполагает наличия
двух программ с двумя точками входа. Типично вирусная технология :-)
Запускать программу, которая компилировалась в расчёте на исполнение в отдельном
процессе, как поток другого... Тут я не берусь предсказать последствия,
скорее всего будут многочисленные конфликты при доступе к общим объектам,
куче, например. Следовательно, надо много извращаться, чтобы такое стало
возможным.
А запустить отдельный процесс не из файла, насколько я знаю, винда не позволит.
Во всяком случае, в описании функции CreateProcess есть на эту тему совершенно
недвусмысленное замечание. Может быть можно ещё как-то создать процесс?
Не знаю.
Программы должны параллельно исполняться или одна за другой (как это делают, например
упаковщики exe'шников)? Если одна за другой, то можно придумать что-нибудь...
А если вместе, то я пас. Слишком много ненадёжного изврата придётся творить.
Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter. Функция может не работать в некоторых версиях броузеров.