![]() |
| ||
|
|
Новости |
Поиск |
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);
.........
kaZaNoVa (2005-02-02 16:57:00) [21]Piter © (02.02.05 16:45) [30]
> А кто эту память будет зачищать?
Игорь Шевченко © (02.02.05 16:53) [31]
> В данном случае - никто. Но никто не мешает
> реализовать освобождение памяти в своем примере,
> равно, как и ReallocMem.
а допускается ли в таких случаях не заботитьсяо очищении памяти - имхо думаю, это некритично а по завершении программы Windows сама освободит память ?
Игорь Шевченко (2005-02-02 16:53:00) [22]
> - в RealQueryListInformation выделяется память, на которую
> указывает Result. А кто эту память будет зачищать?
В данном случае - никто. Но никто не мешает реализовать освобождение памяти в своем примере, равно, как и ReallocMem.
> а что такое QueryListInformation?
В данном случае - функция из внешнего юнита. Советую почитать всю ветку, чтобы мне не повторяться.
Piter (2005-02-02 16:45:00) [23]И еще, я вот посмотрел на код, компилятора под рукой нету, но на взгляд кое что не понял:
- в RealQueryListInformation выделяется память, на которую указывает Result. А кто эту память будет зачищать?
В примере использования написано:
end else
@FQueryInformationFunction := @QueryListInformation;
а что такое QueryListInformation?
Ну и:
FreeMem(Result);
ListSize := ListSize * 2;
GetMem(Result, ListSize);
можно использовать ReallocMem, будет нагляднее :)
Игорь Шевченко (2005-02-02 16:12:00) [24]Piter © (02.02.05 15:54) [28]
Локальная политика безопасности + F1
Piter (2005-02-02 15:54:00) [25]Игорь Шевченко © (02.02.05 10:21)
В сочетании с включенным аудитом процессов
а что это такое, где находится и зачем нужно?
BiN (2005-02-02 12:48:00) [26]Игорь Шевченко © (02.02.05 12:40) [26]
Понятно. Также стало ясно почему именно 14 байт :).
С уважением,
Игорь Шевченко (2005-02-02 12:40:00) [27]BiN © (02.02.05 12:23) [24]
Ни в коем разе. Это совершенно не переносимый вариант будет. Я основываюсь на том, что системные вызовы представляют собой код по вполне определенному шаблону, и он не меняется, так как изменение не имеет смысла. Меняется только номер вызова. Вот его я получаю чтением файла.
С уважением,
kaZaNoVa (2005-02-02 12:32:00) [28]BiN © (02.02.05 12:23) [24]
> "слепки" с заголовков оригинальных функций для каждой
> версии(?).
и будет как антивирус, с "белым списком" )))
BiN (2005-02-02 12:23:00) [29]Игорь Шевченко © (02.02.05 12:18) [23]
Если я правильно понял, ты предлагаешь хранить "слепки" с заголовков оригинальных функций для каждой версии(?).
С уважением,
Игорь Шевченко (2005-02-02 12:18:00) [30]BiN © (02.02.05 12:10) [22]
В принципе, для определения факта, что кто-то скрыт, достаточно сравнить код по адресу NtQuerySystemInformation с одним из трех его шаблонов, если не совпадает, то включать сирену и мигалку :). Считывание требуется для того, чтобы определить номер системного вызова, который меняется от версии к версии и от сервис-пака к сервис-паку.
С уважением,
BiN (2005-02-02 12:10:00) [31]Игорь Шевченко © (02.02.05 12:01) [19]
Если перехватывать NtCreateFile, то с какой целью ? Не дать открыть NtDll ? Так это вся система сломается.
Да, согласен. Я имел ввиду, что можно организовать подмену считываемых с диска данных - тех самых первых 14 байт перехваченной функции. Хоть это и финт ушами.
С уважением,
Игорь Шевченко (2005-02-02 12:08:00) [32]Kerk © (02.02.05 12:02) [20]
Не совсем понял, чем подменить. И главное, с какой целью. NTDLL является первой DLL, отображаемой на адресное пространство процесса.
С уважением,
Kerk (2005-02-02 12:02:00) [33]Игорь Шевченко © (02.02.05 12:01) [19]
Если перехватывать NtCreateFile, то с какой целью ? Не дать открыть NtDll ? Так это вся система сломается.
подменить
Игорь Шевченко (2005-02-02 12:01:00) [34]Всем:
Данный код иллюстирует только идею. Если все детали выкладывать, места не хватит. Остальные используемые модули представляют кучу служебных полезностей, написанных в разное время.
Часть можно взять по адресу
http://www.schevchenko.net.ru/SRC/Common_60.zip
BiN © (02.02.05 11:17) [15]
Если перехватывать NtCreateFile, то с какой целью ? Не дать открыть NtDll ? Так это вся система сломается.
С уважением,
GMan (2005-02-02 11:52:00) [35]2 Игорь Шевченко:
Что такое HsNtDef?
Kerk (2005-02-02 11:19:00) [36]Kerk © (02.02.05 11:16) [14]
причем здесь дугие.
а как ты узнаешь в каком именно процессе код править? или будешь специально под какую-то тулзу затачиваться?
kaZaNoVa (2005-02-02 11:17:00) [37]Kerk © (02.02.05 11:16) [14]
получится бесконечная "гонка вооружений" ))
BiN (2005-02-02 11:17:00) [38]Игорь Шевченко © (02.02.05 11:12) [11]
Но дело в том, что если перехватить, то как тогда остальные будут работать ? Ведь любая программа отображает NTDLL на свое адресное пространство
А разве правка кода будет происходить не в адресном пространстве одного процесса? Не понятно, причем здесь дугие.
С уважением,
Kerk (2005-02-02 11:16:00) [39]Игорь Шевченко © (02.02.05 11:12) [11]
так аккуратненько так... проверять какой файл пытаются открыть и все такое :)
kaZaNoVa (2005-02-02 11:13:00) [40]kaZaNoVa © (02.02.05 11:09) [9]
но подмену IAT кажется не определяет . .(или я ошибаюсь?) - другай пример, который только скрывается от такс-менеджера,но виден Процесс-Эксплореру - тот не определятся как IsNtDllHooked ...