{"id":27083,"date":"2007-04-27T10:00:00","date_gmt":"2007-04-27T10:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2007\/04\/27\/stupid-debugger-tricks-calling-functions-and-methods\/"},"modified":"2007-04-27T10:00:00","modified_gmt":"2007-04-27T10:00:00","slug":"stupid-debugger-tricks-calling-functions-and-methods","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20070427-00\/?p=27083","title":{"rendered":"Stupid debugger tricks: Calling functions and methods"},"content":{"rendered":"<p>\nBack in the old days, if you wanted to call a function from\ninside the debugger, you had to do it by hand:\nSave the registers, push the parameters onto the stack\n(or into registers if the function uses <code>fastcall<\/code>\nor <code>thiscall<\/code>)\npush the address of the <code>ntdll!DbgBreakPoint<\/code> function,\nmove the instruction pointer to the start of the function you want to call,\nthen hit &#8220;g&#8221; to resume execution.\nThe function runs then returns to the <code>ntdll!DbgBreakPoint<\/code>,\nwhere the debugger regains control and you can look at the results.\nThen restore the registers (including the original instruction pointer)\nand resume debugging.\n(That paragraph was just a quick recap;\nI&#8217;m assuming you already knew that.)\n<\/p>\n<p>\nThe Windows symbolic debugger engine (the debugging engine\nbehind <code>ntsd<\/code>, <code>cdb<\/code> and <code>windbg<\/code>)\ncan now automate this process.\nSuppose you want to call this function:\n<\/p>\n<pre>\nint DoSomething(int i, int j);\n<\/pre>\n<p>\nYou can ask the debugger to do all the heavy lifting:\n<\/p>\n<pre>\n0:001&gt; .call ABC!DoSomething(1,2)\nThread is set up for call, 'g' will execute.\nWARNING: This can have serious side-effects,\nincluding deadlocks and corruption of the debuggee.\n0:001&gt; r\neax=7ffde000 ebx=00000001 ecx=00000001 edx=00000003 esi=00000004 edi=00000005\neip=10250132 esp=00a7ffbc ebp=00a7fff4 iopl=0         nv up ei pl zr na po nc\ncs=001b  ss=0023  ds=0023  es=0023  fs=0038  gs=0000             efl=00000246\nABC!DoSomething:\n10250132 55               push    ebp\n0:001&gt; dd esp\n00a7ffbc  00a7ffc8 <font COLOR=\"blue\">00000001 00000002<\/font> ccfdebcc\n<\/pre>\n<p>\nNotice that the debugger nicely pushed the parameters onto the stack\nand set the <code>eip<\/code> register for you.\nAll you have to do is hit &#8220;g&#8221; and the <code>DoSomething<\/code>\nfunction will run.\nOnce it returns, the debugger will restore the original state.\n<\/p>\n<p>\nThis technique even works with C++ methods:\n<\/p>\n<pre>\n\/\/ pretend that we know that 0x00131320 is an IStream pointer\n0:001&gt; .dvalloc 1000\nAllocated 1000 bytes starting at 00a80000\n0:001&gt; .call ABC!CAlphaStream::Read(0x00131320, 0xa80000, 0x1000, 0)\nThread is set up for call, 'g' will execute.\nWARNING: This can have serious side-effects,\nincluding deadlocks and corruption of the debuggee.\n<\/pre>\n<p>\nNotice that when calling a nonstatic C++ method,\nyou have to pass the &#8220;this&#8221; parameter as an explicit first parameter.\nThe debugger knows what calling convention to use and puts the registers\nin the correct location.\nIn this case, it knew that <code>CAlphaStream::Read<\/code> uses\nthe <code>stdcall<\/code> calling convention, so the parameters have\nall been pushed onto the stack.\n<\/p>\n<p>\nAnd what&#8217;s with that <code>.dvalloc<\/code> command?\nThat&#8217;s another debugger helper function that allocates some memory\nin the debugged process&#8217;s address space.\nHere, we used it to allocate a buffer that we want to read into.\n<\/p>\n<p>\nBut what if you want to call a method on an interface, and you\ndon&#8217;t have the source code to the implementation?\nFor example, you want to read from a stream that was passed to you\nfrom some external component.\nWell, you can play a little trick.\nYou can pretend to call a function that you <strong>do<\/strong>\nhave the source code to, one that has the same function signature,\nand then move the <code>eip<\/code> register to the desired\nentry point.\n<\/p>\n<pre>\n\/\/ pretend that we know that 0x00131320 is an IStream pointer\n0:000&gt;  dp 131320 l1\n00131320  77f6b5e8 <font COLOR=\"blue\">\/\/ vtable<\/font>\n0:000&gt; dps 77f6b5e8 l4\n77f6b5e8  77fbff0e SHLWAPI!CFileStream::QueryInterface\n77f6b5ec  77fb34ed SHLWAPI!CAssocW2k::AddRef\n77f6b5f0  77f6b670 SHLWAPI!CFileStream::Release\n77f6b5f4  77f77474 SHLWAPI!CFileStream::Read\n0:000&gt; .call SHLWAPI!CFileStream::Read(0x00131320, 0xa80000, 0x1000, 0)\n                ^ Symbol not a function in '.call SHLWAPI!CFileStream::Read'\n<\/pre>\n<p>\nThat error message is the debugger&#8217;s somewhat confusing way of saying,\n&#8220;I don&#8217;t have enough information available to make that function call.&#8221;\nBut that&#8217;s okay, because we have a function that&#8217;s &#8220;close enough&#8221;,\nnamely <code>CAlphaStream::Read<\/code>:\n<\/p>\n<pre>\n0:001&gt; .call ABC!CAlphaStream::Read(0x00131320, 0xa80000, 0x1000, 0)\nThread is set up for call, 'g' will execute.\nWARNING: This can have serious side-effects,\nincluding deadlocks and corruption of the debuggee.\n0:000&gt; r eip=SHLWAPI!CFileStream::Read\n0:000&gt; r\neax=00131320 ebx=0007d628 ecx=00130000 edx=0013239e esi=00000000 edi=00000003\neip=77f77474 esp=0007d384 ebp=0007d3b0 iopl=0         nv up ei pl zr na po nc\ncs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246\nSHLWAPI!CFileStream::Read:\n77f77474 8bff             mov     edi,edi\n<\/pre>\n<p>\nWoo-hoo!\nWe got <code>ABC!CAlphaStream::Read<\/code> to push all the parameters\nfor us, and then <strong>whoosh<\/strong> we swap out that function\nand slip <code>CFileStream::Read<\/code> in its place.\nNow you can hit &#8220;g&#8221; to execute the <code>CFileStream::Read<\/code> call.\n<\/p>\n<p>\nThis just skims the surface of what you can do with the\n<code>.call<\/code> command.\nMix in some C++ expression evaluation and you&#8217;ve got yourself\na pretty nifty &#8220;pseudo-immediate mode&#8221; expression evaluator.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Back in the old days, if you wanted to call a function from inside the debugger, you had to do it by hand: Save the registers, push the parameters onto the stack (or into registers if the function uses fastcall or thiscall) push the address of the ntdll!DbgBreakPoint function, move the instruction pointer to the [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-27083","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Back in the old days, if you wanted to call a function from inside the debugger, you had to do it by hand: Save the registers, push the parameters onto the stack (or into registers if the function uses fastcall or thiscall) push the address of the ntdll!DbgBreakPoint function, move the instruction pointer to the [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/27083","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=27083"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/27083\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=27083"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=27083"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=27083"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}