It came up at work the other day, and so I guess it’s worth writing down here. Using a debugger on a process affects the process you are debugging. The target process, of course, can ask whether there is a debugger attached and therefore do different things depending on whether one is present or not. Without using reflection though, it is common for extra threads to come into existence in the target process in order to support the debugger break operation, which is going to affect the target.
[I should add that we are talking about debugging unmanaged code here. Debugging a managed process is achieved by talking to an extra debugging support thread that the CLR creates. This is needed because it isn’t sufficient for the debugger to use only the usual low level modification API to insert breakpoints, as the insertion of a breakpoint needs to synchronise with the code actually being jitted in the first place]
To see what’s going on, start two instances of Windbg and connect the first instance to the second. In the first instance set a breakpoint on DbgUiIssueRemoteBreakin.
Attach the second instance to a running process or open an executable in it. When it is successfully debugging something, press the break button.
The first instance will show that we enter DbgUiRemoteBreakin.
and by disassembling we can see that it is going to create a thread in the target process. From the arguments, the new thread is going to run the DbgUiRemoteBreakin function in ntdll.dll.
Press “g” in the first instance, and the second instance will show that we have broken inside the process that it is debugging. We can see that the “int 3” instruction has been called from the DbgUiRemoteBreakin function in the target process’ ntdll.dll.
Likewise setting a breakpoint on WriteProcessMemory and inserting a breakpoint via the second instance, we can see that the debugger writes to the other process’s memory to add a breakpoint instruction.
The debugger also has a way to register for debugging events in the target process, but that is going to have to wait for another blog post.
In other news this post on ten things about C# seems to have generated some controversy (see the comments). I’m reminded of it because at work on Thursday we had to get around point #9, you can suppress ILDASM by using an attribute. I hasten to say that this attribute is no protection at all – you simply use a hex editor to find the string SuppressIldasm and then modify one of the bytes in the name to some other character. ILDASM will then disassembly it without complaint. So be warned. True obfuscation takes a lot more effort.