基本上,我有一个用户模式程序调用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()的内核模式端唤醒调试器.我感谢所有的回复和提示!
有两种方法可以将用户模式调试与内核模式调试结合起来,让您感到困惑和混淆.
您尝试的方法是使用内核模式调试器来调试内核模式代码,使用用户模式调试器(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混乱.