-
-
[求助]win7内核挂钩NtGdiStretchBlt遇到的问题
-
发表于: 2011-6-14 17:19 5587
-
为了实现防止截屏,下面是我挂钩NtGdiStretchBlt的代码片段
//---------------------------------------------------
#define OBJ_PEN 1
#define OBJ_BRUSH 2
#define OBJ_DC 3
#define OBJ_METADC 4
#define OBJ_PAL 5
#define OBJ_FONT 6
#define OBJ_BITMAP 7
#define OBJ_REGION 8
#define OBJ_METAFILE 9
#define OBJ_MEMDC 10
#define OBJ_EXTPEN 11
#define OBJ_ENHMETADC 12
#define OBJ_ENHMETAFILE 13
#define OBJ_COLORSPACE 14
//---------------------------------------------------
#define BLACKNESS 0x00000042 //光栅操作
#define SRCCOPY 0x00CC0020 //光栅操作
//---------------------------------------------------
#define GDI_OBJECT_TYPE_DC 0x00010000
#define GDI_HANDLE_TYPE_MASK 0x007F0000
#define GDI_HANDLE_GET_TYPE(h) (((ULONG_PTR)(h)) & GDI_HANDLE_TYPE_MASK)
//NtGdiGetDCDword(HDC hDC, UINT u, ULONG *Result): u的switch-case的值
typedef enum _GETDCDWORD
{
GdiGetJournal,
GdiGetRelAbs,
GdiGetBreakExtra,
GdiGerCharBreak,
GdiGetArcDirection,
GdiGetEMFRestorDc,
GdiGetFontLanguageInfo,
GdiGetIsMemDc, //GetObjectType用到了此枚举值
GdiGetMapMode,
GdiGetTextCharExtra,
} GETDCDWORD, *PGETDCDWORD;
//NtGdiGetDCPoint(HDC hDC, UINT iPoint, PPOINTL Point): iPoint的switch-case的值
typedef enum _GETDCPOINT
{
GdiGetViewPortExt = 1,
GdiGetWindowExt,
GdiGetViewPortOrg,
GdiGetWindowOrg,
GdiGetAspectRatioFilter,
GdiGetDCOrg = 6,
} GETDCPOINT, *PGETDCPOINT;
//调用NtGdiGetDCDword函数
ULONG GetDCDWord(HDC hDC, INT u, ULONG Result)
{
//NtGdiGetDCDword = (NtGdiGetDCDword_type)*(PULONG)(SSDTShadowBase + NtGdiGetDCDword_ssdt_index*4);
BOOLEAN Ret = NtGdiGetDCDword(hDC, u, (ULONG*) &u);
if (!Ret)
return Result;
else
return u;
}
//该函数确定指定对象的类型
ULONG GetObjectType(HDC h)
{
ULONG Ret = 0;
//LONG Type = GDI_HANDLE_GET_TYPE(h);
if (GDI_HANDLE_GET_TYPE(h) == GDI_OBJECT_TYPE_DC)
{
if (GetDCDWord(h, GdiGetIsMemDc, 0))
Ret = OBJ_MEMDC;
else
Ret = OBJ_DC;
}
return Ret;
}
//判断输入的矩形区域是否为空
BOOLEAN IsRectEmpty(CONST RECT *lprc)
{
return((lprc->left >= lprc->right) || (lprc->top >= lprc->bottom));
}
//判断两个矩形区域是否有重叠,第一个参数返回重叠区域
BOOLEAN IntersectRect(OUT PRECT lprcDst, IN CONST RECT *lprcSrc1, IN CONST RECT *lprcSrc2)
{
if (IsRectEmpty(lprcSrc1) || IsRectEmpty(lprcSrc2) ||
lprcSrc1->left >= lprcSrc2->right ||
lprcSrc2->left >= lprcSrc1->right ||
lprcSrc1->top >= lprcSrc2->bottom ||
lprcSrc2->top >= lprcSrc1->bottom)
{
SetRectEmpty(lprcDst);
return FALSE;
}
lprcDst->left = max(lprcSrc1->left, lprcSrc2->left);
lprcDst->right = min(lprcSrc1->right, lprcSrc2->right);
lprcDst->top = max(lprcSrc1->top, lprcSrc2->top);
lprcDst->bottom = min(lprcSrc1->bottom, lprcSrc2->bottom);
return TRUE;
}
BOOLEAN MyNtGdiStretchBlt(
IN HDC hdcDst, IN INT xDst, IN INT yDst, IN INT cxDst, IN INT cyDst,
IN HDC hdcSrc, IN INT xSrc, IN INT ySrc, IN INT cxSrc, IN INT cySrc,
IN ULONG dwRop, IN ULONG dwBackColor)
{
BOOLEAN bRet;
POINT point;
RECT srcRect, dstRect;
//递增调用记数
InterlockedIncrement((PLONG)&FuncCallingArra[NtGdiStretchBlt_index]);
bRet = OldNtGdiStretchBlt(hdcDst, xDst, yDst, cxDst, cyDst, hdcSrc, xSrc, ySrc, cxSrc, cySrc, dwRop, dwBackColor);
if (ulVKPid != 0 && //虚拟键盘正在运行
!IsPidSafeInput((ULONG)PsGetCurrentProcessId()))//非虚拟键盘调用
{
if (dwRop == SRCCOPY && GetObjectType(hdcSrc) == OBJ_DC)
{
if (GreGetDCPoint(hdcSrc, GdiGetDCOrg, &point))
{
srcRect.left = xSrc + point.x;
srcRect.right = xSrc + cxSrc + point.x;
srcRect.top = ySrc + point.y;
srcRect.bottom = ySrc + cySrc + point.y;
if (IntersectRect(&dstRect, &srcRect, &vkRect))
{
//和虚拟键盘区域有重叠
OldNtGdiStretchBlt(hdcDst, xDst, yDst, cxDst, cyDst,
hdcSrc, dstRect.left, dstRect.top,
dstRect.right-dstRect.left, dstRect.bottom-dstRect.top,
BLACKNESS, dwBackColor);
}
}
else
{
KdPrint(("[SafeInput] GreGetDCPoint error\n"));
}
}
else
{
KdPrint(("[SafeInputMyNtGdiStretchBlt:GetObjectType error\n"));
}
}
//递减调用记数
InterlockedDecrement((PLONG)&FuncCallingArr[NtGdiStretchBlt_index]);
return bRet;
}
这段代码在xp上运行正常,但是在win7上面执行到GreGetDCPoint就会出错。而GreGetDCPoint是未导出符号win32k!GreGetDCPoint,我通过ShadowSSDT首先得到NtGdiGetDCPoint,进一步得到GreGetDCPoint 的地址如下:
//NtGdiGetDCPoint偏移0x16的地方:call win32k!GreGetDCPoint
tmp1 = (ULONG)NtGdiGetDCPoint + 0x16;
tmp2 = *(PULONG)(tmp1 + 1); //CALL操作码长一个字节
GreGetDCPoint = (NtGdiGetDCPoint_type)(tmp2 + tmp1 + 5);
请问有谁知道win7上面这段代码出错的原因吗?
//---------------------------------------------------
#define OBJ_PEN 1
#define OBJ_BRUSH 2
#define OBJ_DC 3
#define OBJ_METADC 4
#define OBJ_PAL 5
#define OBJ_FONT 6
#define OBJ_BITMAP 7
#define OBJ_REGION 8
#define OBJ_METAFILE 9
#define OBJ_MEMDC 10
#define OBJ_EXTPEN 11
#define OBJ_ENHMETADC 12
#define OBJ_ENHMETAFILE 13
#define OBJ_COLORSPACE 14
//---------------------------------------------------
#define BLACKNESS 0x00000042 //光栅操作
#define SRCCOPY 0x00CC0020 //光栅操作
//---------------------------------------------------
#define GDI_OBJECT_TYPE_DC 0x00010000
#define GDI_HANDLE_TYPE_MASK 0x007F0000
#define GDI_HANDLE_GET_TYPE(h) (((ULONG_PTR)(h)) & GDI_HANDLE_TYPE_MASK)
//NtGdiGetDCDword(HDC hDC, UINT u, ULONG *Result): u的switch-case的值
typedef enum _GETDCDWORD
{
GdiGetJournal,
GdiGetRelAbs,
GdiGetBreakExtra,
GdiGerCharBreak,
GdiGetArcDirection,
GdiGetEMFRestorDc,
GdiGetFontLanguageInfo,
GdiGetIsMemDc, //GetObjectType用到了此枚举值
GdiGetMapMode,
GdiGetTextCharExtra,
} GETDCDWORD, *PGETDCDWORD;
//NtGdiGetDCPoint(HDC hDC, UINT iPoint, PPOINTL Point): iPoint的switch-case的值
typedef enum _GETDCPOINT
{
GdiGetViewPortExt = 1,
GdiGetWindowExt,
GdiGetViewPortOrg,
GdiGetWindowOrg,
GdiGetAspectRatioFilter,
GdiGetDCOrg = 6,
} GETDCPOINT, *PGETDCPOINT;
//调用NtGdiGetDCDword函数
ULONG GetDCDWord(HDC hDC, INT u, ULONG Result)
{
//NtGdiGetDCDword = (NtGdiGetDCDword_type)*(PULONG)(SSDTShadowBase + NtGdiGetDCDword_ssdt_index*4);
BOOLEAN Ret = NtGdiGetDCDword(hDC, u, (ULONG*) &u);
if (!Ret)
return Result;
else
return u;
}
//该函数确定指定对象的类型
ULONG GetObjectType(HDC h)
{
ULONG Ret = 0;
//LONG Type = GDI_HANDLE_GET_TYPE(h);
if (GDI_HANDLE_GET_TYPE(h) == GDI_OBJECT_TYPE_DC)
{
if (GetDCDWord(h, GdiGetIsMemDc, 0))
Ret = OBJ_MEMDC;
else
Ret = OBJ_DC;
}
return Ret;
}
//判断输入的矩形区域是否为空
BOOLEAN IsRectEmpty(CONST RECT *lprc)
{
return((lprc->left >= lprc->right) || (lprc->top >= lprc->bottom));
}
//判断两个矩形区域是否有重叠,第一个参数返回重叠区域
BOOLEAN IntersectRect(OUT PRECT lprcDst, IN CONST RECT *lprcSrc1, IN CONST RECT *lprcSrc2)
{
if (IsRectEmpty(lprcSrc1) || IsRectEmpty(lprcSrc2) ||
lprcSrc1->left >= lprcSrc2->right ||
lprcSrc2->left >= lprcSrc1->right ||
lprcSrc1->top >= lprcSrc2->bottom ||
lprcSrc2->top >= lprcSrc1->bottom)
{
SetRectEmpty(lprcDst);
return FALSE;
}
lprcDst->left = max(lprcSrc1->left, lprcSrc2->left);
lprcDst->right = min(lprcSrc1->right, lprcSrc2->right);
lprcDst->top = max(lprcSrc1->top, lprcSrc2->top);
lprcDst->bottom = min(lprcSrc1->bottom, lprcSrc2->bottom);
return TRUE;
}
BOOLEAN MyNtGdiStretchBlt(
IN HDC hdcDst, IN INT xDst, IN INT yDst, IN INT cxDst, IN INT cyDst,
IN HDC hdcSrc, IN INT xSrc, IN INT ySrc, IN INT cxSrc, IN INT cySrc,
IN ULONG dwRop, IN ULONG dwBackColor)
{
BOOLEAN bRet;
POINT point;
RECT srcRect, dstRect;
//递增调用记数
InterlockedIncrement((PLONG)&FuncCallingArra[NtGdiStretchBlt_index]);
bRet = OldNtGdiStretchBlt(hdcDst, xDst, yDst, cxDst, cyDst, hdcSrc, xSrc, ySrc, cxSrc, cySrc, dwRop, dwBackColor);
if (ulVKPid != 0 && //虚拟键盘正在运行
!IsPidSafeInput((ULONG)PsGetCurrentProcessId()))//非虚拟键盘调用
{
if (dwRop == SRCCOPY && GetObjectType(hdcSrc) == OBJ_DC)
{
if (GreGetDCPoint(hdcSrc, GdiGetDCOrg, &point))
{
srcRect.left = xSrc + point.x;
srcRect.right = xSrc + cxSrc + point.x;
srcRect.top = ySrc + point.y;
srcRect.bottom = ySrc + cySrc + point.y;
if (IntersectRect(&dstRect, &srcRect, &vkRect))
{
//和虚拟键盘区域有重叠
OldNtGdiStretchBlt(hdcDst, xDst, yDst, cxDst, cyDst,
hdcSrc, dstRect.left, dstRect.top,
dstRect.right-dstRect.left, dstRect.bottom-dstRect.top,
BLACKNESS, dwBackColor);
}
}
else
{
KdPrint(("[SafeInput] GreGetDCPoint error\n"));
}
}
else
{
KdPrint(("[SafeInputMyNtGdiStretchBlt:GetObjectType error\n"));
}
}
//递减调用记数
InterlockedDecrement((PLONG)&FuncCallingArr[NtGdiStretchBlt_index]);
return bRet;
}
这段代码在xp上运行正常,但是在win7上面执行到GreGetDCPoint就会出错。而GreGetDCPoint是未导出符号win32k!GreGetDCPoint,我通过ShadowSSDT首先得到NtGdiGetDCPoint,进一步得到GreGetDCPoint 的地址如下:
//NtGdiGetDCPoint偏移0x16的地方:call win32k!GreGetDCPoint
tmp1 = (ULONG)NtGdiGetDCPoint + 0x16;
tmp2 = *(PULONG)(tmp1 + 1); //CALL操作码长一个字节
GreGetDCPoint = (NtGdiGetDCPoint_type)(tmp2 + tmp1 + 5);
请问有谁知道win7上面这段代码出错的原因吗?
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
赞赏
他的文章
看原图
赞赏
雪币:
留言: