Четверг, 25.04.2024, 03:07 Приветствую вас Гость | Группа "Гости" 
Меню сайта

Категории раздела
Вирусология [40]
Статьи о вирусах
Системные [1]
Работа с системой
Примеры [45]
Приёмы, функции, процедуры
Ceти [1]
Работа с интернет
Шуточные программы [5]
Пишем шуточные программки
Остальное [6]
Всё что не вошло

Популярные статьи

Недавние темы

Опрос
Какой версией Delphi пользуетесь?
Всего ответов: 774

Главная » Статьи » Delphi » Вирусология

Микроскопические программы в Delphi
Консольное приложение. Тут в общем-то дело очень простое. Открываем Delphi, File-->New-->Other-->Console Application при этом мы имеем вот такую вот заготовочку:

program Project1;
{$APPTYPE CONSOLE}
uses
  SysUtils;
begin
  { TODO -oUser -cConsole Main : Insert code here }
end.

В общем-то тут всё понятно пишем свой код, на чистом паскале и периодически подключаем необходимые модули, по возможности перенося из модулей в прогу то что мы в них юзаем и отключаем их от проекта (это дает уменьшение размера). Ну что тут эще можно пояснить, мотод просто, как 5 копеек и проги на выходе получаются размером от 13,5кб и где-то 8кб если упаковать.
. Вопрос встаёт в том что окошко таким методом не получить и всё равно придётся юзнуть функции системного API, а в этом и есть фишка следующего метода.

2) Приложение WinAPI. Для того что бы писать таким способом необходимо хоть немного представлять себе, как работает винда и что такое WinAPI, поэтому расшарьте эти вопросы, возьмите поудобочитабельней справочничек по функциям WinAPI, и можно считать, что вы готовы. 
Главная особенность использования этих функций состоит в том, что их необходимо импортировать из системы, но в делфи есть модуль windows, подключив к проекту, который большинство функций, типов и констант, нашей нелюбимой-куклы – винды, станут доступными как родные фишки делфи. Пишем мы проги соответственно в чистом dpr-е как и в прошлом методе, только убираем {$APPTYPE CONSOLE} что бы не вылетало чёрное DOS – окошко, которое нам в этом методе не пригодится т.к. мы будем писать оконное приложение. При мер того как создать окошко в АПИ, я бахну, смотрим и удивляемся:
Program WinMin;
uses windows;
const
  WM_DESTROY = $0002;
  ID = PChar(32512);
var
  wc : TWndClassEx;
  Wnd : Integer;
  Mesg : TMsg;

//Функция ловит сообщения окну и передаёт ему необходимые действия
function WindowProc(wnd:Integer; Msg : Integer; Wparam:Longint; Lparam:Longint):LongInt; stdcall;
Begin
  if msg=wm_destroy then //Если узер закрыл окно
  Begin
  postquitmessage(0);//Передаем окну сообщение о закрытии
  Result:=0;
  exit;
  End
  else Result:=DefWindowProc(wnd,msg,wparam,lparam);//Ловим дальше
End;

Procedure RegCls; //Регистрация класса окна
begin
  //Заполнение полей класса
  wc.cbSize:=sizeof(wc);
  wc.style:=cs_hredraw or cs_vredraw;
  wc.lpfnWndProc:=@WindowProc;
  wc.cbClsExtra:=0;
  wc.cbWndExtra:=0;
  wc.hInstance:=1;
  wc.hIcon:=LoadIcon(0,ID);
  wc.hCursor:=LoadCursor(0,ID);
  wc.hbrBackground:=COLOR_BTNFACE+1;
  wc.lpszMenuName:=nil;
  wc.lpszClassName:='TWnd';
  RegisterClassEx(wc);//Регистрация класса
end;

begin
  RegCls; //Коасс окна
  Wnd:=CreateWindowEx ( 0, 'TWnd', 'WinMin', ws_overlappedwindow, 100, 150, 400, 250, 0, 0, 1, nil);
  ShowWindow(Wnd,1); //Показать окно
  While GetMessage(Mesg,0,0,0) do//Получаем сообщения
  begin
  TranslateMessage(Mesg);
  {код}
  DispatchMessage(Mesg);
  end;
end.


Вроде бы не так всё сложно. Получили окошко, примерно, такое как делфи создаёт по дефаулту, но весом в 14,5 кб.. Уже не плохо? Дальше будет страшней))) Разбираемся, думаем и переходим к следующей методу, кстати, оба следующих метода требуют усвоение этого, так, дальше писать придется, только, на АПИ, но плюс к этому примётся ещё и не много «поизвращяться», но думаю, дочитав статейку до этого момента нет смысла бросать.. Сразу залезу, вперед, и попробую вас немного взбодрить, тем фактом, что в конце этой статьи мы получим такое же окошко только весом 1264 байта!! Так что волю в кулак! Переходим дальше…

3) Приложение WinAPI без RTL. Этот способ разработки требует значительно больше усилий, но результат превосходит все ожидаемые от Delphi надежды. В чём суть метода. В том, что Delphi как язык, весьма и очень, совершенный даёт пользователю множество благ, которыми другие не могут похвастаться, например тип string и его конвертация в PChar и обратно, динамические массивы, функции выделения памяти, множество стандартный типов и констант. Всё это добро находится в двух модулях, которые нет необходимости подключать, тат как они подключаются автоматически - System и SysInit, эти вкусности называются RTL (Run Time Library). Эти модули, целиком включаясь в прогу, занимают в ней примерно 10кб. Я думаю, вы понимаете к чему я клоню, к тому, что от этих модулей надо избавиться и научиться обходиться без них… Вот на этом и основан этот принцип. Теперь перейдём конкретно к реализации. 
. Многие наверно по неопытности решили кокнуть файлы system.dcu и sysinit.dcu в папке: %ProgramFiles%\Borland\Delphi7\Lib\ и конечно же тем самым выбить делфи зубы, но это не лучшее решение, т.к. те, файлы пригодятся вам в других прогах, да и компилятору они просто необходимы для работы. Т.о. нам остаётся сделать свои файлы system.dcu и sysinit.dcu не включающие в себя ни чего лишнего, но удовлетворяющие потребности Delphi. Далее эти файлы необходимо размещать в папке с исходником, т.к. Delphi ищет модули в первую очередь в папке с сорцем, а потом уж в своих злачных местах. 
. Создаём модули system и sysinit.
Создаем три текстовых файла: system.pas, sysinit.pas и compil.bat. Пишем в эти файлы следующие строки:
В system.pas:
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.


В sysinit.pas:
unit SysInit;
interface
procedure _InitExe;
procedure _halt0;  
var
  ModuleIsLib : Boolean; 
  TlsIndex : Integer = -1; 
  TlsLast : Byte; 
const
  PtrToNil : Pointer = nil; 
implementation
procedure _InitExe;
asm
end;
procedure ExitProcess(uExitCode: INTEGER); stdcall; external 'kernel32.dll' name 'ExitProcess';
procedure _halt0;
begin
ExitProcess(0);
end;
end.


В compil.bat:
@DCC32 -Q system.pas sysinit.pas -M -Y -Z -$D- -O
@DEL compil.bat


Кладем все три файла в одну папку, запускаем файл compil.bat. После запуска файл compil.bat удаляется, а в появляется два файла: system.dcu и sysinit.dcu. Всё, эта часть окончена, необходимо только сохранить гденибудь в архиве оставшиеся в папке 4 файла, их вы сможете использовать не однократно, для этого достаточно их скопировать в каталог с исходником и открыть исходник в делфи, а далее просто пишем в делфи и в нем же компилируем. Что бы проверить работоспособность метода создайте файл 1.dpr со строками: 
Program mini;
begin 
end.

Далее как оговаривалось киньте в папку с этим файлом те 4 файла что мы до этого создали и запустите проект: 1.dpr в делфи. Теперь жмём Ctrl-F9 и наблюдаем в этой папке файл 1.exe весом 3584 байта (3,5кб), а это как раз на 10кб меньше, чем тот же сорец откомпилированный без этих заморочек.. Теперь если этот exe упаковать замечательным пакером fsg 2.0 его размер составит около 1000 байт – нешуточное уменьшение.
. Теперь осталось разобраться с тем как же, всё-таки, писать программы при использовании такого метода? В общем-то, программы пишутся так же как всегда, только не получится использовать то, что мы теряем, избавляясь от RTL, а это я уже перечислял и в первую очередь это тип string. При написании программ необходимо ограничиться типами: boolean, byte, word, integer, longint, pchar, char, cardinal, pointer. А так же массивы этих типов и записи с полями этого типа. Если, например функция, использует тип DWORD, его придётся заменить на другой 4 байтный тип, например integer, longint или cardinal, в зависимости от возможных значений. Как это делать вы не раз увидите в моих исходниках, и со временем будете делать это автоматически. Все стандартные операторы (условия, циклы), остаются. Приходится писать используя лишь функции WinAPI причем, каждую хоть один раз применяемую функцию, необходимо импортировать из системы, для того что бы её можно было в дальнейшем применять по всему коду.
. Импорт функции осуществляется следующим образом:
function (procedure) в скобках параметры и типов, как всегда, далее stdcall; external ‘имя библиотеки’ name ‘имя функции’;
Некоторые функции требуют переноса из модуля типов и записей которыми они оперируют например функция CreatFile будет иметь такой импорт:
//ТИПЫ
type
  POverlapped = ^TOverlapped;
  TOverlapped = record
  Internal: Cardinal;
  InternalHigh: Cardinal;
  Offset: Cardinal;
  OffsetHigh: Cardinal;
  hEvent: Cardinal;
  end;
  PSecurityAttributes = ^TSecurityAttributes;
  TSecurityAttributes = record
  nLength: Cardinal;
  lpSecurityDescriptor: Pointer;
  bInheritHandle: Boolean;
  end;
//Объявление
function CreateFileA(lpFileName: PAnsiChar; dwDesiredAccess, dwShareMode: Cardinal; 
  lpSecurityAttributes: PSecurityAttributes; dwCreationDisposition, 
  dwFlagsAndAttributes: Cardinal; hTemplateFile: Cardinal): Cardinal; 
  stdcall; external KERNEL32 name '_CreateFileA@28';


вот пример программы Hallo World, которая импортирует из user32.dll функцию MessageBoxA и с помощью неё выводит сообщение Hallo World. 

Program Hallo;
function MessageBoxA(hWnd: cardinal; lpText, lpCaption: PChar; uType: Cardinal): Integer; stdcall; external 'user32.dll' name 'MessageBoxA';
begin
  MessageBoxA(0,’Hallo World’,’Hallo’,0);
end.

Как видите, не так и трудно... Но примеры будут и ещё, но они выходят за рамки этой статьи.. Переходим к разбору последнего метода этой статьи.

4) Приложение WinAPI c ассемблерной сборкой. Хочу напомнить, что все три предыдущих метода рассчитаны на создание исходника программы в файле проекта Delphi (.dpr), этот метод отличается от предыдущих тем, что он рассчитан на разработке в файле модуля (.pas) и его компиляцию. Принцип такой. Программа создаётся по всем правилам предыдущего метода, за исключением двух моментов, которые я сейчас рассмотрю:
. Первое отличие – программа размещается в модуль и основная часть программы размещается в процедуру без параметров, объявление которой, указывается в разделе interface. Например если был исходник:
Program example1;

Procedure pr1(a:integer);
begin
  a:=a-123;
end;

Procedure pr2(b:integer);
begin
  b:=b-234;
end;

var
a,b,c:integer

begin
  c:=pr1(2345)+pr2(5678);
end.


То при переделке в модуль получаем следующий исходник:
UNIT Project1;

INTERFACE

Procedure Run;

IMPLEMENTATION

Procedure pr1(a:integer);
begin
  a:=a-123;
end;

Procedure pr2(b:integer);
begin
  b:=b-234;
end;

var
a,b,c:integer

Procedure Run;
begin
  c:=pr1(2345)+pr2(5678);
end;

end.

. Как видите основная часть размещается в процедуру Run. Далее с помощью командной строки компилятора Delphi 3 (DCC32.exe) осуществляется компиляция модуля, но не в ехе, а в объектный файл СИ(.obj). Далее с помощью ассемблерного компоновщика (линкера) – Link.exe, осуществляется компоновка ехе из obj, с установкой точки входа на процедуру основной части, в нашем случае Run.
. Второе отличие – в этом методе импорт функций осуществляется, немного не так, как в предыдущем методе, но разница не так велика. Отличие заключается в имени функции, при его объявлении. Дело в том что сборка ехе осуществляется линкером (об этом ниже), и поэтому бинарный код функций берется их ассемблерный библиотек .LIB все эти библиотеки необходимо брать из дистрибьютива MASM32 , и в этих же библиотеках необходимо поиском смотреть как необходимо писать имя функции. Например, нам нужно определить имя функции CreatFileA , нам необходимо взять библиотеку kernel32 .lib и поиском найти следующую строку: _CreateFileA@28, число 28 – это выделение памяти под функцию. По этой аналогии исходник, выше приводимого, Hallo World будет иметь вид:
unit hello;
interface
Procedure Run;
implementation
function MessageBoxA(hWnd: cardinal; lpText, lpCaption: PChar; uType: Cardinal): Integer; stdcall; external 'user32.dll' name '_MessageBoxA@16';
const
  msg = 'Hallo';
Procedure Run;
begin
  MessageBoxA(0,msg,msg,0);
end;
end.


. Вот и всё. Теперь поговорим о том, как на практике и какими инструментами такого рода компиляцию можно осуществить.
Инструменты:
1)Компилятор
а)DCC32.EXE - компилятор Delphi3
б)SYSTEM.DCU - модуль SYSTEM Delphi3
в)SYSINIT.DCU - модуль SYSINIT Delphi3

2)Компоновщик(Линкер)
а)LINK.EXE - компоновщик(линкер) MASM32
б)MSPDB50.DLL - Библтотека линкера
в)Набор необходимых библиотек, функции, которых используются в проекте. (файлы *.LIB)

3)Стаб (дос заголовок)
a)STUB.BIN - Укороченный стаб (64 байта)

Что бы создать ехе-шник необходимо сделать три действия:
а)написать нормальный PAS, как я думаю вполне подробно пояснил.
б)Откомпилировать obj
для этого помещаем проект в папку с "инструментами” и выполнить командную строку:
DCC32 -JP имя_проекта.pas.
Выполнять это действие необходимо в CMD что бы можно было посмотреть ошибки и их исправить...
Если все нормально компильнулось... необходимо проверить какчество obj, для этого открываем его листером или блокнотом и ищем строку с именем процедуры в которую мы располажили "основную часть"
... если все гуд то после имени процедуры будут символы:$qqrv... В нашем случае имя Run -->Run$qqrv..

Если этого не получились значит мы не правильно (не везде) заменили типы на разрешённые...

в)Откомпоновать ехе..
Для этого нам необходимо выполнить командную строку:
Link ALING:4(8..16..32..64 - это приходится определять опытным путём... Обычно 4 хватает)
/FORCE:UNRESOLVED /SUBSYSTEM:WINDOWS /MERGE:.data=.text /MERGE:.rdata=.text /ENTRY:Run(имя поцедуры)$qqrv 
/STUB:stub.bin перечисляем либы из которых нужно брать функции + имя odj файла...
2)Т.о. например для программы:

unit w;
interface
procedure Run;
implementation
function ShellExecute(hWnd: Cardinal; Operation, FileName, Parameters, Directory: PAnsiChar; ShowCmd: Integer): Cardinal; stdcall; external 'shell32.dll' name '_ShellExecuteA@24'
procedure Run;
begin
ShellExecute(0,'','notepad','','',1);
end;
end.


размещённой в файле hello.pas

Мы используем командную строку:

для создания obj:
dcc32 -JP hello.pas


для создания ехе:

LINK /ALIGN:4 /FORCE:UNRESOLVED /SUBSYSTEM:WINDOWS /MERGE:.data=.text /MERGE:.rdata=.text /ENTRY:Run$qqrv /STUB:stub.bin user32.lib hello.obj


xakep.su

Категория: Вирусология | Добавил: dolphin (02.08.2008) | Автор: Женёк
Просмотров: 6420 | Рейтинг: 5.0/1

Всего комментариев: 0
avatar
Профиль


Логин:
Пароль:

Поиск

Наша кнопка
Вирусология, взгляд из Delphi

Статистика
Top.Mail.Ru Яндекс.Метрика Счетчик тИЦ и PR
Статистика материалов
Файлов: 454
Форум: 1165/8116
Коментариев: 768
Новостей: 29

Статистика пользователей
Всего: 332
За неделю: 1
Вчера: 0
Сегодня: 0
Всего онлайн: 8
Гостей: 8
Пользователей: 0

delphicode.ru © 2008 - 2024 Хостинг от uCoz