Всем доброго времени суток.На днях мне стукнуло пару тройку людей в асику с целью что бы я объяснил как делаются билдеры каких либо прог.На словах оно конечно не оч ясно,по этому я решил сделать микро-статейку. Билдер будет простой, для наглядности с 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 или любой хекс редактор который Вам по душе и открываем в нем наш билд.Ищем выводимые строки. записываем нужные байты.Теперь нам нужно сделать ресурс.Создаем новый текстовый файл с расширением *.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 спс за внимание.
А не проще просто использовать ресурсы для данных вещей? То есть в данном случае строки брать из ресурсов? Тем более у тебя есть ограничение на размер строк(3 и 6), а в ресурсах такого нет. Жесть.
DooD, не учи плохому... Code: ch:=ord(char(pchar(msg[2]))); setfilepointer(h,m[2],nil,0); writefile(h,ch,sizeof(ch),br,nil); ....
можно конечно и ресурсы,я чутка поизвращался).Если напрягает громоздкий код можно сделать функцию,я просто для наглядности делал. знать такое никогда не помешает.
ты понял о чем я говорю.Да идея stels'a, но код я писал сам,не стоит иронизировать,я ничего сверхплохого не сделал.
Вообще-то не понял. Плохого ты не сделал, ты просто привел в пример плохой код. Хотя тут уже об этом написали. А чья идея - неважно, подход к замене конкретных байтов внутри бинарника - самое простое, что сразу приходит в голову при появлении подобной задачи.
Все прям налетели как всегда "Все не так", "Код грамоздкий". Ваши статьи в студию дамы и господа "критики". Я бы с удовольствием посмотрел на ваши статьи на данную тему P.S. Как по мне так для новичка это самый хороший способ и простой к тому же, DooD спасибо за статью))
как одна из вариаций предложенного способа через ресурсы Код подопытного: 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.