Re: 关于驱动调用win32 api的问题,急求解答!!!
Windows内核调试
关于驱动调用win32 api的问题,急求解答!越搞越古怪,请大家关注!
zyq8709
2011-06-14, 16:06 下午
我在应用程序中写了一个函数并将它回调给内核驱动,并让内核驱动调用它,而应用程序中的这个函数又调用一个win32 api。开始我用的是MessageBoxW,运行后没有出现消息框,跟踪调试发现他的视线比较复杂,于是换成了CreateFileW,运行发现并未创建任何文件。但是跟踪时发现,CreateFileW执行时系统及记录他的Previous_Mode为KernelMode,所以关于对UserMode时的参数检查全部忽略,并且跟踪执行过程中并未报错和出现异常,一切都正常执行,但就是没有出现想要的结果。书上都说驱动无论是显式还是隐式都不能调用Ring 3下的api。
请问为何驱动无论是显式还是隐式都不能调用Ring 3下的api,是系统代码中的哪些关键部分导致了api执行失败,参数检查在本例中是不执行的。针对本例,请问系统是如何进行判定而导致API调用失败的呢?
Re: 关于驱动调用win32 api的问题,急求解答!!!
wrong
2011-06-16, 09:47 上午
你前面不是问过这个问题了。而且有人给出答案了。
Re: 关于驱动调用win32 api的问题,急求解答!!!
zyq8709
2011-06-16, 11:03 上午
你没理解我的问题。
代码已经写在上边了,如果在驱动Ring0中回调一个不含API的过程是没有问题的,关键是为何不能回调含有API的过程,发生这一问题的实质原因是什么,导致调用失败的API中的判定代码是哪些,它是如何判定调用非法的呢?我先看过了通过PreviousMode进行参数地址空间越界检查是不会进行的,因为PreviousMode为KernelMode,那么它又是如何判定调用非法而导致失败的呢?
Re: 关于驱动调用win32 api的问题,急求解答!!!
王宇
2011-06-16, 14:00 下午
这设计 让 SysEnter 等情何以堪呐...
Re: 关于驱动调用win32 api的问题,急求解答!!!
zyq8709
2011-06-16, 16:22 下午
是否是sysenter不能在ring0下执行?intel手册上媒体到这一点呀!就算它不行,那用int 2e不也是一样的吗?int指令不是任何级别都可调用吗?
Re: 关于驱动调用win32 api的问题,急求解答!!!
王宇
2011-06-16, 18:51 下午
看你如此认真我就回你一帖。:P
(1) 你的这种想法 ( 设计 ) 不值得推荐,虽然大部分情况下执行不会出错。
(2) “书上都说驱动无论是显式还是隐式都不能调用 Ring 3下的 API” —— 如果这个不能的原因是“不推荐这么使用”,我赞同;如果书上是想表达“这种方法不可行”,那显然是错的。
(3) 论实现,CreateFileW 比什么 MessageBox 复杂的多。当然,我指的是内核部分 Lookup 对象管理器,循环解析路径,IopParseDevice 发 IRP 等。
(4) “是系统代码中的哪些关键部分导致了 API 执行失败” —— cmp esi,dword ptr [nt!MmUserProbeAddress],就这句话让你的“重入企图”跳转到逻辑 nt!KiSystemCallExit2。
对应微软源码:
FPOFRAME ?FpoValue, 0
mov esi, edx ; (esi)->User arguments
mov ebx, [edi]+SdNumber ; get argument table address
xor ecx, ecx
mov cl, byte ptr [ebx+eax] ; (ecx) = argument size
mov edi, [edi]+SdBase ; get service table address
mov ebx, [edi+eax*4] ; (ebx)-> service routine
sub esp, ecx ; allocate space for arguments
shr ecx, 2 ; (ecx) = number of argument DWORDs
mov edi, esp ; (edi)->location to receive 1st arg
cmp esi, _MmUserProbeAddress ; check if user address
jae kss80 ; if ae, then not user address
(5) 针对楼上的帖子,建议强化一些基本功,呵呵。
Re: 关于驱动调用win32 api的问题,急求解答!!!
zyq8709
2011-06-17, 08:56 上午
多谢王老师的详细解答!还得加强基本功呀!
请教一下需要从哪些方面入手来加强基础更有效?
Re: 关于驱动调用win32 api的问题,急求解答!!!
王宇
2011-06-17, 09:50 上午
我觉得调试就是一个很好的方法,比如你的这个问题其实只要一直单步下去就能找到答案。
Re: 关于驱动调用win32 api的问题,急求解答!!!
wrong
2011-06-17, 10:31 上午
这个例子是
用户态--》内核--》Call 用户态过程-->CreateFileW-->再次进入内核-->Check and Exit ...
这样看来, 是不是内核API不可重入?
Re: 关于驱动调用win32 api的问题,急求解答!!!
zyq8709
2011-06-17, 13:53 下午
王老师,我调试的时候又发现了些问题,对照源码:
kss80: test byte ptr [ebp].TsSegCs, MODE_MASK ; test previous mode
jz KiSystemServiceCopyArguments ; if z, previous mode kernel
mov eax, STATUS_ACCESS_VIOLATION ; set service status
jmp kss60
KiSystemServiceCopyArguments:
rep movsd
kssdoit:
call ebx ; call system service
我之前验证过,previous mode为kernel,所以按照流程它还是会跳到下面去执行call ebx来执行内核对应函数,所以他应该是能执行成功的,这到底是为何呢?
Re: 关于驱动调用win32 api的问题,急求解答!!!
zyq8709
2011-06-17, 15:27 下午
汇报一下我的调试结果:
大致是在回调函数中多次调用CreateFileW,并在每个CreateFileW函数上下各写入几个int 3,结果显示只有在回调函数中第一个CreateFileW之上的可以断下,下边所有的断点和剩余的CreateFileW都没被执行。而且我还发现CreateFileW函数并未执行到sysenter,而调用CreateFileW后第一个执行到sysenter后的第一个内核函数为NtContinue,然后该线程被强行终止,并结束运行,附带的结果是内核的驱动映像也被卸载。
我感觉问题应发生在用户空间,因为一旦进入内核,所有的环境包括堆栈位置、previous mode都与从内核正常发起的调用相同,应该不会出问题。而NtContinue的出现是典型的SEH发生了,应该是SEH的发生导致了失败并结束,但是具体引发的原因和位置我还没有找出来,请大家给予指点。
我感觉这个问题虽小,但是真实的原因可能出乎大家意料,请大家关注!
Re: 关于驱动调用win32 api的问题,急求解答!!!
王宇
2011-06-18, 01:08 上午
光读代码有时会忽略一些细节。所以我会借助调试去理解(但我往往也因此被 PJF 同学“鄙视”,呵呵,P神同学崇尚大脑即调试器的最高境界,极力阻止我用 Windbg) 就这个问题而言,你显然没有真正去调试吧?
如果去跟踪,你就会知道,你列出的代码走不到 call ebx:
805417b0 f6456c01 test byte ptr [ebp+6Ch],1
805417b4 0f844efeffff je nt!KiFastCallEntry+0xf8 (80541608) [br=0] << 注意看这里
805417ba b8050000c0 mov eax,0C0000005h
805417bf e948feffff jmp nt!KiFastCallEntry+0xfc (8054160c)
走的是 STATUS_ACCESS_VIOLATION 赋值,并 KiServiceExit。
至于为什么 previous mode 不是 kernel,请自己分析一下~
“我感觉这个问题虽小,但是真实的原因可能出乎大家意料” << 你的调试过程是混乱的,微软的设计很清晰,没有出乎意料
Re: 关于驱动调用win32 api的问题,急求解答!!!
zyq8709
2011-06-18, 07:29 上午
多谢王老师的回答。
我回顾了一下,发现导致我出问题的两个原因:一是我下载的符号表有问题,无法显示ntdll.dll的符号,导致调试困难。二是最重要的原因,我记错了sysenter的入口,把断点下在了KiSystemService处,而非下在KiFastCallEntry,导致我拦截的都是从内核发起的调用,故而他的previous mode都是Kernel mode,导致了我的调试结果错误。但是我拦截的结果是对的,也就是说由于参数跨界导致了异常处理而调用NtContinue然后导致线程终止驱动映像卸载。
还有一个问题是,在KiFastCallEntry中人为制造了一个自陷框架,并用push 1模拟了UserMode,然后通过sysexit返回使cs变为0x1B,从而导致错误。那么如果不用sysenter和sysexit指令,而是用int 0x2e和iret那么就不会人为设置previous mode,而是进入KiSystemService通过cs的值得到kernel mode,并通过堆栈返回cs为0x8,那么这一切是不是就不会出错了,而能够正常执行了?
Re: 关于驱动调用win32 api的问题,急求解答!!!
王宇
2011-06-19, 00:26 上午
而是用int 0x2e和iret那么就不会人为设置previous mode,而是进入KiSystemService通过cs的值得到kernel mode,并通过堆栈返回cs为0x8,那么这一切是不是就不会出错了,而能够正常执行了? << 是的,这一点很有趣。设置 thread 的 previous mode 在这里(NtCreateFile 成功)不那么重要,重要的是 trap frame 里 +0x06c SegCs,如果是 int 0x2e 则栈上的 CS 域会被压成 0x8,这个 selctor 表明了 kernel mode,进而通过校验。
无论是 Windows 2000 平台还是将:
mov eax,25h
mov edx,offset SharedUserData!SystemCallStub (7ffe0300)
call dword ptr [edx]
ret 2Ch
强制 patch 成:
mov eax,25h
lea edx,[esp+4]
int 2Eh
ret 2Ch
nop
都可以达到这个效果。
也就是说由于参数跨界导致了异常处理而调用NtContinue然后导致线程终止驱动映像卸载。 << 没这回事...
并用push 1模拟了UserMode << 这句 push MODE_MASK 只是构造 trap frame
[ 纪念 300 贴 ^_^ ]
keenjoy95 2011年6月19日0:36:54
Re: 关于驱动调用win32 api的问题,急求解答!!!
zyq8709
2011-06-19, 09:05 上午
多谢王老师的回答。
那么说只要不执行sysenter而换成int 0x2e,就不会有调用Ring 3 API失败的结果了?
那么对于老的系统和CPU,那么这一限制将不复存在?