Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / programming / debugging

Self-debugger attach to process

5.00/5 (5 votes)
14 Sep 2011CPOL 29.2K  
Launching the JIT debugger when you want.

When you use SetWindowsHookEx function or are doing API hooking, most times you need to inject (manually or automatically) a DLL into a target process.

Touching some registry entries, you can make some process to be launched always under the control of a debugger but it is not always the desired method specially if you are dealing with system components or when more than one application instance is active.

Also adding __asm int 3; or calling DebugBreak() API do not always raise an exception as one might expect.

And if you are fixing bugs, launching the target application inside another instance of Visual Studio may became a pain if you have to repeat the process many times.

With the following code snippets, you can do a self-attach by calling the jit debugger. For e.g., when some exported function of your library is called.

C++
BOOL AttachCurrentProcessToDebugger()
{
  STARTUPINFO sSi;
  PROCESS_INFORMATION sPi;
  TCHAR szBufW[2560];
  SIZE_T i;
  BOOL b;
  DWORD dwExitCode;

  if (::IsDebuggerPresent() == FALSE) {
    memset(&sSi, 0, sizeof(sSi));
    memset(&sPi, 0, sizeof(sPi));
    szBufW[0] = L'"';
    ::GetSystemDirectoryW(szBufW+1, 2000);
    i = wcslen(szBufW);
    if (i>0 && szBufW[i]!=L'/' && szBufW[i]!=L'\\')
      szBufW[i++] = L'\\';
    swprintf_s(szBufW+i, 2560-i, L"VSJitDebugger.exe\" -p %lu", ::GetCurrentProcessId());
    b = ::CreateProcessW(NULL, szBufW, NULL, NULL, FALSE, 0, NULL, NULL, &sSi, &sPi);
    if (b != FALSE) {
      ::WaitForSingleObject(sPi.hProcess, INFINITE);
      ::GetExitCodeProcess(sPi.hProcess, &dwExitCode);
      if (dwExitCode != 0) //if exit code is zero, a debugger was selected
        b = FALSE;
    }
    if (sPi.hThread != NULL)
      ::CloseHandle(sPi.hThread);
    if (sPi.hProcess != NULL)
      ::CloseHandle(sPi.hProcess);
    if (b == FALSE)
      return FALSE;
    for (i=0; i<5*60; i++) {
      if (::IsDebuggerPresent() != FALSE)
        break;
      ::Sleep(200);
    }
  }
#if defined _M_IX86
  _asm { int 3 };
#elif defined _M_X64
  __debugbreak();
#else
  ::DebugBreak();
#endif
  return TRUE;
}


The code is simple. If the process is not under the control of a debugger, it launches the jit-debugger (usually located in the System folder) and waits for the debugger attachment.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)