Текущий архив: 2005.03.20;
Скачать: CL | DM;
Вниз
Любителям "скырть процесс" под NT посвящается... Найти похожие ветки
← →
Игорь Шевченко © (2005-02-02 10:21) [0]Небольшой код, позволяющий определить, есть ли в системе потенциально вредоносный процесс, скрывающий себя от 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 10:25) [1]Игорь, приветствую!
Ты наверняка сам знаешь, что перехват можно осуществлять не только правкой IAT.
С уважением.
← →
BiN © (2005-02-02 10:30) [2]Или я чего-то недопонимаю в коде(?)....
← →
kaZaNoVa © (2005-02-02 10:37) [3]BiN © (02.02.05 10:25) [1]
имхо обычно ориентируемся на самые часто-испрользуемые способы перехвата и их отлавливаем .))
//ща тестирую, результаты сообщу))
← →
Игорь Шевченко © (2005-02-02 10:40) [4]BiN © (02.02.05 10:25) [1]
Привет! Данный код как раз служит для вытаскивания за ушко и на солнышко процессов, которые пользуются методом внедрения без правки IAT, а установкой в адресном пространстве "жертвы" кода перехода на свою скрывающую функцию по корректному адресу в NTDLL.DLL
Краткий алгоритм такой: Проверяется соответствие как правленной IAT, так и совпадения кода по адресу NtQuerySystemInformation в загруженной DLL и на диске. Если код не совпадает, то для вызова функции используется тот код, который в файле NTDLL.DLL на диске находится.
С уважением,
← →
BiN © (2005-02-02 10:43) [5]Игорь Шевченко © (02.02.05 10:40) [4]
Проверяется соответствие как правленной IAT, так и совпадения кода по адресу NtQuerySystemInformation в загруженной DLL и на диске
(выделение мое)
Точно, не обратил внимание на эту строку:
Image := THSPEImage.Create (FileName);
в функции IsNtDllCodeHooked
← →
BiN © (2005-02-02 10:46) [6]Правда, тут могут начаться "гонки" с перехватом NtCreateFile и т.п., но это уже из другой оперы...
← →
Игорь Шевченко © (2005-02-02 10:57) [7]BiN © (02.02.05 10:46) [6]
А зачем перехватывать NtCreateFile ? Я, честно говоря, смысла не вижу.
С уважением,
← →
kaZaNoVa © (2005-02-02 11:04) [8]BiN © (02.02.05 10:46) [6]
всё равно всё не перехватят))
95% имхо всех "перехватчиков" останавливаются на том, что не видны в таск-манагере и всё)))
← →
kaZaNoVa © (2005-02-02 11:09) [9]ура, пример работает!!!
//проверял пока только одну функцию - детектор перехватаIsNtDllHooked
- потрясающе))
← →
BiN © (2005-02-02 11:09) [10]Игорь Шевченко © (02.02.05 10:57) [7]
А зачем перехватывать NtCreateFile ? Я, честно говоря, смысла не вижу.
А с помощью каких функций считывается PE-заголовок ntdll.dll?
← →
Игорь Шевченко © (2005-02-02 11:12) [11]BiN © (02.02.05 11:09) [10]
Разумеется, NtCreateFile + NtCreateSection. Но дело в том, что если перехватить, то как тогда остальные будут работать ? Ведь любая программа отображает NTDLL на свое адресное пространство.
С уважением,
← →
BiN © (2005-02-02 11:13) [12]вдогонку к
BiN © (02.02.05 10:46) [6]
Правда, тут могут начаться "гонки" с перехватом NtCreateFile и т.п., но это уже из другой оперы...
Имеется ввиду также перехват остальных функций I/O файловой системы.
← →
kaZaNoVa © (2005-02-02 11:13) [13]kaZaNoVa © (02.02.05 11:09) [9]
но подмену IAT кажется не определяет . .(или я ошибаюсь?) - другай пример, который только скрывается от такс-менеджера,но виден Процесс-Эксплореру - тот не определятся как IsNtDllHooked ...
← →
Kerk © (2005-02-02 11:16) [14]Игорь Шевченко © (02.02.05 11:12) [11]
так аккуратненько так... проверять какой файл пытаются открыть и все такое :)
← →
BiN © (2005-02-02 11:17) [15]Игорь Шевченко © (02.02.05 11:12) [11]
Но дело в том, что если перехватить, то как тогда остальные будут работать ? Ведь любая программа отображает NTDLL на свое адресное пространство
А разве правка кода будет происходить не в адресном пространстве одного процесса? Не понятно, причем здесь дугие.
С уважением,
← →
kaZaNoVa © (2005-02-02 11:17) [16]Kerk © (02.02.05 11:16) [14]
получится бесконечная "гонка вооружений" ))
← →
Kerk © (2005-02-02 11:19) [17]Kerk © (02.02.05 11:16) [14]
причем здесь дугие.
а как ты узнаешь в каком именно процессе код править? или будешь специально под какую-то тулзу затачиваться?
← →
GMan (2005-02-02 11:52) [18]2 Игорь Шевченко:
Что такое HsNtDef?
← →
Игорь Шевченко © (2005-02-02 12:01) [19]Всем:
Данный код иллюстирует только идею. Если все детали выкладывать, места не хватит. Остальные используемые модули представляют кучу служебных полезностей, написанных в разное время.
Часть можно взять по адресу
http://www.schevchenko.net.ru/SRC/Common_60.zip
BiN © (02.02.05 11:17) [15]
Если перехватывать NtCreateFile, то с какой целью ? Не дать открыть NtDll ? Так это вся система сломается.
С уважением,
← →
Kerk © (2005-02-02 12:02) [20]Игорь Шевченко © (02.02.05 12:01) [19]
Если перехватывать NtCreateFile, то с какой целью ? Не дать открыть NtDll ? Так это вся система сломается.
подменить
← →
Игорь Шевченко © (2005-02-02 12:08) [21]Kerk © (02.02.05 12:02) [20]
Не совсем понял, чем подменить. И главное, с какой целью. NTDLL является первой DLL, отображаемой на адресное пространство процесса.
С уважением,
← →
BiN © (2005-02-02 12:10) [22]Игорь Шевченко © (02.02.05 12:01) [19]
Если перехватывать NtCreateFile, то с какой целью ? Не дать открыть NtDll ? Так это вся система сломается.
Да, согласен. Я имел ввиду, что можно организовать подмену считываемых с диска данных - тех самых первых 14 байт перехваченной функции. Хоть это и финт ушами.
С уважением,
← →
Игорь Шевченко © (2005-02-02 12:18) [23]BiN © (02.02.05 12:10) [22]
В принципе, для определения факта, что кто-то скрыт, достаточно сравнить код по адресу NtQuerySystemInformation с одним из трех его шаблонов, если не совпадает, то включать сирену и мигалку :). Считывание требуется для того, чтобы определить номер системного вызова, который меняется от версии к версии и от сервис-пака к сервис-паку.
С уважением,
← →
BiN © (2005-02-02 12:23) [24]Игорь Шевченко © (02.02.05 12:18) [23]
Если я правильно понял, ты предлагаешь хранить "слепки" с заголовков оригинальных функций для каждой версии(?).
С уважением,
← →
kaZaNoVa © (2005-02-02 12:32) [25]BiN © (02.02.05 12:23) [24]
> "слепки" с заголовков оригинальных функций для каждой
> версии(?).
и будет как антивирус, с "белым списком" )))
← →
Игорь Шевченко © (2005-02-02 12:40) [26]BiN © (02.02.05 12:23) [24]
Ни в коем разе. Это совершенно не переносимый вариант будет. Я основываюсь на том, что системные вызовы представляют собой код по вполне определенному шаблону, и он не меняется, так как изменение не имеет смысла. Меняется только номер вызова. Вот его я получаю чтением файла.
С уважением,
← →
BiN © (2005-02-02 12:48) [27]Игорь Шевченко © (02.02.05 12:40) [26]
Понятно. Также стало ясно почему именно 14 байт :).
С уважением,
← →
Piter © (2005-02-02 15:54) [28]Игорь Шевченко © (02.02.05 10:21)
В сочетании с включенным аудитом процессов
а что это такое, где находится и зачем нужно?
← →
Игорь Шевченко © (2005-02-02 16:12) [29]Piter © (02.02.05 15:54) [28]
Локальная политика безопасности + F1
← →
Piter © (2005-02-02 16:45) [30]И еще, я вот посмотрел на код, компилятора под рукой нету, но на взгляд кое что не понял:
- в RealQueryListInformation выделяется память, на которую указывает Result. А кто эту память будет зачищать?
В примере использования написано:
end else
@FQueryInformationFunction := @QueryListInformation;
а что такое QueryListInformation?
Ну и:
FreeMem(Result);
ListSize := ListSize * 2;
GetMem(Result, ListSize);
можно использовать ReallocMem, будет нагляднее :)
← →
Игорь Шевченко © (2005-02-02 16:53) [31]
> - в RealQueryListInformation выделяется память, на которую
> указывает Result. А кто эту память будет зачищать?
В данном случае - никто. Но никто не мешает реализовать освобождение памяти в своем примере, равно, как и ReallocMem.
> а что такое QueryListInformation?
В данном случае - функция из внешнего юнита. Советую почитать всю ветку, чтобы мне не повторяться.
← →
kaZaNoVa © (2005-02-02 16:57) [32]Piter © (02.02.05 16:45) [30]
> А кто эту память будет зачищать?
Игорь Шевченко © (02.02.05 16:53) [31]
> В данном случае - никто. Но никто не мешает
> реализовать освобождение памяти в своем примере,
> равно, как и ReallocMem.
а допускается ли в таких случаях не заботиться о очищении памяти - имхо думаю, это некритично а по завершении программы Windows сама освободит память ?
← →
Piter © (2005-02-02 17:04) [33]Игорь Шевченко © (02.02.05 16:12) [29]
Локальная политика безопасности + F1
Открыл справку, посмотрел. Вот что у меня:
Администрирование
Службы компонентов
Управление компьютером
Источники данных (ODBC)
Окно просмотра событий
Локальная политика безопасности
Системный монитор
Службы
Нигде про аудит процессов не нашел :(
Хочу оговориться, что у меня w2k.
В политиках аудита нашел "Аудит отслеживания процессов". Но что это такое и что будет, если включить - не понял.
← →
Игорь Шевченко © (2005-02-02 17:06) [34]
> Но что это такое и что будет, если включить - не понял.
F1
← →
SammIk © (2005-02-02 21:20) [35]Респект Игорь Шевченко ©.
Все круто, но есть одно но.
Ежели будет стоять хук на NtCreateFileEx, то соответственно
можно будет отловить обращение к хукнутым библиям и вернуть
то, что это детектор хочет.
Есть другой вариант.
Конкретно для kernel32
Через SEH получить базу образа, там в импортах найти куда идти дальше.
Если в импорт ссылается на адрес вне (imgbase,imgbase+imgsiz)
то делаем вывод, что нас прохучили по импорту.
Ежели все в порядке, то проверяем на предмет джампов саму ф-ю
по тойже схеме.
------
Хотя и такой пример работает)
------
Способ для извращенцев, но действенный.
Открывать винт на чтение, искать нужный фаил, и далее как
Игорь делать
← →
Игорь Шевченко © (2005-02-03 10:43) [36]SammIk © (02.02.05 21:20) [35]
Я бы все-таки хотел увидеть, каким образом хук на NtCreateFile может одновременно помешать мне открыть нужный файл и в то же время гарантировать работу других приложений.
С уважением,
← →
SammIk © (2005-02-03 13:43) [37]С тавится хук на чтение и открытие фаила.
Если открыли то, что не надо открывать. Можно вернуть
код ошибки, мол нет доступа или еще что.
Если читают то, что не надо, то возвращаем не верную инфу.
И чего тут невозможного?
← →
Игорь Шевченко © (2005-02-03 14:12) [38]SammIk © (03.02.05 13:43) [37]
Так система тоже читает. И для того, чтобы она работала, необходимо, чтобы читалось то, что запрошено и данные должны быть верными.
← →
Piter © (2005-02-03 15:33) [39]Игорь Шевченко © (03.02.05 14:12) [38]
Так система тоже читает
А она читает тоже через NtCreateFile? Или через какие-то свои внутренние функции?
← →
Игорь Шевченко © (2005-02-03 16:26) [40]Piter © (03.02.05 15:33) [39]
Все замыкается на NtCreateFile - это единственная дырка. И не читает, а получает доступ к файлу.
С уважением,
Страницы: 1 2 вся ветка
Текущий архив: 2005.03.20;
Скачать: CL | DM;
Память: 0.58 MB
Время: 0.059 c