Хранение нескольких различных файлов в одном исполняемом (Пакер)

Часть I. "Пакер"

© 2003 Zero Ice

Эта материал открывает цикл статей для юных программеров (и хакеров :)) интересующихся скрытием своей информации (а так же поиском интересной "чужой" :)). Не секрет что у тебя есть много того, что ты бы не хотел показывать ФСБ, друзьям, Васе Пупкину, и прочей "мировой общественности". Конечно можно использовать запароленные архивы и прочую лабуду (например твой сосед может не увидеть скрытый файл на расшареном диске :), но если задуматься, то станет ясно что, чем больше людей использует одинаковые системы защиты, тем быстрее улучшаются методы взлома этих систем (сорри за тавтологию).

У тебя ёще не появилось желание написать средство для защиты своей ценнейшей инфы (исходников, рефератов, фоток :) и т.д и т.п.) от посторонних глаз. Ведь если ты что-то написал сам, то только ТЫ знаешь, КАК ОНО ПРЯЧЕТСЯ И ДОСТАЁТСЯ. Наши первые программы будут полезны как программерам, так и хакерам. Это будут Пакер и Анпакер (Packer & Unpacker). В этой статье я опишу только пакер (темы анпакера будут затронуты в следующих статьях). Писать мы его будем на всенародно любимом Delphi (у меня шестая версия, но работать должно и на предыдущих). Суть пакера заключается в следующем: в конец некоего экзешника (.exe) дописываем размер файла который мы потом будем из него доставать, далее следует сам файл, потом размер второго файла, и, собственно, второй. Сразу скажу что под "неким экзешником" я подразумеваю анпакер.

Ну, что? Готов? Если да то запускай Делфи и создавай новый проект (File/New/Application). Первым делом назови как-нибудь форму (Caption) (пусть будет что-то типа "Super-Puper-Mega- Packer"). Далее размести на ней OpenDialog и SaveDialog (вкладка Dialogs). Давай сразу посмотрим на настройки OpenDialog'a. Для этого открой Options в Object Inspector'е и сделай поля ofPathMastExist и ofFileMastExist равными True. Всё это нужно для того, чтобы файлы которые мы будем прятать реально существовали. В SaveDialog'е желательно сделать поле ofPathMastExist равным True. Так же размести на форме кнопку (Button) с грозной надписью "GO!", 3 Edit'а (первым двум Edit'aм в поле ReadOnly надо поставить True) и 3 SpeedButton'а. У SpeedButton1 сделай поле Tag равным 1 (это понадобится в дальнейшем). Теперь можно занятся дизайном нашего пакера (это не должно вызвать особых проблем :)). Не забудь только загрузить рисунки в SpeedButton'ы. Отличные пикчурсы можно взять (если у тебя стоит полная версия Delphi) из \Program Files\Common Files\Borland Shared\Images\Buttons. Я нацепил на SpeedButton1 и SpeedButton2 Fileopen.bmp, а на SpeedButton3 - Filesave.bmp.

А теперь переходим к самому интересному - к кодингу. Для начала сделаем обработчик SpeedButton1'а OnClick и укажем его же в SpeedButton2. В нем напишем следующий код:


procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
 if OpenDialog1.Execute then
  if (Sender as TSpeedButton).Tag=1
   then Edit1.Text:=OpenDialog1.FileName
   else Edit2.Text:=OpenDialog1.FileName;
end;

Если пользователь в OpenDialog'е что-то выбрал, то посмотрим какой из SpeedButton'ов он нажал и присвоим соответствующему Edit'у новое значение. Можно было бы сделать два OnClick'a (у каждого SpeedButton'а свой) и написать что-то типа:


procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
 if OpenDialog1.Execute then
  Edit1.Text:=OpenDialog1.FileName;
end;

procedure TForm1.SpeedButton2Click(Sender: TObject);
begin
 if OpenDialog1.Execute then
  Edit2.Text:=OpenDialog1.FileName;
end;

Но мне это кажется неспортивным. Да и откомпилированная прога будет жирнее на пару байт :). Далее обратим свой взор на SpeedButton3. Сделаем обработчик OnClick в котором:


procedure TForm1.SpeedButton3Click(Sender: TObject);
begin
 if SaveDialog1.Execute then
  Edit3.Text:=SaveDialog1.FileName;
end;

Ну а теперь перейдём к самой интересной кнопке - "GO!". В её OnClick'е будет сам упаковщик:


procedure TForm1.Button1Click(Sender: TObject);
var f,f2:file;
    buf:array[1..1024] of byte;
    done:integer;
begin
 if not((FileExists(Edit1.Text))or(FileExists(Edit2.Text))) then
   begin
    ShowMessage('Неправильно указан путь к файлу');
    Exit;
   end;
 if not FileExists(ExtractFilePath((Application.ExeName))+'Unpacker.exe') then
  begin
   ShowMessage('Не могу найти Unpacker.exe');
   Exit;
  end;
 AssignFile(f,ExtractFilePath((Application.ExeName))+'Unpacker.exe');
 AssignFile(f2,Edit3.Text);
 Reset(f,1);
 Rewrite(f2,1);
 while not eof(f) do begin
  blockread(f,buf,sizeof(buf),done);
  blockwrite(f2,buf,done);
 end;
 CloseFile(f);

 AssignFile(f,Edit1.Text);
 Reset(f,1);
 done:=FileSize(f);
 blockwrite(f2,done,4);
 while not eof(f) do begin
  blockread(f,buf,sizeof(buf),done);
  blockwrite(f2,buf,done);
 end;
 CloseFile(f);

 AssignFile(f,Edit2.Text);
 Reset(f,1);
 done:=FileSize(f);
 blockwrite(f2,done,4);
 while not eof(f) do begin
  blockread(f,buf,sizeof(buf),done);
  blockwrite(f2,buf,done);
 end;
 CloseFile(f);
end;

Тут всё совсем просто :). Для начала проверяем все ли необходимые для упаковки файлы присутствуют. Далее создаем файл указанный в Edit3.Text и записываем в него распаковщик, размер первого файла, файл, размер второго и второй соответственно (какой-то бутерброд получается :)). Вот и всё! В результате получается .exe который может достать из себя эти 2 файла. Но сейчас это работать не будет, так как нет Unpacker.exe. Его мы напишем в следующий раз. Хотя для любопытных я приведу листинг альфа версии Unpacker'а:


program Unpacker;

uses classes;

const c=117248;

var mem:tmemorystream;
    i:integer;
    done:integer=0;
    done1:integer;
    f:file;
    buf:array[1..2048] of byte;
begin
 mem:=tmemorystream.Create;
 mem.LoadFromFile(paramstr(0));
 mem.Seek(c,soFromBeginning);
 mem.ReadBuffer(i,$4);
 assignfile(f,'temp1');
 rewrite(f,1);
 while i>=done+2048 do begin
  done1:=mem.Read(buf,sizeof(buf));
  blockwrite(f,buf,done1);
  done:=done+done1;
 end;
 if i>done then begin
  done1:=mem.Read(buf,i-done);
  blockwrite(f,buf,done1);
 end;
 closefile(f);

 done:=0;
 mem.ReadBuffer(i,4);
 assignfile(f,'temp2');
 rewrite(f,1);
 while i>done+2048 do begin
  done1:=mem.Read(buf,sizeof(buf));
  blockwrite(f,buf,done1);
  done:=done+done1;
 end;
 if i>done then begin
  done1:=mem.Read(buf,i-done);
  blockwrite(f,buf,done1);
 end;
 closefile(f);

 mem.Free;
end.

Copyright© 2003 Zero Ice  Специально для Delphi Plus



Опубликовал admin
29 Ноя, Суббота 2003г.
Ну вот: Момент "вот-вот", читайте!


Программирование для чайников.