|   | 
	
	
		|   | 
	
	
		| Hidden Rootkit Process Detection  | 
	
	
		|   | 
	
	
		|   | 
	
	
		|   | 
	
	
	
		
	
		  |  	
		
	
		| 
		
	 | 
	
	
		|   | 
	
	
		|   | 
	
	
	
		|   | 
	
	
	
		
	
		  |  	
	
		 | 
	
	
		|   | 
	
	
		|   | 
	
	
		
	
		  |  	
	
		
			Rootkits are one of the advanced species in today's every 
			changing technical world. They are known for their sophisticated 
			techniques to hide their presence often evading their detection from 
			top notch Antiviruses and detection tools. Antivirus solutions often 
			hit the wall when it comes to Rootkit detection and there is a 
			greater need for dedicated Anti-Rootkit tools.  
			Rootkits use combination of user land and kernel level techniques 
			to evade their detection. In this article we will throw light on how 
			userland Rootkits work under the hood and different techniques which 
			can be used to detect such Rootkits. Though these methods are 
			effective only against user land Rootkits, in some cases they can 
			even detect kernel based Rootkits unless they haven't taken proper 
			care to remove all those traces.    | 
	
	
		| 
		  | 
	
	
		| 
		  | 
	
  |  	
	
		
	
		  |  	
	
		
			Userland Rootkits use different techniques to hide their process 
			and to prevent its termination. One such method is to hook the 
			NtOpenProcess function (OpenProcess API internally calls
			NtOpenProcess) and return negative result whenever Anti-Rootkit 
			application try to open such process. As a result Rootkit process 
			will remain hidden from any process viewer tools.  
			This is just one of the method and often you will find more such 
			internal functions such as NtQuerySystemInformation being hooked to 
			filter out their process from the list.
			 
		  | 
		
		  |  	
	
		|   | 
	
	
		|   | 
	
	
		
	
	  |  	
	
		| 
		 Detection of hidden process is equally challenging as 
			Rootkit can 
			employ one or more methods to cover its presence. Here are some of 
			the very effective methods to detect such userland Rootkit processes. 
			 
			All these detection methods work on common approach. First they 
			get the list of all running processes using standard API functions 
			such as EnumProcesses or Process32First. Then one or more special 
			methods mentioned below are used to enumerate the processes. Finally 
			this new process list is compared with previously obtained list and 
			any new process found in this new list is detected as hidden rootkit process. 
		 | 
	
	
		|   | 
	
	
		|   | 
	
	
		
	
			  |  	
	
		| 
		 This is very effective method to detect any hidden userland rootkit 
		processes. One of the lesser-known methods of enumerating the processes 
		is to use NtQuerySystemInformation function by passing first parameter 
		as SystemProcessesAndThreadsInformation. The drawback of this method is 
		that it can be easily circumvented by hooking the 
		NtQuerySystemInformation function and then by tampering with the 
		results.
  
		The NtQuerySystemInformation is basically stub having few lines of 
		code to transition from user to kernel land. It finally calls the 
		NtQuerySystemInformation function within the kernel. So the trick here 
		is to implement the NtQuerySystemInformation without directly calling 
		the function.
  
		Here is the sample code that shows how one can directly implement 
		NtQuerySystemInformation on various platforms. On Windows2000, 
		INT 2E 
		and from XP onwards 'sysenter' instruction is used to transition from 
		user to kernel. 
		 | 
	
	
		| 
		  | 
	
	
		
		 __declspec(naked)
  NTSTATUS __stdcall DirectNTQuerySystemInformation
          (ULONG SystemInformationClass,
		  PVOID SystemInformation,
		  ULONG SystemInformationLength,
		  PULONG ReturnLength)	
  {
										
										
	  //For Windows 2000
	  if( OSMajorVersion == 5 && OSMinorVersion == 0 )
	  {
		__asm
		{
			mov eax, 0x97
			lea edx, DWORD PTR ss:[esp+4]
			INT 0x2E
			ret 0x10
		}	
	
	}	
	
	//For Windows XP
	if( OSMajorVersion == 5 && OSMinorVersion == 1 )
	{
		__asm
		{
				mov eax, 0xAD     
				call SystemCall_XP
				ret 0x10
				
			SystemCall_XP:
			
				mov edx, esp
				sysenter
		}	
	
	}									
										
	//For Windows Vista & Longhorn
	if( OSMajorVersion == 6 && OSMinorVersion == 0 )
	{
		__asm
		{
				mov eax, 0xF8    
				call SystemCall_VISTA
				ret 0x10
				
			SystemCall_VISTA:
			
				mov edx, esp
				sysenter
		}	
	}
	
	//For Windows 7
	if( OSMajorVersion == 6 && OSMinorVersion == 1 )
	{
		__asm
		{
				mov eax, 0x105    
				call SystemCall_WIN7
				ret 0x10
			SystemCall_WIN7:
				mov edx, esp
				sysenter
		}	
	}					
										
										
     }								
  }
		 | 
	
	 
		|   | 
	
	 
		| This technique can discover any userland rootkit process and only 
		way for rootkit process to defeat against this technique is to move into 
		kernel. However, due to low-level implementation, there is slight risk 
		in using this method in production code. | 
	
	 
		|   | 
	
	 
		|   | 
	
	 
		|   | 
	
	 
		
	
			  |  	
	
		| 
		 This method was first used by BlackLight and it turned out to be very 
		effective yet simple. Here, it enumerates through process id from 0 to 
		0x41DC and then check if that process exist by calling OpenProcess 
		function. Then this list of discovered processes are compared with 
		normal process list got using standard enumeration functions (such as 
		Process32First, EnumProcesses functions).
  
		During the testing, it is found that some process id on server 
		machines were more than magic number 0x41DC. So in order to be effective 
		the magic number is doubled to take care of all possible running 
		processes on latest operating systems.
  
		Here is the sample code that implements PIDB method: 
		 | 
	
	
		| 
		  | 
	
	
		
				for(int i=0; i < 0x83B8; i+=4)
 {
   //These are system idle and system processes
   if( i == 0 || i==4 )
   {
   	 continue;
   }
   hprocess = OpenProcess
  	 (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, i);
   if( hprocess == NULL  )
   {
	
	if( GetLastError() != ERROR_INVALID_PARAMETER)
	{
	// If the error code is other than 
	// ERROR_INVALID_PARAMETER that means this
	// process exists but we are not able to open.
		
	//check if this process is already discovered
	//using standard API functions.
	if( IsHiddenProcess(i) )
	{
		printf("\n Hidden process found %d", i);
	}
	}
	continue;
	}
	dwExitCode = 0;
	GetExitCodeProcess(hprocess, &dwExitCode);
	// check if this is active process...
	// only active process will return error 
	// code as ERROR_NO_MORE_ITEMS
	if( dwExitCode == ERROR_NO_MORE_ITEMS )  
	{
	  //check if this process is already discovered
	  if( IsHiddenProcess(i) )
	  {
		printf("\n Hidden process found %d", i);
	  }
	}
	CloseHandle(hprocess);
 }
		 | 
	
	
		|   | 
	
	
		| Though this is very effective method, rootkit can easily defeat this 
		technique by hooking OpenProcess or its native version NTOpenProcess 
		function and then returning NULL with error code as 
		ERROR_INVALID_PARAMETER. To defend against such tricks anti-rootkit 
		softwares can call NtOpenProcess using direct system call method as 
		shown in "Detection of Hidden Process using Direct NT System Call 
		Implemenation". | 
	
	
		|   | 
	
	
		|   | 
	
	
		|   | 
	
	
		
	
			  |  	
	
		| 
		 Any windows process when run will have lot of open handles realted to 
		process, thread, named objects, file, port, registry, etc. that can be 
		used to detect hidden process. One can use the native API function. The 
		effective way to enumerate handles is to use NtQuerySystemInformation 
		with first parameter as SystemHandleInformation. It lists the handles 
		from all running processes in the system. For each enumerated handle, it 
		provides information such as handle, handle type and process id of the 
		owning process. Hence, by enumerating through all the handles and then 
		using the associated process id, one can detect all possible hidden 
		processes that are not revealed through standard API functions.
  
		There is one interesting system process called CSRSS.EXE, which holds 
		the handles to all running processes. So instead of going through all 
		the different handles, one can just scroll through the process handles 
		of CSRSS.EXE process. Interestingly this method can, not only detect 
		userland hidden processes but also some of the rootkit processes which 
		have used kernel land techniques without taking care of hiding process 
		handles within CSRSS.EXE process.
  
		Here is the code snippet, which can demonstrate this method: 
		 | 
	
	
		| 
		  | 
	
	
		
		PVOID bufHandleTable = malloc(dwSize); 
		status = NtQuerySystemInformation
     (SystemHandleInformation, bufHandleTable, dwSize, 0);
 SYSTEM_HANDLE_INFORMATION *HandleInfo = 
     (SYSTEM_HANDLE_INFORMATION *) bufHandleTable;
// Process handles within CSRSS will not have handle 
// to following processes system idle process, system
// process, smss.exe, csrss.exe.
for(int i=0; i< HandleInfo->NumberOfHandles; i++)
{
  int pid = HandleInfo->Handles[i].UniqueProcessId;
	
  // For XP & 2K3 : HANDLE_TYPE_PROCESS = 0x5
  // For Vista & Longhorn : HANDLE_TYPE_PROCESS = 0x6
	
  if( HandleInfo->Handles[i].ObjectTypeIndex == 
                                  HANDLE_TYPE_PROCESS) 
  {
   //check if this process id is that of CSRSS.EXE process.
   if( IsCSRSSProcess(pid) ) 
   {
 	 hprocess = OpenProcess(PROCESS_DUP_HANDLE, false, pid);
	 
   if( hprocess )
   {
       if( DuplicateHandle(hprocess, 
	   (HANDLE)HandleInfo->Handles[i].Handle, 
	   GetCurrentProcess(), 
	   &tprocess, 
	   PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, 0))
	   {
		
		targetPid = GetProcessId(tprocess);
		 //check if this is hidden process
		 if( IsHiddenProcess(targetPid) )
		 {
		   printf("\n Found hidden process %d", targetPid);
		 }
	   }
	 }// End of if( hprocess )
		
   } // End of if( IsCSRSSProcess(pid) )
  } // End of if
 } // End of for-loop
		 | 
	
	
		|   | 
	
	
		| 
		 Since the CSRSS.EXE is not first process started when Windows boots, 
		it does not contains handles to already started processes such as system 
		idle process(pid=0), system process (pid=4), smss.exe and its process 
		itself.
  
		On Windows Vista system it is possible to more than one CSRSS.EXE 
		process in case of multiple users logged in. Same situation arises on XP 
		system, when more than one user is operating through 'Switch User' 
		mechanism. In such case, one has to check if the enumerated process 
		belongs to any of these CSRSS process ids. The function IsCSRSSProcess() 
		above does exactly the same by comparing the discovered process id with 
		list of all running CSRSS.EXE processes.
  
		One more way is to enumerate all thread handles within CSRSS process 
		instead of process handles, as most rootkits are aware of this 
		technique. The CSRSS process not only has process handles but also 
		thread handles for every running processes. Once the thread handle is 
		known, one can use GetProcessIdOfThread function to get process id 
		associated with that thread after duplicating it.
  
		Though any rootkit process can defeat this technique by hooking 
		NtQuerySystemInformation or NtOpenProcess function, it can easily be 
		circumvented by using direct implementation of these native API 
		functions as described in the "Detection of Hidden Process using Direct 
		NT System Call Implemenation". 
		 | 
	
	
		|   | 
	
	
		|   | 
	
	
		|   | 
	
	
		
	
		  |  	
	
		| 
		 There exists several other userland methods to detect hidden rootkit 
		processes, but they are not as effective as the ones described above. 
		However they can be used on need basis and often to target specific 
		rootkit.
  
		One such method is to enumerate through all the open Windows created 
		by the processes within the system using EnumWindows API function and 
		then calling the GetWindowThreadProcessId function to get the process id 
		associated with that Window.
  
		Here is the sample code that does the same... 
		 | 
	
	
		| 
		  | 
	
	
		
		//Setup the callback function to enumerate through windows
 EnumWindows(EnumWindowsProc, NULL);
 //This is callback function to enumerate windows
 BOOL CALLBACK EnumWindowsProc(HWND hwnd, PARAM lParam)
 {
	DWORD procId;
	
	GetWindowThreadProcessId(hwnd, &procId);
	
	if( IsHiddenProcess(procId) )
	{
		printf("Found hidden process %d", procId);
	}
 }
		 | 
	
	
		|   | 
	
	
		| There exist several other ways to detect the hidden processes in 
		user land and new ways are being discovered everyday. Though these 
		detection techniques can be easily defeated from kernel land, they 
		present simple and less risky mechanism to uncover the userland 
		rootkits. | 
	
	
		|   | 
	
	
		|   | 
	
	
		|   | 
	
	
		
	
			  |  	
	
		1. Detection 
		of Hidden Processes 2. 
		Hiding 
		Rootkit process from CSRSS Handle Enumeration Method | 
	
	
		|   | 
	
	
		|   | 
	
	
	
		|   | 
	
	
	
		
	
		  |  	
		
	
		| 
		
	 | 
	
	
		|   | 
	
	
		|   | 
	
	
	
		|   | 
	
		
	
	
		|   | 
	
	
		|   | 
	
	
		|   | 
	
	
		|   | 
	
	
		|   | 
	
	
		|   |