PDA

Просмотр полной версии : Перехват NtQuerySystemInformation


Simbi0s
05.08.2007, 21:59
Доброго вам времени суток господа! :)
Прошу просмотреть данный листинг и сказать что не так... я хочю перехватить ф-цию NtQuerySystemInformation из библиотеки ntdll.dll...
Ф-ция вроде бы перехвачевается без проблем но вернуть данные системе не получается. С перехватами самописных и простеньких ф-ций всё работает, пример взят из книжки " Зайцев О. Rootkits, SpyWare, AdWare, Keyloggers & BackDoors. Обнаружение и защита "... учусь по ней ;)
Заранее спасибо!

Код библиотеки:

library rootkit_lib;
uses
Windows,
SysUtils,
Classes,
TlHelp32;

const
IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13; // Delay Load Import Descriptors
type
TImageImportDescriptor = packed record // (В C++ это IMAGE_IMPORT_DESCRIPTOR)
OriginalFirstThunk : DWORD; // Ранее это поле называлось Characteristics; в целях сохранения
TimeDateStamp : DWORD; // 0, если импортирование осуществляется без привязки (binding - см. далее)
// При импортировании с привязкой содержит отметку времени файла, из которого идет импорт
ForwarderChain : DWORD; //
Name : DWORD; // Адрес ASCIIZ-строки с именем файла, из которого импортируем функции
FirstThunk : DWORD; // Виртуальный адрес подтаблицы импортируемых символов
end;
PImageImportDescriptor=^TImageImportDescriptor;

SYSTEM_INFORMATION_CLASS = (
SystemBasicInformation,
SystemProcessorInformation,
SystemPerformanceInformation,
SystemTimeOfDayInformation,
SystemNotImplemented1,
SystemProcessesAndThreadsInformation,
SystemCallCounts,
SystemConfigurationInformation,
SystemProcessorTimes,
SystemGlobalFlag,
SystemNotImplemented2,
SystemModuleInformation,
SystemLockInformation,
SystemNotImplemented3,
SystemNotImplemented4,
SystemNotImplemented5,
SystemHandleInformation,
SystemObjectInformation,
SystemPagefileInformation,
SystemInstructionEmulationCounts,
SystemInvalidInfoClass1,
SystemCacheInformation,
SystemPoolTagInformation,
SystemProcessorStatistics,
SystemDpcInformation,
SystemNotImplemented6,
SystemLoadImage,
SystemUnloadImage,
SystemTimeAdjustment,
SystemNotImplemented7,
SystemNotImplemented8,
SystemNotImplemented9,
SystemCrashDumpInformation,
SystemExceptionInformation,
SystemCrashDumpStateInformation,
SystemKernelDebuggerInformation,
SystemContextSwitchInformation,
SystemRegistryQuotaInformation,
SystemLoadAndCallImage,
SystemPrioritySeparation,
SystemNotImplemented10,
SystemNotImplemented11,
SystemInvalidInfoClass2,
SystemInvalidInfoClass3,
SystemTimeZoneInformation,
SystemLookasideInformation,
SystemSetTimeSlipEvent,
SystemCreateSession,
SystemDeleteSession,
SystemInvalidInfoClass4,
SystemRangeStartInformation,
SystemVerifierInformation,
SystemAddVerifier,
SystemSessionProcessesInformation
);

// Таблица отложенного импорта (В C++ ImgDelayDescr в include\delayimp.h)
TImgDelayDescr = packed record
grAttrs : DWORD; // Атрибуты (тип адресации: 0 - RVA, 1 - VA)
rvaDLLName : DWORD; // RVA имени DLL
rvaHmod : DWORD; // handle библиотеки (заполняется загрузчиком)
rvaIAT : DWORD; // Таблица адресов функций, последняя ячейка содержит 0
rvaINT : DWORD; // Таблица указателе на имена функций, последняя ячейка содержит 0
rvaBoundIAT : DWORD; // DWORD of the optional bound IAT
rvaUnloadIAT : DWORD; // DWORD of optional copy of original IAT
dwTimeStamp : DWORD; // 0 if not bound, date/time stamp of DLL bound to (Old BIND)
end;
PImgDelayDescr = ^TImgDelayDescr;

TGetProcAddress = function (hModule: HMODULE; lpProcName: LPCSTR): FARPROC; stdcall;
TLoadLibrary = function (lpLibFileName: PChar): HMODULE; stdcall;
TLoadLibraryA = function (lpLibFileName: PAnsiChar): HMODULE; stdcall;
TLoadLibraryW = function (lpLibFileName: PWideChar): HMODULE; stdcall;
TNtQuerySystemInformation = function (SystemInformationClass: SYSTEM_INFORMATION_CLASS; SystemInformation: Pointer;
SystemInformationLength:ULONG; ReturnLength:PULONG):LongInt; stdcall;


function ImageDirectoryEntryToData(Base: Pointer; MappedAsImage: ByteBool;
DirectoryEntry: Word; var Size: DWORD): Pointer; stdcall;
external 'imagehlp.dll' name 'ImageDirectoryEntryToData';


type
TInterceptInfo = record
LibraryName : string;
OldFunction : Pointer;
NewFunction : Pointer;
end;
var
InterceptedFunctionsList : array of TInterceptInfo;
OldGetProcAddress : TGetProcAddress;
OldLoadLibrary : TLoadLibrary;
OldLoadLibraryA : TLoadLibraryA;
OldLoadLibraryW : TLoadLibraryW;
OldNtQuerySystemInformation:TNtQuerySystemInformat ion;
HookHandle : hHook; // Handle, возвращаемый SetWindowsHookEx
// Замена в IAT модуля AModule адреса OldFunct на NewFunct
function ReplaceIATEntry(AModule: hModule; ALibName : string; OldFunct, NewFunct: Pointer) : boolean;
var
IAT_Size : ULONG; // Размер IAT
ImportDescriptorPtr : PImageImportDescriptor; // Указатель на IAT
LibImportDescriptor : PImageImportDescriptor; // Указатель на запись IAT заданнйо DLL
ThunkPtr : LPDWORD;
OldProtect, Tmp : dword;
begin
Result := false;
// 1. Поиск IAT
ImportDescriptorPtr := ImageDirectoryEntryToData(Pointer(AModule), TRUE,
IMAGE_DIRECTORY_ENTRY_IMPORT, IAT_Size);
// IAT не найдена - дальнейшее продолжение анализа невозможно
if ImportDescriptorPtr = nil then exit;
LibImportDescriptor := nil;
// 2. Поиск секции импорта из DLL с именем ALibName
while ImportDescriptorPtr.Name <> 0 do begin
if (lstrcmpiA(PChar(AModule + ImportDescriptorPtr.Name), PChar(ALibName)) = 0) then begin
LibImportDescriptor := ImportDescriptorPtr;
// 3. Поиск адреса перехватываемой функции в таблице
ThunkPtr := LPDWORD(AModule + LibImportDescriptor.FirstThunk);
while ThunkPtr^ <> 0 do begin
// Адрес найден ? Если да, то выполним его замену на заданный
if (pointer(ThunkPtr^) = OldFunct) then begin
// Настройка защиты - разрешим запись в эту страницу
VirtualProtect(ThunkPtr, 4, PAGE_READWRITE, OldProtect);
// Запись
WriteProcessMemory(GetCurrentProcess, ThunkPtr, @NewFunct, 4, Tmp);
// Восстановление атрибутов защиты
VirtualProtect(ThunkPtr, 4, OldProtect, Tmp);
Result := true;
end;
Inc(ThunkPtr);
end;
end;
Inc(ImportDescriptorPtr);
end;
end;

// Замена в DIT модуля AModule адреса OldFunct на NewFunct
function ReplaceDITEntry(AModule: hModule; ALibName : string; OldFunct, NewFunct: Pointer) : boolean;
var
DIT_Size : ULONG; // Размер DIT
ImgDelayDescr : PImgDelayDescr; // Указатель на DIT
LibImgDelayDescr : PImgDelayDescr;
ThunkPtr : LPDWORD;
OldProtect, Tmp : dword;
RVARel : hModule;
begin
Result := false;
// 1. Поиск DIT
ImgDelayDescr := ImageDirectoryEntryToData(Pointer(AModule), TRUE,
IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT, DIT_Size);
// DIT не найдена - дальнейшее продолжение анализа невозможно
if ImgDelayDescr = nil then exit;
LibImgDelayDescr := nil;
// 2. Поиск секции Delay Import из DLL с именем ALibName
while ImgDelayDescr.rvaDLLName <> 0 do begin
// Учет метода адресации RVA/VA.
if ImgDelayDescr.grAttrs = 1 then RVARel := AModule
else RVARel := 0;
if (lstrcmpiA(PChar(RVARel + ImgDelayDescr.rvaDLLName),
PChar(ALibName)) = 0) then begin
LibImgDelayDescr := ImgDelayDescr;
// 3. Поиск адреса перехватываемой функции в таблице
ThunkPtr := LPDWORD(RVARel + LibImgDelayDescr.rvaIAT);
while ThunkPtr^ <> 0 do begin
// Адрес найден? Если да, то выполним его замену на заданный
if (pointer(ThunkPtr^) = OldFunct) then begin
// Настройка защиты - разрешим запись в эту страницу
VirtualProtect(ThunkPtr, 4, PAGE_READWRITE, OldProtect);
// Запись
WriteProcessMemory(GetCurrentProcess, ThunkPtr, @NewFunct, 4, Tmp);
// Восстановление атрибутов защиты
VirtualProtect(ThunkPtr, 4, OldProtect, Tmp);
Result := true;
end;
Inc(ThunkPtr);
end;
end;
Inc(ImgDelayDescr);
end;
end;

function InterceptFunction(ALibName : string; OldFunct, NewFunct: Pointer) : boolean;
var
hSnapshot : THandle;
me32 : TModuleEntry32;
begin
Result := false;
// Создание "снимка" модулей текущего процесса
hSnapshot := CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId);
if hSnapshot = INVALID_HANDLE_VALUE then
exit;
me32.dwSize := SizeOf(TModuleEntry32);
if (Module32First(hSnapshot, me32)) then
repeat
// Модификация таблицы импорта
ReplaceIATEntry(me32.hModule, ALibName, OldFunct, NewFunct);
// Модификация таблицы отложенного импорта
ReplaceDITEntry(me32.hModule, ALibName, OldFunct, NewFunct);
until not(Module32Next(hSnapshot, me32));
CloseHandle(hSnapshot);
Result := true;
end;

function InterceptFunctionEx(ALibName, AFunctName : string; var OldFunct : pointer; NewFunct: Pointer; ADoLoadLibrary : boolean = false) : boolean;
begin
Result := false;
OldFunct := GetProcAddress(GetModuleHandle(PChar(ALibName)), PChar(AFunctName));
if (OldFunct = nil) and ADoLoadLibrary then
OldFunct := GetProcAddress(LoadLibrary(PChar(ALibName)),
PChar(AFunctName));
if OldFunct = nil then exit;
// Функция уже перехвачена ?
if OldFunct = NewFunct then exit;
Result := InterceptFunction(ALibName, OldFunct, NewFunct);
SetLength(InterceptedFunctionsList, Length(InterceptedFunctionsList)+1);
with InterceptedFunctionsList[Length(InterceptedFunctionsList)-1] do begin
LibraryName := ALibName;
OldFunction := OldFunct;
NewFunction := NewFunct;
end;
end;

function InterceptModuleFunctions(hModule : THandle) : boolean;
var
i : integer;
begin
for i := 0 to Length(InterceptedFunctionsList)-1 do
with InterceptedFunctionsList[i] do begin
// Модификация таблицы импорта
ReplaceIATEntry(hModule, LibraryName, OldFunction, NewFunction);
// Модификация таблицы отложенного импорта
ReplaceDITEntry(hModule, LibraryName, OldFunction, NewFunction);
end;
end;

function myNtQuerySystemInformation(SystemInformationClass: SYSTEM_INFORMATION_CLASS; SystemInformation: Pointer;
SystemInformationLength:ULONG; ReturnLength:PULONG):LongInt; stdcall;
begin
Result:=OldNtQuerySystemInformation(SystemInformat ionClass,SystemInformation,SystemInformationLength ,ReturnLength);
//MessageBox(0,'111','111',0);
end;

function myGetProcAddress(hModule: HMODULE; lpProcName: LPCSTR): FARPROC; stdcall;
var
i : integer;
begin
Result := OldGetProcAddress(hModule, lpProcName);
// Вызов GetProcAddress вернул адрес ?? Проверим, не перехвачена ли эта функция
if Result <> nil then
for i := 0 to Length(InterceptedFunctionsList)-1 do
if InterceptedFunctionsList[i].OldFunction = Result then begin
// Функция перехвачена, вернем адрес перехватчика
Result := Pointer(InterceptedFunctionsList[i].NewFunction);
Break;
end;
end;

function myLoadLibraryA(lpLibFileName: PAnsiChar): HMODULE; stdcall;
var
Loaded : boolean;
begin
// Признак того, что DLL уже загружена
Loaded := GetModuleHandleA(lpLibFileName) <> INVALID_HANDLE_VALUE;
Result := OldLoadLibraryA(lpLibFileName);
// Это загрузка новой DLL ??
if (Result <> INVALID_HANDLE_VALUE) and not(Loaded) then
InterceptModuleFunctions(Result);
end;

function myLoadLibraryW(lpLibFileName: PWideChar): HMODULE; stdcall;
var
Loaded : boolean;
begin
// Признак того, что DLL уже загружена
Loaded := GetModuleHandleW(lpLibFileName) <> INVALID_HANDLE_VALUE;
Result := OldLoadLibraryW(lpLibFileName);
// Это загрузка новой DLL ??
if (Result <> INVALID_HANDLE_VALUE) and not(Loaded) then
InterceptModuleFunctions(Result);
end;


// Функция-обработчик перехватчика
function KeyHook(nCode: integer; WParam: Word; LParam: LongInt): Longint; stdcall;
begin
// Вызов следующего в цепочке обработчика
Result := CallNextHookEx(HookHandle, nCode, WParam, LParam);
end;

begin
InterceptedFunctionsList := nil;
// Перехват LoadLibrary*
InterceptFunctionEx('kernel32.dll','LoadLibraryA',
@OldLoadLibraryA, @myLoadLibraryA);
InterceptFunctionEx('kernel32.dll','LoadLibraryW',
@OldLoadLibraryW, @myLoadLibraryW);
// Перехват GetProcAddress
InterceptFunctionEx('kernel32.dll','GetProcAddress ',
@OldGetProcAddress, @myGetProcAddress);
// Перехват NtQuerySystemInformation
InterceptFunctionEx('ntdll.dll','NtQuerySystemInfo rmation',
@OldNtQuerySystemInformation, @myNtQuerySystemInformation);



HookHandle := SetWindowsHookEx(WH_CBT, @KeyHook, HInstance, 0);
end.


Код загрузчика:

program rktest1;
uses
windows,
Forms;
var
H : THandle;
begin
H := LoadLibrary('rootkit_lib.dll');
MessageBox(0, 'Message3', 'Rootkit', 0);
end.

drmist
05.08.2007, 22:34
А что видно через дебагер?
ЗЫ. А хукать ZwQuerySystemInformation не пробовал?

Ni0x
05.08.2007, 23:22
NtQuerySystemInformation для юзерленда, для тех кто не знает - это всеголишь обертка ZwQuerySystemInformation, которая выполняется на уровне ядра.

Hellsp@wn
06.08.2007, 00:39
а в чём конкретно проблема?

з.ы. я перехватывал Zw и никаких проблем =)

KEZ
06.08.2007, 08:03
> это всеголишь обертка ZwQuerySystemInformation, которая выполняется на уровне ядра.

ага, блядь, на уровне ядра) Nt и Zw в ntdll вообще грубо говоря, одно и тоже, и адреса у них одинаковые, да и какой может быть перехват если ты не знаешь элементарных понятий и пишешь полную ***ню про то что Zw выполняется на уровне ядра)

LEE_ROY
06.08.2007, 08:43
Hxdef , смотри код

Ni0x
06.08.2007, 11:39
KEZ, зачем так нервничать? Я не совсем верно изъяснился, согласен. В ntdll.dll у них одинаковая точка входа - это верно. Я имел ввиду не совсем то что написал.
при дизассемблировании ntoskrnl.exe становится видно, что идентификаторы Nt* указывают на настоящий код, а их разновидность Zw* ссылаются на заглушки INT 2Eh. Это означает, что набор функций Zw* работает через шлюз, переключающий режимы пользователя и ядра, а функции Nt* указывают непосредственно на код, вывполняющийся после переключения режима.
Вот интересная тема на васме: http://wasm.ru/forum/viewtopic.php?pid=188423

_Great_
06.08.2007, 13:28
Ni0x, в любом случае в юзермоде без разницы. А в ядре из собственных драйверов лучше вызывать Zw*.

Ni0x
06.08.2007, 14:07
Ni0x, в любом случае в юзермоде без разницы. А в ядре из собственных драйверов лучше вызывать Zw*.
Так я и не спорю. Просто я не совсем верно написал в первом сообщении.
Кстати, ТС, ты бы описал проблему поподробнее, а то разбирать весь твой листинг желания мало.

Simbi0s
06.08.2007, 14:41
Я же написал, что проблема в том что я немогу вернуть данные системе, а конкретнее мне кажется что у меня неправильно описана функция

function myNtQuerySystemInformation(SystemInformationClass: SYSTEM_INFORMATION_CLASS; SystemInformation: Pointer;
SystemInformationLength:ULONG; ReturnLength:PULONG):LongInt; stdcall;

Дело в том что после перехвата список таскменеджера вообще пустой, ну после этого вылазит куча ошибок в системе. Если верить моей функции то всё в принцепе должно возвращаться...

function myNtQuerySystemInformation(SystemInformationClass: SYSTEM_INFORMATION_CLASS; SystemInformation: Pointer;
SystemInformationLength:ULONG; ReturnLength:PULONG):LongInt; stdcall;
begin
Result:=OldNtQuerySystemInformation(SystemInformat ionClass,SystemInformation,SystemInformationLength ,ReturnLength);

end;

Hellsp@wn
06.08.2007, 15:14
всё правильно описано =)

возьми в зубы отладчик, приатачся в таскменеджеру, поставь бряк и глянь что не так..

KEZ
06.08.2007, 17:16
> Так я и не спорю. Просто я не совсем верно написал в первом сообщении.

какое отношение тогда это вообще имеет к уровню ядра и зачем это писать, если разговор о совершенно другой ф-ии в юзер-моде?

> неправильно описана функция

а ты побольше делфи используй, и не такое будет ; )
аттачится к таскменеджеру не стоит - сделай приложение, в котором будет перехватываться нужная ф-ия и использоваться. там уже отладчиком и смотри, а каждый раз таксмгр копать заебешься.

Ni0x
06.08.2007, 17:27
какое отношение тогда это вообще имеет к уровню ядра и зачем это писать, если разговор о совершенно другой ф-ии в юзер-моде?
Ну я начал писать об этом, так как речь зашла о перехвате тойже функции, но с префиксом Zw.

Simbi0s
06.08.2007, 17:27
to KEZ
хе.. Спасибо, чёт я сразу не сообразил :))

> а ты побольше делфи используй, и не такое будет ; )
так меня ж не спрашивают :), сказали учить делфу, учу делфу, вот в следующем семестре С и asm учить скажут, бум зубрить :)

Hellsp@wn
06.08.2007, 19:27
>> там уже отладчиком и смотри, а каждый раз таксмгр копать заебешься.

дык одного раза отладчиком глянуть вполне достаточно, нафига ещё прогу какую-то лепить?

от языка ничё не зависит =) ну будет он писать на асме, будут те же вопросы,
учи матчасть по перехватам...

LEE_ROY
06.08.2007, 20:18
Вот так должно быть:
http://rapidshare.com/files/47337710/rootkit_lib.rar

AHTOLLlKA
06.08.2007, 20:21
lee_roy
да..красиво тег с кодом замутил =\\\

LEE_ROY
06.08.2007, 20:22
я на один глаз от сыньки уже невижу.. )) залил на рапидшарэ..