When you break into a user-mode application in the kernel debugger, how do you connect a user-mode debugger?

If you need to transfer control from one user-mode debugger to another, you can use a non-invasive debugger as a bridge. But what if you are broken into the kernel debugger, and you want to connect a user-mode debugger to the process? Since the system is broken into the kernel debugger, it is completely frozen. How do you unfreeze the system while still letting the crashed app sit in limbo?

What I do is patch in an infinite loop.

Change the bytes at the current instruction to EB FE, which as I noted some time ago is an unconditional short jump instruction, with an offset of −2. Since the jump target is calculated relative to the start of the instruction after the jump instruction, and since short jump instriction is itself two bytes long, jumping backward two bytes means that the jump instruction jumps to itself. In other words, you patched in an infinite loop.

Once that's done, resume execution in the kernel debugger. The system will roar back to life, except for the thread that crashed, which is now sitting and spinning. At this point, you can open a command prompt or whatever and connect the debugger of your choice. When that debugger breaks into the process, go find the thread that originally crashed, either by recognizing the thread by ID, or recognizing the stack, or by simply looking for the thread that is stuck in a tight infinite loop.

At this point, you can patch the original instruction back in and resume your debugging.

Note that this technique freezes only the thread that crashed. When you resume system execution, the threads that didn't crash will continue execution. Therefore, this solution works well if the problem involves only the thread that crashed or other threads which are not running (say, because they are blocked on a synchronization object). if the problem involves a thread that is running (say, because you have a race condition), then allowing those threads to continue execution means that you lose their state when the system resumes.

Exercise: Suppose there is no user-mode debugger installed on the system at all, and you can't install one. What can you do to at least get a user-mode dump of the crashed process, so you can analyze it offline?

Exercise: In the case where the problem involves multiple threads, what can you do to preserve the states of all the threads?

Comments (13)
  1. Ray Koopa says:

    Exercies 2… uhm… I’m not good at these things, but… wouldn’t I just patch EB FE into all the other threads too, having fun if I have 20 threads of which I should write down the original instructions? =3 Please enlighten me…

    1. I feel like it’d be easier to just suspend the process at that point by invoking the necessary function, then let the user-mode debugger handle the threads once it’s attached.

      1. The kernel-mode PsSuspendProcess function? I can’t find very much information about it, but I’m doubtful that it would help with a race condition – I’m not sure that it’s atomic, and even if it is, I’m not sure how you’d call it in such a way as to ensure that it ran before the threads in question had had a chance to.

        1. I was working under the supposition that you’d call it in the kernel debugger prior to switching to the user-mode debugger.

          1. That doesn’t work because the kernel debugger is broken into user mode.

  2. Koro says:

    The answer to exercise #1 is either:
    1. Patch in an invalid instruction, resume, then hope WER left the dump somewhere on the machine or,
    2. Assuming the former did not work, find a code cave somewhere and put in just enough instructions to (optionally) load dbghelp.dll, call MiniDumpWriteDump, and exit, then patch in a jump to that.

  3. ZLB says:

    Exercise 1) Patch in a call to KeBugCheck?

    Exercise 2) Patch in a call to KeBugCheck and then pack up a go home.

    1. Patching in a call to KeBugCheck wouldn’t work because you can’t call it from user-mode code. Besides, it creates a kernel-mode dump, not a user-mode dump.

      1. alegr1 says:

        You can have a full memory dump, if your system is set up for that.

        1. But that’s less than a user-mode dump because it doesn’t capture data from the pagefile (which is not in memory).

          1. I imagine if you had the kernel debugger attached you could use the .pagein to make sure the user mode memory is present in the dump file.

  4. Alois Kraus says:

    Patch in an __int 3 and let the crash handler create a dump of the process fast enough to get all threads of the process in the right states? That should be most of the time enough. Not sure if suspending a thread is easily possible from the kernel debugger.

  5. Benjamin says:

    I feel like this is too obvious to be the right answer, but can’t you just use Task Manager or ProcDump to get a user-mode dump while the problem thread is spinning?

Comments are closed.

Skip to main content