![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Любителям "скырть процесс" под NT посвящается...
Игорь Шевченко © (2005-02-02 10:21:00)Небольшой код, позволяющий определить, есть ли в системе потенциально вредоносный процесс, скрывающий себя от Task Manager'а, Process Explorer'а и прочих просмотрщиков списка процессов. В сочетании с включенным аудитом процессов поможет выявить поделки доморощенных пакостников.
Проверено на Windows 2000 и Windows XP.
unit CheckNtDll;
interface
uses
Windows, HsNtDef;
function RealQueryListInformation (InfoClass: Integer; var rc: NTSTATUS;
var ReturnLength: DWORD): Pointer;
function IsNtDllHooked: Boolean;
implementation
uses
SysUtils, NtDll, PeImage, NtStatusDefs;
{$IFDEF VER140}
{$WARN SYMBOL_PLATFORM OFF}
{$ENDIF}
type
TSysCallData = array[0..13] of Byte;
TNtQuerySystemInformation = function (SystemInformationClass: LongInt;
SystemInformation: Pointer; SystemInformationLength: ULONG;
ReturnLength: PDWORD): NTSTATUS; stdcall;
var
FRealQuerySystemInformation: TNtQuerySystemInformation;
function RealQueryListInformation (InfoClass: Integer; var rc: NTSTATUS;
var ReturnLength: DWORD): Pointer;
var
ListSize: Integer;
begin
ListSize := $400; { Начальный размер буфера }
GetMem(Result, ListSize);
rc := FRealQuerySystemInformation(InfoClass, Result, ListSize, @ReturnLength);
while rc = STATUS_INFO_LENGTH_MISMATCH do begin
FreeMem(Result);
ListSize := ListSize * 2;
GetMem(Result, ListSize);
rc := FRealQuerySystemInformation(InfoClass, Result, ListSize,
@ReturnLength);
end;
if rc <> STATUS_SUCCESS then begin
FreeMem(Result);
Result := nil;
end;
end;
procedure MakeRealQS (const SysCallData: TSysCallData);
var
OldProtection: DWORD;
FuncPtr: Pointer;
begin
FuncPtr := VirtualAlloc(nil, $1000, MEM_COMMIT, PAGE_READWRITE);
Win32Check(Assigned(FuncPtr));
Move(SysCallData, FuncPtr^, SizeOf(SysCallData));
Win32Check(VirtualProtect(FuncPtr, SizeOf(SysCallData), PAGE_EXECUTE,
OldProtection));
@FRealQuerySystemInformation := FuncPtr;
end;
function IsNtDllCodeHooked (const FileName: string; ProcOffset: ULONG): Boolean;
var
Image: THSPeImage;
SysCall: TSysCallData;
SysCall2: TSysCallData;
QSPtr: Pointer;
begin
Image := THSPEImage.Create (FileName);
try
Move(Image.RVAData[ProcOffset]^, SysCall, SizeOf(SysCall));
finally
Image.Free;
end;
QSPtr := GetProcAddress(GetModuleHandle('ntdll.dll'),
'NtQuerySystemInformation');
Move(QSPtr^, SysCall2, SizeOf(SysCall2));
Result := not CompareMem(@SysCall, @SysCall2, SizeOf(SysCall));
if Result then
MakeRealQS (SysCall);
end;
function IsNtDllHooked: Boolean;
const
SDllPath = '%SystemRoot%\system32\ntdll.dll';
var
DllPath: ZString;
HFile, HMap: THandle;
Map: Pointer;
Headers: PImageNtHeaders;
QSysInfo: Pointer;
begin
Result := false;
Win32Check(
ExpandEnvironmentStringsA(SDllPath, DllPath, SizeOf(DllPath)) <> 0);
HFile := CreateFileA(DllPath, GENERIC_READ, FILE_SHARE_READ, nil,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE);
Win32Check(HFile <> INVALID_HANDLE_VALUE);
try
HMap := CreateFileMappingA(HFile, nil, PAGE_READONLY, 0, 0, nil);
Win32Check(HMap <> 0);
try
Map := MapViewOfFile(HMap, FILE_MAP_READ, 0, 0, 0);
Win32Check(Assigned(Map));
try
Headers := RtlImageNtHeader(HMODULE(Map));
if Assigned(Headers) then
Result :=
Headers.OptionalHeader.ImageBase <> GetModuleHandle('ntdll.dll');
if not Result then begin
QSysInfo := GetProcAddress(GetModuleHandle('ntdll.dll'),
'NtQuerySystemInformation');
if Assigned(QSysInfo) then begin
Result := (Cardinal(QSysInfo) <=
Headers.OptionalHeader.ImageBase) or (Cardinal(QSysInfo) >
Headers.OptionalHeader.ImageBase +
Headers.OptionalHeader.SizeOfCode);
if not Result then
Result := IsNtDllCodeHooked(DllPath, ULONG(QSysInfo) -
Headers.OptionalHeader.ImageBase);
end else
Result := true;
end;
finally
UnmapViewOfFile(Map);
end;
finally
CloseHandle(HMap);
end;
finally
CloseHandle(HFile);
end;
end;
initialization
finalization
if Assigned(FRealQuerySystemInformation) then
VirtualFree(@FRealQuerySystemInformation, $1000, MEM_DECOMMIT);
end.
Пример использования:
FQueryInformationFunction: TQueryListInformation;
.........
if IsNtDllHooked then begin
ShowMessage('NtDll is hooked!');
@FQueryInformationFunction := @RealQueryListInformation;
end else
@FQueryInformationFunction := @QueryListInformation;
.....
var
ProcessInfo: Pointer;
rc: NTSTATUS;
Dummy: ULONG;
begin
ProcessInfo := FQueryInformationFunction (
SystemProcessesAndThreadsInformation, rc, Dummy);
if NT_SUCCESS(rc) then
ShowProcessList (ProcessInfo)
else
RaiseNtError (rc);
.........
BiN (2005-02-02 11:13:00) [41]вдогонку к
BiN © (02.02.05 10:46) [6]
Правда, тут могут начаться "гонки" с перехватом NtCreateFile и т.п., но это уже из другой оперы...
Имеется ввиду также перехват остальных функций I/O файловой системы.
Игорь Шевченко (2005-02-02 11:12:00) [42]BiN © (02.02.05 11:09) [10]
Разумеется, NtCreateFile + NtCreateSection. Но дело в том, что если перехватить, то как тогда остальные будут работать ? Ведь любая программа отображает NTDLL на свое адресное пространство.
С уважением,
BiN (2005-02-02 11:09:00) [43]Игорь Шевченко © (02.02.05 10:57) [7]
А зачем перехватывать NtCreateFile ? Я, честно говоря, смысла не вижу.
А с помощью каких функций считывается PE-заголовок ntdll.dll?
kaZaNoVa (2005-02-02 11:09:00) [44]ура, пример работает!!!
//проверял пока только одну функцию - детектор перехватаIsNtDllHooked- потрясающе))
kaZaNoVa (2005-02-02 11:04:00) [45]BiN © (02.02.05 10:46) [6]
всё равно всё не перехватят))
95% имхо всех "перехватчиков" останавливаются на том, что не видны в таск-манагере и всё)))
Игорь Шевченко (2005-02-02 10:57:00) [46]BiN © (02.02.05 10:46) [6]
А зачем перехватывать NtCreateFile ? Я, честно говоря, смысла не вижу.
С уважением,
BiN (2005-02-02 10:46:00) [47]Правда, тут могут начаться "гонки" с перехватом NtCreateFile и т.п., но это уже из другой оперы...
BiN (2005-02-02 10:43:00) [48]Игорь Шевченко © (02.02.05 10:40) [4]
Проверяется соответствие как правленной IAT, так и совпадения кода по адресу NtQuerySystemInformation в загруженной DLL и на диске
(выделение мое)
Точно, не обратил внимание на эту строку:
Image := THSPEImage.Create (FileName);
в функции IsNtDllCodeHooked
Игорь Шевченко (2005-02-02 10:40:00) [49]BiN © (02.02.05 10:25) [1]
Привет! Данный код как раз служит для вытаскивания за ушко и на солнышко процессов, которые пользуются методом внедрения без правки IAT, а установкой в адресном пространстве "жертвы" кода перехода на свою скрывающую функцию по корректному адресу в NTDLL.DLL
Краткий алгоритм такой: Проверяется соответствие как правленной IAT, так и совпадения кода по адресу NtQuerySystemInformation в загруженной DLL и на диске. Если код не совпадает, то для вызова функции используется тот код, который в файле NTDLL.DLL на диске находится.
С уважением,
kaZaNoVa (2005-02-02 10:37:00) [50]BiN © (02.02.05 10:25) [1]
имхо обычно ориентируемся на самые часто-испрользуемые способы перехвата и их отлавливаем .))
//ща тестирую, результаты сообщу))
BiN (2005-02-02 10:30:00) [51]Или я чего-то недопонимаю в коде(?)....
BiN (2005-02-02 10:25:00) [52]Игорь, приветствую!
Ты наверняка сам знаешь, что перехват можно осуществлять не только правкой IAT.
С уважением.