<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-947269866336625127</id><updated>2024-10-25T01:09:43.342-07:00</updated><title type='text'>Debug and Beyond</title><subtitle type='html'>A developer&#39;s notes - Debugging</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://debugbeyond.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default'/><link rel='alternate' type='text/html' href='http://debugbeyond.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Alex</name><uri>http://www.blogger.com/profile/14466854366502861778</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>19</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-947269866336625127.post-3179107289563845893</id><published>2013-01-28T14:22:00.000-08:00</published><updated>2013-01-28T14:22:40.476-08:00</updated><title type='text'>File used by another process - how to check</title><content type='html'>During my recent debugging, I got the following error when I try to open a file using System.IO.FileStream. 
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;The process cannot access the file &#39;D:\dev\store.db.file&#39; because it is being used by another process.&lt;/b&gt;
&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;
&lt;/div&gt;
The thing is that it was obvious that no other process used the file at the time. Simplified version of the code looks like this.
&lt;br /&gt;
&lt;pre&gt;public void SynchronizeData()
{
    XDrive dr = new XDrive(token);
    var statusCode = dr.Download(&quot;store.db&quot;);
    if (IsValid(statusCode))
    {
        this.MergeData();
    }

    this.CopyFile();
    //....

    dr.UploadDbFile(&quot;store.db&quot;);
}
&lt;/pre&gt;
I wanted to know which process or which part of my application was using the file. I set breakpoint at the begining of the method and went step by step. While steping over line by line, I ran Process Explorer from &lt;a href=&quot;http://technet.microsoft.com/en-us/sysinternals&quot;&gt;sysinternals&lt;/a&gt; and opened [Process Explorer Search] by using [Find] - [Find handle or DLL] menu (or Ctrl - F as a shortcut). In a search box, I put a filename - store.db.file in my case. &lt;br /&gt;
&lt;br /&gt;


&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfiPi1R2PT80KkwtDoC8qlhpgJl16YB_xKl-PuWroZfsqnOP_MimnfkI2-MBjWVewqBrOCN2axebDfUAcMKa4zexq1wJBI80TRMGpnsjKuxvRNWCArDJ1Ol_vP6esB37ldUx6ydGGHa7cl/s1600/procexp-search.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfiPi1R2PT80KkwtDoC8qlhpgJl16YB_xKl-PuWroZfsqnOP_MimnfkI2-MBjWVewqBrOCN2axebDfUAcMKa4zexq1wJBI80TRMGpnsjKuxvRNWCArDJ1Ol_vP6esB37ldUx6ydGGHa7cl/s1600/procexp-search.png&quot; /&gt;&lt;/a&gt;

&lt;br /&gt;
&lt;br /&gt;
In every step I investigated whether the file was used and it turned out one of my function did not close file handle. In my case, MergeData() method used the file but did not close it. (well, I did not call Dispose() method for SQLite data adapter) 

&lt;br /&gt;
&lt;pre&gt;private void MergeData()
{
    //..... cut ....
    string connStr = &quot;Data Source=store.db.file&quot;;
    using (SQLiteConnection cn = new SQLiteConnection(connStr))
    {
        SQLiteDataAdapter adpt = new SQLiteDataAdapter(sql, cn);
        adpt.MissingSchemaAction = MissingSchemaAction.AddWithKey;
        adpt.Fill(dsDown);
        //adpt.Dispose();
    }            

    //..... cut ....
}
&lt;/pre&gt;
&lt;br /&gt;
So Process Explorer can be useful when trying to figure out which process (or which part of the functions) holds a handle or owns a DLL.
&lt;br /&gt;

By the way, the error message &quot;because it is being used by another process&quot; is kind of misleading since in my case, it was not other process, it was its own process.
</content><link rel='replies' type='application/atom+xml' href='http://debugbeyond.blogspot.com/feeds/3179107289563845893/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://debugbeyond.blogspot.com/2013/01/file-used-by-another-process-how-to.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default/3179107289563845893'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default/3179107289563845893'/><link rel='alternate' type='text/html' href='http://debugbeyond.blogspot.com/2013/01/file-used-by-another-process-how-to.html' title='File used by another process - how to check'/><author><name>Alex</name><uri>http://www.blogger.com/profile/14466854366502861778</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfiPi1R2PT80KkwtDoC8qlhpgJl16YB_xKl-PuWroZfsqnOP_MimnfkI2-MBjWVewqBrOCN2axebDfUAcMKa4zexq1wJBI80TRMGpnsjKuxvRNWCArDJ1Ol_vP6esB37ldUx6ydGGHa7cl/s72-c/procexp-search.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-947269866336625127.post-7467155227837586823</id><published>2012-09-28T16:51:00.001-07:00</published><updated>2012-09-28T16:51:17.950-07:00</updated><title type='text'>.NET Assembly 32bit or 64bit, Signed or Unsigned?</title><content type='html'>Sometimes before starting debugging, we need to know whether the .NET assembly is 32bit or 64bit. One simple way of doing it is to use a .NET tool called CorFlags.EXE.
In order to use it, open [Visual Studio Command Prompt (2010)] and run CorFlags.exe with an assembly filename. This will show some assembly information as you see below.
&lt;br /&gt;

&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiP2YqmnzzLdL1nJWsAbPWCLPP9mEeO5anM5ShDarEGLO-p8fRDi4B9Nr01mKJkQpN4vXxA_kpWAxYNnCbkj9QMsKIg5GdfiJMOjPeN9HYm0yuElrKPybNmBO4egY4EYtYzenjdel5DMYE2/s1600/corflags.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiP2YqmnzzLdL1nJWsAbPWCLPP9mEeO5anM5ShDarEGLO-p8fRDi4B9Nr01mKJkQpN4vXxA_kpWAxYNnCbkj9QMsKIg5GdfiJMOjPeN9HYm0yuElrKPybNmBO4egY4EYtYzenjdel5DMYE2/s1600/corflags.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
To see 32bit, 64bit or any CPU, you check PE and 32BIT lines.

&lt;br /&gt;
&lt;b&gt;&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;PE: PE32 / 32BIT: 1  =  x86
&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;PE: PE32 / 32BIT: 0  =  Any CPU
&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;PE: PE32+/ 32BIT: 0  =  x64
&lt;/b&gt;

&lt;br /&gt;
&lt;br /&gt;
You can also check whether the assembly is signed or not. &lt;b&gt;Signed&lt;/b&gt; at the last line indicates whether it&#39;s signed.
 Signed : 0 in above example means that the assembly is not signed by key and so it&#39;s not the strongly named assembly; cannot be put into the GAC.&lt;br /&gt;
&lt;br /&gt;

CorFlags.EXE tool not only shows assembly information but also can be used to change assembly header. For example, if you want to change 32bit to Any CPU, you can run:
&lt;br /&gt;
&lt;br /&gt;

C&amp;gt; CorFlags  MyApp.exe /32bit-

&lt;br /&gt;
</content><link rel='replies' type='application/atom+xml' href='http://debugbeyond.blogspot.com/feeds/7467155227837586823/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://debugbeyond.blogspot.com/2012/09/net-assembly-32bit-or-64bit-signed-or.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default/7467155227837586823'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default/7467155227837586823'/><link rel='alternate' type='text/html' href='http://debugbeyond.blogspot.com/2012/09/net-assembly-32bit-or-64bit-signed-or.html' title='.NET Assembly 32bit or 64bit, Signed or Unsigned?'/><author><name>Alex</name><uri>http://www.blogger.com/profile/14466854366502861778</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiP2YqmnzzLdL1nJWsAbPWCLPP9mEeO5anM5ShDarEGLO-p8fRDi4B9Nr01mKJkQpN4vXxA_kpWAxYNnCbkj9QMsKIg5GdfiJMOjPeN9HYm0yuElrKPybNmBO4egY4EYtYzenjdel5DMYE2/s72-c/corflags.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-947269866336625127.post-82656906102332551</id><published>2012-01-26T10:51:00.000-08:00</published><updated>2012-01-26T10:51:02.867-08:00</updated><title type='text'>Windbg: The call to LoadLibrary(C:\Windows\Microsoft.NET\Framework\v4.0.30319\sos) failed</title><content type='html'>When debugging managed code application in Windbg, we have to load sos,&amp;nbsp;correct version of SOS. One of occasional error during SOS loading is LoadLibrary failure as shown below.&lt;br /&gt;
&lt;br /&gt;
0:000&amp;gt; &lt;strong&gt;.loadby sos clr&lt;/strong&gt;&lt;br /&gt;
&lt;span style=&quot;color: #cc0000;&quot;&gt;The call to LoadLibrary(C:\Windows\Microsoft.NET\Framework\v4.0.30319\sos) failed, HRESULT 0x80004005&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;Unspecified error&quot;&lt;br /&gt;
Please check your debugger configuration and/or network access.&lt;/span&gt;&lt;br /&gt;
A simlar error (The call to  LoadLibrary(C:\Windows\Microsoft.NET\Framework\v2.0.50727\sos) failed, Win32  error 0n193)&amp;nbsp;can occur for &lt;strong&gt;.loadby sos mscorwks&lt;/strong&gt; command for .NET 2.0 application (or prior to .NET 4.0 application).&lt;br /&gt;
&lt;br /&gt;
To investigate the issue, we can check CLR.dll information since .loadby command loads sos.dll based on the clr.dll location information (or based on mscorwks.dll for prior to .NET 4.0).&lt;br /&gt;
&lt;br /&gt;
0:000&amp;gt; &lt;strong&gt;lmvm clr&lt;/strong&gt;start&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; end&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; module name&lt;br /&gt;
00000000`69180000 00000000`697ee000&amp;nbsp;&amp;nbsp; clr&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (deferred)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Image path: &lt;strong&gt;&lt;span style=&quot;color: #cc0000;&quot;&gt;C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll&lt;/span&gt;&lt;/strong&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Image name: clr.dll&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Timestamp:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Sat Jul 09 02:07:57 2011 (4E181A6D)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; CheckSum:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0067171F&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; ImageSize:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0066E000&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; File version:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4.0.30319.239&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Product version:&amp;nbsp; 4.0.30319.239&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; File flags:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 8 (Mask 3F) Private&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; File OS:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4 Unknown Win32&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; File type:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2.0 Dll&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; File date:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 00000000.00000000&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Translations:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0409.04b0&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; CompanyName:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Microsoft Corporation&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; ProductName:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Microsoft® .NET Framework&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; InternalName:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; clr.dll&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; OriginalFilename: clr.dll&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; ProductVersion:&amp;nbsp;&amp;nbsp; 4.0.30319.239&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; FileVersion:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4.0.30319.239 (RTMGDR.030319-2300)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; PrivateBuild:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; DDBLD234&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; FileDescription:&amp;nbsp; Microsoft .NET Runtime Common Language Runtime - WorkStation&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; LegalCopyright:&amp;nbsp;&amp;nbsp; © Microsoft Corporation.&amp;nbsp; All rights reserved.&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Comments:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Flavor=Retail&lt;br /&gt;
&lt;br /&gt;
The lmvm clr command shows that clr.dll is located in 32bit Framework directory. If the clr.dll is located in Framework64 directory (C:\Windows\Microsoft.NET\Framework64\v4.0.30319\clr.dll), it means clr.dll is loaded from 64bit .NET&amp;nbsp; Framework.&lt;br /&gt;
Since the&amp;nbsp;CLR is loaded from 32bit .NET Framework, SOS.dll will be loaded from 32bit Framework which is why the error message said LoadLibrary(..\Framework\sos).&lt;br /&gt;
&lt;br /&gt;
Now why is&amp;nbsp;LoadLibrary() for 32bit SOS.dll failing, even if the sos.dll is there in the directory? The thing is &lt;strong&gt;SOS does not support cross-platform debugging&lt;/strong&gt;. That is, 64bit debugger can only use 64bit SOS, while 32bit debugger only uses 32bit SOS. So for 32bit .NET application debugging, one has to use 32bit debugger and same goes for 64bit.&lt;br /&gt;
&lt;br /&gt;
So original error occurred when using 64bit Windbg against 32bit .NET application dump.&amp;nbsp;When 32 bit Windbg was used, the problem was gone.</content><link rel='replies' type='application/atom+xml' href='http://debugbeyond.blogspot.com/feeds/82656906102332551/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://debugbeyond.blogspot.com/2012/01/windbg-call-to-loadlibrarycwindowsmicro.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default/82656906102332551'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default/82656906102332551'/><link rel='alternate' type='text/html' href='http://debugbeyond.blogspot.com/2012/01/windbg-call-to-loadlibrarycwindowsmicro.html' title='Windbg: The call to LoadLibrary(C:\Windows\Microsoft.NET\Framework\v4.0.30319\sos) failed'/><author><name>Alex</name><uri>http://www.blogger.com/profile/14466854366502861778</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-947269866336625127.post-6865381405655519683</id><published>2012-01-15T15:37:00.000-08:00</published><updated>2012-01-15T15:37:06.054-08:00</updated><title type='text'>Windbg : Display parameters whenever specific function is called</title><content type='html'>Whenever a specific function is called, we might want to&amp;nbsp;know&amp;nbsp;its parameters information for the function. If a function is called once or twice, simple breakpoint (bp) should work well. But, what if the function is called hundreds of time? There is gotta be smarter way and there is. &lt;br /&gt;
&lt;br /&gt;
bp command can be used with &quot;user defined command.&quot;&amp;nbsp;So everytime the breakpoint is hit,&amp;nbsp;we can run some commands accordingly.&lt;br /&gt;
&lt;br /&gt;
Let&#39;s take an example. Let&#39;s say,&amp;nbsp;whenever LoadLibrary() function is called, we&amp;nbsp;want to display&amp;nbsp;its parameter (which is&amp;nbsp;libraray dll name).&lt;br /&gt;
&lt;br /&gt;
(1) First, we have to set breakpoint on LoadLibrary. Whenevery the library is called, we will do something... LoadLibrary() function is in kernel32.dll. One thing to note is that LoadLibrary is actually win32 macro, so there is no actual library in binary DLL level. It is converted to actual function name (LoadLibraryW or LoadLibraryA) depending on ANSI/Unicode.&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; 0:000&amp;gt; &lt;strong&gt;bp kernel32!LoadLibraryW&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
(2) Now, to do some actions, we add multiple commands separated by semi-colon and have the commands&amp;nbsp;enclosed by double quotations.&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;syntax :&amp;nbsp;&amp;nbsp;&quot;command1; command2; command3&quot;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;br /&gt;
Here is an example of displaying first parameter for&amp;nbsp;LoadLibraray() function.&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;0:000&amp;gt; bp kernel32!LoadLibraryW &lt;strong&gt;&quot;.echo *****;du dwo(esp+4);k;g;&quot;&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;.echo command display any text.&lt;/li&gt;
&lt;li&gt;du command display any Unicode string from the specified address.&lt;/li&gt;
&lt;li&gt;dwo() function returns double word value from the specified address. &lt;/li&gt;
&lt;li&gt;esp is ESP register that contacts current stack pointer.&lt;/li&gt;
&lt;li&gt;k is to show callstack to see who is calling this function. This one is just optional.&lt;/li&gt;
&lt;li&gt;g command make the debugger keep running. &lt;/li&gt;
&lt;/ul&gt;So the command above will keep displaying parameters whenever debugger encounters the specific function.&lt;br /&gt;
&lt;br /&gt;
Let&#39;s look at the stack a little further. Whenever a function is called, that is whenever assembly language&amp;nbsp;&#39;call&#39; command is executed,&amp;nbsp;&#39;return address&#39; is automatically saved after parameters in the stack. When a breakpoint is occurred at the beginning of the function, stack pointer is pointing to &#39;return address.&#39; So the first parameter memory address at the breakpoint time is stackpointer (esp) + 4 bytes location.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;/div&gt;﻿ &lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: left; margin-right: 1em; text-align: left;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiD91_FivkNF9UfADCQTMoyc_hz9l4ULNvxBXXIivF9tBKOFBWLzpF5x_bQAzMvwfyx5jFJ3WS1rHfxF3TGOk1d3bzUgGGRKakcdqpd7XF983vP5BOLkOih7LBZCDb1uijUJdvRJa8qxujo/s1600/stack-function-call.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; kba=&quot;true&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiD91_FivkNF9UfADCQTMoyc_hz9l4ULNvxBXXIivF9tBKOFBWLzpF5x_bQAzMvwfyx5jFJ3WS1rHfxF3TGOk1d3bzUgGGRKakcdqpd7XF983vP5BOLkOih7LBZCDb1uijUJdvRJa8qxujo/s1600/stack-function-call.png&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Stack State when a func is called&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;﻿ &lt;br /&gt;
If looking at the result of&amp;nbsp;kb command (display call stack with 3 params) at the breakpoint, the address in ChildEBP&amp;nbsp;points&amp;nbsp;the &quot;Saved EBP.&quot; even if previous EBP is not saved yet (explained later). RetAddr is the value of 0008eb38+4 memory address. Args to Child are the actual parameter values&amp;nbsp;which are located at 0008eb38+8, 0008eb38+C, 0008eb38+0x10. LoadLibraryW only has one parameter, so actually meaningfyl parameter is first parameter only for this function.&lt;br /&gt;
0:000&amp;gt; kb&lt;br /&gt;
ChildEBP RetAddr&amp;nbsp; Args to Child&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;
&lt;strong&gt;&lt;span style=&quot;color: blue;&quot;&gt;0008eb38 76eacf0e 0008eb48 76f10718 003a0043&lt;/span&gt;&lt;/strong&gt; kernel32!LoadLibraryW&lt;br /&gt;
0008ed54 76eab8b3 0008f4dc 0008f420 00000001 USER32!User32InitializeImmEntryTable+0xffa&lt;br /&gt;
0008f40c 776f9950 76e90000 00000001 0008f714 USER32!UserClientDllInitialize+0x1c6&lt;br /&gt;
0008f42c 776fd8c9 76eab6ed 76e90000 00000001 ntdll!RtlQueryEnvironmentVariable+0x241&lt;br /&gt;
0008f520 7770681c 0008f714 7efdd000 7efde000 ntdll!LdrResSearchResource+0xb4d&lt;br /&gt;
0008f6a0 777052d6 0008f714 776c0000 77efe3a9 ntdll!RtlGetNtVersionNumbers+0x9b&lt;br /&gt;
0008f6f0 776f9e79 0008f714 776c0000 00000000 ntdll!RtlSetUnhandledExceptionFilter+0x50&lt;br /&gt;
0008f700 00000000 0008f714 776c0000 00000000 ntdll!LdrInitializeThunk+0x10&lt;br /&gt;
&lt;br /&gt;
When a function is called, the first thing the function does is to save previous EBP and reset stack pointer (ESP) to EBP. This is done by three assembly instructions as you can see below. When this instructions are done, EBP and ESP point to the same address and all local vairables are pushed on top of the stack.&lt;br /&gt;
0:000&amp;gt; u .&lt;br /&gt;
kernel32!LoadLibraryW:&lt;br /&gt;
75a548fb 8bff&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; edi,edi&lt;br /&gt;
75a548fd 55&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; push&amp;nbsp;&amp;nbsp;&amp;nbsp; ebp&lt;br /&gt;
75a548fe 8bec&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ebp,esp</content><link rel='replies' type='application/atom+xml' href='http://debugbeyond.blogspot.com/feeds/6865381405655519683/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://debugbeyond.blogspot.com/2012/01/windbg-display-parameters-whenever.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default/6865381405655519683'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default/6865381405655519683'/><link rel='alternate' type='text/html' href='http://debugbeyond.blogspot.com/2012/01/windbg-display-parameters-whenever.html' title='Windbg : Display parameters whenever specific function is called'/><author><name>Alex</name><uri>http://www.blogger.com/profile/14466854366502861778</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiD91_FivkNF9UfADCQTMoyc_hz9l4ULNvxBXXIivF9tBKOFBWLzpF5x_bQAzMvwfyx5jFJ3WS1rHfxF3TGOk1d3bzUgGGRKakcdqpd7XF983vP5BOLkOih7LBZCDb1uijUJdvRJa8qxujo/s72-c/stack-function-call.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-947269866336625127.post-1660412034492446236</id><published>2011-11-18T14:05:00.000-08:00</published><updated>2011-11-18T14:05:12.418-08:00</updated><title type='text'>Watson dump analysis with SOS</title><content type='html'>This article explains about Watson dump analysis by using WinDBG.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Why Watson?&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Unlike live debugging, postmortem debugging often can take more time to analyze and sometime not successful if the dump is not right. &lt;br /&gt;
Even worse, Watson dump can take longer than full dump since its content is generally limited.&lt;br /&gt;
However, the value of Watson dump is that it often contains the real crash situation the customers encountered, which normally we never reproduce in the lab.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Setting up debugger (WinDbg)&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
1) First thing we need to do is to setup the debugger -in this article, WinDbg. &lt;br /&gt;
Go to  Microsoft Download Center and install latest &lt;a href=&quot;http://msdn.microsoft.com/en-us/windows/hardware/gg463009&quot;&gt;Debugging Tools for Windows&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
2) Next thing we have to set Symbol server path. There are several ways to set symbol path. I prefer to set symbol path into Windbg base workspace so that all other workspaces inherits the symbol path.&lt;br /&gt;
In order to do that, run windbg.exe (with no args) in elevated cmd prompt and click File-&amp;gt;Symbol File Path. Set path below.&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiCIaUhiy9eSdVXUGX5xWOadG-h3Q8-9adlprbe4lFWdV3OJ2bzBeDMPo_qWTescPfooUObm1BIrrD8zS9Qy2sIu2Vc9z__vkN8YaH0cgNxao2sMw8eA2mardm4qRWO-MsiDaR2aTsVe8o/s1600/Symbol-Path.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;232&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiCIaUhiy9eSdVXUGX5xWOadG-h3Q8-9adlprbe4lFWdV3OJ2bzBeDMPo_qWTescPfooUObm1BIrrD8zS9Qy2sIu2Vc9z__vkN8YaH0cgNxao2sMw8eA2mardm4qRWO-MsiDaR2aTsVe8o/s640/Symbol-Path.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
3) Click File-&amp;gt;Save Workspace.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Opening Watson Dump&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
In order to open Watson dump with WinDbg, I typically use the following  -z command.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;C&amp;gt; windbg  -z  memory.hdmp&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Once it’s open, the following information is shown. It’s basically saying the dump contains limited information,&lt;br /&gt;
the server where dump generated is 4 CPU Win2008 x86, and the cause of crash was stack buffer overflow.&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgejTLzSYbYdL4KgjhWyqHNFjLWXi3KYYR-anTLEoLoMuDOy4A_K0aJbtiNApOI2Gk0rlXmm8MSkfDZKHuL5NrfuWEWq4W0nb34FimnkG_qrAj9eyw0IAoEkeG9b8fCl-OBzU70s2DgC4jJ/s1600/memory-dump.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;385&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgejTLzSYbYdL4KgjhWyqHNFjLWXi3KYYR-anTLEoLoMuDOy4A_K0aJbtiNApOI2Gk0rlXmm8MSkfDZKHuL5NrfuWEWq4W0nb34FimnkG_qrAj9eyw0IAoEkeG9b8fCl-OBzU70s2DgC4jJ/s640/memory-dump.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Using !analyze –v&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Using !analyze –v is usually good start. This command is developed by MS Research.&lt;br /&gt;
I think it generally provides valuable where-to-start information.&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Call stack investigation&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
Management Tools are heavily using C# managed code. In order to look at Managed Call Stack, we have to use SOS debugger extension.&lt;br /&gt;
SOS comes with .NET framework, if you have .NET installed (of course), you don’t have to install anything.&lt;br /&gt;
(There is another my favorite debugger extension is SOSEX, but let’s focus on SOS)&lt;br /&gt;
To load SOS debugger extension,&lt;br /&gt;
&lt;br /&gt;
0:00&amp;gt;  &lt;strong&gt;.loadby SOS mscorworks&lt;/strong&gt;                  (CLR 2.0)&lt;br /&gt;
0:00&amp;gt;  &lt;strong&gt;.loadby SOS clr&lt;/strong&gt;                                    (CLR 4.0)&lt;br /&gt;
&lt;br /&gt;
I prefer to reduce typing. So I copied sos.dll from .NET framework folder (under Windows) to C:\Debuggers so that I simply type:&lt;br /&gt;
&lt;br /&gt;
0:00&amp;gt;&lt;strong&gt;  .load sos&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Since we don’t know where the error occurred from, we generally investigate both Native and Managed Call Stack.&lt;br /&gt;
For Native call stack, my favorite command is kp (or kP) which automatically interprets parameters and source lines. &lt;br /&gt;
Here is an example:&lt;br /&gt;
&lt;br /&gt;
0:00&amp;gt;  &lt;strong&gt;kp&lt;/strong&gt;&lt;br /&gt;
….&lt;br /&gt;
098ef14c 7571898e user32!InternalCallWinProc(void)+0x23 [d:\longhorn\windows\core\ntuser\client\i386\callproc.asm @ 106]&lt;br /&gt;
098ef1c4 75718ab9 user32!UserCallWinProcCheckWow(struct _ACTIVATION_CONTEXT * pActCtx = 0x00000000, &lt;function&gt; * pfn = 0x06fa095a, struct HWND__ * hwnd = 0x0003040e, unsigned int msg = 0x202, unsigned int wParam = 0, long lParam = 0n917517, void * pww = 0x00f038f8, int fEnableLiteHooks = 0n1)+0x109 [d:\longhorn\windows\core\ntuser\client\clmsg.c @ 163]&lt;br /&gt;
098ef228 75718b10 user32!DispatchMessageWorker(struct tagMSG * pmsg = 0x06fa095a, int fAnsi = 0n0)+0x380 [d:\longhorn\windows\core\ntuser\client\clmsg.c @ 2440]&lt;br /&gt;
098ef238 0689510e user32!DispatchMessageW(struct tagMSG * lpMsg = 0x098ef2c4)+0xf [d:\longhorn\windows\core\ntuser\client\cltxt.h @ 971]&lt;br /&gt;
098ef254 6e0b8d2e CLRStub[StubLinkStub]@2b0e2400689510e(&lt;win32 0n318=&quot;&quot; error=&quot;&quot;&gt;)&lt;br /&gt;
098ef308 6e0b8997 System_Windows_Forms_ni!System.Windows.Forms.Application+ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(&lt;hresult 0x80004001=&quot;&quot;&gt;)+0x24e [f:\dd\ndp\fx\src\WinForms\Managed\System\WinForms\Application.cs @ 2106]&lt;br /&gt;
098ef360 6e0b87e1 System_Windows_Forms_ni!System.Windows.Forms.Application+ThreadContext.RunMessageLoopInner(&lt;hresult 0x80004001=&quot;&quot;&gt;)+0x177 [f:\dd\ndp\fx\src\WinForms\Managed\System\WinForms\Application.cs @ 3377]&lt;br /&gt;
098ef390 6e5cde2b System_Windows_Forms_ni!System.Windows.Forms.Application+ThreadContext.RunMessageLoop(&lt;hresult 0x80004001=&quot;&quot;&gt;)+0x61 [f:\dd\ndp\fx\src\WinForms\Managed\System\WinForms\Application.cs @ 3261]&lt;br /&gt;
098ef3a8 6e6025ab System_Windows_Forms_ni!System.Windows.Forms.Application.RunDialog(&lt;hresult 0x80004001=&quot;&quot;&gt;)+0x33 [f:\dd\ndp\fx\src\WinForms\Managed\System\WinForms\Application.cs @ 1488]&lt;br /&gt;
098ef434 6e6027c3 System_Windows_Forms_ni!System.Windows.Forms.Form.ShowDialog(&lt;hresult 0x80004001=&quot;&quot;&gt;)+0x373 [f:\dd\ndp\fx\src\WinForms\Managed\System\WinForms\Form.cs @ 6120]&lt;br /&gt;
098ef468 6f16274a System_Windows_Forms_ni!System.Windows.Forms.Form.ShowDialog(&lt;hresult 0x80004001=&quot;&quot;&gt;)+0x7 [f:\dd\ndp\fx\src\WinForms\Managed\System\WinForms\Form.cs @ 6020]&lt;br /&gt;
098ef468 70116e96 SqlMgmt_ni!Microsoft.SqlServer.Management.SqlMgmt.RunningFormsTable+RunningFormsTableImpl+ThreadStarter.StartThread(&lt;hresult 0x80004001=&quot;&quot;&gt;)+0xb2 [e:\sql10_katmai_t\sql\mpu\ssms\shared\SqlMgmt\src\RunningFormsTable.cs @ 415]&lt;br /&gt;
098ef474 7012031f mscorlib_ni!System.Threading.ThreadHelper.ThreadStart_Context(&lt;hresult 0x80004001=&quot;&quot;&gt;)+0x66 [f:\dd\ndp\clr\src\BCL\System\Threading\Thread.cs @ 61]&lt;br /&gt;
098ef488 70116e14 mscorlib_ni!System.Threading.ExecutionContext.Run(&lt;hresult 0x80004001=&quot;&quot;&gt;)+0x6f [f:\dd\ndp\clr\src\BCL\System\Threading\ExecutionContext.cs @ 359]&lt;br /&gt;
….&lt;br /&gt;
&lt;br /&gt;
To get Managed Call Stack, once we load SOS, use “ClrStack –a”&lt;br /&gt;
&lt;br /&gt;
0:00&amp;gt; &lt;strong&gt;clrstack –a&lt;br /&gt;
&lt;/strong&gt;…&lt;br /&gt;
098ef39c 6e5cde2b System.Windows.Forms.Application.RunDialog(System.Windows.Forms.Form)&lt;br /&gt;
PARAMETERS:&lt;br /&gt;
form = &lt;no data=&quot;&quot;&gt;&lt;br /&gt;
098ef3b0 6e6025ab System.Windows.Forms.Form.ShowDialog(System.Windows.Forms.IWin32Window)&lt;br /&gt;
PARAMETERS:&lt;br /&gt;
this = 0x032cf95c&lt;br /&gt;
owner = &lt;no data=&quot;&quot;&gt;&lt;br /&gt;
LOCALS:&lt;br /&gt;
&lt;no data=&quot;&quot;&gt;&lt;br /&gt;
0x098ef410 = 0x00000000&lt;br /&gt;
0x098ef40c = 0x00000000&lt;br /&gt;
0x098ef3dc = 0x00000000&lt;br /&gt;
&lt;no data=&quot;&quot;&gt;&lt;br /&gt;
&lt;no data=&quot;&quot;&gt;&lt;br /&gt;
&lt;no data=&quot;&quot;&gt;&lt;br /&gt;
&lt;no data=&quot;&quot;&gt;&lt;br /&gt;
&lt;no data=&quot;&quot;&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;no data=&quot;&quot;&gt;&lt;br /&gt;
098ef43c 6e6027c3 System.Windows.Forms.Form.ShowDialog()&lt;br /&gt;
PARAMETERS:&lt;br /&gt;
this = &lt;no data=&quot;&quot;&gt;&lt;br /&gt;
098ef440 6f16274a Microsoft.SqlServer.Management.SqlMgmt.RunningFormsTable+RunningFormsTableImpl+ThreadStarter.StartThread()&lt;br /&gt;
PARAMETERS:&lt;br /&gt;
this = 0x032ce1a0&lt;br /&gt;
LOCALS: &amp;amp;lt;CLR reg&amp;amp;gt;&lt;br /&gt;
&lt;clr reg=&quot;&quot;&gt; = &lt;span style=&quot;color: red;&quot;&gt;0x032cf95c&lt;/span&gt;         0x098ef444 = 0x00000001&lt;br /&gt;
&lt;no data=&quot;&quot;&gt;&lt;br /&gt;
&lt;no data=&quot;&quot;&gt;&lt;br /&gt;
098ef470 70116e96 System.Threading.ThreadHelper.ThreadStart_Context(System.Object)&lt;br /&gt;
PARAMETERS:&lt;br /&gt;
state = &lt;no data=&quot;&quot;&gt;&lt;br /&gt;
LOCALS:&lt;br /&gt;
&lt;no data=&quot;&quot;&gt;&lt;br /&gt;
…&lt;br /&gt;
&lt;br /&gt;
Sometimes, we need to dig into local variables or parameters by using command such as dumpobj, dumpvc, dumparray.&lt;br /&gt;
Say for example, we can investigate 0x032cf95c by using !dumpobj (!do for short).&lt;br /&gt;
Now we know that MaintenancePlanWizardForm was launched from SSMS.&lt;br /&gt;
&lt;br /&gt;
0:009&amp;gt; &lt;strong&gt;!do 0x032cf95c&lt;/strong&gt;&lt;br /&gt;
Name: Microsoft.SqlServer.Management.MaintenancePlanWizard.MaintenancePlanWizardForm&lt;br /&gt;
MethodTable: 66438a04&lt;br /&gt;
EEClass: 6639483c&lt;br /&gt;
Size: 568(0x238) bytes&lt;br /&gt;
(E:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\VSShell\Common7\IDE\Microsoft.SqlServer.Management.MaintenancePlanWizard.dll)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
098ee844 6e09f435 System.Windows.Forms.ButtonBase.OnPaint(System.Windows.Forms.PaintEventArgs)&lt;br /&gt;
PARAMETERS:&lt;br /&gt;
this = 0x033bbb8c&lt;br /&gt;
pevent = 0x035ef130&lt;br /&gt;
&lt;br /&gt;
0:009&amp;gt; &lt;strong&gt;!do 0x033bbb8c&lt;/strong&gt;&lt;br /&gt;
Name: System.Windows.Forms.RadioButton&lt;br /&gt;
MethodTable: 6e0f6478&lt;br /&gt;
EEClass: 6debc0d0&lt;br /&gt;
Size: 168(0xa8) bytes&lt;br /&gt;
(C:\Windows\assembly\GAC_MSIL\System.Windows.Forms\2.0.0.0__b77a5c561934e089\System.Windows.Forms.dll)&lt;br /&gt;
Fields:&lt;br /&gt;
MT    Field   Offset                 Type VT     Attr    Value Name&lt;br /&gt;
70170b54  4001130       20        System.String  0 instance &lt;strong&gt;033bc774&lt;/strong&gt; text&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
0:009&amp;gt; !do 033bc774 &lt;br /&gt;
Name: System.String&lt;br /&gt;
MethodTable: 70170b54&lt;br /&gt;
EEClass: 6ff2d65c&lt;br /&gt;
Size: 138(0x8a) bytes&lt;br /&gt;
(C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)&lt;br /&gt;
String: All &amp;amp;user databases  (excluding master, model, msdb, tempdb)&lt;br /&gt;
&lt;br /&gt;
In order for SOS help, you can simply type &lt;strong&gt;!sos.help&lt;/strong&gt; in windbg or visit &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/bb190764.aspx&quot;&gt;http://msdn.microsoft.com/en-us/library/bb190764.aspx&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;/no&gt;&lt;/no&gt;&lt;/no&gt;&lt;/no&gt;&lt;/clr&gt;&lt;/no&gt;&lt;/no&gt;&lt;/no&gt;&lt;/no&gt;&lt;/no&gt;&lt;/no&gt;&lt;/no&gt;&lt;/no&gt;&lt;/no&gt;&lt;/no&gt;&lt;/hresult&gt;&lt;/hresult&gt;&lt;/hresult&gt;&lt;/hresult&gt;&lt;/hresult&gt;&lt;/hresult&gt;&lt;/hresult&gt;&lt;/hresult&gt;&lt;/hresult&gt;&lt;/win32&gt;&lt;/function&gt;</content><link rel='replies' type='application/atom+xml' href='http://debugbeyond.blogspot.com/feeds/1660412034492446236/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://debugbeyond.blogspot.com/2011/11/watson-dump-analysis-with-sos.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default/1660412034492446236'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default/1660412034492446236'/><link rel='alternate' type='text/html' href='http://debugbeyond.blogspot.com/2011/11/watson-dump-analysis-with-sos.html' title='Watson dump analysis with SOS'/><author><name>Alex</name><uri>http://www.blogger.com/profile/14466854366502861778</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiCIaUhiy9eSdVXUGX5xWOadG-h3Q8-9adlprbe4lFWdV3OJ2bzBeDMPo_qWTescPfooUObm1BIrrD8zS9Qy2sIu2Vc9z__vkN8YaH0cgNxao2sMw8eA2mardm4qRWO-MsiDaR2aTsVe8o/s72-c/Symbol-Path.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-947269866336625127.post-9116626935661891943</id><published>2011-10-12T17:35:00.000-07:00</published><updated>2011-10-12T17:35:59.913-07:00</updated><title type='text'>How to call other function manually in Debugger</title><content type='html'>Is it possible to call another function manually in the middle of the debugging? If we manipulate stack and jump to the function properly, it is doable. Here I am taking an example of calling a Win32 function in DebugBreak state. We are going to call RtlAdjustPrivilege() function which is in NTDLL.DLL from WinDBG here. We use x86 debugging here. (64 bit debugging is different; more information can be found at &lt;a href=&quot;http://debugbeyond.blogspot.com/2010/06/64bit-calling-convention.html&quot;&gt;64 bit calling convention&lt;/a&gt;)&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;In this example, I launched mspaint.exe from windbg.&lt;br /&gt;
&lt;br /&gt;
C&amp;gt; windbg mspaint.exe&lt;br /&gt;
&lt;br /&gt;
In the middle of the debugging, let&#39;s say&amp;nbsp;I want to adjust one of privileges for the mspaint process. &lt;br /&gt;
To check current privileges status, !token command can be used.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;0:008&amp;gt; !token -n
Thread is not impersonating. Using process token...
TS Session ID: 0x1
Privs: 
 00 0x000000005 SeIncreaseQuotaPrivilege          Attributes - 
 ......
 11 0x000000013 SeShutdownPrivilege               Attributes - 
 12 0x000000014 SeDebugPrivilege                  Attributes - Enabled 
 13 0x000000016 SeSystemEnvironmentPrivilege      Attributes - 
 14 0x000000017 SeChangeNotifyPrivilege           Attributes - Enabled Default 
 15 0x000000018 SeRemoteShutdownPrivilege         Attributes - 
 16 0x000000019 SeUndockPrivilege                 Attributes - 
 17 0x00000001c SeManageVolumePrivilege           Attributes - 
 18 0x00000001d SeImpersonatePrivilege            Attributes - Enabled Default 
 19 0x00000001e SeCreateGlobalPrivilege           Attributes - Enabled Default 
Auth ID: 0:4d37b
Impersonation Level: Anonymous
TokenType: Primary
Is restricted token: no.
&lt;/pre&gt;&lt;br /&gt;
Here, let&#39;s try to enable SeUndockPrivilege (0x19). To check current registers, r command is used. It is DbgBreak state at this point. &lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;0:008&amp;gt; r
eax=7ffd6000 ebx=00000000 ecx=00000000 edx=77add23d esi=00000000 edi=00000000
eip=77a73540 esp=026ef9ec ebp=026efa18 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
ntdll!DbgBreakPoint:
77a73540 cc              int     3
&lt;/pre&gt;&lt;br /&gt;
Now in order to call RtlAdjustPrivilege() function in NTDLL.DLL, we first manipulate thread stack manually.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt; NTSTATUS RtlAdjustPrivilege
 (
  ULONG    Privilege,
  BOOLEAN  Enable,
  BOOLEAN  CurrentThread,
  PBOOLEAN Enabled
 )
&lt;/pre&gt;&lt;br /&gt;
Since RtlAdjustPrivilege() API has 4 parameters, 4 parameter values should be pushed into the stack from 4th parameter to 1st parameter (due to calling convention). ESP points to current stack location. 4th parameter is located at ESP-8 (since 4th parameter is output pointer type, it is pointing to another memory address; in this case, ESP-4 memory address), 3rd parameter is at ESP-C, and so on. Once 4 parameters are added into stack, return address should be added. Since we want to return back to current point, the example sets ESP-18 to . (which means current address).&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;0:008&amp;gt; ed esp-4 0
0:008&amp;gt; ed esp-8 @esp-4
0:008&amp;gt; ed esp-c 0
0:008&amp;gt; ed esp-10 1
0:008&amp;gt; ed esp-14 19
0:008&amp;gt; ed esp-18 .
0:008&amp;gt; resp=@esp-18
0:008&amp;gt; r $ip=ntdll!RtlAdjustPrivilege
&lt;/pre&gt;&lt;br /&gt;
Now I set stack pointer (esp) to ESP-18 and set instruction pointer to ntdll!RtlAdjustPrivilege function. So all registers are set to go. Since current execution pointer is set to ntdll!RtlAdjustPrivilege, if we use &#39;uf .&#39; command, WinDBG will show the whole RtlAdjustPrivilege function in assembly language.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;0:008&amp;gt; uf .
ntdll!RtlAdjustPrivilege+0x9d:
77a45414 8b45e8          mov     eax,dword ptr [ebp-18h]
77a45417 d1e8            shr     eax,1
77a45419 2401            and     al,1
77a4541b e9b45a0000      jmp     ntdll!RtlAdjustPrivilege+0xa4 (77a4aed4)
.....
&lt;/pre&gt;&lt;br /&gt;
Now, to execute the RtlAdjustPrivilege function, run &#39;gu&#39; command. gu command runs until the current function is complete.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;0:008&amp;gt; gu
(16a0.ec0): Break instruction exception - code 80000003 (first chance)
eax=00000000 ebx=00000000 ecx=5ef2406b edx=77a864f4 esi=00000000 edi=00000000
eip=77a73540 esp=026ef9e8 ebp=026efa18 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
ntdll!DbgBreakPoint:
77a73540 cc              int     3

0:008&amp;gt; r esp=@esp+4
0:008&amp;gt; r
eax=00000000 ebx=00000000 ecx=5ef2406b edx=77a864f4 esi=00000000 edi=00000000
eip=77a73540 esp=026ef9ec ebp=026efa18 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
ntdll!DbgBreakPoint:
77a73540 cc              int     3
&lt;/pre&gt;&lt;br /&gt;
Once the function is successfully run, we can check new privilege list by using !token command again. But how do we know the run is successful? Return value (NTSTATUS for the function) can be checked by looking at EAX register. Since it is 0, we can figure out that the function execution was successful.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;0:008&amp;gt; !token -n
Thread is not impersonating. Using process token...
TS Session ID: 0x1
......
Privs: 
 00 0x000000005 SeIncreaseQuotaPrivilege          Attributes - 
 .......
 12 0x000000014 SeDebugPrivilege                  Attributes - Enabled 
 13 0x000000016 SeSystemEnvironmentPrivilege      Attributes - 
 14 0x000000017 SeChangeNotifyPrivilege           Attributes - Enabled Default 
 15 0x000000018 SeRemoteShutdownPrivilege         Attributes - 
 16 0x000000019 SeUndockPrivilege                 Attributes - Enabled 
 17 0x00000001c SeManageVolumePrivilege           Attributes - 
 18 0x00000001d SeImpersonatePrivilege            Attributes - Enabled Default 
 19 0x00000001e SeCreateGlobalPrivilege           Attributes - Enabled Default 
&lt;/pre&gt;&lt;br /&gt;
As you can see, SeUndockPrivilege is now enabled...&lt;br /&gt;
&lt;br /&gt;
NOTE: setting SeUndockPrivilege might not be useful in real world, but enabling some other privileges such as TCB privilege or DEBUG privilege in the debugger might be useful in some situations.</content><link rel='replies' type='application/atom+xml' href='http://debugbeyond.blogspot.com/feeds/9116626935661891943/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://debugbeyond.blogspot.com/2011/10/how-to-call-other-function-manually-in.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default/9116626935661891943'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default/9116626935661891943'/><link rel='alternate' type='text/html' href='http://debugbeyond.blogspot.com/2011/10/how-to-call-other-function-manually-in.html' title='How to call other function manually in Debugger'/><author><name>Alex</name><uri>http://www.blogger.com/profile/14466854366502861778</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-947269866336625127.post-4060349046037769573</id><published>2011-09-22T21:07:00.000-07:00</published><updated>2011-09-22T21:07:32.737-07:00</updated><title type='text'>ba (Break on Access) in WinDbg</title><content type='html'>There was an&amp;nbsp;Access Violation case during test run. It turned out that one private member, which is supposed to be accessed only from application init routine and exit routine, was overwritten by unknown thread / function.&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Break on memory access command - ba command - is very useful for this kind of case. ba allows us to see who is touching the variable. To simplify the case and demonstrate it easily, I will use notepad.exe in WinDBG.&lt;br /&gt;
&lt;br /&gt;
1) Run notepad.exe from WinDBG&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp; C&amp;gt; Windbg&amp;nbsp; notepad.exe&lt;br /&gt;
&lt;br /&gt;
2) Run notepad.exe until you see UI by typing &quot;g&quot;&lt;br /&gt;
3) Pause notepad process in windbg&lt;br /&gt;
4) In Windbg, check any global variable of notepad process&lt;br /&gt;
&lt;pre&gt;0:000&amp;gt; x notepad!g_*
00000000`ff6f0050 notepad!g_fFontSettingChanged = &lt;no information=&quot;&quot; type=&quot;&quot;&gt;
00000000`ff6f0b28 notepad!g_fUISettingChanged = &lt;no information=&quot;&quot; type=&quot;&quot;&gt;
00000000`ff6f0200 notepad!g_PageSetupDlg = &lt;no information=&quot;&quot; type=&quot;&quot;&gt;
00000000`ff6f1e70 notepad!g_lExisting = &lt;no information=&quot;&quot; type=&quot;&quot;&gt;
00000000`ff6f2720 notepad!g_ftSaveAs = &lt;no information=&quot;&quot; type=&quot;&quot;&gt;
00000000`ff6f0b2c notepad!g_fPageSetupChanges = &lt;no information=&quot;&quot; type=&quot;&quot;&gt;
00000000`ff6f0100 notepad!g_wpOrig = &lt;no information=&quot;&quot; type=&quot;&quot;&gt;
00000000`ff6f0088 notepad!g_ftOpenedAs = &lt;no information=&quot;&quot; type=&quot;&quot;&gt;
&lt;/pre&gt;&lt;br /&gt;
Here let&#39;s pick a variable (notepad!g_ftOpenedAs).&lt;br /&gt;
&lt;br /&gt;
5) Set breakpoint with ba command. &lt;br /&gt;
&lt;pre&gt;0:001&amp;gt; ba w4 notepad!g_ftOpenedAs &quot;.echo ******; ~. ; kp; g;&quot;
&lt;/pre&gt;&lt;br /&gt;
ba command will break into debugger when the specified memory is accessed by any thread / any function. w4 means the debugger will break into if any method is writing to the specificed memory area. second parameter notepad!g_ftOpenedAs is the memory location to watch. And the last parameter is the command that will run when break occurs. If no command is specified, it will break into the debugger and wait at prompt. The command is (1)first print six asterisks, (2) show current thread (~.), (3) show current thread call stack (kp), (4) keep running without break into debugger (g).&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgG5PLAcm9YVLTYfnlWZBHGDDgHrZcQTs7EKe66RsOSl-WLEoTjL2zmMUY2TVdY-zvzNm5zXMaeqSs3Y89NyZBavqpRWKssvVflQ_KILciaabDWc15AebgtO8-NJIbiuL1MO9LPBhwM-bGx/s1600/ba-example.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; cssfloat: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; hca=&quot;true&quot; height=&quot;412&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgG5PLAcm9YVLTYfnlWZBHGDDgHrZcQTs7EKe66RsOSl-WLEoTjL2zmMUY2TVdY-zvzNm5zXMaeqSs3Y89NyZBavqpRWKssvVflQ_KILciaabDWc15AebgtO8-NJIbiuL1MO9LPBhwM-bGx/s640/ba-example.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
6) Run notepad process again (&quot;g&quot;)&lt;br /&gt;
&lt;br /&gt;
7) In notepad UI, click File-&amp;gt;Open. In Open File Dialog, click Cancel.&lt;br /&gt;
This is to let a thread to write a value to global variable.&lt;br /&gt;
&lt;br /&gt;
8) Now, you can see who is touching notepad!g_ftOpenedAs variable by look at the call stack output.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;******
.  0  Id: 1290.dbc Suspend: 1 Teb: 000007ff`fffdd000 Unfrozen
      Start: notepad!WinMainCRTStartup (00000000`ff6e3570) 
      Priority: 0  Priority class: 32  Affinity: f
Child-SP          RetAddr           Call Site
00000000`0019f7b0 00000000`ff6e14eb notepad!NPCommand+0x3fa
00000000`0019f8e0 00000000`77b8c3c1 notepad!NPWndProc+0x540
00000000`0019f920 00000000`77b8c60a USER32!UserCallWinProcCheckWow+0x1ad
00000000`0019f9e0 00000000`ff6e10bc USER32!DispatchMessageWorker+0x3b5
00000000`0019fa60 00000000`ff6e133c notepad!WinMain+0x16f
00000000`0019fae0 00000000`77a6f56d notepad!DisplayNonGenuineDlgWorker+0x2da
00000000`0019fba0 00000000`77ca2cc1 kernel32!BaseThreadInitThunk+0xd
00000000`0019fbd0 00000000`00000000 ntdll!RtlUserThreadStart+0x1d
&lt;/pre&gt;&lt;br /&gt;
If you&#39;re in live debug mode, you can simply break into the debugger to look into suspicious thread.</content><link rel='replies' type='application/atom+xml' href='http://debugbeyond.blogspot.com/feeds/4060349046037769573/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://debugbeyond.blogspot.com/2011/09/ba-break-on-access-in-windbg.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default/4060349046037769573'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default/4060349046037769573'/><link rel='alternate' type='text/html' href='http://debugbeyond.blogspot.com/2011/09/ba-break-on-access-in-windbg.html' title='ba (Break on Access) in WinDbg'/><author><name>Alex</name><uri>http://www.blogger.com/profile/14466854366502861778</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgG5PLAcm9YVLTYfnlWZBHGDDgHrZcQTs7EKe66RsOSl-WLEoTjL2zmMUY2TVdY-zvzNm5zXMaeqSs3Y89NyZBavqpRWKssvVflQ_KILciaabDWc15AebgtO8-NJIbiuL1MO9LPBhwM-bGx/s72-c/ba-example.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-947269866336625127.post-7187862520020684409</id><published>2011-09-20T20:28:00.000-07:00</published><updated>2011-09-20T20:28:32.267-07:00</updated><title type='text'>How to use UMDH</title><content type='html'>UMDH (User Mode Dump Heap) tool&amp;nbsp; in &#39;Debugging Tools for Windows&#39;&amp;nbsp; analyze Windows heap memory and useful for detecting native memory leak.&lt;br /&gt;
&lt;br /&gt;
Here is brief summary of how to use it.&lt;br /&gt;
&lt;br /&gt;
(a) Run gflags.exe.&amp;nbsp;Select [Image File], type filename&amp;nbsp;and check [Create user mode stack trace database].&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; This enables data collection for the specifc process.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHRyxcujWAC3pCsvSyEYb1sSmshtkXhxNOk1RieJKVK17ep6ah1gYPjqiMyb_Ld7rCaMRLSkWjAbkURDb6JmuE0-WnjC4GuDajfF1ggnZr39G-HnqatEG_SVa1Hqpr5qI_bLqdUjbhP27g/s1600/gflags.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;393&quot; rba=&quot;true&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHRyxcujWAC3pCsvSyEYb1sSmshtkXhxNOk1RieJKVK17ep6ah1gYPjqiMyb_Ld7rCaMRLSkWjAbkURDb6JmuE0-WnjC4GuDajfF1ggnZr39G-HnqatEG_SVa1Hqpr5qI_bLqdUjbhP27g/s400/gflags.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Alternatively the&amp;nbsp;command line below can be run:&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; C&amp;gt; gflags -i notepad.exe +ust&lt;br /&gt;
&lt;br /&gt;
(b)&amp;nbsp;Set symbol path.&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;C&amp;gt;&amp;nbsp; SET _NT_SYMBOL_PATH=c:\symbols&lt;br /&gt;
&lt;br /&gt;
(c) Run UMDH.EXE&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Take first snapshot of memory and run your application until memory leak.&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Taks second snapshot and compare two snapshots and get the difference.&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; C&amp;gt;umdh -p:2868 &amp;gt; firstsnap.txt&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;== take first snapshot&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; C&amp;gt;umdh -p:2868 &amp;gt; secondsnap.txt&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;== take&amp;nbsp;2nd snapshot&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; C&amp;gt;umdh firstsnap.txt secondsnap.txt &amp;gt; diff.txt&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;== create diff file&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; C&amp;gt;notepad.exe diff.txt&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;== check the result</content><link rel='replies' type='application/atom+xml' href='http://debugbeyond.blogspot.com/feeds/7187862520020684409/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://debugbeyond.blogspot.com/2011/09/how-to-use-umdh.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default/7187862520020684409'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default/7187862520020684409'/><link rel='alternate' type='text/html' href='http://debugbeyond.blogspot.com/2011/09/how-to-use-umdh.html' title='How to use UMDH'/><author><name>Alex</name><uri>http://www.blogger.com/profile/14466854366502861778</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHRyxcujWAC3pCsvSyEYb1sSmshtkXhxNOk1RieJKVK17ep6ah1gYPjqiMyb_Ld7rCaMRLSkWjAbkURDb6JmuE0-WnjC4GuDajfF1ggnZr39G-HnqatEG_SVa1Hqpr5qI_bLqdUjbhP27g/s72-c/gflags.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-947269866336625127.post-4864261394537618756</id><published>2011-08-15T15:57:00.000-07:00</published><updated>2011-08-15T15:57:14.558-07:00</updated><title type='text'>Windbg - Set break on DLL load</title><content type='html'>When an application crashes when certain DLL is loaded, we normally see the callstack in Windbg at the point of second chance exception. If the application catches the exception internally, the things can get difficult to track down. In this case, we probably want to set break on DLL load to see if which code is accessing the DLL functions. &lt;br /&gt;
&lt;br /&gt;
Here are simple steps:&lt;br /&gt;
&lt;br /&gt;
1) Run the application under Windbg &lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; C&amp;gt; &lt;strong&gt;Windbg MyApp.exe&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
2) In Windbg, run below commands. The command sxe sets exception enabled.&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; 0:000&amp;gt; &lt;strong&gt;sxe ld:suspect.dll&lt;/strong&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; 0:000&amp;gt; &lt;strong&gt;g&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
3) When&amp;nbsp;the application&amp;nbsp;hits the DLL,&amp;nbsp;the application will stop and you can&amp;nbsp;check callstack as below:&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp; 0:004&amp;gt; &lt;strong&gt;kp&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
The result of k command (which is callstack) can provide some clues of what&#39;s going on.&lt;br /&gt;
&lt;br /&gt;
</content><link rel='replies' type='application/atom+xml' href='http://debugbeyond.blogspot.com/feeds/4864261394537618756/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://debugbeyond.blogspot.com/2011/08/windbg-set-break-on-dll-load.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default/4864261394537618756'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default/4864261394537618756'/><link rel='alternate' type='text/html' href='http://debugbeyond.blogspot.com/2011/08/windbg-set-break-on-dll-load.html' title='Windbg - Set break on DLL load'/><author><name>Alex</name><uri>http://www.blogger.com/profile/14466854366502861778</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-947269866336625127.post-3840920543708748907</id><published>2011-01-17T16:48:00.000-08:00</published><updated>2011-08-17T17:07:02.223-07:00</updated><title type='text'>How to set Microsoft Symbol Server</title><content type='html'>When it comes to debugging, symbol files are essential. Whenever you build an application in VS, build system normally generates symbols files (.pdb files)&amp;nbsp;togather regardless of Release or Debug build configuration. So you have symbols files for your own application. But then how can get symbol files for OS. For Windows OS, Microsoft provides public symbol server.&lt;br /&gt;
&lt;br /&gt;
To set the symbol server on your debuggeer,&amp;nbsp;simply set the following&amp;nbsp;symbol server path:&lt;br /&gt;
&lt;strong&gt;&lt;a href=&quot;http://msdl.microsoft.com/download/symbols&quot;&gt;http://msdl.microsoft.com/download/symbols&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For example in WinDbg, &lt;br /&gt;
&lt;br /&gt;
(1) You can set it in command mode:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;indent&quot;&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; .sympath SRV*C:\Symbols*http://msdl.microsoft.com/download/symbols&lt;/b&gt;&lt;/div&gt;&lt;div class=&quot;indent&quot;&gt;&lt;strong&gt;&lt;/strong&gt;&amp;nbsp;&lt;/div&gt;&lt;div class=&quot;indent&quot;&gt;(2) Or set the symbol path in File menu.&amp;nbsp;Select File-&amp;gt; Symbol File Path... and type the path as follows:&lt;/div&gt;&lt;div class=&quot;indent&quot;&gt;&amp;nbsp;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixO-QX_n-VFnOzNPQaFZTZKFLJFbCJRmeX41UEJqF3Cj98-bwWojuFdRiOFY590v2RB0WYRJmC3EicLkJm0oRA4wD8kgV5vRzUGgy0qAmu9tlPrqSq5i4sMvZI0Q6ORYITyyshtIzX6dJm/s1600/Symbol-Path.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; naa=&quot;true&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixO-QX_n-VFnOzNPQaFZTZKFLJFbCJRmeX41UEJqF3Cj98-bwWojuFdRiOFY590v2RB0WYRJmC3EicLkJm0oRA4wD8kgV5vRzUGgy0qAmu9tlPrqSq5i4sMvZI0Q6ORYITyyshtIzX6dJm/s1600/Symbol-Path.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;indent&quot;&gt;&amp;nbsp;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://debugbeyond.blogspot.com/feeds/3840920543708748907/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://debugbeyond.blogspot.com/2011/01/how-to-set-microsoft-symbol-server.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default/3840920543708748907'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default/3840920543708748907'/><link rel='alternate' type='text/html' href='http://debugbeyond.blogspot.com/2011/01/how-to-set-microsoft-symbol-server.html' title='How to set Microsoft Symbol Server'/><author><name>Alex</name><uri>http://www.blogger.com/profile/14466854366502861778</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixO-QX_n-VFnOzNPQaFZTZKFLJFbCJRmeX41UEJqF3Cj98-bwWojuFdRiOFY590v2RB0WYRJmC3EicLkJm0oRA4wD8kgV5vRzUGgy0qAmu9tlPrqSq5i4sMvZI0Q6ORYITyyshtIzX6dJm/s72-c/Symbol-Path.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-947269866336625127.post-4811745396312114088</id><published>2010-10-11T21:02:00.000-07:00</published><updated>2011-10-11T21:22:24.479-07:00</updated><title type='text'>How to debug VBScript (.vbs)</title><content type='html'>In order to debug .vbs file, you can specify &quot;//D //X&quot; options in script host. Both Windows-based script host (wscript.exe)&amp;nbsp;and Command-based script host (cscript.exe) supports the same options. When //D //X options are specified, Visual Studio debugger will be launched and start debugging for the VB script. wscript displays output in Window form such as message box while cscript displays output into the console.&lt;br /&gt;
&lt;div style=&quot;clear: both;&quot;&gt;&lt;/div&gt;&lt;br /&gt;
This command invokes VS debugger for test.vbs script file.&lt;br /&gt;
&lt;br /&gt;
C:\Temp&amp;gt;wscript //D //X test.vbs&lt;br /&gt;
or&lt;br /&gt;
C:\Temp&amp;gt;cscript &amp;nbsp;//D //X test.vbs&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-o1JQuXZWENaJlGKi7UMstrqoTm7IzU1rwGnJMPaue0Hg1AG7uLyTSk0QPB2ied-4prw0U0PKMizZU9S-JNySaFBH5RDSQr8ShUrK7FRYxawN26Ne3Bff0x_dtF3uPTe7j3VQXcfgRHcH/s1600/cscript-debugging.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; cssfloat: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;524&quot; kca=&quot;true&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-o1JQuXZWENaJlGKi7UMstrqoTm7IzU1rwGnJMPaue0Hg1AG7uLyTSk0QPB2ied-4prw0U0PKMizZU9S-JNySaFBH5RDSQr8ShUrK7FRYxawN26Ne3Bff0x_dtF3uPTe7j3VQXcfgRHcH/s640/cscript-debugging.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
[F10] key executes the VB script line by line.</content><link rel='replies' type='application/atom+xml' href='http://debugbeyond.blogspot.com/feeds/4811745396312114088/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://debugbeyond.blogspot.com/2010/10/how-to-debug-vbscript-vbs.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default/4811745396312114088'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default/4811745396312114088'/><link rel='alternate' type='text/html' href='http://debugbeyond.blogspot.com/2010/10/how-to-debug-vbscript-vbs.html' title='How to debug VBScript (.vbs)'/><author><name>Alex</name><uri>http://www.blogger.com/profile/14466854366502861778</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-o1JQuXZWENaJlGKi7UMstrqoTm7IzU1rwGnJMPaue0Hg1AG7uLyTSk0QPB2ied-4prw0U0PKMizZU9S-JNySaFBH5RDSQr8ShUrK7FRYxawN26Ne3Bff0x_dtF3uPTe7j3VQXcfgRHcH/s72-c/cscript-debugging.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-947269866336625127.post-882168056255363706</id><published>2010-10-10T11:15:00.000-07:00</published><updated>2011-08-02T11:17:25.724-07:00</updated><title type='text'>Brute force object search using C++ vtable</title><content type='html'>In C++, object layout in memory depends on compiler and there is no strict standard layout, unfortunately. But, we can look into some details by using the debugger.&lt;br /&gt;
&lt;br /&gt;
Assuming we use VC++, let&#39;s take some examples. Two classes are defined as below. Each class has one data member and Dog class inherits from Animal class. What is the object layout for Dog class? In windbg, we can find the object layout by using dt command (dt &amp;lt;classname&amp;gt;). As you can see below, the Dog object has 2 string objects in its object layout. Data members in base class comes first and then data members in derived class comes after, all in the same order (of data fields) as defined in the class.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;class Animal
{
public:
       Animal() {}  
protected:
       string name;
};

class Dog : public Animal
{
public:
       Dog() {}
protected:
       string petOwner;
};

0:000:x86&amp;gt; &lt;span style=&quot;color: red;&quot;&gt;dt Dog&lt;/span&gt;
MyTest!Dog
   +0x000 name             : std::basic_string&amp;lt;char,std::char_traits&amp;lt;char&amp;gt;,std::allocator&amp;lt;char&amp;gt; &amp;gt;
   +0x020 petOwner         : std::basic_string&amp;lt;char,std::char_traits&amp;lt;char&amp;gt;,std::allocator&amp;lt;char&amp;gt; &amp;gt;

That one is easy. What if we have virtual function?
Does it affect object layout? Let&#39;s see another example.
The below example has 2 virtual function in base class and overrode by subclass.

#include &amp;lt;iostream&amp;gt;
#include &amp;lt;string&amp;gt;
using namespace std;
class Animal
{
public:
       Animal() { name = &quot;Animal&quot;; }    
       virtual void DisplayInfo()
       {
              cout &amp;lt;&amp;lt; name &amp;lt;&amp;lt; endl;
       }
       virtual void Run() {}
protected:
       string name;
};

class Dog : public Animal
{
public:
       Dog() { name = &quot;Dog&quot;; petOwner = &quot;N/A&quot;; }
       void DisplayInfo()
       {
              cout &amp;lt;&amp;lt; name &amp;lt;&amp;lt; &quot;:&quot; &amp;lt;&amp;lt; petOwner &amp;lt;&amp;lt; endl;
       }
       void Run()
       {
              cout &amp;lt;&amp;lt; &quot;Run&quot; &amp;lt;&amp;lt; endl;
       }
protected:
       string petOwner;
};

int _tmain(int argc, _TCHAR* argv[])
{
       Dog* pDog = new Dog();
       Dog* pDog2 = new Dog();

       Animal* pA = pDog; // &amp;lt;== breakpoint
       pA-&amp;gt;DisplayInfo();
       pA = pDog2;
       pA-&amp;gt;Run();

       return 0;
}

If we check the Dog object layout, we can see there is 4 byte vtable pointer
in the first position.

0:000:x86&amp;gt; dt Dog
MyTest!Dog
&lt;span style=&quot;color: red;&quot;&gt;   +0x000 __VFN_table : Ptr32 &lt;/span&gt;
   +0x004 name             : std::basic_string&amp;lt;char,std::char_traits&amp;lt;char&amp;gt;,std::allocator&amp;lt;char&amp;gt; &amp;gt;
   +0x024 petOwner         : std::basic_string&amp;lt;char,std::char_traits&amp;lt;char&amp;gt;,std::allocator&amp;lt;char&amp;gt; &amp;gt;

Now to investigate a little more, I set a breakpoint in main().
When the debugger broke into the breakpoint, two Dog object can be found using dv command.
This is easiest way of finding Dog object in the current process. 

0:000:x86&amp;gt; dv /i
prv param             argc = 0n1
prv param             argv = 0x00585170
prv local               pA = 0xcccccccc
prv local            pDog2 = 0x00585288
prv local             pDog = 0x00589f78

But what if the application is very complex and we&#39;re in the middle of nowhere
but want to find all Dog objects in memory? Well, one way we can try is to search vtable
in the whole memory. Since vtable comes first in the object layout, we can look for it in memory
and find a clue for object instance. It is brute force search but sometimes can be useful.

So in order to do that, first, we find vftable by examining (x command) Dog class.

0:000:x86&amp;gt; x MyTest!Dog::*
012729b0          MyTest!Dog::Dog (void)
01271a90          MyTest!Dog::DisplayInfo (void)
012720a0          MyTest!Dog::Run (void)
01271d50          MyTest!Dog::~Dog = &amp;lt;no type information&amp;gt;
01279680          MyTest!Dog::&#39;RTTI Base Class Array&#39; = &amp;lt;no type information&amp;gt;
01279670          MyTest!Dog::&#39;RTTI Class Hierarchy Descriptor&#39; = &amp;lt;no type information&amp;gt;
01279658          MyTest!Dog::&#39;RTTI Complete Object Locator&#39; = &amp;lt;no type information&amp;gt;
&lt;span style=&quot;color: red;&quot;&gt;01278854          MyTest!Dog::&#39;vftable&#39; = &amp;lt;no type information&amp;gt;&lt;/span&gt;
01279690          MyTest!Dog::&#39;RTTI Base Class Descriptor at (0,-1,0,64)&#39; = &amp;lt;no type information&amp;gt;

Then search (s command) the memory space for the vtable value.

0:000:x86&amp;gt; s -d 0 L?0xffffffff 01278854
00585288  01278854 00585308 00676f44 cd006c61  T.&#39;..SX.Dog.al..
00589f78  01278854 005851f8 00676f44 cd006c61  T.&#39;..QX.Dog.al..

Above result shows 2 Dog objects found. Now we can examine the Dog objects
by using dt command. The second dt /b command shows the content of name field in Dog object.

0:000:x86&amp;gt; dt 00585288 Dog
MyTest!Dog
   +0x000 __VFN_table : 0x01278854
   +0x004 name             : std::basic_string&amp;lt;char,std::char_traits&amp;lt;char&amp;gt;,std::allocator&amp;lt;char&amp;gt; &amp;gt;
   +0x024 petOwner         : std::basic_string&amp;lt;char,std::char_traits&amp;lt;char&amp;gt;,std::allocator&amp;lt;char&amp;gt; &amp;gt;

0:000:x86&amp;gt; dt /b 00585288+4 std::basic_string&amp;lt;char,std::char_traits&amp;lt;char&amp;gt;,std::allocator&amp;lt;char&amp;gt; &amp;gt;
MyTest!std::basic_string&amp;lt;char,std::char_traits&amp;lt;char&amp;gt;,std::allocator&amp;lt;char&amp;gt; &amp;gt;
   +0x000 _Myproxy         : 0x00585308
   +0x004 _Bx              : std::_String_val&amp;lt;char,std::allocator&amp;lt;char&amp;gt; &amp;gt;::_Bxty
&lt;span style=&quot;color: red;&quot;&gt;      +0x000 _Buf             :  &quot;Dog&quot;&lt;/span&gt;
       [00] 68 &#39;D&#39;
       [01] 111 &#39;o&#39;
       [02] 103 &#39;g&#39;
       [03] 0 &#39;&#39;
       [04] 97 &#39;a&#39;
       [05] 108 &#39;l&#39;
       [06] 0 &#39;&#39;
       [07] -51 &#39;&#39;
       [08] -51 &#39;&#39;
       [09] -51 &#39;&#39;
       [10] -51 &#39;&#39;
       [11] -51 &#39;&#39;
       [12] -51 &#39;&#39;
       [13] -51 &#39;&#39;
       [14] -51 &#39;&#39;
       [15] -51 &#39;&#39;
      +0x000 _Ptr             : 0x00676f44  &quot;--- memory read error at address 0x00676f44 ---&quot;
      +0x000 _Alias           :  &quot;Dog&quot;
       [00] 68 &#39;D&#39;
       [01] 111 &#39;o&#39;
       [02] 103 &#39;g&#39;
       [03] 0 &#39;&#39;
       [04] 97 &#39;a&#39;
       [05] 108 &#39;l&#39;
       [06] 0 &#39;&#39;
       [07] -51 &#39;&#39;
       [08] -51 &#39;&#39;
       [09] -51 &#39;&#39;
       [10] -51 &#39;&#39;
       [11] -51 &#39;&#39;
       [12] -51 &#39;&#39;
       [13] -51 &#39;&#39;
       [14] -51 &#39;&#39;
       [15] -51 &#39;&#39;
   +0x014 _Mysize          : 3
   +0x018 _Myres           : 0xf
   +0x01c _Alval           : std::allocator&amp;lt;char&amp;gt;
   =012788f4 npos             : 0xffffffff

 &lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://debugbeyond.blogspot.com/feeds/882168056255363706/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://debugbeyond.blogspot.com/2010/10/brute-force-object-search-using-c.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default/882168056255363706'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default/882168056255363706'/><link rel='alternate' type='text/html' href='http://debugbeyond.blogspot.com/2010/10/brute-force-object-search-using-c.html' title='Brute force object search using C++ vtable'/><author><name>Alex</name><uri>http://www.blogger.com/profile/14466854366502861778</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-947269866336625127.post-3509568082369864324</id><published>2010-09-22T11:18:00.000-07:00</published><updated>2011-08-02T11:19:03.094-07:00</updated><title type='text'>SeDebugPrivilege and Integrity Level</title><content type='html'>&lt;strong&gt;Windows&lt;/strong&gt; Integrity mechanism was introduced in Vista/Win 2008. With this feature, operating system assigns so-called integrity level to process or thread. There are 5 integrity levels - Untrusted level  (0x0000), Low integrity level (0x1000), Medium integrity level (0x2000), High integrity level (0x3000), System integrity level (0x4000). An interesting point is any process or thread with lower integrity level cannot access higher integrity level process or thread.&lt;br /&gt;
&lt;br /&gt;
When an administrator runs an appliication with normal mode, its integrity level is Medium. If an administrator runs the application in elevated mode, its integrity level becomes High integrity level. Then can the elevated application access any process having System integrity level? The anwser is no. The attempt to access system integrity level process or thread will return Access Denied exception.&lt;br /&gt;
&lt;br /&gt;
So if we cannot access any System integrity level process even if the current user is administrator, how can we solve this problem? We know there are various user scenarios that need to access system process.&lt;br /&gt;
&lt;br /&gt;
There is a way. If SeDebugPrivilege is set in elevated process, the process/thread can access System integrity level process or thread. The below code shows one way of enabling (or disabling) SeDebugPrivilege in the access token.&lt;br /&gt;
&lt;br /&gt;
BOOL EnableDebugPrivilege(BOOL bEnable)   &lt;br /&gt;
{&lt;br /&gt;
    HANDLE hToken = NULL;&lt;br /&gt;
&lt;br /&gt;
    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &amp;amp;hToken)) &lt;br /&gt;
        return FALSE;   &lt;br /&gt;
&lt;br /&gt;
    LUID luid;&lt;br /&gt;
    if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &amp;amp;luid ))&lt;br /&gt;
        return FALSE;&lt;br /&gt;
&lt;br /&gt;
    TOKEN_PRIVILEGES tokenPriv;&lt;br /&gt;
    tokenPriv.PrivilegeCount = 1;&lt;br /&gt;
    tokenPriv.Privileges[0].Luid = luid;&lt;br /&gt;
    tokenPriv.Privileges[0].Attributes = bEnable ? SE_PRIVILEGE_ENABLED : 0;&lt;br /&gt;
&lt;br /&gt;
    if (!AdjustTokenPrivileges(hToken, FALSE, &amp;amp;tokenPriv, sizeof(TOKEN_PRIVILEGES), NULL, NULL))&lt;br /&gt;
       return FALSE; &lt;br /&gt;
&lt;br /&gt;
    return TRUE;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Once the code is executed, we can check the SeDebugPrivilege&lt;br /&gt;
by running !token in the debugger.&lt;br /&gt;
&lt;br /&gt;
0:011&amp;gt; !token –n&lt;br /&gt;
Privs:&lt;br /&gt;
 00 0x000000005 SeIncreaseQuotaPrivilege          Attributes -&lt;br /&gt;
 01 0x000000007 SeTcbPrivilege                    Attributes -&lt;br /&gt;
 02 0x000000008 SeSecurityPrivilege               Attributes -&lt;br /&gt;
 03 0x000000009 SeTakeOwnershipPrivilege          Attributes -&lt;br /&gt;
 04 0x00000000a SeLoadDriverPrivilege             Attributes -&lt;br /&gt;
 05 0x00000000b SeSystemProfilePrivilege          Attributes -&lt;br /&gt;
 06 0x00000000c SeSystemtimePrivilege             Attributes -&lt;br /&gt;
 07 0x00000000d SeProfileSingleProcessPrivilege   Attributes -&lt;br /&gt;
 08 0x00000000e SeIncreaseBasePriorityPrivilege   Attributes -&lt;br /&gt;
 09 0x00000000f SeCreatePagefilePrivilege         Attributes -&lt;br /&gt;
 10 0x000000011 SeBackupPrivilege                 Attributes -&lt;br /&gt;
 11 0x000000012 SeRestorePrivilege                Attributes -&lt;br /&gt;
 12 0x000000013 SeShutdownPrivilege               Attributes -&lt;br /&gt;
&lt;span style=&quot;color:#000000;&quot;&gt;&lt;strong&gt; 13 0x000000014 SeDebugPrivilege                  Attributes - Enabled&lt;/strong&gt; &lt;/span&gt;&lt;br /&gt;
 14 0x000000016 SeSystemEnvironmentPrivilege      Attributes -&lt;br /&gt;
 15 0x000000017 SeChangeNotifyPrivilege           Attributes - Enabled Default&lt;br /&gt;
 16 0x000000018 SeRemoteShutdownPrivilege         Attributes -&lt;br /&gt;
 17 0x000000019 SeUndockPrivilege                 Attributes -&lt;br /&gt;
 18 0x00000001c SeManageVolumePrivilege           Attributes -&lt;br /&gt;
 19 0x00000001d SeImpersonatePrivilege            Attributes - Enabled Default&lt;br /&gt;
 20 0x00000001e SeCreateGlobalPrivilege           Attributes - Enabled Default&lt;br /&gt;
 21 0x000000021 SeIncreaseWorkingSetPrivilege     Attributes -&lt;br /&gt;
 22 0x000000022 SeTimeZonePrivilege               Attributes -&lt;br /&gt;
 23 0x000000023 SeCreateSymbolicLinkPrivilege     Attributes -&lt;br /&gt;
&lt;br /&gt;
Auth ID: 0:19c236&lt;br /&gt;
Impersonation Level: Impersonation&lt;br /&gt;
TokenType: Impersonation&lt;br /&gt;
Is restricted token: no.&lt;br /&gt;
&lt;br /&gt;
One more thing. If a process sets debug privilege and calls some function in another process - through impersonation - the debug privilege can be propagated to called process. For instance, if a process with debug privilege calls a method in WMI process, the WMI thread will have the same privilege in its thread.</content><link rel='replies' type='application/atom+xml' href='http://debugbeyond.blogspot.com/feeds/3509568082369864324/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://debugbeyond.blogspot.com/2010/09/sedebugprivilege-and-integrity-level.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default/3509568082369864324'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default/3509568082369864324'/><link rel='alternate' type='text/html' href='http://debugbeyond.blogspot.com/2010/09/sedebugprivilege-and-integrity-level.html' title='SeDebugPrivilege and Integrity Level'/><author><name>Alex</name><uri>http://www.blogger.com/profile/14466854366502861778</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-947269866336625127.post-3903960225795483632</id><published>2010-09-01T11:19:00.000-07:00</published><updated>2011-08-02T11:20:26.382-07:00</updated><title type='text'>STA Reentrancy</title><content type='html'>I recently observed stack overflow issue due to STA reentrancy issue. The issue  occurred when a slew of COM clients called the STA object concurrently and the STA object in question made outgoing cross-apartment (or cross-process) call. When STA COM call is made, the call is sent to a hidden window in STA COM and translated to window message.  When making an out-of-apartment call from an STA apartment, STA COM spins a modal message pump while waiting for the call to return. Many calls that arrived at the message loop can now be dispatched, causing reentrance. Given a lot of calls keep entering to the STA object, the STA thread reached the max limit of the thread stack. Hence the stack overflow.&lt;br /&gt;
&lt;br /&gt;
Looking at the debugger, I observed that many threads showed the same pattern as shown below.&lt;br /&gt;
&lt;br /&gt;
  46  Id: 2444.1a18 Suspend: 1 Teb: 000007ff`fff5e000 Unfrozen&lt;br /&gt;
Child-SP          RetAddr           Call Site&lt;br /&gt;
00000000`03c3dce8 00000000`76f3c0b0 ntdll!ZwWaitForSingleObject+0xa&lt;br /&gt;
00000000`03c3dcf0 000007fe`fdca86b2 kernel32!WaitForSingleObjectEx+0x9c&lt;br /&gt;
00000000`03c3ddb0 000007fe`fddc9d80 &lt;strong&gt;ole32!GetToSTA+0x8a&lt;br /&gt;
&lt;/strong&gt;00000000`03c3de00 000007fe`fddc9375 ole32!CRpcChannelBuffer::SwitchAptAndDispatchCall+0x100&lt;br /&gt;
00000000`03c3de50 000007fe`fdc9f436 ole32!CRpcChannelBuffer::SendReceive2+0xf1&lt;br /&gt;
00000000`03c3e010 000007fe`fdc9f398 ole32!CAptRpcChnl::SendReceive+0x52&lt;br /&gt;
00000000`03c3e0d0 000007fe`fd7d603a ole32!CCtxComChnl::SendReceive+0x6c&lt;br /&gt;
00000000`03c3e180 000007fe`fd7cef90 RPCRT4!NdrProxySendReceive+0x4a&lt;br /&gt;
00000000`03c3e1b0 000007fe`fd7d6157 RPCRT4!NdrpClientCall3+0x246&lt;br /&gt;
00000000`03c3e400 000007fe`fd728772 RPCRT4!ObjectStublessClient+0xa7&lt;br /&gt;
00000000`03c3e770 000007fe`f99a80e8 RPCRT4!ObjectStubless+0x42&lt;br /&gt;
00000000`03c3e7c0 00000000`ffb329cc FastProx!CWbemSvcWrapper::XWbemServices::ExecQueryAsync+0xd4&lt;br /&gt;
00000000`03c3e830 00000000`ffb265ba wmiprvse!CServerObject_StaThread::ExecQueryAsync+0xd4&lt;br /&gt;
00000000`03c3e8a0 00000000`ffb268a8 wmiprvse!CInterceptor_IWbemSyncProvider::Helper_ExecQueryAsync+0x54a&lt;br /&gt;
00000000`03c3e950 000007fe`fd735ec5 wmiprvse!CInterceptor_IWbemSyncProvider::ExecQueryAsync+0x138&lt;br /&gt;
00000000`03c3e9f0 000007fe`fd711f46 RPCRT4!Invoke+0x65&lt;br /&gt;
00000000`03c3ea60 000007fe`fd7d5cae RPCRT4!NdrStubCall2+0x348&lt;br /&gt;
00000000`03c3f040 000007fe`f998412d RPCRT4!CStdStubBuffer_Invoke+0x66&lt;br /&gt;
00000000`03c3f070 000007fe`fddc89b9 FastProx!CBaseStublet::Invoke+0x19&lt;br /&gt;
00000000`03c3f0a0 000007fe`fddc892b ole32!SyncStubInvoke+0x5d&lt;br /&gt;
00000000`03c3f110 000007fe`fdc9d633 ole32!StubInvoke+0xdf&lt;br /&gt;
00000000`03c3f1b0 000007fe`fddc87c6 ole32!CCtxComChnl::ContextInvoke+0x19f&lt;br /&gt;
00000000`03c3f330 000007fe`fddc855f ole32!AppInvoke+0xc2&lt;br /&gt;
00000000`03c3f3a0 000007fe`fddc7314 ole32!ComInvokeWithLockAndIPID+0x407&lt;br /&gt;
00000000`03c3f520 000007fe`fd7368d4 ole32!ThreadInvoke+0x1f0&lt;br /&gt;
00000000`03c3f5d0 000007fe`fd7369f0 RPCRT4!DispatchToStubInCNoAvrf+0x14&lt;br /&gt;
00000000`03c3f600 000007fe`fd70b042 RPCRT4!RPC_INTERFACE::DispatchToStubWorker+0x100&lt;br /&gt;
00000000`03c3f6f0 000007fe`fd70afbb RPCRT4!RPC_INTERFACE::DispatchToStub+0x62&lt;br /&gt;
00000000`03c3f730 000007fe`fd70af4a RPCRT4!RPC_INTERFACE::DispatchToStubWithObject+0x5b&lt;br /&gt;
00000000`03c3f7b0 000007fe`fd737080 RPCRT4!LRPC_SCALL::DispatchRequest+0x436&lt;br /&gt;
00000000`03c3f820 000007fe`fd7362bb RPCRT4!LRPC_SCALL::HandleRequest+0x200&lt;br /&gt;
00000000`03c3f940 000007fe`fd735e1a RPCRT4!LRPC_ADDRESS::ProcessIO+0x44a&lt;br /&gt;
00000000`03c3fa60 000007fe`fd717769 RPCRT4!LOADABLE_TRANSPORT::ProcessIOEvents+0x24a&lt;br /&gt;
00000000`03c3fb10 000007fe`fd717714 RPCRT4!ProcessIOEventsWrapper+0x9&lt;br /&gt;
00000000`03c3fb40 000007fe`fd7177a4 RPCRT4!BaseCachedThreadRoutine+0x94&lt;br /&gt;
00000000`03c3fb80 00000000`76f2be3d RPCRT4!ThreadStartRoutine+0x24&lt;br /&gt;
00000000`03c3fbb0 00000000`77136a51 kernel32!BaseThreadInitThunk+0xd&lt;br /&gt;
00000000`03c3fbe0 00000000`00000000 ntdll!RtlUserThreadStart+0x1d&lt;br /&gt;
&lt;br /&gt;
When checking the GetToSTA, I found the COM call was made to STA thread where WMI component did reside. I learned the client created a lot of multiple async threads and sent OLE requests simultaneously. All those COM calls were entered into STA thread message loop.&lt;br /&gt;
&lt;br /&gt;
Looking at the STA thread, there is repeating pattern of the below red part. That is, the incoming call is processed by the STA thread -&amp;gt; STA thread calls another component and wait for reply -&amp;gt; STA thread peeks message queue to see if there is any other incoming message. If any, the STA thread processes the message. This is STA reentrancy and it is a COM feature.&lt;br /&gt;
&lt;br /&gt;
…..&lt;br /&gt;
00000000`013da270 000007fe`fdca80c9 ole32!ComInvoke+0x85&lt;br /&gt;
00000000`013da2a0 000007fe`fdca7eae ole32!ThreadDispatch+0x29&lt;br /&gt;
00000000`013da2d0 00000000`7705d53e ole32!ThreadWndProc+0xaa&lt;br /&gt;
00000000`013da350 00000000`7705d7c6 USER32!UserCallWinProcCheckWow+0x1ad&lt;br /&gt;
&lt;span style=&quot;color:#ff0000;&quot;&gt;00000000`013da410 000007fe`fdd31433 USER32!DispatchMessageWorker+0x389&lt;br /&gt;
&lt;/span&gt;&lt;span style=&quot;color:#ff0000;&quot;&gt;00000000`013da490 000007fe`fdcb11e0 ole32!CCliModalLoop::PeekRPCAndDDEMessage+0x73&lt;br /&gt;
&lt;/span&gt;&lt;span style=&quot;color:#ff0000;&quot;&gt;00000000`013da500 000007fe`fdc7b093 ole32!CCliModalLoop::BlockFn+0x36100&lt;br /&gt;
&lt;/span&gt;&lt;span style=&quot;color:#ff0000;&quot;&gt;00000000`013da540 000007fe`fddc7689 ole32!ModalLoop+0x6f&lt;br /&gt;
&lt;/span&gt;…..&lt;br /&gt;
00000000`013dc360 000007fe`f4d50263 framedyn!Provider::CreateInstanceEnum+0x34&lt;br /&gt;
….&lt;br /&gt;
00000000`013dd5d0 000007fe`fdca80c9 ole32!ComInvoke+0x85&lt;br /&gt;
00000000`013dd600 000007fe`fdca7eae ole32!ThreadDispatch+0x29&lt;br /&gt;
00000000`013dd630 00000000`7705d53e ole32!ThreadWndProc+0xaa&lt;br /&gt;
00000000`013dd6b0 00000000`7705d7c6 USER32!UserCallWinProcCheckWow+0x1ad&lt;br /&gt;
&lt;span style=&quot;color:#ff0000;&quot;&gt;00000000`013dd770 000007fe`fdd31433 USER32!DispatchMessageWorker+0x389&lt;br /&gt;
&lt;/span&gt;&lt;span style=&quot;color:#ff0000;&quot;&gt;00000000`013dd7f0 000007fe`fdcb11e0 ole32!CCliModalLoop::PeekRPCAndDDEMessage+0x73&lt;br /&gt;
&lt;/span&gt;&lt;span style=&quot;color:#ff0000;&quot;&gt;00000000`013dd860 000007fe`fdc7b093 ole32!CCliModalLoop::BlockFn+0x36100&lt;br /&gt;
&lt;/span&gt;&lt;span style=&quot;color:#ff0000;&quot;&gt;00000000`013dd8a0 000007fe`fddb4cb0 ole32!ModalLoop+0x6f&lt;br /&gt;
&lt;/span&gt;00000000`013dd8f0 000007fe`fddcb946 ole32!SwitchSTA+0x20&lt;br /&gt;
00000000`013dd920 000007fe`fddc9375 ole32!CRpcChannelBuffer::SwitchAptAndDispatchCall+0x24a6&lt;br /&gt;
00000000`013dd970 000007fe`fdc7b3be ole32!CRpcChannelBuffer::SendReceive2+0xf1&lt;br /&gt;
….&lt;br /&gt;
00000000`013de310 000007fe`f4d50d1a FastProx!CWbemSvcWrapper::XWbemServices::GetObjectW+0x95&lt;br /&gt;
00000000`013de370 000007fe`f4d527d5 framedyn!Provider::GetClassObjectInterface+0xda&lt;br /&gt;
00000000`013de420 000007fe`fd735ec5 framedyn!CWbemProviderGlue::ExecQueryAsync+0x2ad&lt;br /&gt;
….&lt;br /&gt;
00000000`013df620 000007fe`fdca80c9 ole32!ComInvoke+0x85&lt;br /&gt;
00000000`013df650 000007fe`fdca7eae ole32!ThreadDispatch+0x29&lt;br /&gt;
00000000`013df680 00000000`7705d53e ole32!ThreadWndProc+0xaa&lt;br /&gt;
00000000`013df700 00000000`7705d7c6 USER32!UserCallWinProcCheckWow+0x1ad&lt;br /&gt;
00000000`013df7c0 00000000`ffb133f3 USER32!DispatchMessageWorker+0x389&lt;br /&gt;
00000000`013df840 00000000`ffb12eb8 wmiprvse!WmiThread&amp;lt;unsigned long&amp;gt;::ThreadWait+0x11b&lt;br /&gt;
00000000`013dfac0 00000000`ffb11aa8 wmiprvse!WmiThread&amp;lt;unsigned long&amp;gt;::ThreadDispatch+0xf4&lt;br /&gt;
00000000`013dfb20 00000000`76f2be3d wmiprvse!WmiThread&amp;lt;unsigned long&amp;gt;::ThreadProc+0x30&lt;br /&gt;
00000000`013dfb50 00000000`77136a51 kernel32!BaseThreadInitThunk+0xd&lt;br /&gt;
00000000`013dfb80 00000000`00000000 ntdll!RtlUserThreadStart+0x1d</content><link rel='replies' type='application/atom+xml' href='http://debugbeyond.blogspot.com/feeds/3903960225795483632/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://debugbeyond.blogspot.com/2010/09/sta-reentrancy.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default/3903960225795483632'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default/3903960225795483632'/><link rel='alternate' type='text/html' href='http://debugbeyond.blogspot.com/2010/09/sta-reentrancy.html' title='STA Reentrancy'/><author><name>Alex</name><uri>http://www.blogger.com/profile/14466854366502861778</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-947269866336625127.post-8982618496904607241</id><published>2010-07-06T11:21:00.000-07:00</published><updated>2011-08-02T11:21:41.993-07:00</updated><title type='text'>COM: GetToSTA</title><content type='html'>When a COM call is made to STA (single-threaded apartment) COM, ole32!GetToSTA is called to send the COM call to target STA thread. An example below shows that a thread was created for RPC server call (SCALL) and its call was dispatched to a WMI provider which is a (STA) COM component. Once the COM call is made to STA thread, the thread (tid=4) is waiting for a event which will be set by STA thread when the COM call is finished.&lt;br /&gt;
&lt;pre&gt;0:004&amp;gt; kL
ChildEBP RetAddr 
00c9e5b0 77175e6c ntdll!KiFastSystemCallRet
00c9e5b4 7532179c ntdll!ZwWaitForSingleObject+0xc
00c9e620 75a0f003 KERNELBASE!WaitForSingleObjectEx+0x98
00c9e638 75a0efb2 kernel32!WaitForSingleObjectExImplementation+0x75
&lt;strong&gt;&lt;span style=&quot;color:#ff0000;&quot;&gt;00c9e64c 75ca88df kernel32!WaitForSingleObject+0x12
00c9e670 75dca819 ole32!GetToSTA+0xad&lt;/span&gt;&lt;/strong&gt;
00c9e6a0 75dcc05f ole32!CRpcChannelBuffer::SwitchAptAndDispatchCall+0x140
00c9e780 75cbd0e5 ole32!CRpcChannelBuffer::SendReceive2+0xef
00c9e7fc 75cbcb09 ole32!CAptRpcChnl::SendReceive+0xaf
00c9e850 75dcbf75 ole32!CCtxComChnl::SendReceive+0x1c5
00c9e86c 76c5178b ole32!NdrExtpProxySendReceive+0x49
00c9e878 76cc5744 RPCRT4!NdrpProxySendReceive+0xe
00c9ec90 75dcba02 RPCRT4!NdrClientCall2+0x1a6
00c9ecb0 75cbc8b5 ole32!ObjectStublessClient+0xa2
00c9ecc0 6b23f6a3 ole32!ObjectStubless+0xf
00c9ecf8 0027d9d9 FastProx!CWbemSvcWrapper::XWbemServices::CreateInstanceEnumAsync+0x6e
00c9ed28 00263778 wmiprvse!CServerObject_StaThread::CreateInstanceEnumAsync+0x92
00c9ed68 002635dc wmiprvse!CInterceptor_IWbemSyncProvider::Helper_CreateInstanceEnumAsync+0x159
00c9edac 76c5fc8f wmiprvse!CInterceptor_IWbemSyncProvider::CreateInstanceEnumAsync+0xf4
00c9edd4 76cc4c53 RPCRT4!Invoke+0x2a
00c9f1dc 75dcd936 RPCRT4!NdrStubCall2+0x2d6
00c9f224 6b234f55 ole32!CStdStubBuffer_Invoke+0xb6
00c9f238 75dcd9c6 FastProx!CBaseStublet::Invoke+0x29
00c9f280 75dcdf1f ole32!SyncStubInvoke+0x3c
00c9f2cc 75ce213c ole32!StubInvoke+0xb9
00c9f3a8 75ce2031 ole32!CCtxComChnl::ContextInvoke+0xfa
00c9f3c4 75dca754 ole32!MTAInvoke+0x1a
00c9f3f4 75dcdcbb ole32!AppInvoke+0xab
00c9f4d4 75dca773 ole32!ComInvokeWithLockAndIPID+0x372
00c9f520 76c5f34a ole32!ThreadInvoke+0x302
00c9f55c 76c5f4da RPCRT4!DispatchToStubInCNoAvrf+0x4a
00c9f5b4 76c5f3c6 RPCRT4!RPC_INTERFACE::DispatchToStubWorker+0x16c
00c9f5dc 76c60cef RPCRT4!RPC_INTERFACE::DispatchToStub+0x8b
00c9f614 76c5f882 RPCRT4!RPC_INTERFACE::DispatchToStubWithObject+0xb2
&lt;span style=&quot;color:#ff0000;&quot;&gt;00c9f660 76c5f7a4 RPCRT4!LRPC_SCALL::DispatchRequest+0x23b&lt;/span&gt;
00c9f680 76c5f763 RPCRT4!LRPC_SCALL::QueueOrDispatchCall+0xbd
00c9f69c 76c5f5ff RPCRT4!LRPC_SCALL::HandleRequest+0x34f
00c9f6d0 76c5f573 RPCRT4!LRPC_SASSOCIATION::HandleRequest+0x144
00c9f708 76c5ee4f RPCRT4!LRPC_ADDRESS::HandleRequest+0xbd
00c9f780 76c5ece7 RPCRT4!LRPC_ADDRESS::ProcessIO+0x50a
00c9f78c 76c61357 RPCRT4!LrpcServerIoHandler+0x16
00c9f79c 7715d3a3 RPCRT4!LrpcIoComplete+0x16
00c9f7c4 77160748 ntdll!TppAlpcpExecuteCallback+0x1c5
00c9f92c 75a11194 ntdll!TppWorkerThread+0x5a4
00c9f938 7718b3f5 kernel32!BaseThreadInitThunk+0xe
00c9f978 7718b3c8 ntdll!__RtlUserThreadStart+0x70
00c9f990 00000000 ntdll!_RtlUserThreadStart+0x1b
0:004&amp;gt; kpL
ChildEBP RetAddr 
00c9e5b0 77175e6c ntdll!KiFastSystemCallRet(void)
00c9e5b4 7532179c ntdll!ZwWaitForSingleObject(void)+0xc
.......
00c9e670 75dca819 ole32!GetToSTA(&lt;strong&gt;&lt;span style=&quot;color:#ff0000;&quot;&gt;class OXIDEntry * pOXIDEntry = 0x00333918&lt;/span&gt;&lt;/strong&gt;, class CMessageCall * pCall = 0x0036af18)+0xad
.......&lt;/pre&gt;As you see above, GetToSTA takes 2 parameters. One for OXIDEntry object pointer and the other for CMessageCall object pointer. If we look into the first parameter, it provides some useful information.  &lt;br /&gt;
&lt;pre&gt;0:004&amp;gt; dt OXIDEntry 0x00333918
ole32!OXIDEntry
   +0x000 _pNext           : 0x75dd68f8 OXIDEntry
   +0x004 _pPrev           : 0x00333898 OXIDEntry
&lt;span style=&quot;color:#ff0000;&quot;&gt;   +0x008 _dwPid           : 0x204
   +0x00c _dwTid           : 0x16bc&lt;/span&gt;
   +0x010 _moxid           : _GUID {9feeca0e-6667-eb70-3925-cbaa316f4a29}
   +0x020 _mid             : 0x294a6f31`aacb2539
   +0x028 _ipidRundown     : _GUID {0000380d-0204-16bc-3099-d83e8ae297f6}
   +0x038 _dwFlags         : 0x303
   +0x03c _hServerSTA      : 0x0c4400f0 HWND__
   +0x040 _pParentApt      : 0x003498e0 CComApartment
   +0x044 _pRpc            : (null)
   +0x048 _pAuthId         : (null)
   +0x04c _pBinding        : (null)
   +0x050 _dwAuthnHint     : 1
   +0x054 _dwAuthnSvc      : 0xffffffff
   +0x058 _pMIDEntry       : 0x003336f0 MIDEntry
   +0x05c _pRUSTA          : 0x0035255c IRemUnknown
   +0x060 _cRefs           : 0n13
   +0x064 _hComplete       : (null)
   +0x068 _cCalls          : 0n1
   +0x06c _cResolverRef    : 0n0
   +0x070 _dwExpiredTime   : 0
   ......&lt;/pre&gt;dwPid and dwTid indicate the process id and thread id to which the COM call is made. In this case thread 4 is making a COM call to thread 7 (PID 0x204, TID 0x16bc) where the STA COM object resides.&lt;br /&gt;
&lt;pre&gt;0:007&amp;gt; ~
.......

.  &lt;span style=&quot;color:#ff0000;&quot;&gt;7  Id: 204.16bc&lt;/span&gt; Suspend: 1 Teb: 7ffd8000 Unfrozen
.......&lt;/pre&gt;When a COM call is made, STA thread receives the call, translates it to window message and put it into hidden window message queue. STA thread processes the message from the queue and set event when the COM method is done. This will release Wait function in caller thread (id=4 in above case).</content><link rel='replies' type='application/atom+xml' href='http://debugbeyond.blogspot.com/feeds/8982618496904607241/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://debugbeyond.blogspot.com/2010/07/com-gettosta.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default/8982618496904607241'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default/8982618496904607241'/><link rel='alternate' type='text/html' href='http://debugbeyond.blogspot.com/2010/07/com-gettosta.html' title='COM: GetToSTA'/><author><name>Alex</name><uri>http://www.blogger.com/profile/14466854366502861778</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-947269866336625127.post-7590031759484807102</id><published>2010-06-13T11:22:00.000-07:00</published><updated>2011-08-02T11:23:14.968-07:00</updated><title type='text'>64bit Calling Convention</title><content type='html'>&lt;h2&gt;64 bit calling convention - what it means to debugging.&lt;/h2&gt;While 32 bit (x86) has multiple calling conventions such as cdecl, stdcall, fastcall, thiscall, 64 bit (x64) only has single calling convention which has unique characteristics. Some important characteristics are&lt;br /&gt;
&lt;ul&gt; &lt;li&gt;64 bit calling converntion passes first 4 parameters to 4 registers (RCX, RDX, R8, R9) and additional parameters to  stack (similar to fastcall calling convention). And even if parameters are less than 4, stack space for 4 parameters are always reserved (this area is called home space or home area).  (&lt;em&gt;Note: Fastcall calling convnetions pass one or more parameters by using registers to make a fast function call. x86 fastcall calling convention passes first 2 parameters to ECX, EDX registers.)&lt;/em&gt;&lt;/li&gt;
 &lt;li&gt;Stack will have 16 bytes alignment to aid performance. This means if there are 5 parameters, there will be 48 bytes reserved for parameters (5 params x 8 bytes + 8 bytes for alignment)&lt;/li&gt;
 &lt;li&gt;Stack pointer (rsp) typically does not change within a given function. Stack size for a function code is pre-calculated and so stack pointer does not change once prolog is done.&lt;/li&gt;
&lt;/ul&gt;Understanding 64 bit calling convention is important for debugging since depending on whether one has optimized or non-optimized build, parameters in call stack can be useless or often misleading. For non-optimization build (ex: when compiled with /Od option in C++), called function, through its prolog code, copies all 4 parameters saved in registers (RCX,RDX,R8,R9) to stack home area. So parameters inspection through dv, kP debug command displays correct parameter values. However, optimization build does not save those parameters in registers to stack area and, even worse, those stack home area are used for other purpose. This behavior in optimziation build can often mislead developers to wrong parameter values. So developer shouldn&#39;t trust call stack parameter values (kP) or display variables (dv) results when debugging againt 64bit optimized build.&lt;br /&gt;
&lt;br /&gt;
Let&#39;s look at a small sample.&lt;br /&gt;
&lt;pre style=&quot;padding-left:30px;&quot;&gt;int Calc(int a, int b, int c, int d, int e)
{                              // &amp;lt;= breakpoint 1
    int result = 0;            // &amp;lt;= breakpoint 2
    for(int i=0; i&amp;lt;10; i++)
    {
       result += a*i + b - c + d * 2 + e;
       printf(&quot;%d : %d\n&quot;, i, result);
    }
    result += a - b + c -d + e;
    return result;
}

int _tmain(int argc, _TCHAR* argv[])
{
    int s1,s2,s3,s4,s5;
    scanf(&quot;%d %d %d %d %d&quot;, &amp;amp;s1, &amp;amp;s2, &amp;amp;s3, &amp;amp;s4, &amp;amp;s5);

    int result = Calc(s1,s2,s3,s4,s5); // &amp;lt;= breakpoint 0
    printf(&quot;Result = %d&quot;, result);

    return 0;
}&lt;/pre&gt;I set 3 breakpoints as marked above.&lt;br /&gt;
&lt;pre&gt;0:000&amp;gt; bl
 0 e 00000001`3f5e10ed     0001 (0001)  0:**** Simple!wmain+0x3d
 1 e 00000001`3f5e1000     0001 (0001)  0:**** Simple!Calc
 2 e 00000001`3f5e1016     0001 (0001)  0:**** Simple!Calc+0x16&lt;/pre&gt;Right before calling a function at breakpoint 0, we can inspect the assembly code to see how the parameters are passed. Basically what it does is to pass first 4 parameters (I entered 1,2,3,4,5 for scanf()) to ECX, EDX, R8D, R9D registers. (Since passing parameters are int32, ECX register is used instead of RCX). The last 5th parameter is passed to stack (rsp+20h).&lt;br /&gt;
&lt;pre&gt;0:000&amp;gt; u .
Simple!wmain+0x3d [c:\temp\simple\simple.cpp @ 18]:
00000001`3fd910ed 8b442434        mov     eax,dword ptr [rsp+34h]
00000001`3fd910f1 89442420        mov     dword ptr [rsp+20h],eax  //5th param: 5
00000001`3fd910f5 448b4c2440      mov     r9d,dword ptr [rsp+40h]  // 4
00000001`3fd910fa 448b442430      mov     r8d,dword ptr [rsp+30h]  // 3
00000001`3fd910ff 8b542438        mov     edx,dword ptr [rsp+38h]  // 2
00000001`3fd91103 8b4c243c        mov     ecx,dword ptr [rsp+3Ch]  //1st param: 1
00000001`3fd91107 e8f4feffff      call    Simple!Calc (00000001`3fd91000)&lt;/pre&gt;Now let&#39;s continue to reach breakpoint 1 at the begining of Calc() function. This is the point where we can check prolog assembly code of the function. For non-optimzition build, here you can see that those registers for parameters are copied to stack home area.&lt;br /&gt;
&lt;pre&gt;0:000&amp;gt; uf .
Simple!Calc [c:\temp\simple\simple.cpp @ 4]:
    4 00000001`3f5d1000 44894c2420      mov     dword ptr [rsp+20h],r9d
    4 00000001`3f5d1005 4489442418      mov     dword ptr [rsp+18h],r8d
    4 00000001`3f5d100a 89542410        mov     dword ptr [rsp+10h],edx
    4 00000001`3f5d100e 894c2408        mov     dword ptr [rsp+8],ecx&lt;/pre&gt;Once those function prolog codes are executed, that is, when we move to breakpoint 2, the stack has correct 5 parameters and thus kP call stack command or dv command displays correct parameter values. Below we can check 5 parameters in stack address 00000000`0026feb0 ~ 00000000`0026fed0. Stack slot 00000000`0026fed8 has garbage value, just for 16 bytes alignment.&lt;br /&gt;
&lt;pre&gt;0:000&amp;gt; p
Breakpoint 2 hit
Simple!Calc+0x16:
00000001`3f5d1016 c744242000000000 mov     dword ptr [rsp+20h],0
0:000&amp;gt; &lt;strong&gt;dq /c 1 @rsp
&lt;/strong&gt;00000000`0026fe70  00000000`00000000
00000000`0026fe78  00000000`5fca10b1
00000000`0026fe80  00000000`00000001
00000000`0026fe88  00000000`00000000
00000000`0026fe90  00000000`00000000
00000000`0026fe98  00000001`3f5d11ac
00000000`0026fea0  00000001`3f5d2150
00000000`0026fea8  00000001`3f5d110c //return address
&lt;span style=&quot;color:#ff0000;&quot;&gt;00000000`0026feb0  00000001`00000001 //param 1
00000000`0026feb8  00000000`00000002
00000000`0026fec0  00000000`00000003
00000000`0026fec8  00000000`00000004
00000000`0026fed0  00000000`00000005 //param 5
00000000`0026fed8  00000000`0026fee4 //for alignment&lt;/span&gt;&lt;/pre&gt;And here is what I got when running kP and dv command.&lt;br /&gt;
&lt;pre&gt;0:000&amp;gt; kP
Child-SP          RetAddr           Call Site
00000000`0026fe70 00000001`3f5d110c Simple!Calc(
   int a = 0n1,
   int b = 0n2,
   int c = 0n3,
   int d = 0n4,
   int e = 0n5)+0x16 [c:\temp\simple\simple.cpp @ 5]
0:000&amp;gt; dv /i /V
prv param  00000000`0026feb0 @rsp+0x0040                     a = 0n1
prv param  00000000`0026feb8 @rsp+0x0048                     b = 0n2
prv param  00000000`0026fec0 @rsp+0x0050                     c = 0n3
prv param  00000000`0026fec8 @rsp+0x0058                     d = 0n4
prv param  00000000`0026fed0 @rsp+0x0060                     e = 0n5
prv local  00000000`0026fe90 @rsp+0x0020                result = 0n0&lt;/pre&gt;Now what if we have optimized build? I recompiled the source code with Maxmimum Speed optimization (/O2). For optimized build, the prolog of Calc() function starts like this.&lt;br /&gt;
&lt;pre&gt;0:000&amp;gt; uf Simple!Calc
Simple!Calc [c:\temp\simple\simple.cpp @ 4]:
    4 00000001`3ff51000 48895c2408      mov     qword ptr [rsp+8],rbx
    4 00000001`3ff51005 48896c2410      mov     qword ptr [rsp+10h],rbp
    4 00000001`3ff5100a 4889742418      mov     qword ptr [rsp+18h],rsi
    4 00000001`3ff5100f 57              push    rdi
    4 00000001`3ff51010 4154            push    r12
    4 00000001`3ff51012 4155            push    r13
    4 00000001`3ff51014 4156            push    r14
    4 00000001`3ff51016 4157            push    r15
    4 00000001`3ff51018 4883ec20        sub     rsp,20h&lt;/pre&gt;As you can see here, there is no mov command for parameter copy. By the time I reached breakpoint 2 where prolog codes are all executed, the first 4 parameter values were not copied at all and only registers held the parameter values.&lt;br /&gt;
&lt;pre&gt;0:000&amp;gt; p
Breakpoint 2 hit
Simple!Calc+0x1c:
00000001`3ff5101c 448b6c2470      mov     r13d,dword ptr [rsp+70h] ss:00000000`0022f8f0=00000005
0:000&amp;gt; kP L1
Child-SP          RetAddr           Call Site
00000000`0022f880 00000001`3ff510e1 Simple!Calc(
   int a = 0n1,
   int b = 0n0,
   int c = 0n0,
   int d = 0n2291968,
   int e = 0n5)+0x1c [c:\temp\simple\simple.cpp @ 5]
0:000&amp;gt; dv /i
prv param                a = 0n1
prv param                b = 0n0
prv param                c = 0n0
prv param                d = 0n2291968
prv param                e = 0n5
0:000&amp;gt; r rcx
rcx=0000000000000001
0:000&amp;gt; r rdx
rdx=0000000000000002
0:000&amp;gt; r r8
r8=0000000000000003
0:000&amp;gt; r r9
r9=0000000000000004&lt;/pre&gt;As you might already notice, this behavior of optimized build can cause a lot of headache for 64 bit debugging. The behavior means that the call stack parameter information in 64 bit optimization build is completely useless. It will be much painful if we need to analyze regular dump file or Watson dump file which has less debugging information. So then how can we find correct parameter values? We know from the previous inspection that only registers hold those 4 parameter values. Starting from this point, we can think we have to trace down what parameter values were entered from previous call frame. When caller calls a function, it saves 4 parameters to registers. Since we can see this in assembly code, we unassmeble the code and can track down the parameter value. But what if the caller doesn&#39;t pass constant value as a parameter? Well, then, it will be much more tedious investigation since we have to dig into the history of the registers or stack area. For unfortunate cases, we might need to inspect many call stack frames and the assmebly codes to figure out how the parameters were passed all the way up to current stack frame.</content><link rel='replies' type='application/atom+xml' href='http://debugbeyond.blogspot.com/feeds/7590031759484807102/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://debugbeyond.blogspot.com/2010/06/64bit-calling-convention.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default/7590031759484807102'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default/7590031759484807102'/><link rel='alternate' type='text/html' href='http://debugbeyond.blogspot.com/2010/06/64bit-calling-convention.html' title='64bit Calling Convention'/><author><name>Alex</name><uri>http://www.blogger.com/profile/14466854366502861778</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-947269866336625127.post-3287752153409114143</id><published>2010-06-10T11:26:00.000-07:00</published><updated>2011-08-02T11:29:59.233-07:00</updated><title type='text'>How To Dump</title><content type='html'>&lt;h2&gt;How to dump user process [101]&lt;/h2&gt;There are many ways to dump the user process. I introduce here some commonly used methods of how to dump a process.&lt;br /&gt;
&lt;h3&gt;A. Using CDB&lt;/h3&gt;CDB is console based general purpose debugging tool and it&#39;s also good tool to dump a process. When dumping a process, we normally want to be &quot;non-invasive&quot; which means we don&#39;t want to ruin the process and just take a snapshot of the process. This can be done by specifying -pv option. If the process name is unique, you can use -pn option with exe file name. But if there are several processes having the same process name, typically we check process PID of interest and use -p option. The -c option below is actual debugger command that the CDB is going to run. The .dump command below dumps the process to specified file.&lt;br /&gt;
&lt;pre&gt;C&amp;gt; &lt;strong&gt;cdb -pv –pn myApp.exe -c &quot;.dump /ma /u c:\tmp\myApp.dmp;q&quot;&lt;/strong&gt;   
  C&amp;gt; &lt;strong&gt;cdb -pv –p 500 -c &quot;.dump /ma c:\tmp\myApp.dmp;q&quot;&lt;/strong&gt;   &lt;/pre&gt;&lt;h3&gt;B. Using ADPLUS&lt;/h3&gt;ADPLUS is the tool that Microsoft CSS often uses to take a dump. There are 2 dump modes in this tool - one for hang and the other for crash dump.&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;&lt;span style=&quot;text-decoration: underline;&quot;&gt;HANG&lt;/span&gt;&lt;/strong&gt; : to capture hang dump, you run ADPLUS with -hang option after hang occurred. It will take a dump and leave the process intact (meaning non-invasive dump). Need to specify -p with PID and -o with output folder.&lt;br /&gt;
&lt;br /&gt;
C:\Debuggers&amp;gt; &lt;strong&gt;adplus -hang -p 433 -o c:\Test &lt;/strong&gt;(PID=433)&lt;br /&gt;
&lt;br /&gt;
Logs and memory dumps will be placed in c:\Test\20100127_111336_Hang_Mode&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;&lt;span style=&quot;text-decoration: underline;&quot;&gt;CRASH&lt;/span&gt;&lt;/strong&gt; : the other ADPLUS mode is crash mode, which takes a dump when the process is crashed. Since we never know when the crash occurs, the ADPLUS command - of course - shoud be run before the crash occurs. If you&#39;re using remote connection (mstsc.exe) , you should use /console. Crash mode is very handy since adplus will wait until the crash occurs.&lt;br /&gt;
&lt;br /&gt;
C:\Debuggers&amp;gt; &lt;strong&gt;adplus -crash -pn App.exe -o c:\test &lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
Logs and memory dumps will be placed in c:\test\20100127_111828_Crash_Mode&lt;br /&gt;
&lt;br /&gt;
Note: adplus was originally written in VBScript but they wrote exe version in recent version. By the way, adplus internally uses CDB to capture dump.&lt;br /&gt;
&lt;h3&gt;C. Using Task Manager&lt;/h3&gt;Since Vista OS, Task Manager has new context menu called &quot;Create Dump File.&quot; In order to create a dump for the specific process, you select a process and rightclick and then choose &#39;Create Dump File&quot; menu. Here is an example of Windows 7 Task Manager.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: left; margin-right: 1em; text-align: left;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-NFibEtMD5WQUgiDNsv8yzKZOQJnTcbHb283SaXQIEAzSn_CE9fTagRJpymS8vrlwcgSX0JvgRtWo1s5e9ZcGRTvI8Ri1N_bFwHzxXeG-ExgRfY-ahB6B-Q5ZSvCinCnCfhkhHKpz88tl/s1600/createdumpfile.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; cssfloat: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-NFibEtMD5WQUgiDNsv8yzKZOQJnTcbHb283SaXQIEAzSn_CE9fTagRJpymS8vrlwcgSX0JvgRtWo1s5e9ZcGRTvI8Ri1N_bFwHzxXeG-ExgRfY-ahB6B-Q5ZSvCinCnCfhkhHKpz88tl/s400/createdumpfile.png&quot; t$=&quot;true&quot; width=&quot;313&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Create Dump File From Task Manager&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;After dumping is done, it shows the dumpe file location in the message box.</content><link rel='replies' type='application/atom+xml' href='http://debugbeyond.blogspot.com/feeds/3287752153409114143/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://debugbeyond.blogspot.com/2010/06/how-to-dump.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default/3287752153409114143'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default/3287752153409114143'/><link rel='alternate' type='text/html' href='http://debugbeyond.blogspot.com/2010/06/how-to-dump.html' title='How To Dump'/><author><name>Alex</name><uri>http://www.blogger.com/profile/14466854366502861778</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-NFibEtMD5WQUgiDNsv8yzKZOQJnTcbHb283SaXQIEAzSn_CE9fTagRJpymS8vrlwcgSX0JvgRtWo1s5e9ZcGRTvI8Ri1N_bFwHzxXeG-ExgRfY-ahB6B-Q5ZSvCinCnCfhkhHKpz88tl/s72-c/createdumpfile.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-947269866336625127.post-4953545140207800163</id><published>2010-04-02T11:36:00.000-07:00</published><updated>2011-08-02T11:38:52.839-07:00</updated><title type='text'>Thread Stack</title><content type='html'>&lt;h1&gt;Thread Stack&lt;/h1&gt;Each thread has two stacks – one stack for kernel mode and the other for user mode. Where can we find those stacks? Well, let’s quickly take a look.&lt;br /&gt;
&lt;br /&gt;
First, run Calc.exe and attached debugger (my favorite Windbg) to the Calc process. Once the debugger is attached, switch thread to 0 and run !teb to display Thread Environment Block(TEB). By looking at TEB, we can figure out the user mode stack area.&lt;br /&gt;
&lt;pre style=&quot;padding-left: 30px;&quot;&gt;0:004&amp;gt; ~0s&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;eax=0012ed84 ebx=00000000 ecx=0012ed84 edx=779764f4 esi=0012ed84 edi=77399442&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;eip=779764f4 esp=0012ec80 ebp=0012ec9c iopl=0         nv up ei pl zr na pe nc&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;ntdll!KiFastSystemCallRet:&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;779764f4 c3              ret&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;0:000&amp;gt; &lt;strong&gt;!teb&lt;/strong&gt;&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;&lt;a href=&quot;http://yongslee.files.wordpress.com/2010/04/threadstackfig1.jpg&quot;&gt;&lt;/a&gt;TEB at 7ffdf000&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;ExceptionList:        0012fa98&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;&lt;strong&gt;    StackBase:            00130000&lt;/strong&gt;&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;&lt;strong&gt;    StackLimit:           0012a000&lt;/strong&gt;&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;SubSystemTib:         00000000&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;FiberData:            00001e00&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;ArbitraryUserPointer: 00000000&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;Self:                 7ffdf000&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;EnvironmentPointer:   00000000&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;……&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;&lt;/pre&gt;In TEB above, we see there is user mode stack base and upper limit of the stack. That is, the stack ranges from 0x00130000 – 0x0012a000 (stack grows from high to low memory).&lt;br /&gt;
&lt;br /&gt;
Secondly, then how can we find kernel mode stack? As you guess, we have to use (local) kernel debugger to find that out. Let’s see local kernel debugger to get this handy. In order to get thread object address, !process command was used as follows.&lt;br /&gt;
&lt;pre style=&quot;padding-left: 30px;&quot;&gt;lkd&amp;gt; !process 0 4 calc.exe&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;PROCESS 86ac47e8  SessionId: 1  Cid: 0558    Peb: 7ff&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;DirBase: ce18ea00  ObjectTable: a3b59140  HandleC&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;Image: calc.exe&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;THREAD 85b92938  Cid 0558.1db8  Teb: 7ffdf000&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;THREAD 85cf19b0  Cid 0558.1768  Teb: 7ffdd000&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;THREAD 86b3f128  Cid 0558.1a3c  Teb: 7ffdc000&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;THREAD 880b1d48  Cid 0558.1bf0  Teb: 7ffdb000&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;THREAD 871c05c8  Cid 0558.1e90  Teb: 7ffda000&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
Once the thread object (&lt;strong&gt;85b92938&lt;/strong&gt; ) is found, the kernel thread block (_KTHREAD) can be displayed with dt command. Bold-face part shows initial stack, max limit and current stack position (KernelStack at 0x30).&lt;br /&gt;
&lt;pre style=&quot;padding-left: 30px;&quot;&gt;lkd&amp;gt; &lt;strong&gt;dt nt!_KTHREAD 85b92938&lt;/strong&gt;&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;+0x000 Header           : _DISPATCHER_HEADER&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;+0x010 CycleTime        : 0x14b1bef8&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;+0x018 HighCycleTime    : 0&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;+0x020 QuantumTarget    : 0x174fbc90&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;&lt;strong&gt;   +0x028 InitialStack     : 0x8f7f0fd0 Void&lt;/strong&gt;&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;&lt;strong&gt;   +0x02c StackLimit       : 0x8f7ee000 Void&lt;/strong&gt;&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;&lt;strong&gt;   +0x030 KernelStack      : 0x8f7f09b0 Void&lt;/strong&gt;&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;+0x034 ThreadLock       : 0&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;……&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;+0x086 SpecialApcDisable : 0n0&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;+0x084 CombinedApcDisable : 0&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;&lt;strong&gt;   +0x088 Teb              : 0x7ffdf000 Void&lt;/strong&gt;&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;+0x090 Timer            : _KTIMER&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;……&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
KTHREAD also includes TEB pointer information, so we can query the TEB with its address.&lt;br /&gt;
&lt;pre style=&quot;padding-left: 30px;&quot;&gt;lkd&amp;gt; &lt;strong&gt;!teb 0x7ffdf000&lt;/strong&gt;&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;TEB at 7ffdf000&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;ExceptionList:        00078914&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;&lt;strong&gt; StackBase:            00080000&lt;/strong&gt;&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;&lt;strong&gt;    StackLimit:           00069000&lt;/strong&gt;&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;SubSystemTib:         00000000&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;FiberData:            00001e00&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;ArbitraryUserPointer: 00000000&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;Self:                 7ffdf000&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;EnvironmentPointer:   00000000&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;ClientId:             00000ea8 . 0000131c&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;RpcHandle:            00000000&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;Tls Storage:          7ffdf02c&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;PEB Address:          7ffd6000&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;LastErrorValue:       0&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;LastStatusValue:      c0000139&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;Count Owned Locks:    0&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;HardErrorMode:        0&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
If we compare this TEB output with user mode TEB data, we find something wrong. This is because TEB data is located in user address space, not kernel address space. So to retrieve correct thread data, we have to set thread context and prepare physical memory before access (by using .thread command).&lt;br /&gt;
&lt;pre style=&quot;padding-left: 30px;&quot;&gt;lkd&amp;gt; &lt;strong&gt;.thread /p /r 85b92938&lt;/strong&gt;&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;Implicit thread is now 85b92938&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;Implicit process is now 86ac47e8&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;Loading User Symbols&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;................................&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;lkd&amp;gt; &lt;strong&gt;!teb 0x7ffdf000&lt;/strong&gt;&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;TEB at 7ffdf000&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;ExceptionList:        0012fa98&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;&lt;strong&gt; StackBase:            00130000&lt;/strong&gt;&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;&lt;strong&gt;    StackLimit:           0012a000&lt;/strong&gt;&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;SubSystemTib:         00000000&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;FiberData:            00001e00&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;ArbitraryUserPointer: 00000000&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;Self:                 7ffdf000&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;EnvironmentPointer:   00000000&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;ClientId:             00000558 . 00001db8&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;RpcHandle:            00000000&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;Tls Storage:          7ffdf02c&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;PEB Address:          7ffde000&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;LastErrorValue:       0&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;LastStatusValue:      c0150008&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;Count Owned Locks:    0&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;HardErrorMode:        0&lt;/pre&gt;Plesae note that the thread object (ex:&lt;strong&gt;85b92938)&lt;/strong&gt; points to an executive thread block (ETHREAD) which includes its kernel thread block (KTHREAD) as its first member of the ETHREAD structure. KTHREAD contains TEB pointer in its structure.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtfTCGUk_rBBHabgGn12RHlWuw2k1QLNX2vp9WvOqsmSqB_JTl2jVEJGZDAkrXw_8SfyRQv-qgYGsJ_S4tgUhs3ZGKvQUZkjnWlkx0TMpHJbNn4z5aJlcyAxHhlLWsFXLdRSPYNZ34YQeZ/s1600/thread-stack.jpg&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; cssfloat: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;366&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtfTCGUk_rBBHabgGn12RHlWuw2k1QLNX2vp9WvOqsmSqB_JTl2jVEJGZDAkrXw_8SfyRQv-qgYGsJ_S4tgUhs3ZGKvQUZkjnWlkx0TMpHJbNn4z5aJlcyAxHhlLWsFXLdRSPYNZ34YQeZ/s640/thread-stack.jpg&quot; t$=&quot;true&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
By the way, another easy way to discover kernel thread stack is to simply use !thread command. In the middle of the output below, there is kernel stack information. And as seen below, ChildEBP addresses are all within kernel stack range.&lt;br /&gt;
&lt;pre style=&quot;padding-left: 30px;&quot;&gt;lkd&amp;gt; &lt;strong&gt;!thread 85b92938&lt;/strong&gt;&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;THREAD 85b92938  Cid 0558.1db8  Teb: 7ffdf000 Win32Thread: fe5a34f8 WAIT: (Suspended) KernelMode Non-Alertable&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;SuspendCount 1&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;FreezeCount 1&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;85b92b00  Semaphore Limit 0x2&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;Not impersonating&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;DeviceMap                 bf992858&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;Owning Process            86ac47e8       Image:         calc.exe&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;Attached Process          N/A            Image:         N/A&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;Wait Start TickCount      13525527       Ticks: 79995 (0:00:20:47.929)&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;Context Switch Count      1580&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;UserTime                  00:00:00.031&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;KernelTime                00:00:00.078&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;Win32 Start Address 0x00959768&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;&lt;strong&gt;Stack Init 8f7f0fd0 Current 8f7f09b0 Base 8f7f1000 Limit 8f7ee000&lt;/strong&gt; Call 0&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;Priority 11 BasePriority 8 UnusualBoost 0 ForegroundBoost 2 IoPriority 2 PagePriority 5&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;ChildEBP RetAddr  Args to Child&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;8f7f09c8 82a71c15 85b92938 00000000 807c8120 nt!KiSwapContext+0x26 (FPO: [Uses EBP] [0,0,4])&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;8f7f0a00 82a704f3 85b929f8 85b92938 85b92b00 nt!KiSwapThread+0x266 (CONV: fastcall)&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;8f7f0a28 82a6a3cf 85b92938 85b929f8 00000000 nt!KiCommitThreadWait+0x1df (CONV: stdcall)&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;8f7f0aa4 82aad0d6 85b92b00 00000005 00000000 nt!KeWaitForSingleObject+0x393 (CONV: stdcall)&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;8f7f0abc 82aab117 00000000 00000000 00000000 nt!KiSuspendThread+0x18 (FPO: [3,0,0]) (CONV: stdcall)&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;8f7f0b04 82a71bfd 00000000 00000000 00000000 nt!KiDeliverApc+0x17f (CONV: stdcall)&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;8f7f0b48 82a704f3 85b929f8 85b92938 87965ff0 nt!KiSwapThread+0x24e (CONV: fastcall)&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;8f7f0b70 82a6a3cf 85b92938 85b929f8 00000000 nt!KiCommitThreadWait+0x1df (CONV: stdcall)&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;8f7f0be8 9af10d75 87965ff0 0000000d 00000001 nt!KeWaitForSingleObject+0x393 (CONV: stdcall)&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;WARNING: Frame IP not in any known module. Following frames may be wrong.&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;8f7f0d1c 82a4647a 0012ed84 00000000 00000000 0x9af10d75&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;8f7f0d1c 00000000 0012ed84 00000000 00000000 nt!KiFastCallEntry+0x12a (FPO: [0,3] TrapFrame @ 8f7f0c&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;60)&lt;/pre&gt;&lt;pre style=&quot;padding-left: 30px;&quot;&gt;8f7f0ce8 00000000 9af152a2 001b0b8e 0000000f 0x0&lt;/pre&gt;More topics to come:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Calling convention and stack&lt;/li&gt;
&lt;li&gt;64bit calling convention and stack&lt;/li&gt;
&lt;/ul&gt;</content><link rel='replies' type='application/atom+xml' href='http://debugbeyond.blogspot.com/feeds/4953545140207800163/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://debugbeyond.blogspot.com/2010/04/thread-stack.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default/4953545140207800163'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default/4953545140207800163'/><link rel='alternate' type='text/html' href='http://debugbeyond.blogspot.com/2010/04/thread-stack.html' title='Thread Stack'/><author><name>Alex</name><uri>http://www.blogger.com/profile/14466854366502861778</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtfTCGUk_rBBHabgGn12RHlWuw2k1QLNX2vp9WvOqsmSqB_JTl2jVEJGZDAkrXw_8SfyRQv-qgYGsJ_S4tgUhs3ZGKvQUZkjnWlkx0TMpHJbNn4z5aJlcyAxHhlLWsFXLdRSPYNZ34YQeZ/s72-c/thread-stack.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-947269866336625127.post-6395843703417422448</id><published>2010-03-23T11:43:00.000-07:00</published><updated>2011-08-02T11:44:02.688-07:00</updated><title type='text'>Understanding Impersonation</title><content type='html'>&lt;h1&gt;Understanding Impersonation&lt;/h1&gt; &lt;br /&gt;
&lt;h2&gt;Process Token&lt;/h2&gt; Whenever a process is created, its process access token is also created in the kernel. This process token is used when access permission check is required. Roughly speaking, process token is the user identity of the process. For example, if the process tries to access system resources such as registry or file, the process shows its process token and the operating system checks access permission by using security descriptor (SD) of the system resources. SD contains the complete list of who is allowed and who is denied. Generally, all threads in the process inherit the process token, “unless” thread is impersonating.&lt;br /&gt;
&lt;br /&gt;
 Let’s take an example. I ran SQL Configuration Manager, attached the debugger and picked one of threads (thread#1).  To inspect the thread token, switch to the thread#1 and run !token –n.&lt;br /&gt;
&lt;pre style=&quot;padding-left:30px;&quot;&gt;0:000&amp;gt;  ~1s&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;0:001&amp;gt;  !token -n&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;&lt;strong&gt;Thread is not impersonating. Using process token...&lt;/strong&gt;&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;TS Session ID: 0x1&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;User: S-1-5-21-2127521184-1604012920-1887927527-570548 (User: TDomain\yongslee)&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;Groups:&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;00 S-1-5-21-2127521184-1604012920-1887927527-513 (Group: TDomain\Domain Users)&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;Attributes - Mandatory Default Enabled&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;01 S-1-1-0&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;Attributes - Mandatory Default Enabled&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;.....&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;.....   &lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;&lt;strong&gt;Impersonation Level: Anonymous&lt;/strong&gt;&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;&lt;strong&gt;TokenType: Primary&lt;/strong&gt;&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;Is restricted token: no.&lt;/pre&gt;As bold-face text says, the thread is not impersonating any and using primary access token which is the process token.&lt;br /&gt;
&lt;h2&gt;Impersonation and Thread Token&lt;/h2&gt; Sometimes thread might need to impersonate other user. This basically means that the thread does not use process access token and rather uses different user token. This scenario often occurs when client is accessing server resources. To access server resources, the server code impersonates (and acts as) the client identity and performs resource access with it. If the client user doesn’t have permission to access server resource, it throws access denied.&lt;br /&gt;
&lt;br /&gt;
To see how it works, let’s run SQL Configuration Manager and invoke SQL WMI provider.  &lt;a title=&quot;SQL WMI Provider&quot; href=&quot;http://yongslee.wordpress.com/2010/02/15/sql-wmi-provider/&quot; target=&quot;_blank&quot;&gt;SQL WMI provider &lt;/a&gt;is run as Network Service account in the wmiprvse.exe process and thus its process token is representing Network Service. WMI providers are typically using impersonation so we expect that worker thread in WMI provider is using client account, not Network Service. If worker thread uses Network Service, it might be a big security hole.&lt;br /&gt;
&lt;br /&gt;
(1)    Run SQL Configuration Manager (SQLCM)&lt;br /&gt;
&lt;p style=&quot;padding-left:30px;&quot;&gt;=&amp;gt;  Whenever SQLCM is launched, new SQL WMI provider process (wmiprvse) will be created (if already doesn’t exist)&lt;/p&gt;&lt;p style=&quot;padding-left:30px;&quot;&gt;=&amp;gt;  Run tlist.exe to find SQL WMI provider&lt;/p&gt;&lt;p style=&quot;padding-left:30px;&quot;&gt;C&amp;gt; tlist –m sqlmgmprovider.dll&lt;/p&gt; &lt;br /&gt;
&lt;br /&gt;
(2)    Attach to SQL WMI provider by using windbg&lt;br /&gt;
&lt;br /&gt;
         C&amp;gt; windbg –p 2202   (ex: 2202 = pid of wmiprvse.exe)&lt;br /&gt;
&lt;br /&gt;
(3)    Set breakpoint in one of SQL WMI classes. Let’s try SqlServiceAdvancedProperty.&lt;br /&gt;
&lt;br /&gt;
          To break in when Advanced properties is clicked, set bp against this method and keep debugger going.&lt;br /&gt;
&lt;pre style=&quot;padding-left:30px;&quot;&gt;0:011&amp;gt; bp sqlmgmprovider!SqlServiceAdvancedProperty::EnumerateInstances&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;0:011&amp;gt; g&lt;/pre&gt;(4)    In SQLCM, select SQL Server Services -&amp;gt; doubleclick SQL Server (MSSQLSERVER) to bring up the Properties page -&amp;gt; Click Advanced tab to display advanced properties. (This will call SqlServiceAdvancedProperty:: EnumerateInstances method in  SQL WMI provider)&lt;br /&gt;
&lt;br /&gt;
Now,  breakpoint will be hit and we can check thread token by using !token command.&lt;br /&gt;
&lt;pre style=&quot;padding-left:30px;&quot;&gt;Breakpoint 0 hit&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;eax=541c1d58 ebx=80041024 ecx=54214588 edx=6d599bc9 esi=54214588 edi=0095e3c8&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;eip=541def70 esp=00deefb8 ebp=00deefc8 iopl=0         nv up ei pl zr na pe nc&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;sqlmgmprovider!SqlServiceAdvancedProperty::EnumerateInstances:&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;541def70 8bff            mov     edi,edi&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;0:007&amp;gt; !token -n&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;TS Session ID: 0x1&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;User: S-1-5-21-2127521184-1604012920-1887927527-570548 (User: &lt;strong&gt;TDomain\yongslee&lt;/strong&gt;)&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;Groups:&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;00 S-1-5-21-2127521184-1604012920-1887927527-513 (Group: TDomain\Domain Users)&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;Attributes - Mandatory Default Enabled&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;....&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;Primary Group: S-1-5-21-2127521184-1604012920-1887927527-513 (Group: TDomain\Domain Users)&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;Privs:&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;…&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;15 0x000000017 SeChangeNotifyPrivilege           Attributes - Enabled Default&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;19 0x00000001d SeImpersonatePrivilege            Attributes - Enabled Default&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;20 0x00000001e SeCreateGlobalPrivilege           Attributes - Enabled Default&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;Auth ID: 0:5eeba&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;&lt;strong&gt;Impersonation Level: Impersonation&lt;/strong&gt;&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;&lt;strong&gt;TokenType: Impersonation&lt;/strong&gt;&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;Is restricted token: no.&lt;/pre&gt;The thread token here is impersonating and acts as TDomain\yongslee, not using Network Service. Please note this user is the same one that invoked SQLCM process. So even if the SQL WMI provider process is run as Network Service, actual worker thread is using the client user principal that makes WMI request. If the client application is run in low privilege account and the account cannot access system resource such as registry, the WMI request accessing registry resource won’t be successful.&lt;br /&gt;
&lt;h2&gt;Impersonation in SQL WMI&lt;/h2&gt;Then how can the worker thread in SQL WMI provider impersonate the client principal? It is using internally WbemCoImpersonateClient method in WMI framework API. Before this method is called, the worker thread is using process token (Network Service). Once the WbemCoImpersonateClient is executed, the thread acquires impersonation token.&lt;br /&gt;
&lt;pre style=&quot;padding-left:30px;&quot;&gt;0:010&amp;gt; bp framedyn!WbemCoImpersonateClient&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;0:010&amp;gt; g&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;framedyn!WbemCoImpersonateClient:&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;0:007&amp;gt; !token –n    &lt;strong&gt;//Check token before impersonation&lt;/strong&gt;&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;&lt;strong&gt;Thread is not impersonating. Using process token...&lt;/strong&gt;&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;TS Session ID: 0&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;User: S-1-5-20 (Well Known Group: &lt;strong&gt;NT AUTHORITY\NETWORK SERVICE&lt;/strong&gt;)&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;.....&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;Impersonation Level: Anonymous&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;TokenType: Primary&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;Is restricted token: no.&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;0:007&amp;gt; gu            &lt;strong&gt;// Execute WbemCoImpersonateClient()&lt;/strong&gt;&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;framedyn!CWbemProviderGlue::CheckImpersonationLevel+0x39:&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;0:007&amp;gt; !token –n    &lt;strong&gt; // Check token after impersonation&lt;/strong&gt;&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;TS Session ID: 0x1&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;User: S-1-5-21-2127521184-1604012920-1887927527-570548 (User: &lt;strong&gt;TDomain\yongslee&lt;/strong&gt;)&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;.....&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;&lt;strong&gt;Impersonation Level: Impersonation&lt;/strong&gt;&lt;/pre&gt;&lt;pre style=&quot;padding-left:30px;&quot;&gt;&lt;strong&gt;TokenType: Impersonation&lt;/strong&gt;&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://debugbeyond.blogspot.com/feeds/6395843703417422448/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://debugbeyond.blogspot.com/2010/03/understanding-impersonation.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default/6395843703417422448'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/947269866336625127/posts/default/6395843703417422448'/><link rel='alternate' type='text/html' href='http://debugbeyond.blogspot.com/2010/03/understanding-impersonation.html' title='Understanding Impersonation'/><author><name>Alex</name><uri>http://www.blogger.com/profile/14466854366502861778</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>