Делаем простенький билдер

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by DooD, 20 Nov 2011.

  1. DooD

    DooD Elder - Старейшина

    Joined:
    30 Sep 2010
    Messages:
    1,168
    Likes Received:
    450
    Reputations:
    288
    Всем доброго времени суток.На днях мне стукнуло пару тройку людей в асику с целью что бы я объяснил как делаются билдеры каких либо прог.На словах оно конечно не оч ясно,по этому я решил сделать микро-статейку.
    Билдер будет простой, для наглядности с messagebox-ом.
    Приступим.
    Напишем для начала наш билд.Писать можно на любом языке,я буду на масме.
    Code:
    .386
    .model flat, stdcall
    option casemap:none
    
    include include\windows.inc
    include include\kernel32.inc
    include include\user32.inc
    include include\shell32.inc
    
    includelib lib\shell32.lib
    includelib lib\user32.lib
    includelib lib\kernel32.lib
    
    .data
    cap db 'MSG',0
    msg db 'Hello!',0
    
    start:
    invoke MessageBox,0,addr msg,addr cap,0
    invoke ExitProcess,0
    
    end start
    Билд есть.Суть билдера будет в том что бы изменять нужные данные (заголовок и сообщение) билда.Это будет делаться с помощью замены байтов.Как узнать нужные байты?Берем hiew или любой хекс редактор который Вам по душе и открываем в нем наш билд.Ищем выводимые строки.
    [​IMG]
    [​IMG]
    записываем нужные байты.Теперь нам нужно сделать ресурс.Создаем новый текстовый файл с расширением *.rс в нем пишем например:FILE1 EXEFILE NEW.EXE
    где new.exe- наш билд.Теперь нужно скомпилировать ресурс.Это можно сделать любым компилятором ресурсов,можно взять тот что в delphi brcc32.exe.
    кидаем на него файл rс и получаем файл *.res. Данный ресурс мы прилинкуем в наш билдер (билдер пишем на делфи) таким образом:
    {$R Res.res} вписав это после implementation, где res.res- имя вашего файла ресурсов.Далее следует код билдера.Алгоритм создания билда таков:
    1)Извлечь из ресурсов наш первоначальный билд
    2)Пропатчить необходимые байты
    3)Переименовать билд в заданное имя.
    Итак код билдера:
    Code:
    var
      Form1: TForm1;
      m:array[1..6]of integer; // массив байтов сообщения
      c:array[1..3]of integer; // массив байтов заголовка
      
    implementation
    
    {$R *.dfm}
    {$R res.res} // прилинкованный файл ресурсов
    procedure TForm1.Button1Click(Sender: TObject);
    var fn,msg,cap:string;
    ch:byte;
    BR:dword;
    h:Thandle;
    Res:TResourceStream;
    begin
    
    m[1]:=$404; // массив байтов заполняем нужными байтами
    m[2]:=$405;
    m[3]:=$406;
    m[4]:=$407;
    m[5]:=$408;
    m[6]:=$409;
    
    c[1]:=$400;
    c[2]:=$401;
    c[3]:=$402;
    
    fn:=edit1.Text;  //тут имя билда
    msg:=edit2.Text; //тут сообщение 
    cap:=edit3.Text; // заголовок
    
    Res:=TResourceStream.Create(HInstance,'FILE1','EXEFILE');
    Res.SaveToFile(ExtractFilePath(Application.ExeName)+'new.exe');
    Res.Free; // извлекаем файл из ресурсов
    
    h:=fileopen('new.exe',fmopenwrite); // открываем на запись
    
    ch:=ord(char(pchar(msg[1]))); // берем первый символ, преобразовавши его в его код.
    setfilepointer(h,m[1],nil,0);  // указываем позицию в файле
    writefile(h,ch,sizeof(ch),br,nil); // заменяем байт. т.д.
    
    ch:=ord(char(pchar(msg[2])));
    setfilepointer(h,m[2],nil,0);
    writefile(h,ch,sizeof(ch),br,nil);
    
    ch:=ord(char(pchar(msg[3])));
    setfilepointer(h,m[3],nil,0);
    writefile(h,ch,sizeof(ch),br,nil);
    
    ch:=ord(char(pchar(msg[4])));
    setfilepointer(h,m[4],nil,0);
    writefile(h,ch,sizeof(ch),br,nil);
    
    ch:=ord(char(pchar(msg[5])));
    setfilepointer(h,m[5],nil,0);
    writefile(h,ch,sizeof(ch),br,nil);
    
    ch:=ord(char(pchar(msg[6])));
    setfilepointer(h,m[6],nil,0);
    writefile(h,ch,sizeof(ch),br,nil);
    
    ch:=ord(char(pchar(cap[1])));
    setfilepointer(h,c[1],nil,0);
    writefile(h,ch,sizeof(ch),br,nil);
    
    ch:=ord(char(pchar(cap[2])));
    setfilepointer(h,c[2],nil,0);
    writefile(h,ch,sizeof(ch),br,nil);
    
    ch:=ord(char(pchar(cap[3])));
    setfilepointer(h,c[3],nil,0);
    writefile(h,ch,sizeof(ch),br,nil);
    
    closehandle(h);
    renamefile('new.exe',fn); // переименовуем файл.
    end;
    
    end.
    
    
    Вот собсно и все.Простенький билдер готов.Сильно не пинайте.Взять все готовое мона тута: http://splashed.ucoz.ru/builder.rar спс за внимание.
     
    #1 DooD, 20 Nov 2011
    Last edited: 20 Nov 2011
    1 person likes this.
  2. Jingo Bo

    Jingo Bo Member

    Joined:
    25 Oct 2009
    Messages:
    368
    Likes Received:
    51
    Reputations:
    7
    А не проще просто использовать ресурсы для данных вещей? То есть в данном случае строки брать из ресурсов? Тем более у тебя есть ограничение на размер строк(3 и 6), а в ресурсах такого нет.
    Жесть.
     
    1 person likes this.
  3. alexey-m

    alexey-m Elder - Старейшина

    Joined:
    15 Jul 2009
    Messages:
    518
    Likes Received:
    100
    Reputations:
    37
    DooD, не учи плохому...
    Code:
    ch:=ord(char(pchar(msg[2])));
    setfilepointer(h,m[2],nil,0);
    writefile(h,ch,sizeof(ch),br,nil);
    ....
     
  4. DooD

    DooD Elder - Старейшина

    Joined:
    30 Sep 2010
    Messages:
    1,168
    Likes Received:
    450
    Reputations:
    288
    можно конечно и ресурсы,я чутка поизвращался).Если напрягает громоздкий код можно сделать функцию,я просто для наглядности делал.

    знать такое никогда не помешает.
     
    #4 DooD, 20 Nov 2011
    Last edited: 20 Nov 2011
  5. GRRRL Power

    GRRRL Power Elder - Старейшина

    Joined:
    13 Jul 2010
    Messages:
    823
    Likes Received:
    185
    Reputations:
    84
    Знать что? То что иногда полезно применять дублирование кода и копипаст?) Это вряд ли)
     
    1 person likes this.
  6. DooD

    DooD Elder - Старейшина

    Joined:
    30 Sep 2010
    Messages:
    1,168
    Likes Received:
    450
    Reputations:
    288
    ты понял о чем я говорю.Да идея stels'a, но код я писал сам,не стоит иронизировать,я ничего сверхплохого не сделал.
     
  7. GRRRL Power

    GRRRL Power Elder - Старейшина

    Joined:
    13 Jul 2010
    Messages:
    823
    Likes Received:
    185
    Reputations:
    84
    Вообще-то не понял. Плохого ты не сделал, ты просто привел в пример плохой код. Хотя тут уже об этом написали. А чья идея - неважно, подход к замене конкретных байтов внутри бинарника - самое простое, что сразу приходит в голову при появлении подобной задачи.
     
  8. Kandi

    Kandi Member

    Joined:
    18 Nov 2009
    Messages:
    344
    Likes Received:
    17
    Reputations:
    0
    Все прям налетели как всегда "Все не так", "Код грамоздкий". Ваши статьи в студию дамы и господа "критики". Я бы с удовольствием посмотрел на ваши статьи на данную тему :)
    P.S. Как по мне так для новичка это самый хороший способ и простой к тому же, DooD спасибо за статью))
     
  9. alexey-m

    alexey-m Elder - Старейшина

    Joined:
    15 Jul 2009
    Messages:
    518
    Likes Received:
    100
    Reputations:
    37
    как одна из вариаций предложенного способа через ресурсы

    Код подопытного:
    Code:
    program test;
    {$APPTYPE CONSOLE}
    uses  Windows, SysUtils;
    
    const
      _SIGN = $FFAAEECC;
    
    {------------------------------------------------------------------
       Процедура Parser чисто для примера и будет 
       зависеть от структуры придуманного конфига
    --------------------------------------------------------------------}
    procedure Parser(const pCfg: Pointer; cdSize: DWORD);
    var
      P: Pointer;
      nSize,sz: Integer;
      S: String;
    
      function pSet(pMem: Pointer; o: Integer): Pointer;
      asm
        add eax,edx
      end;
    
    begin
      if (DWORD(pCfg^) = _SIGN) then begin
        P:= pSet(pCfg, 4); nSize:= cdSize - 4;
        while (nSize > 0) do begin
          sz:= Word(P^); P:= pSet(P, 2);
          S:= Copy(PChar(P), 1, sz); P:= pSet(P, sz);
          Dec(nSize, sz+2);
          WriteLn(S);
        end;
      end;
    end;
    
    //---------------------------------------------------------------------------
    
    var
      hResInfo: THandle;
      hResData: HGLOBAL;
      pData: Pointer;
      cdSize: DWORD;
    begin
      hResInfo:= FindResource(0, MakeIntResource(100), 'BIN');
      if (hResInfo <> 0) then begin
    
        cdSize:= SizeofResource(0, hResInfo);
        hResData:= LoadResource(0, hResInfo);
        if (cdSize = 0) or (hResData = 0) then Exit;
        pData:= LockResource(hResData);
        if (pData <> nil) then begin
          // парсим наш конфиг
          Parser(pData, cdSize);
        end;
      end;
    end.
    
    Сорс пытающего:
    Code:
    program Builder;
    {$APPTYPE CONSOLE}
    uses  Windows, SysUtils;
    
    (* Лень расписывать заполнение конфига, не в этом суть, поэтому вставлено просто массивом *)
    const
    data: array[0..33] of byte = (
      $CC, $EE, $AA, $FF,     // sign
      $07, $00,               // size field 1
      // text "field 1"
      $66, $69, $65, $6C, $64, $20, $31,
      $13, $00,               // size field 2
      // text "Это второй параметр"
      $9D, $E2, $AE, $20, $A2, $E2, $AE, $E0, $AE, $A9, $20, $AF, $A0, $E0, $A0, $AC, $A5, $E2, $E0
    );
    
    (* запись конфига в ресурсы test.exe *)
    var
      hUpdateRes: THandle;
    begin
      hUpdateRes:= BeginUpdateResource('test.exe', False);
      if (hUpdateRes <> 0) then begin
        if UpdateResource(hUpdateRes, 'BIN', MakeIntResource(100), 0,@data, sizeof(data)) then begin
          WriteLn('Config: Ok');
          EndUpdateResource(hUpdateRes, False);
        end else WriteLn('Config: Error');
      end;
    end.
    
     
    #9 alexey-m, 22 Nov 2011
    Last edited: 22 Nov 2011