无论如何,这是一个关于 Windows 内部结构的好问题,但我现在对它感兴趣的原因是它已成为我的一个实际问题。在我从事有偿工作的地方是三台计算机,每台计算机都有不同的 Windows 版本甚至不同的调试器,使用这种 IFEO 技巧会导致调试器本身调试,显然陷入了困扰 OP 的同一个循环中。
调试器通常如何避免这种循环?好吧,他们自己没有。Windows 为他们避免了它。
但让我们先看看循环性。PowerShell concoctions 对简单的演示几乎没有帮助,而且 calc.exe 也不再像以前那样了。让我们改为设置to的Debugger
值。Windows 会将此解释为尝试运行应正常运行的意思。CMD 会将此解释为运行和挂起的意思。但是这个执行也会变成,以此类推。任务管理器将很快向您显示数百个 cmd.exe 实例。(好消息是它们都在一个控制台上并且可以一起被杀死。)notepad.exe
c:\windows\system32\cmd.exe /k
notepad.exe
c:\windows\system32\cmd.exe /k notepad.exe
notepad.exe
notepad.exe
c:\windows\system32\cmd.exe /k notepad.exe
OP 的问题是,为什么 CMD 及其/k
(或/c
)用于运行子进程的开关会在 Debugger 值中循环,但例如 WinDbg 不会。
从某种意义上说,答案可以归结为未记录结构中的一位,即在用户模式和内核模式之间为函数PS_CREATE_INFO
交换的. NtCreateUserProcess
这种结构在某些圈子里已经变得相当有名,但他们似乎从来没有说过如何。我认为该结构可以追溯到 Windows Vista,但直到 Windows 8 才从 Microsoft 的公共符号文件中得知,甚至从内核中得知,但从 Internet Explorer 组件 URLMON.DLL 之类的东西中得知。
无论如何,在现代形式的PS_CREATE_INFO
结构中,偏移量 0x08(32 位)或 0x10(64 位)处的 0x04 位控制内核是否检查 Debugger 值。符号文件告诉我们这个位被微软称为IFEOSkipDebugger
. 如果该位被清除并且有一个 Debugger 值,则NtCreateUserProcess
失败。通过该结构的其他反馈PS_CREATE_INFO
告诉KERNELBASE
,对于它的处理CreateProcessInternalW
,有自己的查看 Debugger 值并NtCreateUserProcess
再次调用,但(可能)一些其他可执行文件和命令行。
相反,当设置该位时,内核不关心 Debugger 值并且NtCreateUserProcess
可以成功。该位通常是如何设置的,KERNELBASE
因为调用者不仅要求创建一个进程,而且还特别要求成为新进程的调试器,即已设置DEBUG_PROCESS
或设置DEBUG_ONLY_THIS_PROCESS
进程创建标志。这就是我所说的调试器自己不做任何事情来避免循环的意思。Windows 为他们这样做只是因为他们想要调试可执行文件。
将 Debugger 值视为可执行 X 的图像文件执行选项的一种方法是,该值的存在意味着 X 只能在调试器下执行,并且该值的内容可能会告诉您如何执行此操作。正如黑客早就注意到的那样,内核的程序员早就注意到了,内容不需要指定调试器,并且可以调整值,以便尝试运行 X 而不是运行 Y。较少注意到的是 Y 将无法除非 Y 调试 X(或禁用 Debugger 值),否则运行 X。同样较少注意到的是,并非所有运行 X 的尝试都会运行 Y:调试器尝试将 X 作为被调试对象运行不会被转移。