Праздники, после двух бутылок водки я неожиданно задумался, как дольше жить а не написать-ли свой Джойнер (Склейщик файлов + запуск нужных)…
В начале начал писать на си билдере, но как оказалась, что она глючит с 7-ой, запарился перед тем-как понял это, было у меня перекрытие памяти при работе с AnsiString, из-за чего такое возникло не знаю, может даже дело и не в винде,а в руках лень разбиратьтся, да и пофиг…
Вспомнил я что на виртуалбоксе у меня стоит делфя, ну и решил я переделать там, благо использовал в основном APIвинды, переделать не составило не какого труда…
Что-то я отвлёкся, ах-да теперь по делу:
Для начала разберёмся, что должен делать наш джойнер:
1)Распаковывать в темп нужные файлы;
2)Запускать необходимые файлы из темпа;
3)Я ещё сделал смену иконки в билде, но не доделал, это ложится на Вас гы-гы…
Данные штуки можно делать по всякому, но я делал по такому алгоритму:
Так-же как и у крипторов, наша прога будет состоят из двух частей (Две программы):
1)Первая программа – Это конструктор, он имеет графический интерфейс, предназначен для сборки нашего билда, т.е. он в зависимости от настроек пользователя создаст нам джойнер (билд):
2)Вторая программа – Это загрузчик (Stub), это по сути и есть основная программа, она отвечает за «Мозги», она и вытаскивает файлы из нашего джойнера при запуске, а также запускает их из папки темп !
Лучше стабы писать на асме, т.к. будет маленький размер, работать будет быстрее, да и вообще меньше будет глюков…
Конструктор-же лучше писать на языках высокого уровня типо там Делфи и т.д.
Мы-же в этой статье напишем и-то и-то на делфи, т.к. статья учебная, что-бы вкурить суть, да и с асмом мне лень разбираться, может позже перепишу, но там всё переделывать надо будет…
Итак начнём:
1)Пишем Конструктор:
Создаём стандартный проект в Делфи…
Создали, теперь что будет делать наш конструктор:
1)Записывать в конец нашего стаба служебную информацию, у нас это: Размер файла, Имя Файла, Имя файла, который нужно запустить, общее число файлов, общее число файлов которые нужно запустить !
Для этих целей я создал структуру, да-да схитрил, можно конечно сделать проще и лучше, но я что-бы не тратить время тупо записывал «слепок» структуры в стаб, а потом стабом и считывал её…
Делается всё на самом деле легко, ниже покажу как, сейчас покажу код самой структуры:
Type
FileInfRecord = record //Это наша структура куда будет считываться вся информация из стаба
_filesize: array [0..1000] of cardinal; // Размерфайла
_filename: array [0..1000] of string[100]; //Имяфайла
_filenameStart: array [0..1000] of string[100]; //Имяфайла, которыйнужнозапустить
_fileCount: cardinal; //Числофайлов (Общее)
_fileCountStart: cardinal; //Число файлов (Которые нужно запустить)
End;
Далее для работы с ней объявляем переменную: _FileHeader: FileInfRecord;
В общем-то весь код объяснять не буду, кому интересно глянете исходник, а расскажу основные моменты и принцип действия:
Нам нужно для начала наполнить структуру необходимыми данными: Размер файла, Имя Файла, Имя файла, который нужно запустить, общее число файлов, общее число файлов которые нужно запустить !
Для этого используем APIвинды, смотри комменты в коде:
Наполняем нашу структуру данными, которые ввёл пользователь в GUI-интерфейсе:
Далее копируем наш стаб, что-бы не портить исходный, в него и будем заносить служебную информацию, а также файлы которые нужно склеить:
Далее, когда структура заполнена нужными данными, нужно её записать в стаб, для этого:
1)Открываем наш скопированный стаб;
2)Перемещаемся в конец файла;
3)Записываем нашу структуру;
4)Далее в цикле записываем файлы, которые нужно склеить.
Смотрите код и читайте комментарии:
Для ускорения копирования чтение файла-источника происходит блоком. За один раз читается и записывается ровно 1024 байта. После записи очередной порции данных нужно позаботиться об очищении памяти. В модуле Windows.pas для этого предусмотрена процедура ZeroMemory. От нас требуется только передать ей два параметра: указатель на буфер, который подлежит очистке, и его размер. В общем-то и всё, переходим к созданию стаба !
2)Конструктор у нас есть. Но вот беда: без программы-загрузчика он мало чем полезен, поэтому нам придется создать новый пустой проект и написать в нем несколько строчек кода. Для программы-загрузчика форма нам не потребуется, поэтому сразу ее удаляй. Вообще, программа-загрузчик должна иметь минимальный размер, а значит, нужно избавиться от всего лишнего. Удали из Uses все модули, оставь лишь Windows и ShellAPI. Их нам будет вполне достаточно. Опиши структуру FileInfRecord. Она должна выглядеть точно так же, как и в программе-конструкторе. Если ты укажешь разные размеры массивов или еще чего-нибудь, то наш загрузчик будет неправильно работать (точнее, не будет работать вовсе).
Для начала разберёмся что-же делает наш стаб:
1)При запуске открывает сам-себя;
2)Считывает нашу структуру;
3)На основании данных в структуре, вытаскивает файлы в папку темп и запускает их.
В общем-то и всё, теперь как это сделать:
Объявляем структуру ТАКУЮ-ЖЕ что и в конструкторе:
type
FileInfRecord = record //Это наша структура куда будет считываться вся информация из стаба
_filesize: array [0..1000] of cardinal; // Размерфайла
_filename: array [0..1000] of string[100]; //Имяфайла
_filenameStart: array [0..1000] of string[100];
_fileCount: cardinal; //Числофайлов (Общее)
_fileCountStart: cardinal; //Число файлов (Которые нужно запустить)
End;
Далее создаём переменную для работы со структурой, например так:_fileHeader:FileInfRecord;
Далее читайте коментраии в коде:
Создай константу mySize. В этой константе у нас будет храниться наш собственный размер стаба, то есть размер программы-загрузчика. На данном этапе мы его не знаем, поэтому пока указываем 0. Код программы-загрузчика приведён выше, но не всё а основные моменты !
Сначала нам нужно открыть для чтения файл программы-загрузчика, то есть самого себя. После открытия выполняем смещение до адреса, с которого начинается код нашего блока с информаций. Как его узнать? Очень просто! Поскольку программа-конструктор записала структуру с информаций в самый конец программы-загрузчика, нужно просто перейти в файле на размер файла загрузчика. Этот размер у нас будет определен в объявленной ранее константе. Позиционирование в файле опять же выполняется с помощью SetFilePointer.
При переходе на нужную позицию становится возможным считать структуру. А раз так, то после выполнения «ReadFile(_fileSource, _fileHeader, sizeOf(_fileHeader), _temp, nil); » вся наша структура будет считана. Ну а это значит, что мы обладаем всей необходимой информацией для выдергивания остальных файлов. Код разбивки тела загрузчика на файлы похож на код программы-конструктора, поэтому не будем на нем останавливаться.
Окончательно дописав код и прочитав предыдущие строки, скомпилируй проект. После завершения компиляции зайди в меню «Project -> Information» и обрати внимание на строку File Size.
В ней указан конечный размер exe нашего проекта. У меня он равен 16384. Именно это число нужно присвоить нашей константе mySize. После этого еще раз сохраняй все изменения в проекте и выполняй компиляцию. Все, наш joiner полностью готов.
Разместите две программы (Два экзешника) в одной папки:
Я назвал их так Joiner.exe– конструктор, Stub.exe– Это наш стаб !
Далее запускаете Joiner.exeесли хотите что-то склеить…
Во вложении (Джойнер.rar) исходники стаба (Папка Stub2) и конструктора (Папка Bulder), а также уже готовый вариант в папке «Бинарник», я также реализовал смену иконки, но глючит, можете доделать ! ;)
И ещё не смог сдержаться и склеил с картинкой страшный руткит, файл Блондинка.exe, во вложении гы-гы-гы !
И ещё вопрос нужно-ли развивать данную тему ?
Могу доработать Джойнер:
1)Переписать стаб на асме;
2)Сделать опцию криптования файлов, т.е. склеевать их шифруя;
3)Доделать смену иконок нормально;
4)Сделать протектор.
Кто-что думает ?
Обновил исходник, "Джойнер2.rar" более новый, немного другой функционал, читай тему ! ;)
В начале начал писать на си билдере, но как оказалась, что она глючит с 7-ой, запарился перед тем-как понял это, было у меня перекрытие памяти при работе с AnsiString, из-за чего такое возникло не знаю, может даже дело и не в винде,
Вспомнил я что на виртуалбоксе у меня стоит делфя, ну и решил я переделать там, благо использовал в основном APIвинды, переделать не составило не какого труда…
Что-то я отвлёкся, ах-да теперь по делу:
Для начала разберёмся, что должен делать наш джойнер:
1)Распаковывать в темп нужные файлы;
2)Запускать необходимые файлы из темпа;
3)Я ещё сделал смену иконки в билде, но не доделал, это ложится на Вас гы-гы…
Данные штуки можно делать по всякому, но я делал по такому алгоритму:
Так-же как и у крипторов, наша прога будет состоят из двух частей (Две программы):
1)Первая программа – Это конструктор, он имеет графический интерфейс, предназначен для сборки нашего билда, т.е. он в зависимости от настроек пользователя создаст нам джойнер (билд):
2)Вторая программа – Это загрузчик (Stub), это по сути и есть основная программа, она отвечает за «Мозги», она и вытаскивает файлы из нашего джойнера при запуске, а также запускает их из папки темп !
Лучше стабы писать на асме, т.к. будет маленький размер, работать будет быстрее, да и вообще меньше будет глюков…
Конструктор-же лучше писать на языках высокого уровня типо там Делфи и т.д.
Мы-же в этой статье напишем и-то и-то на делфи, т.к. статья учебная, что-бы вкурить суть, да и с асмом мне лень разбираться, может позже перепишу, но там всё переделывать надо будет…
Итак начнём:
1)Пишем Конструктор:
Создаём стандартный проект в Делфи…
Создали, теперь что будет делать наш конструктор:
1)Записывать в конец нашего стаба служебную информацию, у нас это: Размер файла, Имя Файла, Имя файла, который нужно запустить, общее число файлов, общее число файлов которые нужно запустить !
Для этих целей я создал структуру, да-да схитрил, можно конечно сделать проще и лучше, но я что-бы не тратить время тупо записывал «слепок» структуры в стаб, а потом стабом и считывал её…
Делается всё на самом деле легко, ниже покажу как, сейчас покажу код самой структуры:
Type
FileInfRecord = record //Это наша структура куда будет считываться вся информация из стаба
_filesize: array [0..1000] of cardinal; // Размерфайла
_filename: array [0..1000] of string[100]; //Имяфайла
_filenameStart: array [0..1000] of string[100]; //Имяфайла, которыйнужнозапустить
_fileCount: cardinal; //Числофайлов (Общее)
_fileCountStart: cardinal; //Число файлов (Которые нужно запустить)
End;
Далее для работы с ней объявляем переменную: _FileHeader: FileInfRecord;
В общем-то весь код объяснять не буду, кому интересно глянете исходник, а расскажу основные моменты и принцип действия:
Нам нужно для начала наполнить структуру необходимыми данными: Размер файла, Имя Файла, Имя файла, который нужно запустить, общее число файлов, общее число файлов которые нужно запустить !
Для этого используем APIвинды, смотри комменты в коде:
Наполняем нашу структуру данными, которые ввёл пользователь в GUI-интерфейсе:
Код:
for i:=0 to ListView1.Items.Count-1 do //Наполняем нашу структуру данными, т.е. заносим имя наших файлов и размер в цикле
begin
_fileHeader._filename[i]:=ListView1.Items.Item[i].Caption; //Имя файла
_fileHeader._filesize[i]:=GetFileSized(ListView1.Items.Item[I].SubItems.Strings[0]+ ListView1.Items.Item[I].Caption); //Размер
end;
for i:=0 to memo1.lines.count-1 do _FileHeader._filenameStart[i]:=Memo1.Lines[i]; //Сюда заносим имя файла, который нужно запускать
_fileHeader._fileCount:=ListView1.Items.Count; //Cюда количество таких файлов
Код:
CopyFile(pchar(extractFilePath(application.ExeName)+ 'stub.exe'), pchar(SaveDialog1.FileName), false); //Скопируем наш стаб в указанный пользователем путь
Sleep(100); //Ждём 100 миллесекунд, это что-бы файл успел скопироваться
1)Открываем наш скопированный стаб;
2)Перемещаемся в конец файла;
3)Записываем нашу структуру;
4)Далее в цикле записываем файлы, которые нужно склеить.
Смотрите код и читайте комментарии:
Код:
_distFile:=CreateFile(pchar(SaveDialog1.FileName), GENERIC_WRITE, 0, nil, OPEN_EXISTING, 0, 0); //Открываем наш уже скопированный стаб
SetFilePointer(_distFile, 0, nil, FILE_END); //Перемещаемся в конец стаба
WriteFile(_distFile, _fileHeader, sizeOf(_fileHeader), _temp, nil); //Записываем нашу структуру в стаб
for i:=0 to ListView1.Items.Count-1 do //Далее нам нужно записать сами файлы, которые мы хотим склееть в стаб, делаем это в цикле
begin
_fromFile:=CreateFile(pchar(ListView1.Items.Item[i].SubItems.Strings[0]+ ListView1.Items.Item[i].Caption), GENERIC_READ, 0, nil, OPEN_EXISTING, 0, 0); //Открываем файл который хотим склееть
repeat
ReadFile(_fromFile, _buff, sizeOf(_buff), _temp, nil); //Читаем файл который хотим склееть
WriteFile(_distFile, _buff, _temp, _temp2, nil);//Записываем эти данные в стаб
ZeroMemory(@_buff, sizeOf(_buff));//Чистим буфер
until _temp<>1025;
CloseHandle(_fromFile);
end;
CloseHandle(_distFile);
ShowMessage('Склейка успешно завершилась!');
2)Конструктор у нас есть. Но вот беда: без программы-загрузчика он мало чем полезен, поэтому нам придется создать новый пустой проект и написать в нем несколько строчек кода. Для программы-загрузчика форма нам не потребуется, поэтому сразу ее удаляй. Вообще, программа-загрузчик должна иметь минимальный размер, а значит, нужно избавиться от всего лишнего. Удали из Uses все модули, оставь лишь Windows и ShellAPI. Их нам будет вполне достаточно. Опиши структуру FileInfRecord. Она должна выглядеть точно так же, как и в программе-конструкторе. Если ты укажешь разные размеры массивов или еще чего-нибудь, то наш загрузчик будет неправильно работать (точнее, не будет работать вовсе).
Для начала разберёмся что-же делает наш стаб:
1)При запуске открывает сам-себя;
2)Считывает нашу структуру;
3)На основании данных в структуре, вытаскивает файлы в папку темп и запускает их.
В общем-то и всё, теперь как это сделать:
Объявляем структуру ТАКУЮ-ЖЕ что и в конструкторе:
type
FileInfRecord = record //Это наша структура куда будет считываться вся информация из стаба
_filesize: array [0..1000] of cardinal; // Размерфайла
_filename: array [0..1000] of string[100]; //Имяфайла
_filenameStart: array [0..1000] of string[100];
_fileCount: cardinal; //Числофайлов (Общее)
_fileCountStart: cardinal; //Число файлов (Которые нужно запустить)
End;
Далее создаём переменную для работы со структурой, например так:_fileHeader:FileInfRecord;
Далее читайте коментраии в коде:
Код:
_fileSource:=Createfile(pchar(ParamStr(0)), GENERIC_READ, 0, nil, OPEN_EXISTING, 0, 0); //Открываем сами себя :)
SetFilePointer(_fileSource, mySize, nil, FILE_BEGIN); //Перемещаемся в конец стаба
ReadFile(_fileSource, _fileHeader, sizeOf(_fileHeader), _temp, nil); // Считываем загаловок в нашу структуру
Start:=_fileHeader._fileCountStart;//В эту переменную заносим число файлов которые нужно запустить
if _fileHeader._fileCount=0 //Если не хуя не считалось
then
begin
Exit; //И выйдем
end;
GetTempPath(MAX_PATH, ShortPath); //Определим папку темп
for i:=0 to _fileHeader._FileCount-1 do
begin
//Создаём файл, в который будем записывать данные, это и есть склеенный файл:
_fileDist:=CreateFile(pchar(string(ShortPath)+string(_fileHeader._filename[i])), GENERIC_WRITE, FILE_SHARE_WRITE,nil,CREATE_NEW, 0, 0);
for j:=1 to _fileHeader._filesize[i] do
begin
ReadFile(_fileSource, _buff, sizeOf(_buff), _temp, nil);// Считываем данные из стаба
WriteFile(_fileDist, _buff, sizeOf(_buff), _temp, nil); // Записываем эти данные в файл, который создали
end;
CloseHandle(_fileDist);
Sleep(100);
end;
Создай константу mySize. В этой константе у нас будет храниться наш собственный размер стаба, то есть размер программы-загрузчика. На данном этапе мы его не знаем, поэтому пока указываем 0. Код программы-загрузчика приведён выше, но не всё а основные моменты !
Сначала нам нужно открыть для чтения файл программы-загрузчика, то есть самого себя. После открытия выполняем смещение до адреса, с которого начинается код нашего блока с информаций. Как его узнать? Очень просто! Поскольку программа-конструктор записала структуру с информаций в самый конец программы-загрузчика, нужно просто перейти в файле на размер файла загрузчика. Этот размер у нас будет определен в объявленной ранее константе. Позиционирование в файле опять же выполняется с помощью SetFilePointer.
При переходе на нужную позицию становится возможным считать структуру. А раз так, то после выполнения «ReadFile(_fileSource, _fileHeader, sizeOf(_fileHeader), _temp, nil); » вся наша структура будет считана. Ну а это значит, что мы обладаем всей необходимой информацией для выдергивания остальных файлов. Код разбивки тела загрузчика на файлы похож на код программы-конструктора, поэтому не будем на нем останавливаться.
Окончательно дописав код и прочитав предыдущие строки, скомпилируй проект. После завершения компиляции зайди в меню «Project -> Information» и обрати внимание на строку File Size.
В ней указан конечный размер exe нашего проекта. У меня он равен 16384. Именно это число нужно присвоить нашей константе mySize. После этого еще раз сохраняй все изменения в проекте и выполняй компиляцию. Все, наш joiner полностью готов.
Разместите две программы (Два экзешника) в одной папки:
Я назвал их так Joiner.exe– конструктор, Stub.exe– Это наш стаб !
Далее запускаете Joiner.exeесли хотите что-то склеить…
Во вложении (Джойнер.rar) исходники стаба (Папка Stub2) и конструктора (Папка Bulder), а также уже готовый вариант в папке «Бинарник», я также реализовал смену иконки, но глючит, можете доделать ! ;)
И ещё не смог сдержаться и склеил с картинкой страшный руткит, файл Блондинка.exe, во вложении гы-гы-гы !
И ещё вопрос нужно-ли развивать данную тему ?
Могу доработать Джойнер:
1)Переписать стаб на асме;
2)Сделать опцию криптования файлов, т.е. склеевать их шифруя;
3)Доделать смену иконок нормально;
4)Сделать протектор.
Кто-что думает ?
Обновил исходник, "Джойнер2.rar" более новый, немного другой функционал, читай тему ! ;)