Retired Microsoft Blog disclaimer

This directory is a mirror of retired "Decrypt My World" MSDN blog and is provided as is. All posting authorship and copyrights belong to respective authors.

Posts on this page:

Original URL: https://blogs.msdn.microsoft.com/alejacma/2009/09/29/how-to-timestamp-authenticode-signatures-when-our-proxy-requires-authentication/
Post name: How to timestamp Authenticode signatures when our proxy requires authentication
Original author: Alejandro Campos Magencio
Posting date: 2009-09-29T06:47:00+00:00


Hi all,


The other day a customer of minewas trying to add an Authenticode signature with timestamp to their PowerShell scripts with PowerShell itselfand its Set-AuthenticodeSignature cmdlet. He was able to sign the scripts just fine, but when using the timestamp option the cmdlet was not honoring Internet Explorer Proxy settings and the timestamping process failed.


If you have never seen how to add such a signature with PowerShell, check the following sample:


First we can create a test certificate in i.e. a cmd.exe:

c:\>makecert -n "CN=PowerShell Local Certificate Root" -a sha1 -eku 1.3.6.1.5.5.7.3.3 -r -sv root.pvk root.cer -ss Root -sr localMachine
c:\>makecert -pe -n "CN=Powershell User" -ss MY -a sha1 -eku 1.3.6.1.5.5.7.3.3 -iv root.pvk -ic root.cer

Then we can create a signature with timestamp in PowerShell:

C:\PS>$cert=Get-ChildItem -Path cert:\CurrentUser\my -CodeSigningCert
C:\PS>Set-AuthenticodeSignature -filepath c:\notepad.exe -certificate $cert -IncludeChain All -TimeStampServer "http://timestamp.globalsign.com/scripts/timstamp.dll"

Additionally, remember that we have several other ways to do Authenticode signing as I already commented here:


How to sign EXE files with an Authenticode certificate (VB.NET)


How to sign EXE files with an Authenticode certificate (part 2)


So my customer tried to use signtool.exe instead, with the same results: IE proxy settings are not getting used at all and they get an error like the following:

C:\Program Files\Microsoft SDKs\Windows\v6.1\Bin>signtool timestamp /v /t http://timestamp.globalsign.com/scripts/timstamp.dll c:\notepad.exe

Timestamping: c:\notepad.exe
SignTool Error: The specified timestamp server could not be reached.
SignTool Error: An error occurred while attempting to timestamp: c:\notepad.exe

Number of files successfully timestamped: 0
Number of errors: 1



Note that if we open Internet Explorer and enter http://timestamp.globalsign.com/scripts/timstamp.dll into the address bar, IE presents the credentials dialog box to send to the proxy and we can access the timestamp server without problems.



The cause of this issue is the following:


All signingmethods we saw in my previous posts (SignTool, CAPICOM, etc.) end up using SignerSignEx API to sign, and SignerTimeStampEx API to timestamp the signature. The same applies to PowerShell's Set-AuthenticodeSignature cmdlet.


SignerTimeStampEx will connect to the remote timestamp server in a very simple way, without using any proxy info or user credentials. And this is not configurable in any way.


So I'm afraid all signing methods we have at our disposal suffer from this limitation in the API.



In order to timestamp code, it is necessary to have unrestricted access to the Internet.




I hope this helps.


Regards,



Alex (Alejandro Campos Magencio)


Original URL: https://blogs.msdn.microsoft.com/alejacma/2009/09/29/managed-debugging-with-windbg-locks/
Post name: MANAGED DEBUGGING with WINDBG. Locks
Original author: Alejandro Campos Magencio
Posting date: 2009-09-29T04:19:00+00:00


Hi all,

This post is a continuation of MANAGED DEBUGGING with WINDBG. Breaking on an Exception. Part 2.

LOCKS

· We can see threads waiting for managed locks:

All managed objects have a syncblock (4 bytes) before their Method Table and properties. It can hold locking information for thread-safe operations. All syncblocks being used are stored in a table. A class like System.Threading.Monitor will use them to synchronize access to resources.

With this command we get the Index of the syncblock in the table, the address of the syncblock, the thread holding it & the object which syncblock we are waiting for. Let’s take a look to this sample:

0:006> !SyncBlk

Index SyncBlock MonitorHeld Recursion Owning Thread Info SyncBlock Owner

19 00358ddc 5 2 0032c848 ca8 0 01a2d45c System.Object

-----------------------------

Total 23

CCW 0

RCW 0

ComClassFactory 0

Free 0

Thread 0 is holding another 2 threads (MonitorHeld = 1 for each owner and 2 for each waiter) with a synchronization object.

We can analyze the thread call stacks and see which threads may be held by thread 0:

0:006> ~*kpL

...

4 Id: 1868.ac Suspend: 1 Teb: 7ffdb000 Unfrozen

ChildEBP RetAddr

0461e89c 77550690 ntdll!KiFastSystemCallRet(void)

0461e8a0 76207e09 ntdll!ZwWaitForMultipleObjects(void)+0xc

0461e93c 79ed98fd KERNEL32!WaitForMultipleObjectsEx(unsigned long nCount = 0x461e8f0, void ** lpHandles = 0x00358df0, int bWaitAll = 0, unsigned long dwMilliseconds = 0xffffffff, int bAlertable = 1)+0x11d

0461e9a4 79ed9889 mscorwks!WaitForMultipleObjectsEx_SO_TOLERANT(unsigned long nCount = 1, void ** lpHandles = 0x00358df0, int bWaitAll = 0, unsigned long dwMilliseconds = 0xffffffff, int bAlertable = 1)+0x6f

0461e9c4 79ed9808 mscorwks!Thread::DoAppropriateAptStateWait(int numWaiters = 1, void ** pHandles = 0x00358df0, int bWaitAll = 0, unsigned long timeout = 0xffffffff, WaitMode mode = WaitMode_Alertable (1))+0x3c

0461ea48 79ed96c4 mscorwks!Thread::DoAppropriateWaitWorker(int countHandles = 1, void ** handles = 0x00358df0, int waitAll = 0, unsigned long millis = 0xffffffff, WaitMode mode = WaitMode_Alertable (1))+0x13c

0461ea98 79ed9a62 mscorwks!Thread::DoAppropriateWait(int countHandles = 1, void ** handles = 0x00358df0, int waitAll = 0, unsigned long millis = 0xffffffff, WaitMode mode = WaitMode_Alertable (1), struct PendingSync * syncState = 0x00000000)+0x40

0461eaf4 79e78944 mscorwks!CLREvent::WaitEx(unsigned long dwMilliseconds = 0xffffffff, WaitMode mode = WaitMode_Alertable (1), struct PendingSync * syncState = 0x00000000)+0xf7

0461eb08 79ed7b37 mscorwks!CLREvent::Wait(unsigned long dwMilliseconds = 0xffffffff, int alertable = 1, struct PendingSync * syncState = 0x00000000)+0x17

0461eb94 79ed7a9e mscorwks!AwareLock::EnterEpilog(class Thread * pCurThread = 0x00386aa0, int timeOut = -1)+0x8c

0461ebb0 79ebd7e4 mscorwks!AwareLock::Enter(void)+0x61

0461ec50 0080201c mscorwks!JIT_MonEnterWorker_Portable(class Object * obj = 0x00386aa0)+0xb3

0461ec70 793b0d1f WindowsApplication1!WindowsApplication1.Form1.Run8(<HRESULT 0x80004001>)+0x24

...

5 Id: 1868.1fa8 Suspend: 1 Teb: 7ffd9000 Unfrozen

ChildEBP RetAddr

0446eac4 77550690 ntdll!KiFastSystemCallRet(void)

0446eac8 76207e09 ntdll!ZwWaitForMultipleObjects(void)+0xc

0446eb64 79ed98fd KERNEL32!WaitForMultipleObjectsEx(unsigned long nCount = 0x446eb18, void ** lpHandles = 0x00358df0, int bWaitAll = 0, unsigned long dwMilliseconds = 0xffffffff, int bAlertable = 1)+0x11d

0446ebcc 79ed9889 mscorwks!WaitForMultipleObjectsEx_SO_TOLERANT(unsigned long nCount = 1, void ** lpHandles = 0x00358df0, int bWaitAll = 0, unsigned long dwMilliseconds = 0xffffffff, int bAlertable = 1)+0x6f

0446ebec 79ed9808 mscorwks!Thread::DoAppropriateAptStateWait(int numWaiters = 1, void ** pHandles = 0x00358df0, int bWaitAll = 0, unsigned long timeout = 0xffffffff, WaitMode mode = WaitMode_Alertable (1))+0x3c

0446ec70 79ed96c4 mscorwks!Thread::DoAppropriateWaitWorker(int countHandles = 1, void ** handles = 0x00358df0, int waitAll = 0, unsigned long millis = 0xffffffff, WaitMode mode = WaitMode_Alertable (1))+0x13c

0446ecc0 79ed9a62 mscorwks!Thread::DoAppropriateWait(int countHandles = 1, void ** handles = 0x00358df0, int waitAll = 0, unsigned long millis = 0xffffffff, WaitMode mode = WaitMode_Alertable (1), struct PendingSync * syncState = 0x00000000)+0x40

0446ed1c 79e78944 mscorwks!CLREvent::WaitEx(unsigned long dwMilliseconds = 0xffffffff, WaitMode mode = WaitMode_Alertable (1), struct PendingSync * syncState = 0x00000000)+0xf7

0446ed30 79ed7b37 mscorwks!CLREvent::Wait(unsigned long dwMilliseconds = 0xffffffff, int alertable = 1, struct PendingSync * syncState = 0x00000000)+0x17

0446edbc 79ed7a9e mscorwks!AwareLock::EnterEpilog(class Thread * pCurThread = 0x0038ec10, int timeOut = -1)+0x8c

0446edd8 79f59024 mscorwks!AwareLock::Enter(void)+0x61

0446ee40 79fc6352 mscorwks!AwareLock::Contention(int timeOut = -1)+0x199

0446eee0 0080201c mscorwks!JITutil_MonContention(class AwareLock * lock = 0x00358ddc)+0xa3

0446ef00 793b0d1f WindowsApplication1!WindowsApplication1.Form1.Run8(<HRESULT 0x80004001>)+0x24

...

0:006> ~4e !CLRStack -p

OS Thread Id: 0xac (4)

ESP EIP

0461eb30 77550f34 [GCFrame: 0461eb30]

0461ec00 77550f34 [HelperMethodFrame_1OBJ: 0461ec00] System.Threading.Monitor.Enter(System.Object)

0461ec58 0080201c WindowsApplication1.Form1.Run8()

...

So thread 5 is indeed waiting for our problematic syncblock, and I guess thread 4, too. But I couldn’t see any reference to the syncblock or the related object in the parameters of the call stack of thread 4. Well, the object we used with Monitor.Enter should be near the top of the stack of the thread, as we passed it as a parameter to the managed function at the top of the managed call stack:

0:006> ~4e !dso

OS Thread Id: 0xac (4)

ESP/REG Object Name

0461eb68 01a2d45c System.Object

0461ebc0 01a2d45c System.Object

0461ebd4 01a2d45c System.Object

0461ec30 01a669a4 System.Threading.ThreadStart

0461ec3c 01a2d45c System.Object

0461ec58 01a669fc System.Threading.ThreadHelper

...

And indeed it is, so both threads 4 & 5 are the ones being held by thread 0.

· We can see threads waiting for unmanaged locks:

A class like System.Threading.Mutex is not based on syncblocks, but on kernel mutexes instead. When not working with syncblocks, we can use the same unmanaged commands we’ll use with any unmanaged app:

0:006> !locks

0:006> !critsec

0:006> !SIEExtPub.critlist

Index: MANAGED DEBUGGING with WINDBG. Introduction and Index.

Note: this is the last post on the MANAGED DEBUGGING with WINDBG series. I hope my posts help you the same way they help me in my everyday work.

Regards,

Alex (Alejandro Campos Magencio)

Original URL: https://blogs.msdn.microsoft.com/alejacma/2009/09/29/managed-debugging-with-windbg-breaking-on-an-exception-part-2/
Post name: MANAGED DEBUGGING with WINDBG. Breaking on an Exception. Part 2
Original author: Alejandro Campos Magencio
Posting date: 2009-09-29T04:07:00+00:00


Hi all,

This post is a continuation of MANAGED DEBUGGING with WINDBG. Breaking on an Exception. Part 1.

BREAKING ON AN EXCEPTION. Part 2

What happens if !PrintException doesn’t return anything, or when we break (i.e. with a breakpoint or manually – Ctrl+Break) we can’t see mscorwks!RaiseTheExceptionInternalOnly in the call stack? What if we already missed the exception when we break?


We could still find the exception near the top of the managed stack of the current thread:

0:000> !DumpStackObjects

...

0:000> !dso

OS Thread Id: 0x15e4 (0)

ESP/REG Object Name

0020eb50 0195fe94 System.IndexOutOfRangeException

0020eb98 0195fe94 System.IndexOutOfRangeException

0020ebdc 01929a04 WindowsApplication1.Form1

0020ebe0 01941958 System.Int32[]

...

0:000> !pe 0x0195fe94

...

If not, we can try to find significant exceptions in the managed heap, as all recent exceptions are stored there:

0:000> !DumpHeap -type Exception

Address MT Size

01991024 790fe044 72

0199106c 790fe0e0 72

019910b4 790fe17c 72

019910fc 790fe284 72

01991144 790fe284 72

0199f848 79103c58 12

0199f860 79103ca4 12

019df490 79117f8c 72

019fc5c8 79117f8c 72

total 9 objects

Statistics:

MT Count TotalSize Class Name

79103ca4 1 12 System.Text.DecoderExceptionFallback

79103c58 1 12 System.Text.EncoderExceptionFallback

790fe17c 1 72 System.ExecutionEngineException

790fe0e0 1 72 System.StackOverflowException

790fe044 1 72 System.OutOfMemoryException

79117f8c 2 144 System.IndexOutOfRangeException

790fe284 2 144 System.Threading.ThreadAbortException

Total 9 objects

0:000> !DumpHeap -mt 79117f8c

Address MT Size

019df490 79117f8c 72

019fc5c8 79117f8c 72

total 2 objects

Statistics:

MT Count TotalSize Class Name

79117f8c 2 144 System.IndexOutOfRangeException

Total 2 objects

0:000> !pe 019df490

...

0:000> !pe 019fc5c8

...

We can also do the following to find all exceptions of a given type in the managed heap:

0:000> .foreach(ex {!dumpheap -type System.IndexOutOfRangeException -short}){!pe ex;.echo *************}

Exception object: 019df490

Exception type: System.IndexOutOfRangeException

Message: Index was outside the bounds of the array.

InnerException: <none>

StackTrace (generated):

SP IP Function

0017EE80 00861AAD WindowsApplication1!WindowsApplication1.Form1.PlayWithArray(Int32[])+0x55

StackTraceString: <none>

HResult: 80131508

*************

Exception object: 019fc5c8

Exception type: System.IndexOutOfRangeException

Message: Index was outside the bounds of the array.

InnerException: <none>

StackTrace (generated):

<none>

StackTraceString: <none>

HResult: 80131508

*************

Note that exception objects are normally created when they are needed. But there are a few exception objects which are created when process starts as they can’t be created when they need to be raised: OutOfMemoryException, ExecutionEngineException, StackOverflowException. So we will always see these exceptions in the heap. That doesn’t mean that they were ever raised.

· We can inspect the method where we got the exception:

We can get i.e. the source code line which failed:

0:000> !pe 019df490

Exception object: 019df490

Exception type: System.IndexOutOfRangeException

Message: Index was outside the bounds of the array.

InnerException: <none>

StackTrace (generated):

SP IP Function

0017EE80 00861AAD WindowsApplication1!WindowsApplication1.Form1.PlayWithArray(Int32[])+0x55

StackTraceString: <none>

HResult: 80131508

0:000> !u 00861AAD

Normal JIT generated code

WindowsApplication1.Form1.PlayWithArray(Int32[])

Begin 00861a58, size c0

00861a58 55 push ebp

...

00861aa3 3b5104 cmp edx,dword ptr [ecx+4]

00861aa6 7205 jb WindowsApplication1!WindowsApplication1.Form1.PlayWithArray(Int32[])+0x55 (00861aad)

00861aa8 e8d67e8c79 call mscorwks!JIT_RngChkFail (7a129983)

>>> 00861aad 03449108 add eax,dword ptr [ecx+edx*4+8]

00861ab1 7105 jno WindowsApplication1!WindowsApplication1.Form1.PlayWithArray(Int32[])+0x60 (00861ab8)

00861ab3 e8837f8c79 call mscorwks!JIT_Overflow (7a129a3b)

...

00861b16 5d pop ebp

00861b17 c3 ret

0:000> u 00861aa8

WindowsApplication1!WindowsApplication1.Form1.PlayWithArray(Int32[])+0x50 [C:\__WORKSHOP\Demos\BuggyNETApp\Form1.vb @ 135]:

00861aa8 e8d67e8c79 call mscorwks!JIT_RngChkFail (7a129983)

...

Note that not all exceptions we saw have the StackTrace field set. I’ve seen that when the debugger just breaks on an exception, the field is empty. Once we go beyond that point and we i.e. enter the “catch” section of the “try{}catch(){}” statement in the code, that field is set.

But if we just broke on an exception, we can still see the call stack with k, !CLRStack, !DumpStack and related commands as we saw in the Call Stack section before, and get the instruction pointer (IP) we need from there.

· We can stop breaking on CLR exceptions:

If we don’t want to break on any other CLR exception we do the following:

0:000> sxn clr

If we were breaking on specific exception types (!StopOnException) before, and we stop breaking on all CLR exceptions, we will still see those exceptions in the debugger:

0:000> g

(1728.1f58): C++ EH exception - code e06d7363 (first chance)

(1728.1f58): CLR exception - code e0434f4d (first chance)

'System.IndexOutOfRangeException hit'

Next post: MANAGED DEBUGGING with WINDBG. Locks.

Index: MANAGED DEBUGGING with WINDBG. Introduction and Index.

Regards,

Alex (Alejandro Campos Magencio)

Original URL: https://blogs.msdn.microsoft.com/alejacma/2009/09/01/subauthentication-package-gets-zero-logonid/
Post name: SubAuthentication package gets Zero LogonId
Original author: Alejandro Campos Magencio
Posting date: 2009-09-01T09:08:00+00:00


Hi all,

The other day I worked on an issue related to a SubAuthentication package that one of my customers had developed. One of the things that package was doing was getting the LogonId field of the LogonInformation struct being passed to Msv1_0SubAuthenticationFilter method by the Authentication package.

This SubAuth package had been working fine on i.e. Windows XP, but when doing interactive logon on a Windows Server 2003 Domain Controller, LogonId field was always set to Zero. But doing i.e. Network logon on the same DC returned a valid LogonId value. Why?

I debugged the issue and I found out what was going on.

SubAuth packages can only get called by the following Authentication packages: Kerberos or MSV1_0/NTLM.

MSV1_0 (MICROSOFT_AUTHENTICATION_PACKAGE_V1_0) package will provide our SubAuth dll with LogonId info, while Kerberos package won’t. Kerberos ignores LogonId on purpose. This is by design and happens in all versions of Windows.

So every time we get a valid LogonId, it is because logon is taking place through MSV1_0 Auth package. Note that LogonId is just a local ID on the machine and it's not of actual use for SubAuth packages. The purpose of SubAuth packages is not for capturing or tracking logon activities.

SubAuth package supplements part of the authentication and validation criteria used by the main Auth package. It can enforce additional restrictions to the authentication sequence when the DLL is registered under Auth0 registry value for MSV1_0 or Kerberos.

SubAuth package (Msv1_0SubAuthenticationFilter) will get called only after the corresponding Windows logon authentication is successful. The built-in Auth packages get first chance at logon authentication, before SubAuth DLL code gets invoked.

For domain user logon authentication, SubAuth DLLs installed on the DCs of that domain will be called. For local user logon authentication, SubAuth DLLs installed on that member machine will be called.

If you are simply tracking logon events, you would need to enable Auditing Account Logon and look for events logged in the Security Event Log. Audit logon events and Audit account logon events provide tracking of logons at workstations, servers, and DCs (see Audit Account Logon Eventsfor details).

Then an application may get those events programmatically with i.e. WMI and its Win32_NTLogEvent class. I’ve seen people using this idea, for instance here.


There is one thing left to explain. Why is Kerberos always getting used on the DC when doing Interactive logon? We've already seen the Auth packages that can get used, and according to MSDN:

Kerberos
"
The Kerberos authentication package is used when logging on to a network; local logons are handled by MSV1_0.
"

MSV1_0
"
MSV1_0 also supports domain logons. MSV1_0 processes domain logons using pass-through authentication
"

Summing up, MSV1_0 deals with local logons and both MSV1_0 and Kerberos with network logons.

Now, whether Negotiate/Kerberos or NTLM/MSV1_0 is used for network logon depends on the client machine and the component that is doing the authentication. Windows logon components will always attempt to use Kerberos if they can, if there is an SPN (Service Principal Name) for the target name specified. For example,if you are accessing a server say MYSERVER that requires windows authentication and you want to use Kerberos, you have to supply a name that matches an SPN defined on the server account such as MYSERVER.MYDOMAIN.COM. Just specifying MYSERVER may use NTLM if there is no matching SPN. If there is no matching SPN, Kerberos will fall-back to NTLM.

So in my customer's environment we ended up using NTLM/MSV1_0 with network logons and most of local logons, thus getting a valid LogonId thanks to MSV1_0 Auth package.

Now, the exception for local logons are the DCs. Local logon is for local accounts only and not for AD (Active Directory) accounts. Doing an Interactive logon on a DC is not considered a local logon. Because of that we try to use Negotiate/Kerberos first as expected, and we just succeed. And we don't get LogonId because Kerberos Auth package won't provide us with it.

I hope this helps.
Regards,

Alex (Alejandro Campos Magencio)

Original URL: https://blogs.msdn.microsoft.com/alejacma/2009/08/24/managed-debugging-with-windbg-breaking-on-an-exception-part-1/
Post name: MANAGED DEBUGGING with WINDBG. Breaking on an Exception. Part 1
Original author: Alejandro Campos Magencio
Posting date: 2009-08-24T05:57:00+00:00


Hi all,

This post is a continuation of MANAGED DEBUGGING with WINDBG. Managed Heap. Part 5.

BREAKING ON AN EXCEPTION. Part 1

We can only break on exceptions when doing live debugging, but many of the commands explained here can be used when doing dump analysis, too.

· Exceptions we may get in .NET applications:

§ CLR exception (0xe0434f4d).

§ Stack Overflow exception (0x800703e9).

§ Access Violation (0xc0000005).

§ Integer divide-by-zero exception (0xc0000094).

§ ...

§ Fatal Execution Engine Error (<address of failure>). This normally indicates a bug in CLR or NT Heap corruption when doing P/Invoke with not big enough buffers. The address associated to this exception will tell us where in the code the issue happened.

The debugger will break by default when the process raises most of these exception types, but not on CLR exceptions, for instance.

In ASP.NET, if exceptions are raised in managed threads and they are unhandled, Global Error Handle catches them. But if they are raised in another thread like Timer or Finalizer threads, we will crash the process (it will be recycled).

· We can break on any CLR exception:

When our code raises a CLR exception, we see the following line in the debugger:

(1728.1f58): CLR exception - code e0434f4d (first chance)

Unmanaged world doesn’t know about specific CLR exception types, so all of them are raised with the same exception code: 0xe0434f4d.

As we’ve seen, WinDbg won’t break on any CLR exception by default, as they may be expected. We can break on all CLR exceptions with any of these commands:

0:000> sxe clr

0:000> sxe 0xe0434f4d

And when we break we’ll see something like this:

0:000> g

(1728.1f58): C++ EH exception - code e06d7363 (first chance)

(1728.1f58): CLR exception - code e0434f4d (first chance)

First chance exceptions are reported before any exception handling.

This exception may be expected and handled.

eax=002de8e0 ebx=e0434f4d ecx=00000001 edx=00000000 esi=002de968 edi=0047c600

eip=77a1b09e esp=002de8e0 ebp=002de930 iopl=0 nv up ei pl nz ac po nc

cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000212

KERNEL32!RaiseException+0x58:

77a1b09e c9 leave

· We can break on a specific CLR exception type:

If we know the exact exception type, we can do the following:

0:004> !StopOnException -create System.IndexOutOfRangeException 1

Breakpoint set

0:004> !soe -create System.IndexOutOfRangeException 1

Breakpoint set

And when we break we’ll see something like this:

0:000> g

(1728.1f58): C++ EH exception - code e06d7363 (first chance)

(1728.1f58): CLR exception - code e0434f4d (first chance)

'System.IndexOutOfRangeException hit'

First chance exceptions are reported before any exception handling.

This exception may be expected and handled.

...

77a1b09e c9 leave

We can also stop only on those exceptions which type derives from a given one:

0:004> !soe -derived -create System.SystemException 1

Breakpoint set

· When we break, we can inspect the CLR exception:

Let’s take a look to the call stack of the thread which raised the exception when the debugger breaks:

0:000> kpL

ChildEBP RetAddr

002de930 79f071ac KERNEL32!RaiseException(unsigned long dwExceptionCode = 0xe0434f4d, unsigned long dwExceptionFlags = 1, unsigned long nNumberOfArguments = 1, unsigned long * lpArguments = 0x002de968)+0x58

002de990 79f9293a mscorwks!RaiseTheExceptionInternalOnly(class Object * throwable = 0x01940e4c, int rethrow = 0, int fForStackOverflow = 0)+0x2a8

002de9c8 7a129a34 mscorwks!UnwindAndContinueRethrowHelperAfterCatch(class Frame * pEntryFrame = 0x002dea20, class Exception * pException = 0x004d2aa8)+0x70

002dea68 00b81aad mscorwks!JIT_RngChkFail(void)+0xb0

002deab0 00b819fe WindowsApplication1!WindowsApplication1.Form1.PlayWithArray(<HRESULT 0x80004001>)+0x55

KERNEL32!RaiseException raises the generic CLR exception (0xe0434f4d) to the unmanaged world, but the specific exception we are getting is the one that mscorwks!RaiseTheExceptionInternalOnly raises. We can inspect that specific exception as any other .NET object:

0:000> !DumpObj 0x0195fe94

...

0:000> !do 0x0195fe94

Name: System.IndexOutOfRangeException

MethodTable: 79117f8c

EEClass: 79117f1c

Size: 72(0x48) bytes

(C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)

Fields:

MT Field Offset Type VT Attr Value Name

790fd8c4 40000b5 4 System.String 0 instance 00000000 _className

7910ebc8 40000b6 8 ...ection.MethodBase 0 instance 00000000 _exceptionMethod

790fd8c4 40000b7 c System.String 0 instance 00000000 _exceptionMethodString

790fd8c4 40000b8 10 System.String 0 instance 01935108 _message

79116114 40000b9 14 ...tions.IDictionary 0 instance 00000000 _data

790fdf04 40000ba 18 System.Exception 0 instance 00000000 _innerException

790fd8c4 40000bb 1c System.String 0 instance 00000000 _helpURL

790fd0f0 40000bc 20 System.Object 0 instance 00000000 _stackTrace

790fd8c4 40000bd 24 System.String 0 instance 00000000 _stackTraceString

...

79102290 40000c1 38 System.Int32 0 instance -2146233080 _HResult

790fd8c4 40000c2 30 System.String 0 instance 00000000 _source

...

0:000> !do 01935108

Name: System.String

MethodTable: 790fd8c4

EEClass: 790fd824

Size: 102(0x66) bytes

(C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)

String: Index was outside the bounds of the array.

Fields:

...

Or we can inspect the exception in a more user friendly way:

0:000> !PrintException 0x0195fe94

...

0:000> !pe 0x0195fe94

Exception object: 0195fe94

Exception type: System.IndexOutOfRangeException

Message: Index was outside the bounds of the array.

InnerException: <none>

StackTrace (generated):

<none>

StackTraceString: <none>

HResult: 80131508

We can save some time if we directly inspect the last thrown exception on the current thread:

0:000> !pe

Exception object: 0195fe94

Exception type: System.IndexOutOfRangeException

Message: Index was outside the bounds of the array.

InnerException: <none>

StackTrace (generated):

<none>

StackTraceString: <none>

HResult: 80131508

Next post: MANAGED DEBUGGING with WINDBG. Breaking on an Exception. Part 2.

Index: MANAGED DEBUGGING with WINDBG. Introduction and Index.

Regards,

Alex (Alejandro Campos Magencio)