{"id":614,"date":"2013-12-09T00:12:48","date_gmt":"2013-12-09T00:12:48","guid":{"rendered":"http:\/\/www.gironsec.com\/blog\/?p=614"},"modified":"2013-12-09T00:14:27","modified_gmt":"2013-12-09T00:14:27","slug":"writing-your-own-debugger-windows-in-c","status":"publish","type":"post","link":"https:\/\/www.gironsec.com\/blog\/2013\/12\/writing-your-own-debugger-windows-in-c\/","title":{"rendered":"Writing your own windows debugger in C"},"content":{"rendered":"<p>Hello all!<\/p>\n<p>I&#8217;m cracking away on various projects and trying to keep focus. As I was going through my old notes, I came across a talk I wanted to give but could not due to my car accident and the subsequent down time caused me to forget. I wanted to cover making your own debugger in windows, but I never completed the project. I had dumping, I had a disassembler, etc, but it never panned out. It was more of a learning experience.<\/p>\n<p>None the less, I will share with you all some snippets I was able to piece together. We&#8217;ll go over the basics of &#8220;Break &#038; Enter&#8221;. There are a few steps involved, but its pretty easy. By break and enter, I mean open a process \/ thread and break-point on the current instruction, sort of like how you would do when you attach to a process in Immunity \/ Olly \/ WinDBG \/ IDA. Luckily for me, windows provides the means to do so internally and we need only invoke these functions to do our own low level debugging. Disassebmly and dumping however is not supported internally on windows, so we would have to use a 3rd party library or write our own functionality if we wanted to do this. Debugging on the other hand is easy. Perhaps in the future I&#8217;ll finish my debugger when time is more permissive and I have more interest. <\/p>\n<p>These are the steps:<\/p>\n<p>Step 1 &#8211; get process id &#8211; can be done programatically with win32 snapshots \/ psapi or with task manager<\/p>\n<p>Step 2 &#8211; get handle to said process id &#8211; OpenProcess() win32 api<\/p>\n<p>Step 3 &#8211; getthreadcontenxt and store in structure- Windows api which stores the registers (eax, esi, etc)<\/p>\n<p>Step 4 &#8211; Enable debug privileges and suspend the thread so we can mess with it. <\/p>\n<p>Step 5 &#8211; call the DebugBreakProcess() function which writes an int3 call into the EIP for the process. <\/p>\n<p>Step 6 &#8211; Handle the debug loop. The debug loop is responsible for handling debug events such as single step interrupts, access violations, thread \/ process creation and the like. <\/p>\n<p>The code is below and I&#8217;ve tried my best to comment it and add the appropriate links to MSDN.  <\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;\">\n<pre style=\"margin: 0; line-height: 125%\">DWORD pid <span style=\"color: #333333\">=<\/span> <span style=\"color: #0000DD; font-weight: bold\">2182<\/span>; <span style=\"color: #888888\">\/\/ PID grabbed from task manager<\/span>\r\n\r\nHANDLE myproc <span style=\"color: #333333\">=<\/span> OpenProcess(PROCESS_VM_READ <span style=\"color: #333333\">|<\/span> PROCESS_QUERY_INFORMATION ,TRUE,pid); <span style=\"color: #888888\">\/\/ open it, may have to do debug for the main loop<\/span>\r\n\r\n\r\n<span style=\"color: #333399; font-weight: bold\">void<\/span> <span style=\"color: #0066BB; font-weight: bold\">BreakAndEnter<\/span>(HANDLE proc)\r\n{\r\n    CONTEXT tcx;\r\n    <span style=\"color: #888888\">\/\/ http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/ms679297%28v=vs.85%29.aspx<\/span>\r\n    <span style=\"color: #888888\">\/\/ there are 2 ways to do this<\/span>\r\n    <span style=\"color: #888888\">\/\/ 1) WriteProcessMemory() and pass he int3 opcode to the stack of the currently executing process<\/span>\r\n    <span style=\"color: #888888\">\/\/ 2) DebugBreakProcess() function which does the same thing essentially<\/span>\r\n    <span style=\"color: #888888\">\/\/ but first, you NEED to set the debug privilege<\/span>\r\n    EnableDebugPriv(proc);\r\n    SuspendThread(proc);\r\n    <span style=\"color: #888888\">\/\/ You need to suspend the thread b4 calling getthreadcontext<\/span>\r\n    GetThreadContext(proc,<span style=\"color: #333333\">&amp;<\/span>tcx);\r\n    printf(<span style=\"background-color: #fff0f0\">&quot;Register info for debugged process: <\/span><span style=\"color: #666666; font-weight: bold; background-color: #fff0f0\">\\r\\n<\/span><span style=\"background-color: #fff0f0\">&quot;<\/span>);\r\n    printf(<span style=\"background-color: #fff0f0\">&quot;EAX: %d<\/span><span style=\"color: #666666; font-weight: bold; background-color: #fff0f0\">\\r\\n<\/span><span style=\"background-color: #fff0f0\">&quot;<\/span>,tcx.Eax);\r\n    printf(<span style=\"background-color: #fff0f0\">&quot;EBX: %d<\/span><span style=\"color: #666666; font-weight: bold; background-color: #fff0f0\">\\r\\n<\/span><span style=\"background-color: #fff0f0\">&quot;<\/span>,tcx.Ebx);\r\n    printf(<span style=\"background-color: #fff0f0\">&quot;ECX: %d<\/span><span style=\"color: #666666; font-weight: bold; background-color: #fff0f0\">\\r\\n<\/span><span style=\"background-color: #fff0f0\">&quot;<\/span>,tcx.Ecx);\r\n    printf(<span style=\"background-color: #fff0f0\">&quot;EDX: %d<\/span><span style=\"color: #666666; font-weight: bold; background-color: #fff0f0\">\\r\\n<\/span><span style=\"background-color: #fff0f0\">&quot;<\/span>,tcx.Edx);\r\n    printf(<span style=\"background-color: #fff0f0\">&quot;ESI: %d<\/span><span style=\"color: #666666; font-weight: bold; background-color: #fff0f0\">\\r\\n<\/span><span style=\"background-color: #fff0f0\">&quot;<\/span>,tcx.Esi);\r\n    printf(<span style=\"background-color: #fff0f0\">&quot;ESP: %d<\/span><span style=\"color: #666666; font-weight: bold; background-color: #fff0f0\">\\r\\n<\/span><span style=\"background-color: #fff0f0\">&quot;<\/span>,tcx.Esp);\r\n    printf(<span style=\"background-color: #fff0f0\">&quot;EIP: %d<\/span><span style=\"color: #666666; font-weight: bold; background-color: #fff0f0\">\\r\\n<\/span><span style=\"background-color: #fff0f0\">&quot;<\/span>,tcx.Eip);\r\n    DebugBreakProcess(proc);\r\n    <span style=\"color: #888888\">\/\/ after calling into this, we need to tell our remote thread to continue<\/span>\r\n    ContinueDebugEvent();\r\n    <span style=\"color: #888888\">\/\/ Our debug debug loop will handle any and all exceptions<\/span>\r\n    system(<span style=\"background-color: #fff0f0\">&quot;pause&quot;<\/span>);\r\n    EnterDebugLoop();\r\n    <span style=\"color: #888888\">\/\/Applications should call FlushInstructionCache if they generate or modify code in memory. The CPU cannot detect the change, and may execute the old code it cached.<\/span>\r\n   <span style=\"color: #888888\">\/\/ FlushInstructionCache(proc,baseaddr,sizeofregion);<\/span>\r\n    <span style=\"color: #888888\">\/\/ After all this is called, we can handle our debug events<\/span>\r\n    <span style=\"color: #888888\">\/\/ http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/ms679302%28v=vs.85%29.aspx<\/span>\r\n\r\n\r\n}\r\n\r\nBOOL <span style=\"color: #0066BB; font-weight: bold\">EnableDebugPriv<\/span>(HANDLE proc)\r\n{\r\n\t    HANDLE hToken;\r\n\t    LUID sedebugnameValue;\r\n\t    TOKEN_PRIVILEGES tkp;\r\n\t    <span style=\"color: #888888\">\/\/ pass our opened process handle<\/span>\r\n\t    OpenProcessToken(proc, TOKEN_ADJUST_PRIVILEGES <span style=\"color: #333333\">|<\/span> TOKEN_QUERY, <span style=\"color: #333333\">&amp;<\/span>hToken);\r\n        LookupPrivilegeValue(<span style=\"color: #007020\">NULL<\/span>, SE_DEBUG_NAME, <span style=\"color: #333333\">&amp;<\/span>sedebugnameValue);\r\n\t    tkp.PrivilegeCount <span style=\"color: #333333\">=<\/span> <span style=\"color: #0000DD; font-weight: bold\">1<\/span>;\r\n\t    tkp.Privileges[<span style=\"color: #0000DD; font-weight: bold\">0<\/span>].Luid <span style=\"color: #333333\">=<\/span> sedebugnameValue;\r\n\t    tkp.Privileges[<span style=\"color: #0000DD; font-weight: bold\">0<\/span>].Attributes <span style=\"color: #333333\">=<\/span> SE_PRIVILEGE_ENABLED;\r\n\t    <span style=\"color: #008800; font-weight: bold\">if<\/span>(AdjustTokenPrivileges(hToken, FALSE, <span style=\"color: #333333\">&amp;<\/span>tkp, <span style=\"color: #008800; font-weight: bold\">sizeof<\/span> tkp, <span style=\"color: #007020\">NULL<\/span>, <span style=\"color: #007020\">NULL<\/span>))\r\n\t    {\r\n        CloseHandle(hToken);\r\n\t    <span style=\"color: #008800; font-weight: bold\">return<\/span> TRUE;\r\n\t    }\r\n\t    <span style=\"color: #008800; font-weight: bold\">else<\/span>\r\n\t    {\r\n\t        MessageBox(<span style=\"color: #007020\">NULL<\/span>,<span style=\"background-color: #fff0f0\">&quot;Bro, you gotta be an admin to set privs like this&quot;<\/span>, <span style=\"background-color: #fff0f0\">&quot;Shit&quot;<\/span>, MB_OK);\r\n\t        CloseHandle(hToken);\r\n\t        <span style=\"color: #008800; font-weight: bold\">return<\/span> FALSE;\r\n\t    }\r\n\r\n\r\n}\r\n\r\n<span style=\"color: #333399; font-weight: bold\">void<\/span> <span style=\"color: #0066BB; font-weight: bold\">EnterDebugLoop<\/span>(<span style=\"color: #008800; font-weight: bold\">const<\/span> LPDEBUG_EVENT DebugEv)\r\n{\r\n   DWORD dwContinueStatus <span style=\"color: #333333\">=<\/span> DBG_CONTINUE; <span style=\"color: #888888\">\/\/ exception continuation<\/span>\r\n\r\n   <span style=\"color: #008800; font-weight: bold\">for<\/span>(;;)\r\n   {\r\n   <span style=\"color: #888888\">\/\/ Wait for a debugging event to occur. The second parameter indicates<\/span>\r\n   <span style=\"color: #888888\">\/\/ that the function does not return until a debugging event occurs.<\/span>\r\n\r\n      WaitForDebugEvent(DebugEv, INFINITE);\r\n\r\n   <span style=\"color: #888888\">\/\/ Process the debugging event code.<\/span>\r\n\r\n      <span style=\"color: #008800; font-weight: bold\">switch<\/span> (DebugEv<span style=\"color: #333333\">-&gt;<\/span>dwDebugEventCode)\r\n      {\r\n         <span style=\"color: #008800; font-weight: bold\">case<\/span> EXCEPTION_DEBUG_EVENT:\r\n         <span style=\"color: #888888\">\/\/ Process the exception code. When handling<\/span>\r\n         <span style=\"color: #888888\">\/\/ exceptions, remember to set the continuation<\/span>\r\n         <span style=\"color: #888888\">\/\/ status parameter (dwContinueStatus). This value<\/span>\r\n         <span style=\"color: #888888\">\/\/ is used by the ContinueDebugEvent function.<\/span>\r\n\r\n            <span style=\"color: #008800; font-weight: bold\">switch<\/span>(DebugEv<span style=\"color: #333333\">-&gt;<\/span>u.Exception.ExceptionRecord.ExceptionCode)\r\n            {\r\n               <span style=\"color: #008800; font-weight: bold\">case<\/span> EXCEPTION_ACCESS_VIOLATION:\r\n               <span style=\"color: #888888\">\/\/ First chance: Pass this on to the system.<\/span>\r\n               <span style=\"color: #888888\">\/\/ Last chance: Display an appropriate error.<\/span>\r\n                  <span style=\"color: #008800; font-weight: bold\">break<\/span>;\r\n\r\n               <span style=\"color: #008800; font-weight: bold\">case<\/span> EXCEPTION_BREAKPOINT:\r\n               <span style=\"color: #888888\">\/\/ First chance: Display the current<\/span>\r\n               <span style=\"color: #888888\">\/\/ instruction and register values.<\/span>\r\n                  <span style=\"color: #008800; font-weight: bold\">break<\/span>;\r\n\r\n               <span style=\"color: #008800; font-weight: bold\">case<\/span> EXCEPTION_DATATYPE_MISALIGNMENT:\r\n               <span style=\"color: #888888\">\/\/ First chance: Pass this on to the system.<\/span>\r\n               <span style=\"color: #888888\">\/\/ Last chance: Display an appropriate error.<\/span>\r\n                  <span style=\"color: #008800; font-weight: bold\">break<\/span>;\r\n\r\n               <span style=\"color: #008800; font-weight: bold\">case<\/span> EXCEPTION_SINGLE_STEP:\r\n               <span style=\"color: #888888\">\/\/ First chance: Update the display of the<\/span>\r\n               <span style=\"color: #888888\">\/\/ current instruction and register values.<\/span>\r\n                  <span style=\"color: #008800; font-weight: bold\">break<\/span>;\r\n\r\n               <span style=\"color: #008800; font-weight: bold\">case<\/span> DBG_CONTROL_C:\r\n               <span style=\"color: #888888\">\/\/ First chance: Pass this on to the system.<\/span>\r\n               <span style=\"color: #888888\">\/\/ Last chance: Display an appropriate error.<\/span>\r\n                  <span style=\"color: #008800; font-weight: bold\">break<\/span>;\r\n\r\n               <span style=\"color: #997700; font-weight: bold\">default:<\/span>\r\n               <span style=\"color: #888888\">\/\/ Handle other exceptions.<\/span>\r\n                  <span style=\"color: #008800; font-weight: bold\">break<\/span>;\r\n            }\r\n\r\n            <span style=\"color: #008800; font-weight: bold\">break<\/span>;\r\n\r\n         <span style=\"color: #008800; font-weight: bold\">case<\/span> CREATE_THREAD_DEBUG_EVENT:\r\n         <span style=\"color: #888888\">\/\/ As needed, examine or change the thread&#39;s registers<\/span>\r\n         <span style=\"color: #888888\">\/\/ with the GetThreadContext and SetThreadContext functions;<\/span>\r\n         <span style=\"color: #888888\">\/\/ and suspend and resume thread execution with the<\/span>\r\n         <span style=\"color: #888888\">\/\/ SuspendThread and ResumeThread functions.<\/span>\r\n\r\n            dwContinueStatus <span style=\"color: #333333\">=<\/span> OnCreateThreadDebugEvent(DebugEv);\r\n\r\n            <span style=\"color: #008800; font-weight: bold\">break<\/span>;\r\n\r\n         <span style=\"color: #008800; font-weight: bold\">case<\/span> CREATE_PROCESS_DEBUG_EVENT:\r\n         <span style=\"color: #888888\">\/\/ As needed, examine or change the registers of the<\/span>\r\n         <span style=\"color: #888888\">\/\/ process&#39;s initial thread with the GetThreadContext and<\/span>\r\n         <span style=\"color: #888888\">\/\/ SetThreadContext functions; read from and write to the<\/span>\r\n         <span style=\"color: #888888\">\/\/ process&#39;s virtual memory with the ReadProcessMemory and<\/span>\r\n         <span style=\"color: #888888\">\/\/ WriteProcessMemory functions; and suspend and resume<\/span>\r\n         <span style=\"color: #888888\">\/\/ thread execution with the SuspendThread and ResumeThread<\/span>\r\n         <span style=\"color: #888888\">\/\/ functions. Be sure to close the handle to the process image<\/span>\r\n         <span style=\"color: #888888\">\/\/ file with CloseHandle.<\/span>\r\n\r\n            dwContinueStatus <span style=\"color: #333333\">=<\/span> OnCreateProcessDebugEvent(DebugEv);\r\n            <span style=\"color: #008800; font-weight: bold\">break<\/span>;\r\n\r\n         <span style=\"color: #008800; font-weight: bold\">case<\/span> EXIT_THREAD_DEBUG_EVENT:\r\n         <span style=\"color: #888888\">\/\/ Display the thread&#39;s exit code.<\/span>\r\n\r\n            dwContinueStatus <span style=\"color: #333333\">=<\/span> OnExitThreadDebugEvent(DebugEv);\r\n            <span style=\"color: #008800; font-weight: bold\">break<\/span>;\r\n\r\n         <span style=\"color: #008800; font-weight: bold\">case<\/span> EXIT_PROCESS_DEBUG_EVENT:\r\n         <span style=\"color: #888888\">\/\/ Display the process&#39;s exit code.<\/span>\r\n\r\n            dwContinueStatus <span style=\"color: #333333\">=<\/span> OnExitProcessDebugEvent(DebugEv);\r\n            <span style=\"color: #008800; font-weight: bold\">break<\/span>;\r\n\r\n         <span style=\"color: #008800; font-weight: bold\">case<\/span> LOAD_DLL_DEBUG_EVENT:\r\n         <span style=\"color: #888888\">\/\/ Read the debugging information included in the newly<\/span>\r\n         <span style=\"color: #888888\">\/\/ loaded DLL. Be sure to close the handle to the loaded DLL<\/span>\r\n         <span style=\"color: #888888\">\/\/ with CloseHandle.<\/span>\r\n\r\n         <span style=\"color: #888888\">\/\/   dwContinueStatus = OnLoadDllDebugEvent(DebugEv); busted<\/span>\r\n            <span style=\"color: #008800; font-weight: bold\">break<\/span>;\r\n\r\n         <span style=\"color: #008800; font-weight: bold\">case<\/span> UNLOAD_DLL_DEBUG_EVENT:\r\n         <span style=\"color: #888888\">\/\/ Display a message that the DLL has been unloaded.<\/span>\r\n\r\n<span style=\"color: #888888\">\/\/            dwContinueStatus = OnUnloadDllDebugEvent(DebugEv); busted<\/span>\r\n            <span style=\"color: #008800; font-weight: bold\">break<\/span>;\r\n\r\n         <span style=\"color: #008800; font-weight: bold\">case<\/span> OUTPUT_DEBUG_STRING_EVENT:\r\n         <span style=\"color: #888888\">\/\/ Display the output debugging string. doesnt fucking work<\/span>\r\n\r\n<span style=\"color: #888888\">\/\/            dwContinueStatus = OnOutputDebugStringEvent(DebugEv);<\/span>\r\n            <span style=\"color: #008800; font-weight: bold\">break<\/span>;\r\n\r\n         <span style=\"color: #008800; font-weight: bold\">case<\/span> RIP_EVENT:\r\n<span style=\"color: #888888\">\/\/            dwContinueStatus = OnRipEvent(DebugEv); doesnt fucking work<\/span>\r\n\r\n         <span style=\"color: #888888\">\/\/   http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/ms681675%28v=vs.85%29.aspx<\/span>\r\n          <span style=\"color: #888888\">\/\/  http:\/\/support.microsoft.com\/kb\/121093<\/span>\r\n            <span style=\"color: #008800; font-weight: bold\">break<\/span>;\r\n      }\r\n\r\n   <span style=\"color: #888888\">\/\/ Resume executing the thread that reported the debugging event.<\/span>\r\n\r\n   ContinueDebugEvent(DebugEv<span style=\"color: #333333\">-&gt;<\/span>dwProcessId,DebugEv<span style=\"color: #333333\">-&gt;<\/span>dwThreadId,dwContinueStatus);\r\n   }\r\n}\r\n<\/pre>\n<\/div>\n<p>Happy hacking!<br \/>\n<a href=\"http:\/\/www.gironsec.com\/blog\/wp-content\/uploads\/2013\/12\/k9AnYwF.jpg\"><img decoding=\"async\" loading=\"lazy\" src=\"http:\/\/www.gironsec.com\/blog\/wp-content\/uploads\/2013\/12\/k9AnYwF.jpg\" alt=\"k9AnYwF\" width=\"405\" height=\"720\" class=\"alignnone size-full wp-image-617\" srcset=\"https:\/\/www.gironsec.com\/blog\/wp-content\/uploads\/2013\/12\/k9AnYwF.jpg 405w, https:\/\/www.gironsec.com\/blog\/wp-content\/uploads\/2013\/12\/k9AnYwF-168x300.jpg 168w\" sizes=\"(max-width: 405px) 100vw, 405px\" \/><\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hello all! I&#8217;m cracking away on various projects and trying to keep focus. As I was going through my old notes, I came across a talk I wanted to give but could not due to my car accident and the subsequent down time caused me to forget. I wanted to cover making your own debugger [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[4,7],"tags":[105,74,106,75],"_links":{"self":[{"href":"https:\/\/www.gironsec.com\/blog\/wp-json\/wp\/v2\/posts\/614"}],"collection":[{"href":"https:\/\/www.gironsec.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.gironsec.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.gironsec.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.gironsec.com\/blog\/wp-json\/wp\/v2\/comments?post=614"}],"version-history":[{"count":3,"href":"https:\/\/www.gironsec.com\/blog\/wp-json\/wp\/v2\/posts\/614\/revisions"}],"predecessor-version":[{"id":616,"href":"https:\/\/www.gironsec.com\/blog\/wp-json\/wp\/v2\/posts\/614\/revisions\/616"}],"wp:attachment":[{"href":"https:\/\/www.gironsec.com\/blog\/wp-json\/wp\/v2\/media?parent=614"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.gironsec.com\/blog\/wp-json\/wp\/v2\/categories?post=614"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.gironsec.com\/blog\/wp-json\/wp\/v2\/tags?post=614"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}