Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР #80, АВГУСТ 2005 г.

Delphi всемогущий

Ms-Rem

Хакер, номер #080, стр. 080-112-3


program Sample;

begin

end.

После компиляции в Delphi 7 мы получаем экзешник размером в 13,5 Кб. Откуда?! Ведь в программе ничего нет! Ответ на этот вопрос опять поможет дать IDA. Дизассемблируем экзешник и посмотрим, что он содержит. Точка входа в программу будет выглядеть так:

public start

start:

push ebp

mov ebp, esp

add esp, 0FFFFFFF0h

mov eax, offset ModuleId

call _InitExe

; здесь мог бы быть наш код

call _HandleFinally

CODE ends

Весь лишний код находится в функциях _InitExe и _HandleFinally. Дело в том, что к каждой Delphi программе неявно подключается код, входящий в состав RTL (Run Time Library). Эта либа нужна для поддержки таких возможностей языка, как ООП, работа со строками (string) и специфичные для паскаля функции (AssignFile, ReadLn, WriteLn, etc.). InitExe выполняет инициализацию всего этого добра, а HandleFinally обеспечивает корректное освобождение ресурсов.

Сделано это, опять же, для упрощения жизни программистам, и применение RTL иногда оправданно, так как может не понизить, а повысить эффективность кода. Например, в состав RTL входит менеджер кучи, который позволяет быстро выделять и освобождать маленькие блоки памяти. По своей эффективности он в три раза превосходит системный. В плане производительности генерируемого кода работа со строками реализована в RTL тоже довольно неплохо, правда все равно, в увеличении размера файла, RTL - виновник номер два после ООП.

[уменьшаем размер]

Если минимальный размер в 13,5 Кб тебя не устраивает, то будем убирать Delphi RTL. Весь код либы находится в двух файлах: System.pas и SysInit.pas. К сожалению, компилятор подключает их к программе в любом случае, поэтому единственное, что можно сделать, - удалить из этих модулей весь код, без которого программа может работать, и перекомпилить модули, а полученные DCU-файлы положить в папку с программой.

Файл System.pas содержит основной код RTL и поддержки классов, но все это мы выбросим. Минимальное содержимое этого файла должно быть таким:

unit System;

interface

procedure _HandleFinally;

type

TGUID = record

D1: LongWord;

D2: Word;

D3: Word;

D4: array [0..7] of Byte;

end;

PInitContext = ^TInitContext;

TInitContext = record

OuterContext: PInitContext;

ExcFrame: Pointer;

InitTable: pointer;

InitCount: Integer;

Module: pointer;

DLLSaveEBP: Pointer;

DLLSaveEBX: Pointer;

DLLSaveESI: Pointer;

DLLSaveEDI: Pointer;

ExitProcessTLS: procedure;

DLLInitState: Byte;

end;

implementation

procedure _HandleFinally;

asm

end;

end.

Описания структуры TGUID компилятор требует в любом случае и без нее компилировать модуль отказывается. TInitContext понадобится линкеру, если мы будем собирать DLL. HandleFinally - процедура освобождения ресурсов RTL, компилятору она тоже необходима, хотя может быть пустой.

Назад на стр. 080-112-2  Содержание  Вперед на стр. 080-112-4