{"id":7583,"date":"2012-05-18T07:00:00","date_gmt":"2012-05-18T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2012\/05\/18\/how-to-view-the-stack-of-threads-that-were-terminated-as-part-of-process-teardown-from-user-mode\/"},"modified":"2012-05-18T07:00:00","modified_gmt":"2012-05-18T07:00:00","slug":"how-to-view-the-stack-of-threads-that-were-terminated-as-part-of-process-teardown-from-user-mode","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20120518-00\/?p=7583","title":{"rendered":"How to view the stack of threads that were terminated as part of process teardown from user mode"},"content":{"rendered":"<p>\nLast time we saw\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2012\/05\/17\/10306078.aspx\">\nhow to view the stack of threads that were terminated\nas part of process teardown from the kernel debugger<\/a>.\nYou can do the same thing from a user-mode debugger,\nand it&#8217;s actually a bit easier there.\n(The user-mode debugger I&#8217;m using is the one that comes with the\n<a HREF=\"http:\/\/msdn.microsoft.com\/en-us\/windows\/hardware\/gg463009\">\nDebugging Tools for Windows<\/a>,\nthe debugging engine that goes by a number of different front-ends,\nsuch as <code>ntsd<\/code>, <code>cdb<\/code>, and <code>windbg<\/code>.)\n<\/p>\n<p>\nA direct translation of the kernel-mode technique from last\ntime would involve using the\n<code>!vadump<\/code> command and picking through for the\nmemory blocks with candidate size and attributes.\nBut there&#8217;s an easier way.\n<\/p>\n<blockquote CLASS=\"m\"><p>\nNow would be a good point for me to remind you that\nthis information is\n<b>for debugging purposes only<\/b>.\nThe structures and offsets are all implementation details\nwhich can change from release to release.\n<\/p><\/blockquote>\n<p>\nRecall that the TEB begins with some pointers which\nbound the stack, and the seventh pointer is a self-pointer.\nWhat&#8217;s even more useful is the thirteenth pointer\n(offset 0x30 for 32-bit TEBs, offset 0x60 for 64-bit TEBs),\nbecause that is where the\n<a HREF=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ff564670.aspx\">\nPEB<\/a> is stored.\n<\/p>\n<p>\nEach process has a single global PEB, so all the TEBs will have\nthe same PEB value at offset 0x30\/0x60.\nAnd you can figure out the address of the current process&#8217;s\nPEB either by using the !peb command or by simply looking\nat the TEB you already have.\n<\/p>\n<pre>\n0:000&gt; dd fs:30 l1\n0053:00000030  <u>7efde000<\/u>\n<\/pre>\n<p>\nNow you can search through memory looking for that value.\nIf you see any hits at offset 0x30\/0x60, then that&#8217;s a candidate TEB.\n<\/p>\n<p>\nThe debugger normally limits memory scans to 256MB.\n<\/p>\n<pre>\n0:001&gt; s 00000000 L 80000000 00 e0 fd 7e\n                           ^ Range error in 's 00000000 l 80000000 00 e0 fd 7e'\n<\/pre>\n<p>\nTherefore, you have to issue the search eight times (for 32-bit processes)\nto cover the 2GB user-mode address space.\n<\/p>\n<pre>\n0:001&gt; s 00000000 L 10000000 00 e0 fd 7e\n0009e01c  00 e0 fd 7e 00 d0 fd 7e-44 e0 09 00 7b ef 17 77  ...~...~D...{..w\n0009fdc0  00 e0 fd 7e 44 00 00 00-f0 ee 3a 00 10 ef 3a 00  ...~D.....:...:.\n0009fe34  00 e0 fd 7e 78 fe 09 00-02 9f 18 77 00 e0 fd 7e  ...~x......w...~\n0:001&gt; s 10000000 L 10000000 00 e0 fd 7e\n0:001&gt; s 20000000 L 10000000 00 e0 fd 7e\n0:001&gt; s 30000000 L 10000000 00 e0 fd 7e\n0:001&gt; s 40000000 L 10000000 00 e0 fd 7e\n0:001&gt; s 50000000 L 10000000 00 e0 fd 7e\n0:001&gt; s 60000000 L 10000000 00 e0 fd 7e\n0:001&gt; s 70000000 L 10000000 00 e0 fd 7e\n7486af70  00 e0 fd 7e 00 00 00 00-b8 00 16 77 28 00 16 77  ...~.......w(..w\n7efda030  00 e0 fd 7e 00 00 00 00-00 00 00 00 00 00 00 00  ...~............\n7efdd030  00 e0 fd 7e 00 00 00 00-00 00 00 00 00 00 00 00  ...~............\n<\/pre>\n<p>\nAlternatively, you can use the &#8220;length sanity check override&#8221;\nby inserting a question mark after the L:\n<\/p>\n<pre>\n0:001&gt; s 00000000 L?80000000 00 e0 fd 7e\n0009e01c  00 e0 fd 7e 00 d0 fd 7e-44 e0 09 00 7b ef 17 77  ...~...~D...{..w\n0009fdc0  00 e0 fd 7e 44 00 00 00-f0 ee 3a 00 10 ef 3a 00  ...~D.....:...:.\n0009fe34  00 e0 fd 7e 78 fe 09 00-02 9f 18 77 00 e0 fd 7e  ...~x......w...~\n7486af70  00 e0 fd 7e 00 00 00 00-b8 00 16 77 28 00 16 77  ...~.......w(..w\n7efda030  00 e0 fd 7e 00 00 00 00-00 00 00 00 00 00 00 00  ...~............\n7efdd030  00 e0 fd 7e 00 00 00 00-00 00 00 00 00 00 00 00  ...~............\n<\/pre>\n<p>\nFrom the above output, we see that we can quickly reject all but\nthe last two entries because the offset within the page is not\nthe magic value 0x30.\n(This is a 32-bit process.)\nHooray, two debugger commands reduce the search space to just\ntwo pages!\n<\/p>\n<p>\nAt this point, you can continue with the debugging technique from last\ntime, looking at each candidate TEB to see if there&#8217;s a valid stack in there.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Last time we saw how to view the stack of threads that were terminated as part of process teardown from the kernel debugger. You can do the same thing from a user-mode debugger, and it&#8217;s actually a bit easier there. (The user-mode debugger I&#8217;m using is the one that comes with the Debugging Tools for [&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":[26],"class_list":["post-7583","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-other"],"acf":[],"blog_post_summary":"<p>Last time we saw how to view the stack of threads that were terminated as part of process teardown from the kernel debugger. You can do the same thing from a user-mode debugger, and it&#8217;s actually a bit easier there. (The user-mode debugger I&#8217;m using is the one that comes with the Debugging Tools for [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/7583","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=7583"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/7583\/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=7583"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=7583"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=7583"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}