Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Любителям "скырть процесс" под NT посвящается...


Страницы:   1 2 3

Игорь Шевченко ©   (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 ...


Страницы:   1 2 3

Наверх

Титульная страница Поиск, карта сайта Написать письмо