Welcome to TechNet Blogs Sign in | Join | Help

Mfartura's blog

Marcelo Fartura's blog about debugging and general troubleshooting
How to manually translate virtual addresses into physical ones

In previous posts we talked about virtual address space and how virtual memory is managed.  I've never posted anything about virtual address translation though, and for the ones interested on the details behing this operation I recommend reading the chapter 7 - Memory Management (specifically the Address Translation section) of the Windows Internals 4th Edition book.  So I won't go too deep on the details of how the system does the translation itself, my goal here is just how to show you how easily translate from one address to another once you have a memory dump or a live debugging session.

Once you choose the virtual address you want to do the translation the first step is to run the command !pte and find out some additional information for the corresponding PTE.  For this example I'm going to use the virtual address used as a base address to load the tcpip driver itself on a 32-bit Windows 2003 SP2 system:

 

0: kd> lmvm tcpip

start    end        module name

f7625000 f7686000   tcpip      (deferred)            

    Image path: \SystemRoot\system32\DRIVERS\tcpip.sys

    Image name: tcpip.sys

    Timestamp:        Thu Mar 24 19:40:31 2005 (42435DFF)

    CheckSum:         0005606F

    ImageSize:        00061000

Above highlighted in yellow we have the base address where the tcpip driver has been loaded (virtual address).  Now we run the command !pte passing this address as an argument:

0: kd> !pte f7625000

               VA f7625000

PDE at   C0300F74        PTE at C03DD894

contains 00ACC963      contains 1C055963

pfn acc -G-DA--KWEV    pfn 1c055 -G-DA—KWEV

 

The highlighted information above is about the PFN correlated to the physical address associated with the  virtual address we passed as an input to !pte.  However you noticed that 1c055 uses up to 20 bits (which are used to locate the PDE and PTE itself which will point to the physical page) and we know the completed addresses are 32 bits wide.  The last 12 bits on the translation process are used as a byte index to the physical page where the content is actually stored, so they come straight from the virtual address.

 

The final physical address will then be 1c055 followed by the last 12 bits of the virtual address which in this case is 000.  So putting them together we have that 1c055000 is the physical address correlated to the virtual address f7652000.  Let’s verify that by dumping both address and comparing their content:

 

Dumping the virtual address first:

0: kd> dc f7625000

f7625000  00905a4d 00000003 00000004 0000ffff  MZ..............

f7625010  000000b8 00000000 00000040 00000000  ........@.......

f7625020  00000000 00000000 00000000 00000000  ................

f7625030  00000000 00000000 00000000 000000e0  ................

f7625040  0eba1f0e cd09b400 4c01b821 685421cd  ........!..L.!Th

f7625050  70207369 72676f72 63206d61 6f6e6e61  is program canno

f7625060  65622074 6e757220 206e6920 20534f44  t be run in DOS

f7625070  65646f6d 0a0d0d2e 00000024 00000000  mode....$.......

 

Now let’s dump the physical address and compare the results:

0: kd> dc /p 1c055000

1c055000  00905a4d 00000003 00000004 0000ffff  MZ..............

1c055010  000000b8 00000000 00000040 00000000  ........@.......

1c055020  00000000 00000000 00000000 00000000  ................

1c055030  00000000 00000000 00000000 000000e0  ................

1c055040  0eba1f0e cd09b400 4c01b821 685421cd  ........!..L.!Th

1c055050  70207369 72676f72 63206d61 6f6e6e61  is program canno

1c055060  65622074 6e757220 206e6920 20534f44  t be run in DOS

1c055070  65646f6d 0a0d0d2e 00000024 00000000  mode....$.......

 

The content is identical as expected J.  

 

A new phase...

Even though this has been a strictly technical channel (I've never posted about anything else other than technical stuff) I know a lot of friends read it and so I decided to open an exception on this post and use it to publish something about me that also has a direct effect on how often and what type of content I will be able to keep publishing here.... Effective this week I started a new phase on my career at Microsoft assuming a non-technical role.  I will be working as a people manager for the same group I had once worked before and have a great admiration. 

As a manager I will need to change my focus to better serve my team and make sure they have everything they need from me to succeed.  I'm still passionate about technology as I think I will be forever, but keeping up with the level of knowledge of our engineers here requires a lot of dedication which from now on will be focused on other matters other than only tecnology.  I'm really excited about this new phase and have no doubt it happened at the right time for me. 

 

Kernel dump analysis - Bugcheck 0xA (IRQL_NOT_LESS_OR_EQUAL)

Yet another kernel memory dump to be analyzed - The bugcheck this time is the 0xA - IRQL_NOT_LESS_OR_EQUAL.   To better understand what this message means we would need a little background on Windows Internals but basically when executing anything at a interrupt request level (IRQL) = 2 or higher (in normal circumstances instructions get executed at IRQL = 0) we can't page fault.   On the situation of this specific dump, we would crash even on IRQL = 0 since we're trying to write to the memory address 0x0 which is in user mode address space and is reserved (the first useable address in the user mode address space is 0x00010000)

 

Let's jump to the analysis.

  

Bugcheck info:

0: kd> .bugcheck

Bugcheck code 0000000A

Arguments 00000000 00000002 00000001 8087bb19

                                |              |                    |                        |à This is the failing instruction address

                                |              |                    |à 0x1 means WRITE, 0x0 means READ, so it crashed when trying to WRITE to 0x0

                                |              |à This is the IRQL at which problem happened (IRQL=2)

                                |à This is the memory address where the problem happened

 

So it crashed basically because it failed to access a memory address (which at a lower IRQLs would result in a page fault) on the IRQL = 2.  At IRQL = 2 and above page faults are not allowed to happen.

 

Current thread stack:

 

0: kd> kvnL

 # ChildEBP RetAddr  Args to Child             

00 b7d6ebbc 8087bb19 badb0d00 00000000 00000000 nt!_KiTrap0E+0x2a7 (FPO: [0,0] TrapFrame @ b7d6ebbc)

01 b7d6ec40 80972b03 f7ca7008 80a56be4 00000000 nt!ExDeleteResourceLite+0x1f (FPO: [Non-Fpo]) (CONV: stdcall)

02 b7d6ec5c 80932ca2 ef4d0860 ef4d0848 00000000 nt!SepTokenDeleteMethod+0x9d (FPO: [Non-Fpo]) (CONV: stdcall)

03 b7d6ec74 8086c1a5 ef4d0860 00000000 8b478df0 nt!ObpRemoveObjectRoutine+0xde (FPO: [Non-Fpo]) (CONV: stdcall)

04 b7d6ec94 b7765ada f7ca3444 b7764007 f7ca8460 nt!ObfDereferenceObject+0x67 (FPO: [Non-Fpo]) (CONV: fastcall)

WARNING: Stack unwind information not available. Following frames may be wrong.

05 b7d6ecb0 b776037a f7cbf004 b7d6ece0 f82cde28 naiavf5x+0xcada

06 b7d6ecf0 b775b520 f82cde28 f82cde28 8b572548 naiavf5x+0x737a

07 b7d6ed04 8081dcdf 8b478990 f82cde28 f82cde38 naiavf5x+0x2520

08 b7d6ed18 808f8be4 00000000 00000000 f7ca8448 nt!IofCallDriver+0x45 (FPO: [Non-Fpo]) (CONV: fastcall)

09 b7d6ed50 80932ca2 00ca8460 f7ca8460 00000001 nt!IopDeleteFile+0x13a (FPO: [Non-Fpo]) (CONV: stdcall)

0a b7d6ed68 80932cec f7ca8460 00000001 8ad47770 nt!ObpRemoveObjectRoutine+0xde (FPO: [Non-Fpo]) (CONV: stdcall)

0b b7d6ed80 8087f92f 00000000 00000000 8ad47770 nt!ObpProcessRemoveObjectQueue+0x36 (FPO: [1,0,0]) (CONV: stdcall)

0c b7d6edac 80948bd0 00000000 00000000 00000000 nt!ExpWorkerThread+0xeb (FPO: [Non-Fpo]) (CONV: stdcall)

0d b7d6eddc 8088d4e2 8087f844 80000000 00000000 nt!PspSystemThreadStartup+0x2e (FPO: [Non-Fpo]) (CONV: stdcall)

0e 00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x16

 

The current frame being executed is a post-exception frame, I mean, it's just handling the situation.  The problem really happened here:

 

0: kd> .trap b7d6ebbc

ErrCode = 00000002

eax=00000000 ebx=ef4d0848 ecx=00000000 edx=00000000 esi=f7ca7008 edi=00000000

eip=8087bb19 esp=b7d6ec30 ebp=b7d6ec40 iopl=0         nv up ei ng nz na po nc

cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010282

nt!ExDeleteResourceLite+0x1f:

8087bb19 8901            mov     dword ptr [ecx],eax  ds:0023:00000000=????????

0: kd> kvnL

  *** Stack trace for last set context - .thread/.cxr resets it

 # ChildEBP RetAddr  Args to Child             

00 b7d6ec40 80972b03 f7ca7008 80a56be4 00000000 nt!ExDeleteResourceLite+0x1f (FPO: [Non-Fpo]) (CONV: stdcall)

01 b7d6ec5c 80932ca2 ef4d0860 ef4d0848 00000000 nt!SepTokenDeleteMethod+0x9d (FPO: [Non-Fpo]) (CONV: stdcall)

02 b7d6ec74 8086c1a5 ef4d0860 00000000 8b478df0 nt!ObpRemoveObjectRoutine+0xde (FPO: [Non-Fpo]) (CONV: stdcall)

03 b7d6ec94 b7765ada f7ca3444 b7764007 f7ca8460 nt!ObfDereferenceObject+0x67 (FPO: [Non-Fpo]) (CONV: fastcall)

WARNING: Stack unwind information not available. Following frames may be wrong.

04 b7d6ecb0 b776037a f7cbf004 b7d6ece0 f82cde28 naiavf5x+0xcada

05 b7d6ecf0 b775b520 f82cde28 f82cde28 8b572548 naiavf5x+0x737a

06 b7d6ed04 8081dcdf 8b478990 f82cde28 f82cde38 naiavf5x+0x2520

07 b7d6ed18 808f8be4 00000000 00000000 f7ca8448 nt!IofCallDriver+0x45 (FPO: [Non-Fpo]) (CONV: fastcall)

08 b7d6ed50 80932ca2 00ca8460 f7ca8460 00000001 nt!IopDeleteFile+0x13a (FPO: [Non-Fpo]) (CONV: stdcall)

09 b7d6ed68 80932cec f7ca8460 00000001 8ad47770 nt!ObpRemoveObjectRoutine+0xde (FPO: [Non-Fpo]) (CONV: stdcall)

0a b7d6ed80 8087f92f 00000000 00000000 8ad47770 nt!ObpProcessRemoveObjectQueue+0x36 (FPO: [1,0,0]) (CONV: stdcall)

0b b7d6edac 80948bd0 00000000 00000000 00000000 nt!ExpWorkerThread+0xeb (FPO: [Non-Fpo]) (CONV: stdcall)

0c b7d6eddc 8088d4e2 8087f844 80000000 00000000 nt!PspSystemThreadStartup+0x2e (FPO: [Non-Fpo]) (CONV: stdcall)

0d 00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x16

 

So it's crashing when trying to write to the address pointed by ECX - mov dword ptr [ecx], eax - This is the assembly code of the function where it crashed from the start to the crash instruction :

 

0: kd> u nt!ExDeleteResourceLite nt!ExDeleteResourceLite+0x1f + 1

nt!ExDeleteResourceLite [d:\nt\base\ntos\ex\resource.c @ 2250]:

8087bafa 8bff            mov     edi,edi

8087bafc 55              push    ebp

8087bafd 8bec            mov     ebp,esp

8087baff 83ec0c          sub     esp,0Ch

8087bb02 56              push    esi

8087bb03 8d55f4          lea     edx,[ebp-0Ch]

8087bb06 b9c0418b80      mov     ecx,offset nt!ExpResourceSpinLock (808b41c0)

8087bb0b ff1508118080    call    dword ptr [nt!_imp_KeAcquireInStackQueuedSpinLock (80801108)]

8087bb11 8b7508          mov     esi,dword ptr [ebp+8]  ßESI is obtaining its value from the content of EBP+8

8087bb14 8b4e04          mov     ecx,dword ptr [esi+4]  ß ECX is obtaining its value from the content of ESI+4

8087bb17 8b06            mov     eax,dword ptr [esi]

8087bb19 8901            mov     dword ptr [ecx],eax  ß This is where it crashed

 

 

ECX is getting its value from the address pointed by ESI + 4, and ESI is getting its value from the address pointed by EBP + 8 which is a pointer to the first parameter passed from the previous function on the stack.  Confirming:

 

0: kd> dd esi+4 l1

f7ca700c  00000000

0: kd> dd poi(ebp+8) l1

f7ca7008  00000000

 

Next step is look to the previous function on the stack.  The assembly for the next function up to the point it calls the current one is this:

 

 

0: kd> u nt!SepTokenDeleteMethod nt!SepTokenDeleteMethod+0x9d

nt!SepTokenDeleteMethod [d:\nt\base\ntos\se\token.c @ 2652]:

80972a66 8bff            mov     edi,edi

80972a68 55              push    ebp

80972a69 8bec            mov     ebp,esp

80972a6b 51              push    ecx

80972a6c 51              push    ecx

80972a6d 56              push    esi

80972a6e 8b7508          mov     esi,dword ptr [ebp+8] ß ESI is coming from the content  EBP + 8  (first parameter passed from the previous function)

80972a71 f6868800000020  test    byte ptr [esi+88h],20h

80972a78 57              push    edi

80972a79 7538            jne     nt!SepTokenDeleteMethod+0x4d (80972ab3)

80972a7b 8bbe94000000    mov     edi,dword ptr [esi+94h]

80972a81 53              push    ebx

80972a82 8d4f0c          lea     ecx,[edi+0Ch]

80972a85 eb0f            jmp     nt!SepTokenDeleteMethod+0x30 (80972a96)

80972a87 8d42ff          lea     eax,[edx-1]

80972a8a 8bd8            mov     ebx,eax

80972a8c 8bc2            mov     eax,edx

80972a8e f00fb119        lock cmpxchg dword ptr [ecx],ebx

80972a92 3bc2            cmp     eax,edx

80972a94 741c            je      nt!SepTokenDeleteMethod+0x4c (80972ab2)

80972a96 8b11            mov     edx,dword ptr [ecx]

80972a98 83fa01          cmp     edx,1

80972a9b 75ea            jne     nt!SepTokenDeleteMethod+0x21 (80972a87)

80972a9d 8b4704          mov     eax,dword ptr [edi+4]

80972aa0 8945f8          mov     dword ptr [ebp-8],eax

80972aa3 8b4708          mov     eax,dword ptr [edi+8]

80972aa6 8945fc          mov     dword ptr [ebp-4],eax

80972aa9 8d45f8          lea     eax,[ebp-8]

80972aac 50              push    eax

80972aad e890ecffff      call    nt!SepDeReferenceLogonSession (80971742)

80972ab2 5b              pop     ebx

80972ab3 8d4638          lea     eax,[esi+38h]

80972ab6 8b08            mov     ecx,dword ptr [eax]

80972ab8 0b4804          or      ecx,dword ptr [eax+4]

80972abb 6a00            push    0

80972abd 5f              pop     edi

80972abe 7407            je      nt!SepTokenDeleteMethod+0x61 (80972ac7)

80972ac0 57              push    edi

80972ac1 50              push    eax

80972ac2 e8b5140000      call    nt!SepModifyTokenPolicyCounter (80973f7c)

80972ac7 8b4678          mov     eax,dword ptr [esi+78h]

80972aca 3bc7            cmp     eax,edi

80972acc 7407            je      nt!SepTokenDeleteMethod+0x6f (80972ad5)

80972ace 57              push    edi

80972acf 50              push    eax

80972ad0 e86ff8f1ff      call    nt!ExFreePoolWithTag (80892344)

80972ad5 8b868c000000    mov     eax,dword ptr [esi+8Ch]

80972adb 3bc7            cmp     eax,edi

80972add 7406            je      nt!SepTokenDeleteMethod+0x7f (80972ae5)

80972adf 50              push    eax

80972ae0 e85766ffff      call    nt!SeFreeCapturedObjectTypeList (8096913c)

80972ae5 8b8690000000    mov     eax,dword ptr [esi+90h]

80972aeb 3bc7            cmp     eax,edi

80972aed 7407            je      nt!SepTokenDeleteMethod+0x90 (80972af6)

80972aef 57              push    edi

80972af0 50              push    eax

80972af1 e84ef8f1ff      call    nt!ExFreePoolWithTag (80892344)

80972af6 8b4630          mov     eax,dword ptr [esi+30h]  ß EAX is coming from the content of ESI + 0x30

80972af9 3bc7            cmp     eax,edi

80972afb 740f            je      nt!SepTokenDeleteMethod+0xa6 (80972b0c)

80972afd 50              push    eax  ß EAX is pushed on the stack as the first parameter

80972afe e8f78ff0ff      call    nt!ExDeleteResourceLite (8087bafa)

 

So once again we need to look at the previous function since this one is also receiving the bad value as parameter.  By revisiting the stack we see the first parameter it passes is also received as below:

 

0: kd> kbL5

ChildEBP RetAddr  Args to Child             

b7d6ec40 80972b03 f7ca7008 80a56be4 00000000 nt!ExDeleteResourceLite+0x1f

b7d6ec5c 80932ca2 ef4d0860 ef4d0848 00000000 nt!SepTokenDeleteMethod+0x9d

b7d6ec74 8086c1a5 ef4d0860 00000000 8b478df0 nt!ObpRemoveObjectRoutine+0xde

b7d6ec94 b7765ada f7ca3444 b7764007 f7ca8460 nt!ObfDereferenceObject+0x67

WARNING: Stack unwind information not available. Following frames may be wrong.

b7d6ecb0 b776037a f7cbf004 b7d6ece0 f82cde28 naiavf5x+0xcada

 

 

As we can go directly to the function nt!ObfDereferenceObject+0x67 and try to see where its setting up that parameter from.  The assembly code from this function to the point it calls the next one is this:

 

0: kd> u  nt!ObfDereferenceObject nt!ObfDereferenceObject+0x67 ß This is a fastcall function so the first two parameters are passed through the registers ECX and EDX instead of using the stack (EBP as a reference)

nt!ObfDereferenceObject [d:\nt\base\ntos\ob\obref.c @ 2441]:

8086c13e 8bff            mov     edi,edi

8086c140 55              push    ebp

8086c141 8bec            mov     ebp,esp

8086c143 51              push    ecx

8086c144 803de0088a8000  cmp     byte ptr [nt!ObpTraceEnabled (808a08e0)],0

8086c14b 53              push    ebx

8086c14c 56              push    esi

8086c14d 57              push    edi

8086c14e 894dfc          mov     dword ptr [ebp-4],ecx ß The location pointed by EBP-0x4 which is local variable is receiving the value of ECX which is the first parameter passed to this function

8086c151 8d71e8          lea     esi,[ecx-18h]

8086c154 7408            je      nt!ObfDereferenceObject+0x20 (8086c15e)

8086c156 6a00            push    0

8086c158 56              push    esi

8086c159 e8c8fcffff      call    nt!ObpPushStackInfo (8086be26)

8086c15e 83cbff          or      ebx,0FFFFFFFFh

8086c161 f00fc11e        lock xadd dword ptr [esi],ebx

8086c165 4b              dec     ebx

8086c166 7547            jne     nt!ObfDereferenceObject+0x71 (8086c1af)

8086c168 8b3d90108080    mov     edi,dword ptr [nt!_imp__KeGetCurrentIrql (80801090)]

8086c16e ffd7            call    edi

8086c170 64a124010000    mov     eax,dword ptr fs:[00000124h]

8086c176 6683787200      cmp     word ptr [eax+72h],0

8086c17b 752c            jne     nt!ObfDereferenceObject+0x6b (8086c1a9)

8086c17d ffd7            call    edi

8086c17f 3c01            cmp     al,1

8086c181 7326            jae     nt!ObfDereferenceObject+0x6b (8086c1a9)

8086c183 803de0088a8000  cmp     byte ptr [nt!ObpTraceEnabled (808a08e0)],0

8086c18a 740f            je      nt!ObfDereferenceObject+0x5d (8086c19b)

8086c18c 833dd8078a8000  cmp     dword ptr [nt!ObpTraceNoDeregister (808a07d8)],0

8086c193 7506            jne     nt!ObfDereferenceObject+0x5d (8086c19b)

8086c195 56              push    esi

8086c196 e805fcffff      call    nt!ObpDeregisterObject (8086bda0)

8086c19b 6a00            push    0

8086c19d ff75fc          push    dword ptr [ebp-4] ß Here it is pushing the content of EBP-4 which we know is coming from ECX (first parameter) as a first parameter to the next function

8086c1a0 e81f6a0c00      call    nt!ObpRemoveObjectRoutine (80932bc4)  ß this is the function call to the next function

 

So we know the bad value is coming from the previous function on the stack which is naiavf5x+0xcada.  By looking at the assembly for that we have this:

 

0: kd> u b7765ac1-10 b7765ad5+2

naiavf5x+0xcab1:

b7765ab1 ff1550a476b7    call    dword ptr [naiavf5x+0x11450 (b776a450)]

b7765ab7 5f              pop     edi

b7765ab8 8bc6            mov     eax,esi

b7765aba 5e              pop     esi

b7765abb 5b              pop     ebx

b7765abc 5d              pop     ebp

b7765abd c20800          ret     8

b7765ac0 56              push    esi

b7765ac1 8bf1            mov     esi,ecx  ß ESI is coming from ECX

b7765ac3 8d86a8000000    lea     eax,[esi+0A8h]

b7765ac9 50              push    eax

b7765aca e8818affff      call    naiavf5x+0x5550 (b775e550)

b7765acf 85c0            test    eax,eax

b7765ad1 7516            jne     naiavf5x+0xcae9 (b7765ae9)

b7765ad3 8bce            mov     ecx,esi ß ECX which will be the first parameter to the next function is coming from ESI

b7765ad5 e8b6f7ffff      call    naiavf5x+0xc290 (b7765290)

 

 

CONCLUSION:

So at this point we can’t move further since we have no symbols for the NAIAVF5X.SYS driver – which is a file system filter driver from McAfee.  The conclusion would be that this driver is bad until the  McAfee analyze this same dump and prove us wrong J.  Here is some addition info about the driver:

 

0: kd> lmvm naiavf5x

start    end        module name

b7759000 b776d440   naiavf5x   (no symbols)          

    Loaded symbol image file: naiavf5x.sys

    Image path: \SystemRoot\system32\drivers\naiavf5x.sys

    Image name: naiavf5x.sys

    Timestamp:        Mon Aug 04 20:08:00 2003 (3F2F0370) ß By the way, this is old stuff.  They might have already corrected this on newer versions of the driver and I wouldn’t be surprised to find some documentation about  this on McAfee’s web site.

 

    CheckSum:         00020D5B

    ImageSize:        00014440

    Translations:     0000.04b0 0000.04e0 0409.04b0 0409.04e0

 

By the way, for this dump, “!analyze –v” does the job and points to the right guilty driver.

 

Until the next dump analysis, I mean, next post :)

Kernel dump analysis - Bugcheck 1E (KMODE_EXCEPTION_NOT_HANDLED)

It’s been a long time since my last post, but for some reason lately I’ve been receiving so many nice feedbacks about the blog and the other posts that I feel really motivated again to post a new article.  See how important your feedback is for me? J

Ok, normally I post about user mode debugging, but last week I was working on developing some content and I got this kernel memory dump I decided to take the risk of analyzing it, even considering Kernel debugging is not my specialty. 

Normally the first step when you’re analyzing dumps resultant from Blue Screens (I will write about the differences between kernel mode dumps and user mode dumps in another post) is to run the command !analyze –v.  Well, for this specific dump, !analyze –v is just not pointing to the right driver, at least I did not think so and that’s what motivated me to make a manual analysis of this specific dump.  Ok, too much said and very little action here… Let’s start with some hands on!

 

After opening the dump with Windbg.exe, setting the correct symbol path and running the command !analyze –v, this is what we have in summary:

 

KMODE_EXCEPTION_NOT_HANDLED (1e)

Arguments:

Arg1: c0000005, The exception code that was not handled

Arg2: a012a6c5, The address that the exception occurred at

Arg3: 00000000, Parameter 0 of the exception

Arg4: 00000014, Parameter 1 of the exception

 

FAULTING_IP:

win32k!DdDxApiOpenCaptureDevice+18

a012a6c5 8b5814          mov     ebx,dword ptr [eax+14h]

EXCEPTION_PARAMETER1:  00000000

EXCEPTION_PARAMETER2:  00000014

READ_ADDRESS:  00000014

DEFAULT_BUCKET_ID:  DRIVER_FAULT

BUGCHECK_STR:  0x1E

 

FOLLOWUP_IP:

Dxapi!DxApi+43

bdae59f7 8bc6            mov     eax,esi

SYMBOL_STACK_INDEX:  3

SYMBOL_NAME:  Dxapi!DxApi+43

FOLLOWUP_NAME:  MachineOwner

MODULE_NAME: Dxapi

IMAGE_NAME:  Dxapi.sys

DEBUG_FLR_IMAGE_TIMESTAMP:  382b8097

FAILURE_BUCKET_ID:  0x1E_Dxapi!DxApi+43

BUCKET_ID:  0x1E_Dxapi!DxApi+43

Followup: MachineOwner

 

So it’s telling us a lot of useful information like what was the bugcheck (1E), what kind of unhandled exception happened (Access Violation – 0xC0000005) and what was the instruction pointer (IP) when the exception happened.  In this case it was address 0xa012a6c5.  It’s also pointing to the driver Dxapi.sys as the probable guilty for the problem.  Well, my curiosity on that was exactly because the instruction pointer was pointing to an address that doesn’t belong to Dxapi.sys.  Let’s check that:

kd> lmvm Dxapi

start    end        module name

bdae4000 bdae6640   Dxapi      (pdb symbols)          c:\debuggers\sym\dxapi.pdb\382B80971\dxapi.pdb

    Loaded symbol image file: c:\debuggers\sym\Dxapi.dbg\382B80972640\Dxapi.dbg

    Image path: \SystemRoot\System32\DRIVERS\Dxapi.sys

    Image name: Dxapi.sys

    Timestamp:        Fri Nov 12 00:51:03 1999 (382B8097)

    CheckSum:         0000730A

    ImageSize:        00002640

    File version:     5.0.2180.1

    Product version:  5.0.2180.1

    File flags:       0 (Mask 3F)

    File OS:          40004 NT Win32

    File type:        3.7 Driver

    File date:        00000000.00000000

    Translations:     0409.04b0

    CompanyName:      Microsoft Corporation

    ProductName:      Microsoft(R) Windows (R) 2000 Operating System

    InternalName:     dxapi.sys

    OriginalFilename: dxapi.sys

    ProductVersion:   5.00.2180.1

    FileVersion:      5.00.2180.1

    FileDescription:  DirectX API Driver

    LegalCopyright:   Copyright (C) Microsoft Corp. 1981-1999

 

By checking the base address (yellow) of the module and its end address (green) we notice that the address for the instruction pointers is not in between them.  Actually the instruction point address was from Win32k.sys:

 

kd> lmvm win32k

start    end        module name

a0000000 a01a5e60   win32k     (pdb symbols)          c:\debuggers\sym\win32k.pdb\38E910C02\win32k.pdb

    Loaded symbol image file: c:\debuggers\sym\win32k.dbg\3947E2231a5e60\win32k.dbg

    Image path: \??\D:\WINNT\system32\win32k.sys

    Image name: win32k.sys

    Timestamp:        Wed Jun 14 16:50:59 2000 (3947E223)

    CheckSum:         001B02D1

    ImageSize:        001A5E60

    Translations:     0000.04b0 0000.04e0 0409.04b0 0409.04e0

 

So the address 0xa012a6c5 is indeed in between those addresses which means it was an instruction from this driver (Win32k.sys) that tried to an illegal operation.  But let’s wait a little bit before blaming the poor kernel image of the Win32 Subsystem (This is basically what the Win32k.sys is).  Let’s check our assembly code and try to see what really happened here…

 

Checking our thread’s stack:

 

kd> k

ChildEBP RetAddr 

bd2858a0 80463b2b nt!KiDispatchException+0x30e

bd285908 80463add nt!CommonDispatchException+0x4d

bd285908 a012a6c5 nt!KiUnexpectedInterruptTail+0x1f4

bd2859b4 f0593a8e Dxapi!DxApi+0x43

WARNING: Stack unwind information not available. Following frames may be wrong.

bd285a14 f0592bb4 3dfxV3TV+0x3a8e

bd285a34 f05928cc 3dfxV3TV+0x2bb4

bd285a4c f05a0cfd 3dfxV3TV+0x28cc

00000000 00000000 STREAM!SCIssueRequestToDevice+0xad

 

This actually happened after the exception happened – It was dispatching the exception.  The original context (call stack and registers) was actually saved on a trap frame.  From the debugger help we get the information which states that the third parameter passed to the function KiDispatchException is a pointer to our trap frame.  The command .trap will load the context saved on the trap.

 

kd> kb1

ChildEBP RetAddr  Args to Child             

bd2858a0 80463b2b bd2858bc 00000000 bd285910 nt!KiDispatchException+0x30e

 

kd> .trap bd285910

ErrCode = 00000000

eax=00000000 ebx=84f0ba10 ecx=a012a6ad edx=00000020 esi=bd2859dc edi=80d724a8

eip=a012a6c5 esp=bd285984 ebp=bd2859a0 iopl=0         nv up ei pl zr na pe nc

cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010246

win32k!DdDxApiOpenCaptureDevice+0x18:

a012a6c5 8b5814          mov     ebx,dword ptr [eax+14h] ds:0023:00000014=????????

 

Ok, now we have the right context where the exception happened.  Notice that our current EIP on this context matches the one pointed by the !analyze –v as the one where the exception happened (in red above).  We basically crashed because we’re trying to move the content pointed by EAX+0x14 to EBX.  Since EAX = 0 (green above) we failed when trying to read from the invalid address 0x00000014 (which is the resultant address from 0x0 + 0x14).

 

Let’s look at the assembly code that execute immediately before this a012a6c5.

 

kd> ub a012a6c8

win32k!DdDxApiOpenCaptureDevice+0x7:

a012a6b4 56              push    esi

a012a6b5 8b7508          mov     esi,dword ptr [ebp+8]

a012a6b8 57              push    edi

a012a6b9 8365fc00        and     dword ptr [ebp-4],0

a012a6bd 8b06            mov     eax,dword ptr [esi]