A forum for reverse engineering, OS internals and malware analysis 

Forum for discussion about kernel-mode development.
 #8648  by Tigzy
 Tue Sep 20, 2011 11:20 am
Hi guys!

I'm currently trying to bypass every sort ok hooks to kill a PID.
I already got the true adresses of NtOpenProcess & NtTerminateProcess. My prototypes for theses funcs are good too.

The problem is NtOpenProcess always returns STATUS_ACCESS_VIOLATION, while ZwOpenProcess does not.
The parameteres are the same. Anybody knows why? It must be a check inside , but how to avoid this?

Here's my code:
Code: Select all
				
				HANDLE process;					
				OBJECT_ATTRIBUTES ObjectAttributes; 
				CLIENT_ID ClientId; 
				ACCESS_MASK DesiredAccess;	
				
				if (OrigNtTerminateProcess != 0x0 && OrigNtOpenProcess != 0x0)
				{
					DesiredAccess = PROCESS_TERMINATE;				
					InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
					ClientId.UniqueProcess = (HANDLE)pBufferIn[0]; //My pid to kill
					ClientId.UniqueThread = 0;		
				
					Status  =  ((NTOPENPROCESS) OrigNtOpenProcess)( &process, DesiredAccess, &ObjectAttributes,  &ClientId); 
					//Status  = ZwOpenProcess( &process, DesiredAccess, &ObjectAttributes,  &ClientId);  //If I replace the line above with this one, all works!
					if (NT_SUCCESS(Status))
					{						
						retVal = ((NTTERMINATEPROCESS)(OrigNtTerminateProcess)) (process, 0);						
						pIrp->IoStatus.Information = 1;
						ZwClose(process);
					}
					else
					{
						DbgPrint("OpenProcess failed 0x%x\n", Status);
						retVal = STATUS_UNSUCCESSFUL;
						pIrp->IoStatus.Information = 0;
					}
				}
...
 #8649  by r2nwcnydc
 Tue Sep 20, 2011 11:46 am
The Zw version sets the previous mode to KernelMode, while calling the Nt function directly uses which ever mode your function is using. More then likely your function is being called with previous mode set to UserMode and your process does not have permission to terminate the process. If you want to set previous mode manually, it can be found in the KTHREAD structure. Just be sure to set it back to it's original value before you do so.
 #8650  by Tigzy
 Tue Sep 20, 2011 12:04 pm
So I need to set the previousmode to KernelMode manually, then call my NtTerminateProcess and return to UserMode ?
The thing I don't understand is that all is called from KerneMode, so why my previousmode wouldn't be KernelMode? The flag is toogled when passing throught my driver isn't it?
 #8651  by r2nwcnydc
 Tue Sep 20, 2011 12:54 pm
Tigzy wrote:So I need to set the previousmode to KernelMode manually, then call my NtTerminateProcess and return to UserMode ?
Yes, but don't forget to store the original mode and reset it after the call to NtTerminateProcess.
Tigzy wrote:The thing I don't understand is that all is called from KerneMode, so why my previousmode wouldn't be KernelMode? The flag is toogled when passing throught my driver isn't it?
Previous mode doesn't indicate whether you are in the kernel or in user land, but rather who is controlling you.

Let's say a call comes in from user mode to NtQueryInformationFile. The parameters passed to NtQueryInformationFile were allocated in usermode. This means that if a process context switch occurs any parameters that were pointers are no longer valid.

Now let's say a call comes in from kernel mode to NtQueryInformationFile (with previous mode set to kernel). The parameters passed to NtQueryInformationFile are now assumed to be allocated in kernel mode. This means that if a process context switch occurs the parameters are still valid.

Now let's say a call comes in from user mode to your driver (via DeviceIoControl or something similar), and your driver calls NtQueryInformationFile using parameters passed in from user mode. If the kernel were to assume the call was from kernel mode the parameters would be treated as if they were allocated in the kernel, however, really the parameters are process dependent.

Using the same scenario as above, in case 1 and 3 the access rights to objects should be bound by the process who is calling the function/driver, otherwise, drivers like these would allow root access to any process. However, in case 2 the function call is not bound to a process but rather a driver, so the access rights of the current process are irrelavent, as the driver should only be making the call for internal purposes.
 #8652  by Tigzy
 Tue Sep 20, 2011 1:13 pm
Ok

Here, the only thing coming from UL is my pid
Code: Select all
ClientId.UniqueProcess = (HANDLE)pBufferIn[0]; 
But it's not a pointer, only a value.
How could the OS knows this comes either from UL or Kernel?

--

If this is true, we could say that almost everything comes from userland?
Only the threads created inside the kernel are sure to be interpreted as it should.
 #8653  by r2nwcnydc
 Tue Sep 20, 2011 1:33 pm
In your case the parameters don't matter, which is why I did use NtTerminateProcess in my example. My point was that previous mode can not be set automatically simply because you are calling a function from the kernel. You must specify which mode should be used for your call to a function (which is done for you by the Zw versions), as sometimes you want to act as a pass through for user mode code, and sometimes you want complete access to the system.
 #8654  by Tigzy
 Tue Sep 20, 2011 1:50 pm
ok, thanks.
I will now try to modify that previousmode

EDIT: Well, this is obvious after reading that : http://www.osronline.com/article.cfm?id=257
The NtXxxx version of the native system service is the name of the function itself. Thus, when a Kernel Mode component calls the NtXxxx version of the system service, whatever is presently set into previous mode is unchanged. Thus, it is quite possible that the Kernel component could be running on an arbitrary User stack, with the requestor mode set to User. The system service will not know any better, attempt to validate the request parameters, possibly using the credentials of the arbitrary User Mode thread, and thus possibly fail the request. Another problem here is that one step in the validation process for a User Mode request is that all passed in buffers have either ProbeForRead or ProbeForWrite executed on them, depending on the buffer’s usage. These routines raise exceptions if executed on Kernel Mode addresses. Therefore, if you pass in Kernel Mode buffers with your request mode set to User, your calls into the native API return STATUS_ACCESS_VIOLATION.
 #8657  by Tigzy
 Tue Sep 20, 2011 2:23 pm
I guess I can retrieve the Previous mode offest in the KTHREAD with the ExGetPreviousMode call?

EDIT:

As the first instruction is the same in ExGetPreviousMode and PsGetCurrentThread, I can say eax contains the current KTHREAD
So the previousmode offset might be 140h. Right?
I'm not good at asm programming, How can I retrieve this dynamically ?
nt!ExGetPreviousMode:
8052793a 64a124010000 mov eax,dword ptr fs:[00000124h]
80527940 8a8040010000 mov al,byte ptr [eax+140h]
80527946 c3 ret
80527947 cc int 3
80527948 cc int 3
80527949 cc int 3
8052794a cc int 3
8052794b cc int 3
nt!PsGetCurrentThread:
8052790c 64a124010000 mov eax,dword ptr fs:[00000124h]
80527912 c3 ret
 #8658  by r2nwcnydc
 Tue Sep 20, 2011 2:43 pm
Tigzy wrote:So the previousmode offset might be 140h. Right?
Yes.
Tigzy wrote:How can I retrieve this dynamically ?
You can either do as you are doing, and get the offset from the mov al instruction in ExGetPreviousMode, or you can hardcode the offset (or define the structure) for each OS version.