Windows Cloud Files Mini Filter 驱动中存在越界写入漏洞,在解析Reparse point数据时,由于memcpy函数的长度参数用户可控,源内存可控,导致攻击者可以构造恶意结构并传递给Windows Cloud Files Mini Filter 驱动,造成越界写入,并在内核执行任意代码。
略
cldflt.sys驱动中实现了云文件的各项功能,diff该驱动,修改函数如下:
在HsmpRpiDecompressBuffer
函数中有如下修改,对*(_WORD *)(a1 + 10)
添加了一个判断,是否>0x4000
,
如果大于则抛出错误 0xC000CF02
对应 STATUS_CLOUD_FILE_METADATA_CORRUPT
65bK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6W2L8X3c8G2k6r3g2J5L8h3W2K6y4e0W2Q4x3X3g2J5M7%4y4A6L8X3N6Q4x3X3g2U0L8$3#2Q4x3V1k6U0K9r3q4F1i4K6u0V1x3K6j5#2z5o6M7@1y4K6m8Q4x3V1k6S2L8r3I4Q4y4h3k6H3y4W2)9J5k6h3S2@1L8h3H3`.
AI输出
HsmpRpiDecompressBuffer
由 HsmpRpReadBuffer
调用
AI解释
HsmpRpReadBuffer
由 HsmpRpCommitNoLock
和 HsmpSetupContexts
调用。
HsmpRpCommitNoLock
解释如下
在 HsmpRpCommitNoLock
中有如下代码,可以看到在前面diff中出现的0x4000和0x3FFC,可以猜测漏洞产生于该函数中
继续审查代码,发现在HsmpRpCommitNoLock
中有如下代码,在do while循环中调用memmove函数时,传入的src来源于 HsmpRpReadBuffer
解压后的element[10]
数据,dst为ExAllocatePoolWithTag
分配的大小为0x4000的内存。长度参数来源于ElementInfos[10].Length
,不难看出由此可以造成越界写入,且用户可控。
搜索Reparse point RtlCompressBuffer
,找到文章,根据文章 _REPARSE_DATA_BUFFER
定义如下,可以知道传入 HsmpRpiDecompressBuffer
的是 REPARSE_DATA_BUFFER
,其中 ReparseTag
为IO_REPARSE_TAG_CLOUD_3
值 0x9000301A
并且在结构体 HsmReparseBufferRaw
的RawData
成员中存储了由 RtlCompressBuffer
压缩的数据HsmReparseBufferRaw
_REPARSE_DATA_BUFFER
定义
在这个Github仓库 中实现了对Reparse point的解析,其中定义了HSM_REPARSE_DATA
对应在 REPARSE_DATA_BUFFER
的偏移如下
结构体_HSM_ELEMENT_INFO
内存信息
PoC构造
将结构体导入到ida中,在HsmpRpCommitNoLock
中首先对ReparseTag进行验证,而后将hsm_reparse_data和对应的长度导入到 HsmpRpValidateBuffer
函数中验证。
在 HsmpRpValidateBuffer
函数中对HSM_DATA结构体的一些字段做了如下校验。
特别的,从如下代码中可以看到对ElementInfos[0]
和ElementInfos[1]
进行了校验,容易得出如下条件:
如下代码对ElementInfos[2]
进行了校验,有如下:
后面还有一堆校验逻辑就不贴了。
在 HsmpRpCommitNoLock
中对 HsmpRpValidateBuffer
返回值做了校验,如果IsReparseBufferSupported
不为0则会进入报错逻辑,而在 HsmpRpValidateBuffer
在HsmpRpValidateBuffer
中可以看到当通过第一次校验后,如果ElementInfos[1]
的Data & 0x10 则会直接返回,此时IsReparseBufferSupported=0
能通过校验。
通过构造ElementInfos[0]
和ElementInfos[1]
可以通过HsmpRpValidateBuffer
校验,而后漏洞触发点会读取ElementInfos[10]
的数据和Length通过memcpy进行拷贝,所以还需要构造ElementInfos[10]
的数据,并且ElementInfos[10]
的Length需要超过目标缓冲区,特别的在计算CRC32后,需要通过RtlCompressBuffer压缩目标数据,并放入到FileData处。
构造多大的缓冲区?根据前面补丁分析,在补丁中限制了ReparseDataLength < 0x4000,所以超过四千的部分会造成溢出,如果想溢出8个字节则需要构造0x4008 + 8 = 0x4010,依此类推,在构造缓冲区时。
如何将构造好的数据传递给驱动并在目标位置触发呢?在网上查到有类似漏洞分析文章Windows云文件迷你过滤器驱动程序中的提权漏洞(CVE-2021-31969) ,不难看出CVE-2021-31969修复和本次分析的漏洞CVE-2023-36036修复位置类似,都对ReparseDataLength进行了判断,所以本次PoC编写也可以借鉴。
在CVE-2021-31969分析文章中贴出了部分PoC,结合这部分PoC和前面的结构体,写出PoC也就不难了。
RtlCompressBuffer声明bc5K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2U0L8X3u0D9L8$3N6K6i4K6u0W2j5$3!0E0i4K6u0r3e0s2W2e0K9r3q4J5K9#2)9J5c8Y4m8Q4x3V1j5I4y4K6R3@1z5o6M7J5y4q4)9J5k6h3S2@1L8h3H3`.
动态调试
在如下两个位置下断点
运行poc,可以看到已经进入HsmpRpCommitNoLock
函数
继续运行,触发第二个断点
此时memmove已经被优化为memcpy,而要拷贝的长度为0x3f94,dst所在的堆大小为0x4000,dst指向偏移0x74处,最多有0x3f8c大小,所以memcpy拷贝时会越界写入8个字节,造成堆溢出。
继续运行,则在memcpy内部触发异常,因为尝试往未分配的内存里面写入00
对应代码为
以下为调用栈
febK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6h3y4Z5x3K6g2@1L8Y4g2@1i4K6u0W2M7$3W2@1k6g2)9J5c8X3W2E0j5h3N6W2M7#2)9J5c8Y4k6#2L8r3&6W2M7X3q4T1K9h3I4A6N6s2W2Q4x3V1k6o6g2V1g2Q4x3X3b7J5x3o6t1K6i4K6u0V1x3K6j5H3x3K6k6Q4x3X3c8i4K9h3&6V1L8%4N6K6i4K6u0V1b7$3I4G2N6h3c8Q4x3X3c8r3K9h3I4W2M7#2)9J5k6p5#2A6L8X3W2Q4x3X3c8r3K9h3I4@1k6i4u0Q4x3X3c8p5M7X3W2$3k6i4u0Q4x3X3c8q4L8%4m8Q4x3X3g2*7K9q4)9J5k6r3y4F1i4K6u0W2j5i4y4K6k6i4c8K6i4K6u0r3x3#2)9J5k6i4m8F1k6H3`.`." style="max-width: 100%;" alt="">
这里调用HsmpRpValidateBuffer
这里调用ExAllocatePoolWithTag
PoC会在过几天上传到GitHub
本次漏洞分析离不开业内前辈逆向得出的_HSM_REPARSE_DATA结构体信息,这个结构体微软没有公开的文档,相关资料也很少。目前只有这一个仓库有相关信息,向前辈致敬。
![[../../../images/vulneribility/CVE-2023-36036/7.png]]
这里引用一下前辈的主页。
f7fK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2*7k6i4A6#2L8r3q4Q4x3X3g2F1k6i4c8Q4x3V1k6W2L8W2)9J5c8Y4c8G2L8$3I4K6i4K6u0r3L8h3q4A6L8W2)9J5k6h3S2@1L8h3H3`.
整体来看,这个漏洞原理和触发方式较为简单,在使用memcpy之前没有校验长度,而修复也简单,再解压之前验证长度是否超过0x4000,超过则认为数据有错,进入到错误逻辑,从而在源头阻止了触发漏洞逻辑。
在漏洞修复处在修复上个整数下溢的漏洞时,开发人员只修复当时的整数下溢漏洞,没有去考虑长度会不会过长,某些程度来说这也是开发的粗心大意导致了这个漏洞留到现在。
在编写PoC参考了其他安全研究员已有的分析。
参考链接
187K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6E0M7%4u0U0i4K6u0W2L8h3W2U0M7X3!0K6L8$3k6@1i4K6u0W2j5$3!0E0i4K6u0r3N6i4m8V1j5i4c8W2i4K6u0V1k6%4g2A6k6r3g2Q4x3V1k6$3N6h3I4F1k6i4u0S2j5X3W2D9K9i4c8&6i4K6u0r3b7#2k6q4i4K6u0V1x3U0l9J5x3#2)9J5k6o6x3$3x3o6x3$3 2a6K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6*7K9s2g2S2L8X3I4S2L8W2)9J5k6i4A6Z5K9h3S2#2i4K6u0W2j5$3!0E0i4K6u0r3M7q4)9J5c8U0x3&6x3U0p5&6y4o6b7$3y4l9`.`. 4abK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6E0K9h3y4J5L8%4y4G2k6Y4c8Q4x3V1k6i4K9h3&6V1L8%4N6K6i4K6u0V1j5$3I4S2M7%4y4A6j5#2)9J5k6s2y4S2L8i4m8D9k6i4y4Q4x3V1k6@1M7X3g2W2i4K6u0r3L8h3q4A6L8W2)9J5c8W2y4S2L8i4m8D9k6i4y4Q4x3V1k6o6L8r3!0#2k6p5#2A6M7Y4u0G2M7R3`.`. 510K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6D9k6h3q4J5L8W2)9J5k6h3#2A6j5%4u0G2M7$3!0X3N6q4)9J5k6h3y4G2L8g2)9J5c8X3g2F1i4K6u0V1N6i4y4Q4x3V1k6%4K9h3&6V1L8%4N6K6i4K6u0r3N6$3W2F1x3K6u0Q4x3V1k6U0k6X3q4H3K9g2)9J5c8X3y4D9L8%4g2V1i4K6u0V1k6X3W2D9N6r3g2J5i4K6u0V1M7X3g2X3k6i4u0W2L8X3y4W2 55dK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6D9k6h3q4J5L8W2)9J5k6h3#2A6j5%4u0G2M7$3!0X3N6q4)9J5k6h3y4G2L8g2)9J5c8Y4A6Z5i4K6u0V1j5$3&6Q4x3V1k6%4K9h3&6V1L8%4N6K6i4K6u0r3N6$3W2F1x3K6u0Q4x3V1k6U0k6X3q4H3K9g2)9J5c8X3y4D9L8%4g2V1i4K6u0V1k6X3W2D9k6i4y4Q4x3X3c8X3N6h3&6U0N6r3W2G2L8Y4x3`. 8e4K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6D9k6h3q4J5L8W2)9J5k6h3#2A6j5%4u0G2M7$3!0X3N6q4)9J5k6h3y4G2L8g2)9J5c8X3g2F1i4K6u0V1N6i4y4Q4x3V1k6%4K9h3&6V1L8%4N6K6i4K6u0r3N6$3W2F1x3K6u0Q4x3V1k6S2M7r3W2Q4x3V1k6Q4y4h3k6U0L8r3!0#2k6r3q4H3K9g2)9J5c8R3`.`.
HsmpRpiDecompressBuffer函数的作用是解压压缩后的Reparse Point数据。
主要功能包括:
1. 校验传入数据的完整性和魔数是否正确
2. 如果数据被压缩,则根据原长度分配解压缓冲区
3. 调用RtlDecompressBuffer进行实际解压
4. 检查解压后数据长度是否匹配
5. 如果解压成功,返回解压后的数据
6. 否则返回错误码
所以它是一个典型的压缩数据解压函数,接收原始压缩数据,校验->分配缓冲区->解压->返回解压后数据的过程。
通过解压让后续代码可以处理未压缩的Reparse Point数据,一般在需要提交/更新数据时会解压。
主要作用就是将压缩后的Reparse Point还原为可读的未压缩数据。
HsmpRpiDecompressBuffer函数的作用是解压压缩后的Reparse Point数据。
主要功能包括:
1. 校验传入数据的完整性和魔数是否正确
2. 如果数据被压缩,则根据原长度分配解压缓冲区
3. 调用RtlDecompressBuffer进行实际解压
4. 检查解压后数据长度是否匹配
5. 如果解压成功,返回解压后的数据
6. 否则返回错误码
所以它是一个典型的压缩数据解压函数,接收原始压缩数据,校验->分配缓冲区->解压->返回解压后数据的过程。
通过解压让后续代码可以处理未压缩的Reparse Point数据,一般在需要提交/更新数据时会解压。
主要作用就是将压缩后的Reparse Point还原为可读的未压缩数据。
__int64
__fastcall HsmpRpReadBuffer(PFLT_INSTANCE Instance, PFILE_OBJECT FileObject, unsigned
__int16
**a3)
{
...
*a3 = 0i64;
v6 = 1024;
OutputBuffer = (unsigned
__int16
*)ExAllocatePoolWithTag(PagedPool, 0x400ui64, 0x70527348u);
v8 = OutputBuffer;
......
}
LODWORD(v9) = HsmpRpiDecompressBuffer((
__int64
)v8, v6, a3);
HsmDbgBreakOnStatus((unsigned
int
)v9);
if
( (
int
)v9 < 0 )
{
v16 = WPP_GLOBAL_Control;
if
( WPP_GLOBAL_Control == (PDEVICE_OBJECT)&WPP_GLOBAL_Control
|| (HIDWORD(WPP_GLOBAL_Control->Timer) & 1) == 0
|| BYTE1(WPP_GLOBAL_Control->Timer) < 2u )
{
goto
LABEL_8;
}
v17 = 20i64;
goto
LABEL_30;
}
if
( *a3 != v8 )
LABEL_8:
ExFreePoolWithTag(v8, 0x70527348u);
return
(unsigned
int
)v9;
}
__int64
__fastcall HsmpRpReadBuffer(PFLT_INSTANCE Instance, PFILE_OBJECT FileObject, unsigned
__int16
**a3)
{
...
*a3 = 0i64;
v6 = 1024;
OutputBuffer = (unsigned
__int16
*)ExAllocatePoolWithTag(PagedPool, 0x400ui64, 0x70527348u);
v8 = OutputBuffer;
......
}
LODWORD(v9) = HsmpRpiDecompressBuffer((
__int64
)v8, v6, a3);
HsmDbgBreakOnStatus((unsigned
int
)v9);
if
( (
int
)v9 < 0 )
{
v16 = WPP_GLOBAL_Control;
if
( WPP_GLOBAL_Control == (PDEVICE_OBJECT)&WPP_GLOBAL_Control
|| (HIDWORD(WPP_GLOBAL_Control->Timer) & 1) == 0
|| BYTE1(WPP_GLOBAL_Control->Timer) < 2u )
{
goto
LABEL_8;
}
v17 = 20i64;
goto
LABEL_30;
}
if
( *a3 != v8 )
LABEL_8:
ExFreePoolWithTag(v8, 0x70527348u);
return
(unsigned
int
)v9;
}
这段代码实现了解析和解压Reparse Point数据的功能:
1.
分配OutputBuffer内存用于读取Reparse数据。
2.
调用FltFsControlFile读取Reparse数据到OutputBuffer。
3.
如果读取失败,并且错误码表示
buffer
太小,则重新分配更大的
buffer
并重试读取。
4.
调用HsmpRpiDecompressBuffer对读取到的数据进行解压。
5.
如果解压成功,返回解压后的数据,否则返回错误码。
6.
释放原始数据内存。
7.
其中包含了详细的错误和日志记录逻辑。
所以总的来说,这段代码用于从文件系统读取Reparse Point数据,然后对数据进行解压和解析,最后返回解析后的数据。
主要功能聚焦在读取压缩数据并解压这块。
这段代码实现了解析和解压Reparse Point数据的功能:
1.
分配OutputBuffer内存用于读取Reparse数据。
2.
调用FltFsControlFile读取Reparse数据到OutputBuffer。
3.
如果读取失败,并且错误码表示
buffer
太小,则重新分配更大的
buffer
并重试读取。
4.
调用HsmpRpiDecompressBuffer对读取到的数据进行解压。
5.
如果解压成功,返回解压后的数据,否则返回错误码。
6.
释放原始数据内存。
7.
其中包含了详细的错误和日志记录逻辑。
所以总的来说,这段代码用于从文件系统读取Reparse Point数据,然后对数据进行解压和解析,最后返回解析后的数据。
主要功能聚焦在读取压缩数据并解压这块。
这个C函数实现了HsmpRpCommitNoLock,它似乎是用于在没有锁的情况下提交页面重播(Page Replay)数据。
主要的逻辑如下:
1. 校验和准备输入数据
2. 分配内存池来存储提交的数据
3. 构建数据结构,填充各种元数据
4. 尝试压缩数据
5. 将数据写入文件
6. 清理临时数据结构和内存
具体来说,这个函数做了以下工作:
1. 验证输入参数的有效性
2. 为输出缓冲区分配内存
3. 构建输出缓冲区的数据结构
4. 填充输出缓冲区的头部
5. 将输入缓冲区的数据复制到输出缓冲区
6. 计算校验和
7. 尝试压缩输出缓冲区
8. 标记文件属性
9. 将输出缓冲区的数据写入文件
10. 重置文件属性
11. 释放临时缓冲区和内存
所以总的来说,这个函数的主要目的是准备并提交页面重播数据,同时处理必要的校验、压缩和清理工作。
这个C函数实现了HsmpRpCommitNoLock,它似乎是用于在没有锁的情况下提交页面重播(Page Replay)数据。
主要的逻辑如下:
1. 校验和准备输入数据
2. 分配内存池来存储提交的数据
3. 构建数据结构,填充各种元数据
4. 尝试压缩数据
5. 将数据写入文件
6. 清理临时数据结构和内存
具体来说,这个函数做了以下工作:
1. 验证输入参数的有效性
2. 为输出缓冲区分配内存
3. 构建输出缓冲区的数据结构
4. 填充输出缓冲区的头部
5. 将输入缓冲区的数据复制到输出缓冲区
6. 计算校验和
7. 尝试压缩输出缓冲区
8. 标记文件属性
9. 将输出缓冲区的数据写入文件
10. 重置文件属性
11. 释放临时缓冲区和内存
所以总的来说,这个函数的主要目的是准备并提交页面重播数据,同时处理必要的校验、压缩和清理工作。
LABEL_156:
PoolWithTag = (unsigned
int
*)ExAllocatePoolWithTag(PagedPool, 0x4000ui64, 0x70527348u);
v142 = PoolWithTag;
v11 = (
char
*)PoolWithTag;
if
( PoolWithTag )
{
memset
(PoolWithTag, 0, 0x4000ui64);
v57 = InputBuffer;
v58 = v11 + 4;
if
( v8 && *((_WORD *)v8 + 7) > 0xAu )
v57 = *((_WORD *)v8 + 7);
v59 = (unsigned
int
*)(v58 + 8);
*((_WORD *)v58 + 6) = 0;
v9 = (unsigned
__int64
)(v58 + 16);
*((_WORD *)v58 + 7) = v57;
*((_DWORD *)v58 + 2) = 8 * v57 + 16;
*(_DWORD *)v58 =
'pReF'
;
memset
(v58 + 16, 0, 8i64 * v57);
if
( *((_WORD *)v58 + 7) )
{
v60 = *v59;
if
( ((v60 + 3) & 0xFFFFFFFFFFFFFFFCui64) + 1 <= 0x3FFC )
{
*v59 = (v60 + 3) & 0xFFFFFFFC;
if
( *(_WORD *)v9 )
*((_WORD *)v58 + 6) |= 1u;
*(_WORD *)v9 = 7;
LODWORD(v9) = 0;
*((_WORD *)v58 + 9) = 1;
v61 = *v59;
*((_DWORD *)v58 + 5) = v61;
v58[v61] = 1;
LABEL_156:
PoolWithTag = (unsigned
int
*)ExAllocatePoolWithTag(PagedPool, 0x4000ui64, 0x70527348u);
v142 = PoolWithTag;
v11 = (
char
*)PoolWithTag;
if
( PoolWithTag )
{
memset
(PoolWithTag, 0, 0x4000ui64);
v57 = InputBuffer;
v58 = v11 + 4;
if
( v8 && *((_WORD *)v8 + 7) > 0xAu )
v57 = *((_WORD *)v8 + 7);
v59 = (unsigned
int
*)(v58 + 8);
*((_WORD *)v58 + 6) = 0;
v9 = (unsigned
__int64
)(v58 + 16);
*((_WORD *)v58 + 7) = v57;
*((_DWORD *)v58 + 2) = 8 * v57 + 16;
*(_DWORD *)v58 =
'pReF'
;
memset
(v58 + 16, 0, 8i64 * v57);
if
( *((_WORD *)v58 + 7) )
{
v60 = *v59;
if
( ((v60 + 3) & 0xFFFFFFFFFFFFFFFCui64) + 1 <= 0x3FFC )
{
*v59 = (v60 + 3) & 0xFFFFFFFC;
if
( *(_WORD *)v9 )
*((_WORD *)v58 + 6) |= 1u;
*(_WORD *)v9 = 7;
LODWORD(v9) = 0;
*((_WORD *)v58 + 9) = 1;
v61 = *v59;
*((_DWORD *)v58 + 5) = v61;
v58[v61] = 1;
v32 = 0i64;
if
( (v9 & 0x80000000) == 0i64 )
{
v8 = (
char
*)P + 12;
...
{
if
( (_DWORD)v54 && (_WORD)v55 )
v167 = &v8[v54];
else
v167 = v32;
.....
PoolWithTag = (unsigned
int
*)ExAllocatePoolWithTag(PagedPool, 0x4000ui64, 0x70527348u);
v142 = PoolWithTag;
v11 = (
char
*)PoolWithTag;
if
( PoolWithTag )
{
memset
(PoolWithTag, 0, 0x4000ui64);
v57 = InputBuffer;
v58 = v11 + 4;
if
( v8 && *((_WORD *)v8 + 7) > 0xAu )
v57 = *((_WORD *)v8 + 7);
v59 = (unsigned
int
*)(v58 + 8);
*((_WORD *)v58 + 6) = 0;
v9 = (unsigned
__int64
)(v58 + 16);
*((_WORD *)v58 + 7) = v57;
*((_DWORD *)v58 + 2) = 8 * v57 + 16;
*(_DWORD *)v58 =
'pReF'
;
memset
(v58 + 16, 0, 8i64 * v57);
.....
}
*v59 += v109;
.....
if
( *((_WORD *)v58 + 28) )
*((_WORD *)v58 + 6) |= 1u;
*v59 = (v113 + 3) & 0xFFFFFFFC;
....
*v59 += v114;
.....
v117 = (
char
*)v167;
v107 = (
char
*)Src;
*v59 = (v118 + 3) & 0xFFFFFFFC;
*((_WORD *)v58 + 32) = 17;
*((_WORD *)v58 + 33) = v119;
v121 = *v59;
*((_DWORD *)v58 + 17) = v121;
if
( &v58[v121] != v117 )
{
memmove
(&v58[v121], v117, v120);
......
v125 = 10;
do
{
v126 = v125;
*(HSM_ELEMENT_INFO *)&v58[8 * v125 + 16] = v124->ElementInfos[v125];
memmove
(&v58[*v59], (
char
*)v124 + v124->ElementInfos[v125].Offset, v124->ElementInfos[v125].Length);
++v125;
*(_DWORD *)&v58[8 * v126 + 20] = *v59;
*v59 += *(unsigned
__int16
*)&v58[8 * v126 + 18];
}
while
( v125 < v124->NumberOfElements );
...
if
( v14 )
ExFreePoolWithTag(v14, 0x70527348u);
if
( v11 )
ExFreePoolWithTag(v11, 0x70527348u);
return
(unsigned
int
)v9;
}
v32 = 0i64;
if
( (v9 & 0x80000000) == 0i64 )
{
v8 = (
char
*)P + 12;
...
{
if
( (_DWORD)v54 && (_WORD)v55 )
v167 = &v8[v54];
else
v167 = v32;
.....
PoolWithTag = (unsigned
int
*)ExAllocatePoolWithTag(PagedPool, 0x4000ui64, 0x70527348u);
v142 = PoolWithTag;
v11 = (
char
*)PoolWithTag;
if
( PoolWithTag )
{
memset
(PoolWithTag, 0, 0x4000ui64);
v57 = InputBuffer;
v58 = v11 + 4;
if
( v8 && *((_WORD *)v8 + 7) > 0xAu )
v57 = *((_WORD *)v8 + 7);
v59 = (unsigned
int
*)(v58 + 8);
*((_WORD *)v58 + 6) = 0;
v9 = (unsigned
__int64
)(v58 + 16);
*((_WORD *)v58 + 7) = v57;
*((_DWORD *)v58 + 2) = 8 * v57 + 16;
*(_DWORD *)v58 =
'pReF'
;
memset
(v58 + 16, 0, 8i64 * v57);
.....
}
*v59 += v109;
.....
if
( *((_WORD *)v58 + 28) )
*((_WORD *)v58 + 6) |= 1u;
*v59 = (v113 + 3) & 0xFFFFFFFC;
....
*v59 += v114;
.....
v117 = (
char
*)v167;
v107 = (
char
*)Src;
*v59 = (v118 + 3) & 0xFFFFFFFC;
*((_WORD *)v58 + 32) = 17;
*((_WORD *)v58 + 33) = v119;
v121 = *v59;
*((_DWORD *)v58 + 17) = v121;
if
( &v58[v121] != v117 )
{
memmove
(&v58[v121], v117, v120);
......
v125 = 10;
do
{
v126 = v125;
*(HSM_ELEMENT_INFO *)&v58[8 * v125 + 16] = v124->ElementInfos[v125];
memmove
(&v58[*v59], (
char
*)v124 + v124->ElementInfos[v125].Offset, v124->ElementInfos[v125].Length);
++v125;
*(_DWORD *)&v58[8 * v126 + 20] = *v59;
*v59 += *(unsigned
__int16
*)&v58[8 * v126 + 18];
}
while
( v125 < v124->NumberOfElements );
...
if
( v14 )
ExFreePoolWithTag(v14, 0x70527348u);
if
( v11 )
ExFreePoolWithTag(v11, 0x70527348u);
return
(unsigned
int
)v9;
}
struct
{
USHORT
Flags;
USHORT
Length;
BYTE
RawData[1];
} HsmReparseBufferRaw;
struct
{
USHORT
Flags;
USHORT
Length;
BYTE
RawData[1];
} HsmReparseBufferRaw;
typedef
struct
_REPARSE_DATA_BUFFER {
ULONG
ReparseTag;
USHORT
ReparseDataLength;
USHORT
Reserved;
union
{
struct
{
USHORT
SubstituteNameOffset;
USHORT
SubstituteNameLength;
USHORT
PrintNameOffset;
USHORT
PrintNameLength;
ULONG
Flags;
WCHAR
PathBuffer[1];
} SymbolicLinkReparseBuffer;
struct
{
USHORT
SubstituteNameOffset;
USHORT
SubstituteNameLength;
USHORT
PrintNameOffset;
USHORT
PrintNameLength;
WCHAR
PathBuffer[1];
} MountPointReparseBuffer;
struct
{
GUID ImageGuid;
BYTE
ImagePathHash[0x14];
} WimImageReparseBuffer;
struct
{
ULONG
Wof_Version;
ULONG
Wof_Provider;
ULONG
FileInfo_Version;
ULONG
FileInfo_Algorithm;
} WofReparseBuffer;
struct
{
ULONG
StringCount;
WCHAR
StringList[1];
} AppExecLinkReparseBuffer;
struct
{
ULONG
Version;
ULONG
Reserved;
GUID LookupGuid;
USHORT
WciNameLength;
WCHAR
WciName[1];
} WcifsReparseBuffer;
struct
{
USHORT
Flags;
USHORT
Length;
BYTE
RawData[1];
} HsmReparseBufferRaw;
struct
{
UCHAR
DataBuffer[1];
} GenericReparseBuffer;
} DUMMYUNIONNAME;
} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
typedef
struct
_REPARSE_DATA_BUFFER {
ULONG
ReparseTag;
USHORT
ReparseDataLength;
USHORT
Reserved;
union
{
struct
{
USHORT
SubstituteNameOffset;
USHORT
SubstituteNameLength;
USHORT
PrintNameOffset;
USHORT
PrintNameLength;
ULONG
Flags;
WCHAR
PathBuffer[1];
} SymbolicLinkReparseBuffer;
struct
{
USHORT
SubstituteNameOffset;
USHORT
SubstituteNameLength;
USHORT
PrintNameOffset;
USHORT
PrintNameLength;
WCHAR
PathBuffer[1];
} MountPointReparseBuffer;
struct
{
GUID ImageGuid;
BYTE
ImagePathHash[0x14];
} WimImageReparseBuffer;
struct
{
ULONG
Wof_Version;
ULONG
Wof_Provider;
ULONG
FileInfo_Version;
ULONG
FileInfo_Algorithm;
} WofReparseBuffer;
struct
{
ULONG
StringCount;
WCHAR
StringList[1];
} AppExecLinkReparseBuffer;
struct
{
ULONG
Version;
ULONG
Reserved;
GUID LookupGuid;
USHORT
WciNameLength;
WCHAR
WciName[1];
} WcifsReparseBuffer;
struct
{
USHORT
Flags;
USHORT
Length;
BYTE
RawData[1];
} HsmReparseBufferRaw;
struct
{
UCHAR
DataBuffer[1];
} GenericReparseBuffer;
} DUMMYUNIONNAME;
} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
typedef
struct
_HSM_ELEMENT_INFO
{
USHORT
Type;
USHORT
Length;
ULONG
Offset;
} HSM_ELEMENT_INFO, *PHSM_ELEMENT_INFO;
typedef
struct
_HSM_DATA
{
ULONG
Magic;
ULONG
Crc32;
ULONG
Length;
USHORT
Flags;
USHORT
NumberOfElements;
HSM_ELEMENT_INFO ElementInfos[1];
} HSM_DATA, *PHSM_DATA;
typedef
struct
_HSM_REPARSE_DATA
{
USHORT
Flags;
USHORT
Length;
HSM_DATA FileData;
} HSM_REPARSE_DATA, *PHSM_REPARSE_DATA;
[注意]看雪招聘,专注安全领域的专业人才平台!