可能是我表达的不够清楚
不过楼上的认识也是有错误的
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.
内核组件是可能运行在任意线程的上下文中的
在Nt*函数中会检查PreviousMode 而 这个PreViousMode从哪里来?
看Nt*函数的代码
PAGE:004990D8 ; NTSTATUS __stdcall NtReadFile(HANDLE FileHandle,HANDLE Event,PIO_APC_ROUTINE ApcRoutine,PVOID ApcContext,PIO_STATUS_BLOCK IoStatusBlock,PVOID Buffer,ULONG Length,PLARGE_INTEGER ByteOffset,PULONG Key)
PAGE:004990D8 push 68h
PAGE:004990DA push offset stru_418748
PAGE:004990DF call __SEH_prolog
PAGE:004990E4 xor esi, esi
PAGE:004990E6 mov [ebp+var_20], esi
PAGE:004990E9 mov [ebp+var_34], esi
PAGE:004990EC mov [ebp+var_70], esi
PAGE:004990EF mov [ebp+var_6C], esi
PAGE:004990F2 mov eax, large fs:124h ;内核态fs指向KPCR
/* ;fs:120为KPRCB
lkd> dt _kprcb
nt!_KPRCB
+0x000 MinorVersion : Uint2B
+0x002 MajorVersion : Uint2B
+0x004 CurrentThread : Ptr32 _KTHREAD ;fs:124
+0x008 NextThread
*/
我已经注释的很清楚了 Nt*会根据这个PreviousMode来判断调是否需要参数检查
而现在的问题就是如果我们调用的是Zw*函数的话 Zw*函数会把PreviousMode设置为KernelMode 然后再调用Nt*函数 因此在Nt*函数中就不会进行参数检查 而如果我们直接调用Nt*函数的话(it is quite possible that the Kernel component could be running on an arbitrary User stack, with the requestor mode set to User) ,我们必须自己将PreviousMode设置为KernelMode,否则PreviousMode很可能仍然是User , 这样的话 Nt*函数就会认为对它的调用来自用户态,从而做一些检查,这时就会产生问题了(不明白的话,再看一篇那段英文)......因此我们要自己调用Nt*的话必须先将PreviousMode设为KernelMode.
谢谢楼上的回复
对我的表达能力深表抱歉!!!!