Windows IPv6 协议栈存在一处拒绝服务漏洞,未经身份认证的远程攻击者可通过向目标系统发送特制数据包来利用此漏洞,成功利用此漏洞可导致目标系统拒绝服务(蓝屏)。
近日,奇安信 CERT 监测到此漏洞 POC 在 Github 上公开发布,经测试,该 POC 有效,以下为复现截图:
以下为崩溃现场,可以发现,事故出现在 tcpip!Ipv6pReassembleDatagram 函数中,程序试图向 rax 指向的地址处写入数据,但 rax 中的值为 0,由于内存地址 0 不允许访问,因而会触发异常。
使用 IDA 查看 tcpip!Ipv6pReassembleDatagram 函数,查找 rax 被赋值为 0 的线索。如下所示,rax(buffer_ptr)为 NdisGetDataBuffer 函数的返回值,NdisGetDataBuffer 函数可返回数据指针或者 NULL。也就是说 buffer_ptr 有可能被赋值为 0,但后面在向其复制数据时并没有判断其是否是空指针,这将会导致异常。
在 ndis!NdisGetDataBuffer 函数中,如下所示,如果 net_buffer->DataLength 小于传进来的第二个参数 BytesNeeded 就会返回 0。
重新调试,在 tcpip!Ipv6pReassembleDatagram 函数下断点,重点关注 ndis!NdisGetDataBuffer 函数,调试过程如下, net_buffer->DataLength(0x10)确实小于 BytesNeeded(0x10010):
在调用 ndis!NdisGetDataBuffer 函数之前,还调用了 NetioRetreatNetBuffer 函数:
在该函数调用之前,netbuffer->CurrentMdlOffset 还没有被设置,因而会调用 NdisRetreatNetBufferDataStart 函数来设置 net_buffer 结构,net_buffer->DataLength 就是在这里被设置为 0x10,在函数调用处可以发现,此处 BytesNeeded 被限制为 unsigned __int16,也就是 2 个字节(可以看成整数溢出),而后面的 ndis!NdisGetDataBuffer 函数调用中使用的是 unsigned int 类型,由于 0x10010 > 0x10,函数返回了0:
下一步,就是追踪 BytesNeeded ,搞清楚它从何而来。经过静态分析,可知 BytesNeeded 为 v3 加 0x28,而 v3 来自于 a2 偏移 0x88 处。参数 a2 最初由 IppCreateInReassemblySet 生成(Ipv6pReceiveFragment 函数中),当满足一定条件时,才会调用 tcpip!Ipv6pReassembleDatagram 函数进行重组。因而下一步便是追踪 important_D8 结构中偏移 0x88 处的长度数据(为何会那么大,加造成 v3 整数溢出):
总体来说,Ipv6pReceiveFragment 函数是用来处理分片选项的,它将分片数据排列到一起,当最后一个分片到来且校验通过,就会调用 Ipv6pReassembleDatagram 函数进行重组。重组之后需要处理 IPv6 分片后隐藏的其他 option,这还是会调用 IppReceiveHeaderBatch 函数进行分配处理的(后面会介绍)。
Ipv6pReceiveFragment 函数 当数据传递进这个函数的时候,就已经处理到 Fragment header for IPv6 这个选项了。该函数从 net_buffer 结构中读取 Fragment header for IPv6 选项数据,并对其进行解析和处理。
Fragment header for IPv6 的结构如下(这里是测试用的 ICMP 数据包),1字节的 next header,1字节的保留字段,2字节的offset长度(最低 3 bits不参与,因此长度定是 8 的倍数,最后 1 bit是 more fragments 标志),最后 4 字节为Identification 字段,是整个数据包重组的标志。
这样就可以得到这样一个结构体。
好啦,经过调试可以发现 Ipv6pReceiveFragment 函数首先会从 net_buffer 结构中读取 IPv6 分片头数据。
下面分别看一下,这几个字段都是怎么处理的(这一段可以略过 )。首先是 next header,如下所示,当 fragment offset 为 0 (意味着正在处理的是第一个分片包) 且 more fragment flag 为 0 (这意味着这个包是最后一个分片……) 时,会将 next header 字段存放在 v1 偏移 0x2c 处。在一般的场景下,不会走到这部分代码。
然后再看 offset 字段,除了上面那一处,它的出现几乎都伴随着 netbuffer->DataLength,netbuffer->DataLength 一般指当前 mdl 结构指向数据的剩余长度。然后是 more fragments 标志,可以看下面第 2 条,当检测出 more fragments 标志为 0 时,就会跳转到 LABEL_36,通过 fragment_offset + length_last 计算出分片载荷的原始长度 sum_length,判断 important_D8->field_8C 有没有更新(初始化是 0xFFFFFFFF的),如果没有更新就将其赋值为 sum_length。
最后是 identification 字段,其主要用做以下两个函数的参数。通过它来标识一个数据包的所有分片。
大概流程是调用 NdisGetDataBuffer 函数取出 IPv6 分片头,然后通过 Ipv6pFragmentLookup 函数寻找相同 identification 标记的数据包的 important_D8 结构。如果没有找到的话(处理第一个分片包是这样的),会调用 IppCreateInReassemblySet 函数初始化这个包的 important_D8 结构。然后通过 IppReassemblyFindLocation 函数寻找上一个分片的 data_mdl 结构。然后通过 MmSizeOfMdl、ExAllocatePoolWithTagPriority、MmBuildMdlForNonPagedPool 等函数为当前分片初始化一个 data_mdl 结构,0x10 长度的头,0x40 长度的 MDL 结构,以及后面不定长度的分片载荷数据。这个结构体大概如下:
如果 IPv6 分片头前面还有其他 options 数据也需要计算出来(当然也是第一个分片包才有的机会),关键代码如下,会从 v1 偏移 0x30 处取出长度,然后减去 0x30 的长度(0x28 的 IPv6 头 + 0x8 的 IPv6 分片头),如果在这之间有未分片的 options 数据,需要申请空间将其存放,并将指针存放在 important_D8->options_data,将其长度存放在 important_D8->options_data_length。
接着,将分片载荷数据复制到 data_mdl_struct 结构体后面。将当前分片链到 important_D8 偏移 0x60 处的 MDL_data 的链表中,并更新其 MDL_data_last 指针。重复这个流程,直到 important_D8->fragment_sum_length 更新,且 important_D8->frag_accum_length == important_D8->fragment_sum_length 时,进行分片重组。
通过栈回溯可知,该函数的调用链为 tcpip!IppReceiveHeaderBatch -> tcpip!Ipv6pReceiveFragmentList -> tcpip!Ipv6pReceiveFragment。在 IppReceiveHeaderBatch 函数中会通过 next_header_index 计算出对应的处理函数,比如 0x2c 就对应了 Ipv6pReceiveFragmentList 函数,0x3c 对应了 Ipv6pReceiveDestinationOptions 函数。Ipv6pReceiveFragmentList 函数会调用 Ipv6pReceiveFragment 函数循环处理一组分片包中的 IPv6 分片头。
在最后一个分片包被处理时,会更新 important_D8->fragment_sum_length,然后经过条件判断进入 tcpip!Ipv6pReassembleDatagram 函数进行重组,实际上是申请一个新的 NET_BUFFER 结构并将重组数据链入其 MDL 链中。也就是前面漏洞复现时的场景。以下为部分相关代码:
值得注意的是,在这个函数中还是会调用 IppReceiveHeaderBatch 函数进行后续处理,若分片载荷中存在需要解析的 option,该函数会继续对它们进行处理。
以下为部分 POC 截图,值得关注的是,在第一组分片数据的最后加入了一个 Fragment header for IPv6 选项(0x2c),但其 identification 设置为了第二个数据包的 identification。这应该就是漏洞触发的关键,通过在 tcpip!Ipv6pReassembleDatagram 函数再次调用 IppReceiveHeaderBatch 函数进行分片中选项的处理,对结构体中的长度进行累加。并利用 0x2C 对应 Ipv6pReceiveFragmentList 函数的特点再次进行分片头处理,由于 identification 标识不同了,这样使程序将上一组数据包累计的处理长度当作第二组数据包未分片数据的长度。从而在后续流程中引发异常。
以下为验证吧,追踪 important_D8 结构中偏移 0x88 处的长度数据。分析其上层函数 Ipv6pReceiveFragment 可以发现,当数据包的第一个分片进来的时候,会从第一个参数 v1 偏移 0x30 处取出一个长度,并用它减去 0x30,经过前面的分析可知,该长度为前面读取过的 IPv6 数据长度,包括 IPv6 分片头(也就是没有参与分片的数据长度),减去 0x30 就是前面的所有 option 数据的长度。下面来继续分析为什么会出现异常的长度。
在 tcpip!Ipv6pReassembleDatagram 函数中会调用 IppCopyPacket 函数复制 Ipv6pReassembleDatagram 函数第一个参数指向的关键结构。然后需要关注该结构偏移 0x30 处长度的变化。
在这个结构偏移 0x30 处下断点,可以清晰的看出程序对数据的处理。首先将其设置为 0x28,然后逐个 option 处理,处理完成后累加这个长度。对比 POC 可知,需要处理的选项都是 Destination Option,长度为 0x710,如下所示:
在 tcpip!IppReceiveHeaderBatch 函数中会通过 option_header_number 来计算相应的处理函数,并在处理函数中将下一个 option 的 number 写入结构体偏移 0x2C 处。
后面的操作就很明显了,程序会继续处理重组后的 option,并将处理过的长度累加,存放在结构体偏移 0x30 处。注意到 POC 中第一组数据的最后一个包,最后一个选项被设置为 IPv6 分片选项,并且将其 identification 设置为下一个包的 identification(0x0c02f90a)。这将会导致 tcpip!IppReceiveHeaderBatch 函数再次调用 tcpip!Ipv6pReceiveFragmentList 函数,并且上下文环境为第一组数据包的信息。
如下所示, 该结构体偏移 0x30 处的长度本是上一组数据包处理过的数据长度,而一个新的 identification 会使程序认为它是新的数据包已经处理过的数据长度。
在 tcpip!Ipv6pReceiveFragment 函数中会为其设置一个新的 important_D8 结构,并将其 options_data_length 设置为 0x10010+8-0x30,即 0xffe8。
因而在 tcpip!Ipv6pReassembleDatagram 函数中,使用该长度加 0x28(IPv6 头长度)会导致一个溢出。而在之前最后一个分片进来,函数对其进行校验时,比较的是最后一个分片包的长度加其偏移是否大于 0xFFFF,以及当前累加长度是否大于最后一个分片中的分片长度加偏移的值,没有去校验未分片的 option 数据长度。
在后续 NetioRetreatNetBuffer 函数中使用了 2 个字节长度来设置 _NET_BUFFER,而在 NdisGetDataBuffer 函数中使用 4 字节长度来请求 _NET_BUFFER,导致该函数校验失败,返回空指针。并且程序在没有判断的情况下向其赋值,导致拒绝服务。
Windows IPv6 协议栈存在一处拒绝服务漏洞,在进行 IPv6 分片重组时,由于 NetioRetreatNetBuffer 函数和 NdisGetDataBuffer 函数使用的参数类型不匹配,可导致后者返回空指针,在后续复制操作时引发空指针问题。攻击者可通过向一个超大数据包最后分片的末尾插入带有另一个标识的 Fragment header for IPv6 选项,并且继续发送带有该标识数据包的剩余分片,从而在第二组数据包重组的时候触发漏洞,导致目标系统拒绝服务。
对比 tcpip.sys 补丁前后,可发现主要修改了三个函数 (用以修补 2 月这几个 TCP/IP 漏洞):Ipv6pReassembleDatagram、Ipv6pReceiveFragment 和 Ipv4pReassembleDatagram。
在 Ipv6pReassembleDatagram 函数中,增加了一处判断,当重组数据包的 options_data_length 和 fragment_sum_length 之和大于 0xFFFF 会调用 IppDeleteFromReassmblySet 函数删除这个包的信息,然后跳过重组。
在 NetioRetreatNetBuffer 函数调用处,将第二个参数的长度由原来的 16位 变为 32 位 (DWORD),避免了在后续调用 NdisGetDataBuffer 函数时参数不一致的情况。
https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-24086
https://github.com/0vercl0k/CVE-2021-24086
https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ndis/ns-ndis-_net_buffer_list
https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ndis/nf-ndis-ndisgetdatabuffer
https://blog.csdn.net/luguifang2011/article/details/81667826
0
: kd> .trap
0xfffff80572ea1a40
NOTE: The trap frame does
not
contain
all
registers.
Some register values may be zeroed
or
incorrect.
rax
=
0000000000000000
rbx
=
0000000000000000
rcx
=
0000000000000014
rdx
=
0000000000000000
rsi
=
0000000000000000
rdi
=
0000000000000000
rip
=
fffff805727cc27b rsp
=
fffff80572ea1bd0 rbp
=
ffffb88d5bfff4a0
r8
=
ffffb88d5be14990 r9
=
0000000000000001
r10
=
ffffb88d5eb7d2c0
r11
=
0000000000000002
r12
=
0000000000000000
r13
=
0000000000000000
r14
=
0000000000000000
r15
=
0000000000000000
iopl
=
0
nv up ei ng nz na po cy
tcpip!Ipv6pReassembleDatagram
+
0x14f
:
fffff805`
727cc27b
0f1100
movups xmmword ptr [rax],xmm0 ds:
00000000
`
00000000
=
????????????????????????????????
0
: kd> kb
*
*
*
Stack trace
for
last
set
context
-
.thread
/
.cxr resets it
00
fffff805`
727cd002
: ffffb88d`
5bc72000
00000000
`
00000000
00000000
`
00000002
ffffb88d`
0000fffa
: tcpip!Ipv6pReassembleDatagram
+
0x14f
01
fffff805`
727cd122
: ffffb88d`
610850a0
00000000
`
00000008
ffffb88d`
5bc70028
ffffb88d`
5b83c460
: tcpip!Ipv6pReceiveFragment
+
0x83a
02
fffff805`
726415e7
: fffff805`
00000001
ffffb88d`
5d5d0780
ffffb88d`
610d9c50
00000000
`
00000000
: tcpip!Ipv6pReceiveFragmentList
+
0x42
03
fffff805`
726964df
: fffff805`
72818000
ffffb88d`
5bd19720
ffffb88d`
5bc72000
00000000
`
00000000
: tcpip!IppReceiveHeaderBatch
+
0x4c7
04
fffff805`
7269617c
: ffffb88d`
5bcbead0
00000000
`
00000001
00000000
`
00000001
00000000
`
00000000
: tcpip!IppFlcReceivePacketsCore
+
0x34f
05
fffff805`
72662bdf
: ffffb88d`
5d5cf030
00000000
`
00000000
00000000
`
00000000
fffff805`
72ea2014
: tcpip!IpFlcReceivePackets
+
0xc
06
fffff805`
726620b2
: ffffb88d`
5bcbd901
ffffb88d`
5be9e800
fffff805`
72650690
fffff805`
72ea22f8
: tcpip!FlpReceiveNonPreValidatedNetBufferListChain
+
0x25f
07
fffff805`
6fad98f8
: fffff805`
72ea2390
00000000
`
00000002
ffffb88d`
5b0d8080
fffff805`
72ea2318
: tcpip!FlReceiveNetBufferListChainCalloutRoutine
+
0xd2
08
fffff805`
6fad986d
: fffff805`
72661fe0
fffff805`
72ea2318
ffffb88d`
5bae0110
00000000
`
00000000
: nt!KeExpandKernelStackAndCalloutInternal
+
0x78
09
fffff805`
72650bc1
: ffffb88d`
5d5cf030
fffff805`
72ea2390
00000000
`
00000000
00060080
`
02000000
: nt!KeExpandKernelStackAndCalloutEx
+
0x1d
0a
fffff805`
723cb561
: ffffb88d`
5d6bd4b0
fffff805`
72ea2690
00000000
`
00000000
00000000
`
00000000
: tcpip!FlReceiveNetBufferListChain
+
0x311
0b
fffff805`
723cb057
: ffffb88d`
5be8e7f0
00000000
`
0000dd01
00000000
`
00000000
ffffb88d`
00000001
: ndis!ndisMIndicateNetBufferListsToOpen
+
0x141
0c
fffff805`
723d0ee1
: ffffb88d`
5b7681a0
ffffb88d`
00000000
ffffb88d`
5b7681a0
00000000
`
00000001
: ndis!ndisMTopReceiveNetBufferLists
+
0x227
0d
fffff805`
724017d6
: ffffb88d`
5d5cf030
fffff805`
72ea27e1
00000000
`
00000000
fffff805`
72ea2810
: ndis!ndisCallReceiveHandler
+
0x61
0e
fffff805`
723ce8a4
:
00000000
`
00003293
00000000
`
00000801
ffffb88d`
5b7681a0
00000000
`
00000001
: ndis!ndisInvokeNextReceiveHandler
+
0x206e6
0f
fffff805`
73c383b3
:
00000000
`
00000000
00000000
`
00000801
00000000
`
00000001
ffffb88d`
5d5cf030
: ndis!NdisMIndicateReceiveNetBufferLists
+
0x104
10
fffff805`
73c3947a
: ffffb88d`
5d5cf000
ffffb88d`
5bb4e000
ffffb88d`
5bb4f080
00000000
`
00000000
: e1i65x64!RECEIVE::RxIndicateNBLs
+
0x12f
11
fffff805`
73c40c14
: ffffb88d`
5ba54bd0
ffffb88d`
5bb4e000
ffffb88d`
5bb4e001
00000000
`
00000000
: e1i65x64!RECEIVE::RxProcessInterrupts
+
0x20a
12
fffff805`
73c4108f
: ffffb88d`
5ba54b70
ffff0001`
00000000
ffff0001`
00000000
fffff805`
73c5b560
: e1i65x64!INTERRUPT::MsgIntDpcTxRxProcessing
+
0x124
13
fffff805`
73c40668
: ffffb88d`
5ba54b70
00000000
`fffffffe ffffb88d`
00000000
00000000
`
00000000
: e1i65x64!INTERRUPT::MsgIntMessageInterruptDPC
+
0x1ff
14
fffff805`
723cf2fd
: ffffb88d`
5b75e1a0
ffffb88d`
5b75eb90
ffffb88d`
5b75e050
fffff805`
72211f53
: e1i65x64!INTERRUPT::MiniportMessageInterruptDPC
+
0x28
......
0
: kd> .trap
0xfffff80572ea1a40
NOTE: The trap frame does
not
contain
all
registers.
Some register values may be zeroed
or
incorrect.
rax
=
0000000000000000
rbx
=
0000000000000000
rcx
=
0000000000000014
rdx
=
0000000000000000
rsi
=
0000000000000000
rdi
=
0000000000000000
rip
=
fffff805727cc27b rsp
=
fffff80572ea1bd0 rbp
=
ffffb88d5bfff4a0
r8
=
ffffb88d5be14990 r9
=
0000000000000001
r10
=
ffffb88d5eb7d2c0
r11
=
0000000000000002
r12
=
0000000000000000
r13
=
0000000000000000
r14
=
0000000000000000
r15
=
0000000000000000
iopl
=
0
nv up ei ng nz na po cy
tcpip!Ipv6pReassembleDatagram
+
0x14f
:
fffff805`
727cc27b
0f1100
movups xmmword ptr [rax],xmm0 ds:
00000000
`
00000000
=
????????????????????????????????
0
: kd> kb
*
*
*
Stack trace
for
last
set
context
-
.thread
/
.cxr resets it
00
fffff805`
727cd002
: ffffb88d`
5bc72000
00000000
`
00000000
00000000
`
00000002
ffffb88d`
0000fffa
: tcpip!Ipv6pReassembleDatagram
+
0x14f
01
fffff805`
727cd122
: ffffb88d`
610850a0
00000000
`
00000008
ffffb88d`
5bc70028
ffffb88d`
5b83c460
: tcpip!Ipv6pReceiveFragment
+
0x83a
02
fffff805`
726415e7
: fffff805`
00000001
ffffb88d`
5d5d0780
ffffb88d`
610d9c50
00000000
`
00000000
: tcpip!Ipv6pReceiveFragmentList
+
0x42
03
fffff805`
726964df
: fffff805`
72818000
ffffb88d`
5bd19720
ffffb88d`
5bc72000
00000000
`
00000000
: tcpip!IppReceiveHeaderBatch
+
0x4c7
04
fffff805`
7269617c
: ffffb88d`
5bcbead0
00000000
`
00000001
00000000
`
00000001
00000000
`
00000000
: tcpip!IppFlcReceivePacketsCore
+
0x34f
05
fffff805`
72662bdf
: ffffb88d`
5d5cf030
00000000
`
00000000
00000000
`
00000000
fffff805`
72ea2014
: tcpip!IpFlcReceivePackets
+
0xc
06
fffff805`
726620b2
: ffffb88d`
5bcbd901
ffffb88d`
5be9e800
fffff805`
72650690
fffff805`
72ea22f8
: tcpip!FlpReceiveNonPreValidatedNetBufferListChain
+
0x25f
07
fffff805`
6fad98f8
: fffff805`
72ea2390
00000000
`
00000002
ffffb88d`
5b0d8080
fffff805`
72ea2318
: tcpip!FlReceiveNetBufferListChainCalloutRoutine
+
0xd2
08
fffff805`
6fad986d
: fffff805`
72661fe0
fffff805`
72ea2318
ffffb88d`
5bae0110
00000000
`
00000000
: nt!KeExpandKernelStackAndCalloutInternal
+
0x78
09
fffff805`
72650bc1
: ffffb88d`
5d5cf030
fffff805`
72ea2390
00000000
`
00000000
00060080
`
02000000
: nt!KeExpandKernelStackAndCalloutEx
+
0x1d
0a
fffff805`
723cb561
: ffffb88d`
5d6bd4b0
fffff805`
72ea2690
00000000
`
00000000
00000000
`
00000000
: tcpip!FlReceiveNetBufferListChain
+
0x311
0b
fffff805`
723cb057
: ffffb88d`
5be8e7f0
00000000
`
0000dd01
00000000
`
00000000
ffffb88d`
00000001
: ndis!ndisMIndicateNetBufferListsToOpen
+
0x141
0c
fffff805`
723d0ee1
: ffffb88d`
5b7681a0
ffffb88d`
00000000
ffffb88d`
5b7681a0
00000000
`
00000001
: ndis!ndisMTopReceiveNetBufferLists
+
0x227
0d
fffff805`
724017d6
: ffffb88d`
5d5cf030
fffff805`
72ea27e1
00000000
`
00000000
fffff805`
72ea2810
: ndis!ndisCallReceiveHandler
+
0x61
0e
fffff805`
723ce8a4
:
00000000
`
00003293
00000000
`
00000801
ffffb88d`
5b7681a0
00000000
`
00000001
: ndis!ndisInvokeNextReceiveHandler
+
0x206e6
0f
fffff805`
73c383b3
:
00000000
`
00000000
00000000
`
00000801
00000000
`
00000001
ffffb88d`
5d5cf030
: ndis!NdisMIndicateReceiveNetBufferLists
+
0x104
10
fffff805`
73c3947a
: ffffb88d`
5d5cf000
ffffb88d`
5bb4e000
ffffb88d`
5bb4f080
00000000
`
00000000
: e1i65x64!RECEIVE::RxIndicateNBLs
+
0x12f
11
fffff805`
73c40c14
: ffffb88d`
5ba54bd0
ffffb88d`
5bb4e000
ffffb88d`
5bb4e001
00000000
`
00000000
: e1i65x64!RECEIVE::RxProcessInterrupts
+
0x20a
12
fffff805`
73c4108f
: ffffb88d`
5ba54b70
ffff0001`
00000000
ffff0001`
00000000
fffff805`
73c5b560
: e1i65x64!INTERRUPT::MsgIntDpcTxRxProcessing
+
0x124
13
fffff805`
73c40668
: ffffb88d`
5ba54b70
00000000
`fffffffe ffffb88d`
00000000
00000000
`
00000000
: e1i65x64!INTERRUPT::MsgIntMessageInterruptDPC
+
0x1ff
14
fffff805`
723cf2fd
: ffffb88d`
5b75e1a0
ffffb88d`
5b75eb90
ffffb88d`
5b75e050
fffff805`
72211f53
: e1i65x64!INTERRUPT::MiniportMessageInterruptDPC
+
0x28
......
/
/
tcpip!Ipv6pReassembleDatagram
buffer_ptr
=
NdisGetDataBuffer(NetBuffer, BytesNeeded,
0i64
,
1i64
,
0
);
……
*
(_OWORD
*
)buffer_ptr
=
*
(_OWORD
*
)(v1
+
0x90
);
*
(_OWORD
*
)(buffer_ptr
+
0x10
)
=
*
(_OWORD
*
)(v1
+
0xA0
);
*
(_QWORD
*
)(buffer_ptr
+
0x20
)
=
*
(_QWORD
*
)(v1
+
0xB0
);
/
/
tcpip!Ipv6pReassembleDatagram
buffer_ptr
=
NdisGetDataBuffer(NetBuffer, BytesNeeded,
0i64
,
1i64
,
0
);
……
*
(_OWORD
*
)buffer_ptr
=
*
(_OWORD
*
)(v1
+
0x90
);
*
(_OWORD
*
)(buffer_ptr
+
0x10
)
=
*
(_OWORD
*
)(v1
+
0xA0
);
*
(_QWORD
*
)(buffer_ptr
+
0x20
)
=
*
(_QWORD
*
)(v1
+
0xB0
);
/
/
ndis!NdisGetDataBuffer
if
( !a2 || !current_mdl || net_buffer
-
>DataLength < a2 )
goto LABEL_25;
……
LABEL_25:
result
=
0i64
;
}
return
result;
/
/
ndis!NdisGetDataBuffer
if
( !a2 || !current_mdl || net_buffer
-
>DataLength < a2 )
goto LABEL_25;
……
LABEL_25:
result
=
0i64
;
}
return
result;
0
: kd>
ndis!NdisGetDataBuffer
+
0x33
:
fffff805`
723ce133
395118
cmp
dword ptr [rcx
+
18h
],edx
0
: kd> ?poi(rcx
+
18
)
Evaluate expression:
16
=
00000000
`
00000010
0
: kd> r edx
edx
=
10010
0
: kd> p
ndis!NdisGetDataBuffer
+
0x36
:
fffff805`
723ce136
0f82be000000
jb ndis!NdisGetDataBuffer
+
0xfa
(fffff805`
723ce1fa
)
0
: kd>
ndis!NdisGetDataBuffer
+
0xfa
:
fffff805`
723ce1fa
33c0
xor eax,eax
0
: kd>
ndis!NdisGetDataBuffer
+
0xfc
:
fffff805`
723ce1fc
e971ffffff jmp ndis!NdisGetDataBuffer
+
0x72
(fffff805`
723ce172
)
0
: kd> u fffff805`
723ce172
ndis!NdisGetDataBuffer
+
0x72
:
fffff805`
723ce172
488b5c2450
mov rbx,qword ptr [rsp
+
50h
]
fffff805`
723ce177
488b6c2458
mov rbp,qword ptr [rsp
+
58h
]
fffff805`
723ce17c
488b742460
mov rsi,qword ptr [rsp
+
60h
]
fffff805`
723ce181
4883c430
add rsp,
30h
fffff805`
723ce185
415f
pop r15
fffff805`
723ce187
415e
pop r14
fffff805`
723ce189
5f
pop rdi
fffff805`
723ce18a
c3 ret
0
: kd>
ndis!NdisGetDataBuffer
+
0x33
:
fffff805`
723ce133
395118
cmp
dword ptr [rcx
+
18h
],edx
0
: kd> ?poi(rcx
+
18
)
Evaluate expression:
16
=
00000000
`
00000010
0
: kd> r edx
edx
=
10010
0
: kd> p
ndis!NdisGetDataBuffer
+
0x36
:
fffff805`
723ce136
0f82be000000
jb ndis!NdisGetDataBuffer
+
0xfa
(fffff805`
723ce1fa
)
0
: kd>
ndis!NdisGetDataBuffer
+
0xfa
:
fffff805`
723ce1fa
33c0
xor eax,eax
0
: kd>
ndis!NdisGetDataBuffer
+
0xfc
:
fffff805`
723ce1fc
e971ffffff jmp ndis!NdisGetDataBuffer
+
0x72
(fffff805`
723ce172
)
0
: kd> u fffff805`
723ce172
ndis!NdisGetDataBuffer
+
0x72
:
fffff805`
723ce172
488b5c2450
mov rbx,qword ptr [rsp
+
50h
]
fffff805`
723ce177
488b6c2458
mov rbp,qword ptr [rsp
+
58h
]
fffff805`
723ce17c
488b742460
mov rsi,qword ptr [rsp
+
60h
]
fffff805`
723ce181
4883c430
add rsp,
30h
fffff805`
723ce185
415f
pop r15
fffff805`
723ce187
415e
pop r14
fffff805`
723ce189
5f
pop rdi
fffff805`
723ce18a
c3 ret
__int64 __fastcall NetioRetreatNetBuffer(_NET_BUFFER
*
netbuffer, __int64 a2, __int64 a3)
{
ULONG v3;
/
/
eax
__int64 v5;
/
/
[rsp
+
20h
] [rbp
-
8h
]
v3
=
netbuffer
-
>CurrentMdlOffset;
if
( v3 < (unsigned
int
)a2 )
return
NdisRetreatNetBufferDataStart(netbuffer, a2, a3, NetioAllocateMdl, v5);
netbuffer
-
>DataOffset
-
=
a2;
netbuffer
-
>DataLength
+
=
a2;
netbuffer
-
>CurrentMdlOffset
=
v3
-
a2;
return
0i64
;
}
__int64 __fastcall NetioRetreatNetBuffer(_NET_BUFFER
*
netbuffer, __int64 a2, __int64 a3)
{
ULONG v3;
/
/
eax
__int64 v5;
/
/
[rsp
+
20h
] [rbp
-
8h
]
v3
=
netbuffer
-
>CurrentMdlOffset;
if
( v3 < (unsigned
int
)a2 )
return
NdisRetreatNetBufferDataStart(netbuffer, a2, a3, NetioAllocateMdl, v5);
netbuffer
-
>DataOffset
-
=
a2;
netbuffer
-
>DataLength
+
=
a2;
netbuffer
-
>CurrentMdlOffset
=
v3
-
a2;
return
0i64
;
}
/
/
NetioRetreatNetBuffer(
*
(_NET_BUFFER
*
*
)(v11
+
8
), (unsigned __int16)BytesNeeded,
0i64
)
0
: kd>
tcpip!Ipv6pReassembleDatagram
+
0xd9
:
fffff805`
727cc205
e8dafce8ff call tcpip!NetioRetreatNetBuffer (fffff805`
7265bee4
)
0
: kd> dt _net_buffer @rcx
ndis!_NET_BUFFER
+
0x000
Next
: (null)
+
0x008
CurrentMdl : (null)
+
0x010
CurrentMdlOffset :
0
+
0x018
DataLength :
0
+
0x018
stDataLength :
0
+
0x020
MdlChain : (null)
+
0x028
DataOffset :
0
+
0x000
Link : _SLIST_HEADER
+
0x000
NetBufferHeader : _NET_BUFFER_HEADER
+
0x030
ChecksumBias :
0
+
0x032
Reserved :
0
+
0x038
NdisPoolHandle :
0xffffb88d
`
5ba47940
Void
+
0x040
NdisReserved : [
2
] (null)
+
0x050
ProtocolReserved : [
6
] (null)
+
0x080
MiniportReserved : [
4
] (null)
+
0x0a0
DataPhysicalAddress : _LARGE_INTEGER
0x0
+
0x0a8
SharedMemoryInfo : (null)
+
0x0a8
ScatterGatherList : (null)
0
: kd> r rcx
rcx
=
ffffb88d5df85f20
0
: kd> t
tcpip!NetioRetreatNetBuffer:
fffff805`
7265bee4
4883ec28
sub rsp,
28h
0
: kd> pc
tcpip!NetioRetreatNetBuffer
+
0x19
:
fffff805`
7265befd
e8ce39d7ff call ndis!NdisRetreatNetBufferDataStart (fffff805`
723cf8d0
)
0
: kd> p
tcpip!NetioRetreatNetBuffer
+
0x1e
:
fffff805`
7265bf02
4883c428
add rsp,
28h
0
: kd> dt _net_buffer ffffb88d5df85f20
ndis!_NET_BUFFER
+
0x000
Next
: (null)
+
0x008
CurrentMdl :
0xffffb88d
`
5bec4220
_MDL
+
0x010
CurrentMdlOffset :
0x50
+
0x018
DataLength :
0x10
+
0x018
stDataLength :
0x10
+
0x020
MdlChain :
0xffffb88d
`
5bec4220
_MDL
+
0x028
DataOffset :
0x50
+
0x000
Link : _SLIST_HEADER
+
0x000
NetBufferHeader : _NET_BUFFER_HEADER
+
0x030
ChecksumBias :
0
+
0x032
Reserved :
0
+
0x038
NdisPoolHandle :
0xffffb88d
`
5ba47940
Void
+
0x040
NdisReserved : [
2
] (null)
+
0x050
ProtocolReserved : [
6
] (null)
+
0x080
MiniportReserved : [
4
] (null)
+
0x0a0
DataPhysicalAddress : _LARGE_INTEGER
0x0
+
0x0a8
SharedMemoryInfo : (null)
+
0x0a8
ScatterGatherList : (null)
/
/
NetioRetreatNetBuffer(
*
(_NET_BUFFER
*
*
)(v11
+
8
), (unsigned __int16)BytesNeeded,
0i64
)
0
: kd>
tcpip!Ipv6pReassembleDatagram
+
0xd9
:
fffff805`
727cc205
e8dafce8ff call tcpip!NetioRetreatNetBuffer (fffff805`
7265bee4
)
0
: kd> dt _net_buffer @rcx
ndis!_NET_BUFFER
+
0x000
Next
: (null)
+
0x008
CurrentMdl : (null)
+
0x010
CurrentMdlOffset :
0
+
0x018
DataLength :
0
+
0x018
stDataLength :
0
+
0x020
MdlChain : (null)
+
0x028
DataOffset :
0
+
0x000
Link : _SLIST_HEADER
+
0x000
NetBufferHeader : _NET_BUFFER_HEADER
+
0x030
ChecksumBias :
0
+
0x032
Reserved :
0
+
0x038
NdisPoolHandle :
0xffffb88d
`
5ba47940
Void
+
0x040
NdisReserved : [
2
] (null)
+
0x050
ProtocolReserved : [
6
] (null)
+
0x080
MiniportReserved : [
4
] (null)
+
0x0a0
DataPhysicalAddress : _LARGE_INTEGER
0x0
+
0x0a8
SharedMemoryInfo : (null)
+
0x0a8
ScatterGatherList : (null)
0
: kd> r rcx
rcx
=
ffffb88d5df85f20
0
: kd> t
tcpip!NetioRetreatNetBuffer:
fffff805`
7265bee4
4883ec28
sub rsp,
28h
0
: kd> pc
tcpip!NetioRetreatNetBuffer
+
0x19
:
fffff805`
7265befd
e8ce39d7ff call ndis!NdisRetreatNetBufferDataStart (fffff805`
723cf8d0
)
0
: kd> p
tcpip!NetioRetreatNetBuffer
+
0x1e
:
fffff805`
7265bf02
4883c428
add rsp,
28h
0
: kd> dt _net_buffer ffffb88d5df85f20
ndis!_NET_BUFFER
+
0x000
Next
: (null)
+
0x008
CurrentMdl :
0xffffb88d
`
5bec4220
_MDL
+
0x010
CurrentMdlOffset :
0x50
+
0x018
DataLength :
0x10
+
0x018
stDataLength :
0x10
+
0x020
MdlChain :
0xffffb88d
`
5bec4220
_MDL
+
0x028
DataOffset :
0x50
+
0x000
Link : _SLIST_HEADER
+
0x000
NetBufferHeader : _NET_BUFFER_HEADER
+
0x030
ChecksumBias :
0
+
0x032
Reserved :
0
+
0x038
NdisPoolHandle :
0xffffb88d
`
5ba47940
Void
+
0x040
NdisReserved : [
2
] (null)
+
0x050
ProtocolReserved : [
6
] (null)
+
0x080
MiniportReserved : [
4
] (null)
+
0x0a0
DataPhysicalAddress : _LARGE_INTEGER
0x0
+
0x0a8
SharedMemoryInfo : (null)
+
0x0a8
ScatterGatherList : (null)
/
/
tcpip!Ipv6pReassembleDatagram
v3
=
*
(unsigned __int16
*
)(a2
+
0x88
)
BytesNeeded
=
v3
+
0x28
;
/
/
tcpip!Ipv6pReceiveFragment
important_D8
=
IppCreateInReassemblySet(
(PKSPIN_LOCK)(v5
+
0x4F50
),
*
(void
*
*
)(v1
+
0x110
),
v59,
*
((_DWORD
*
)v11
+
1
),
(KIRQL)arg_0);
if
(
*
((unsigned __int16
*
)important_D8
+
0x2A
)
=
=
*
((_DWORD
*
)important_D8
+
0x23
) )
Ipv6pReassembleDatagram(v1, (__int64)important_D8, v23);
/
/
tcpip!Ipv6pReassembleDatagram
v3
=
*
(unsigned __int16
*
)(a2
+
0x88
)
BytesNeeded
=
v3
+
0x28
;
/
/
tcpip!Ipv6pReceiveFragment
important_D8
=
IppCreateInReassemblySet(
(PKSPIN_LOCK)(v5
+
0x4F50
),
*
(void
*
*
)(v1
+
0x110
),
v59,
*
((_DWORD
*
)v11
+
1
),
(KIRQL)arg_0);
if
(
*
((unsigned __int16
*
)important_D8
+
0x2A
)
=
=
*
((_DWORD
*
)important_D8
+
0x23
) )
Ipv6pReassembleDatagram(v1, (__int64)important_D8, v23);
1.
netbuffer
-
>DataLength
+
fragment_offset >
0xFFFF
2.
if
( !length_last )
{
if
( fragment_offset || fragment_header_for_ipv6_p2
-
>offset_more_fragment_flag &
0x100
)
goto label_error_30;
LABEL_36:
v30
=
important_D8
-
>fragment_sum_length;
v31
=
fragment_offset
+
length_last;
if
( v30
=
=
0xFFFFFFFF
)
/
/
判断是不是还没有更新长度
{
v32
=
(unsigned __int16)important_D8
-
>unknow_length;
important_D8
-
>fragment_sum_length
=
v31;
if
( v32 > v31 || (unsigned __int16)important_D8
-
>field_56 > v31 )
goto label_error_30;
}
else
if
( v31 !
=
v30 )
{
goto label_error_30;
}
goto LABEL_41;
}
if
( !(fragment_header_for_ipv6_p2
-
>offset_more_fragment_flag &
0x100
) )
goto LABEL_36;
3.
*
(_WORD
*
)(data_mdl_struct
+
0xA
)
=
fragment_offset;
/
/
data_mdl_struct 结构体偏移
0xA
处也会刷新 fragment_offset
1.
netbuffer
-
>DataLength
+
fragment_offset >
0xFFFF
2.
if
( !length_last )
{
if
( fragment_offset || fragment_header_for_ipv6_p2
-
>offset_more_fragment_flag &
0x100
)
goto label_error_30;
LABEL_36:
v30
=
important_D8
-
>fragment_sum_length;
v31
=
fragment_offset
+
length_last;
if
( v30
=
=
0xFFFFFFFF
)
/
/
判断是不是还没有更新长度
{
v32
=
(unsigned __int16)important_D8
-
>unknow_length;
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2021-4-10 10:12
被嫣语菲菲~编辑
,原因: