如何进行混合用户模式/内核模式调试?

byt*_*ptr 10 windbg ida

基本上,我有一个用户模式程序调用kernel32.CreateProcessA(),它在内部调用kernel32.CreateProcessInternalW().在这个函数中,我对ntdll.NtCreateSection()中发生的事情感兴趣,它试图在虚拟内存中映射可执行文件.进入此函数后,程序会快速将内核调用设置为EAX = 0x32并执行SYSENTER指令.

显然,我无法在用户模式调试器中看到超出调用门.我有一点调试内核模式驱动程序的经验,所以我在VMWare窗口中加载了一个XP SP3副本,并使用VirtualKD将管道连接到WinDbg(我碰巧在IDA中运行).连接内核调试器后,我将用户模式EXE程序和PDB复制到虚拟机上,但我对如何在用户模式程序中正确设置初始断点感到茫然.我不想拦截对等效ntdll.ZwCreateSection()的所有调用,我认为这些调用是在调用门的另一端.理想情况下,我想进入用户模式代码并逐步通过该调用门,因为我正在使用内核调试器,但我不知道第一步是什么.

我做了一些谷歌搜索,我已经接近设置一个"ntsd -d"值

HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\myprocess.exe
Run Code Online (Sandbox Code Playgroud)

当我启动进程时,这会导致内核调试器中断,但我似乎无法在.breakin命令之后设置任何断点我需要向IDA发出以进入WinDbg提示符.我一直在关注这个指南,在那里我找到我的进程!进程然后切换到上下文,并重新加载符号,但我在设置我的进程中的断点或超过由"ntsd -d"设置的初始断点时遇到问题.在收到无法解析断点并添加延迟断点的消息之后,如果没有任何意义,我似乎无法在不清除断点的情况下"进入"流程.这是我在初次突破时看起来所处的堆栈:

ChildEBP RetAddr  
b2b55ccc 8060e302 nt!RtlpBreakWithStatusInstruction
b2b55d44 8053d638 nt!NtSystemDebugControl+0x128
b2b55d44 7c90e4f4 nt!KiFastCallEntry+0xf8
0007b270 7c90de3c ntdll!KiFastSystemCallRet
0007b274 6d5f5ca6 ntdll!ZwSystemDebugControl+0xc
0007bd48 6d5f6102 dbgeng!DotCommand+0xd0d
0007de8c 6d5f7077 dbgeng!ProcessCommands+0x318
0007dec4 6d5bec6c dbgeng!ProcessCommandsAndCatch+0x1a
0007eedc 6d5bed4d dbgeng!Execute+0x113
0007ef0c 010052ce dbgeng!DebugClient::Execute+0x63
0007ff3c 010069fb ntsd!MainLoop+0x1ec
0007ff44 01006b31 ntsd!main+0x10e
0007ffc0 7c817067 ntsd!mainCRTStartup+0x125
0007fff0 00000000 kernel32!BaseProcessStart+0x23
Run Code Online (Sandbox Code Playgroud)

说实话,我不确定我的PDB是否正在加载,但我怀疑它可能不是我的直接问题; 我的模块窗格仅显示内核驱动程序模块,而不是用户模式模块.当我过去做过驱动程序调试时,我可以在这个窗格中看到我的驱动程序图像以及符号是否已加载,所以我不确定用户模式图像会发生什么.没有图像,我真的不希望调试器解决任何断点.

我意识到我可能会完全错误,但我没有运气寻找如何进行用户模式/内核模式混合调试.有没有人可以指出我正确的方向,所以我可以从特定的用户模式进程进入这个内核模式功能?或者,至少设置一个适当的内核模式断点,以便仅在我的特定用户模式进程中触发它?

更新:我在调试的操作系统上的用户模式调试器中加载了我的模块(恰好名为runlist.exe)(我碰巧使用了OllyDbg).一旦我在用户模式断点处暂停了SYSENTER的几条指令,我就使用内核调试器暂停了操作系统.然后我设置了流程上下文.WinDbg命令窗口内容如下:

WINDBG>!process 0 0 runlist.exe

PROCESS 820645a8  SessionId: 0  Cid: 01b4    Peb: 7ffd7000  ParentCid: 02b0
    DirBase: 089c02e0  ObjectTable: e1671bb0  HandleCount:   8.
    Image: runlist.exe

WINDBG>.process /i /r /p 820645a8
You need to continue execution (press 'g' <enter>) for the context
to be switched. When the debugger breaks in again, you will be in
the new process context.
WINDBG>g
This command cannot be passed to the WinDbg plugin directly, please use IDA Debugger menu to achieve the same result.
Break instruction exception - code 80000003 (first chance)
WINDBG>.reload /user
Loading User Symbols
....
Caching 'Modules'... ok
WINDBG>lmu
start    end        module name
00400000 00405000   runlist  C (no symbols)           
7c340000 7c396000   MSVCR71    (private pdb symbols)  g:\symcache\msvcr71.pdb\630C79175C1942C099C9BC4ED019C6092\msvcr71.pdb
7c800000 7c8f6000   kernel32   (pdb symbols)          e:\windows\symbols\dll\kernel32.pdb
7c900000 7c9af000   ntdll      (pdb symbols)          e:\windows\symbols\dll\ntdll.pdb
WINDBG>bp 0x7c90d16a
WINDBG>bl
 0 e 7c90d16a     0001 (0001) ntdll!ZwCreateSection+0xa
Run Code Online (Sandbox Code Playgroud)

虽然我无法使用".reload"加载我的进程'符号(PDB在同一目录中 - 可能需要将其复制到我的符号dir),但是我关心的断点是在ntdll,所以我设置它调试器识别为在ntdll.ZwCreateSection()内的地址0x7C90D16A.奇怪的是,在用户模式代码中,这个地址解析为ntdll.NtCreateSection(),但无论哪种方式,断点只有2条指令来自我的用户模式中断.当我恢复机器时,我的目的是"运行"用户模式调试过程,这将触发内核模式断点2指令.内核断点从未被击中,应用程序恢复了这一点.但是我可以在ntdll上设置断点!ZwCreateSection()但是当恢复操作系统时,断点会被其他进程反复命中,导致我无法返回到用户模式调试器,所以我只能在其中"运行"到该位置我自己的过程.

更新 合并@conio提供的提示,以下步骤适合我:

1>附加内核调试器并引导目标操作系统后,暂停操作系统并应用一些配置选项:

!gflag +ksl         //allow sxe to report user-mode module load events under kernel debugger
sxe ld myproc.exe   //cause kernel debugger break upon process load
.sympath+ <path>    //path to HOST machine's user-mode app's symbols
Run Code Online (Sandbox Code Playgroud)

2>运行调试器以恢复目标OS

3>在目标上,运行我们要调试的EXE

4>内核调试器应该中断; 现在输入以下命令切换到usermode上下文:

!process 0 0 myproc.exe                 //get address of EProcess structure (first number on 1st line after "PROCESS")
.process /i /r /p <eprocess*>           //set kernel debugger to process context
g                                       //continue execution to allow the context switch; debugger will break after switch complete
.reload /user                           //reload user symbols
lmu                                     //ensure you have symbols although not really necessary in my particular case
Run Code Online (Sandbox Code Playgroud)

5>既然我已经知道在ntdll.NtCreateSection()的用户模式端发生了什么,我只是继续为该函数的内核模式端设置一个断点,但指定我希望断点只在我的过程的背景.这样,断点不会触发OS范围:

bu /p <eprocess*> nt!NtCreateSection        //set breakpoint in kernel side of function
g                                           //run to break
Run Code Online (Sandbox Code Playgroud)

6>如果一切按计划进行,断点将在NtCreateSection()的内核模式端唤醒调试器.我感谢所有的回复和提示!

con*_*nio 8

有两种方法可以将用户模式调试与内核模式调试结合起来,让您感到困惑和混淆.

您尝试的方法是使用内核模式调试器来调试内核模式代码,使用用户模式调试器(ntsd)来调试用户模式代码,并从内核调试器控制在目标机器上运行的用户模式调试器.这就是要做的-d旗帜ntsd.在" 内核调试器"页面及其MSDN上的子页面中控制用户模式调试器中描述了此方法.

这样做(或多或少)是将ntsd输入和输出重定向到内核​​调试器.模块窗格 - 作为WinDbg中的其余窗口 - 属于内核调试器.您与用户模式调试器的唯一交互是通过内核调试器创建的隧道,您只能通过命令窗口访问它.这在-d标志的文档中有记录:

-d

        将此调试器的控制权传递给内核调试器.如果您正在调试CSRSS,则此控件重定向始终处于活动状态,即使未指定-d也是如此.(在远程调试期间不能使用此选项 - 请改用-ddefer.)有关详细信息,请参阅从内核调试器控制用户模式调试器.此选项不能与-ddefer选项或-noio选项一起使用.

        注意   如果使用WinDbg作为内核调试程序,则WinDbg的许多常见功能在此方案中不可用.例如,您无法使用"本地"窗口,"反汇编"窗口或"调用堆栈"窗口,也无法单步执行源代码.这是因为WinDbg仅充当目标计算机上运行的调试器(NTSD或CDB)的查看器.

第二种方法是使用内核调试器来调试内核模式代码和用户模式代码.没有用户模式调试器.不ntsd.你说你已经按照指南,但实际上你没有.如果你有,那就不会有ntsd.

我建议您使用此方法启动,并在您使用用户模式调试器后,如果您发现需要(例如,因为您想使用用户模式扩展).

为了使内核调试器能够很好地与用户模式模块配合使用,您必须启用启用内核调试器符号 GlobalFlag的加载.使用!gflag +ksl这样做.

一旦你这样做,打破你的进程加载sxe ld:runlist,设置断点(可能与/p选项)并调试你想要的任何东西.

只是做那而不是所有的ntsd混乱.