通过内核HOOK处理某个进程对SetCursorPos的调用

最近打开一个游戏,发现该游戏不断调用SetCursorPos这个函数,所以想着在内核中PASS掉它,经过两周断断续续的研究,终于在今晚成功PASS掉它。

经过两周断断续续的查资料,看视频,分析,终于达到目的。
关于鼠标的处理:
获得鼠标的位置函数GetCursorPos,设置鼠标的位置SetCursorPos
获得暂且不分析,这里只说SetCursorPos,其实这两个也是异曲同工。
SetCursorPos的调用过程: User32!SetCursorPos-->User32!NtUserCallTwoParam-->win32k!NtUserCallTwoParam
通过反汇编可以看出来调用NtUserCallTwoParam这个函数时候 根据第一个参数的不同而区分不同的函数
SetCursorPos的参数正是74h,另外两个参数随机,只需要判断该参数是74h就知道是SetCursorPos在调用
关于win32k!NtUserCallTwoParam的HOOK,该函数是ShadowSSDT表中的函数
在程序中想获得ShadowSSDT就必须先附加一个进程 它的结构和SSDT相同但是不是导出的
1.所以先获得ShadowSSDT表地址:
<1>声明SSDT表结构

typedef struct _SDT_ENTRY  //SSDT
{
	PVOID *ServiceTableBase;
	PULONG ServiceCounterTableBase;
	ULONG NumberOfServices;
	PUCHAR ParamTableBase;
}SDT_ENTRY, *PSDT_ENTRY;

<2>声明一个SSDT结构的变量

EXTERN_C SDT_ENTRY *KeServiceDescriptorTable;  
<3>要获得ShadowSSDT表的地址,必须得通过特征码定义,IDA中可以看出KeRemoveSystemServiceTable该函数是导出的,
在该函数中有它的地址,然后通过特征码定位到,这个即为ShadowSSDT的地址。
具体代码:

PVOID GetShadowSSDTAddr()
{
	ULONG uKeRemoveSystemServiceTable = (ULONG)KeRemoveSystemServiceTable;
	PUCHAR p = NULL;
	PVOID uKeServiceDescriptionShadowTableAddr = NULL;
	for (int i = 0; i < 50; i++, uKeRemoveSystemServiceTable++)
	{
		p = (PUCHAR)*(PULONG)uKeRemoveSystemServiceTable;
		if (MmIsAddressValid(p) && MmIsAddressValid(p + sizeof(SDT_ENTRY) - 1))
		{
			__try
			{
				if (memcmp(p, KeServiceDescriptorTable, sizeof(SDT_ENTRY)) == 0)
				{
					if (p == (PUCHAR)KeServiceDescriptorTable)
					{
						continue;
					}
					uKeServiceDescriptionShadowTableAddr = p;
					return  (PVOID)p;
				}
			}
			__except (EXCEPTION_EXECUTE_HANDLER)
			{
				return NULL;
			}
		}
	}
	if (uKeServiceDescriptionShadowTableAddr == NULL)
	{
		KdPrint(("获取ShadowSSDT 地址失败"));
	}
	return NULL;
}
2.关于附加进程:  
要附加进程得先获得某个进程的EPROCESS,据查看csrss.exe该进程在WIN7 32系统里面长存,可以获得该进程的EPRCESS来进行附加
要获得csrss.exe进程,首先需要遍历进程,我采用的是ZwQuerySystemInformation来遍历,通过获得进程结构体,来获得进程名
就可以来判断获得的进程是不是csrss.exe,直到遍历得到csrss.exe退出循环。
得到目标进程的结构体后  里面有ProcessId表示进程标识PID ,通过PID可以调用NtOpenProcess来获得进程句柄
然后就可以通过进程句柄调用ObReferenceObjectByHandle函数来获得EPROCESS结构
最后通过KeStackAttachProcess来附加进程 到这里进程就附加成功了 
具体代码如下..

PRKAPC_STATE AttachToProcess()
{
	//1.get csrss.exe eprocess
	UNICODE_STRING targetProcessName;
	int recount = 1;
	int checkProcess = 0;
	PSYSTEM_PROCESS_INFORMATION pInfo = NULL;
	PVOID pBuffer = NULL;
	ULONG rtnLen = 0;
	ULONG dwSize = 1000 * sizeof(SYSTEM_PROCESS_INFORMATION);
	NTSTATUS status = STATUS_SUCCESS; 
	PRKAPC_STATE ApcState = NULL;
	RtlInitUnicodeString(&targetProcessName, L"csrss.exe");
	do
	{
		if (pBuffer != NULL)
		{
			ExFreePoolWithTag(pBuffer, '0123');
			pBuffer = NULL;
		}
		pBuffer = ExAllocatePoolWithTag(PagedPool, dwSize, '0123');
		if (pBuffer == NULL)
		{
			KdPrint(("分配内存空间失败\n"));
			return NULL;
		}
		status = ZwQuerySystemInformation(SystemProcessInformation, pBuffer, dwSize, &rtnLen);
		if (status == STATUS_INFO_LENGTH_MISMATCH)
		{
			KdPrint(("缓冲区大小不足"));
			dwSize = 2 * dwSize;
			KdPrint(("重新分配大小%d次\n",recount++));
			continue;
		}
	} while (status == STATUS_INFO_LENGTH_MISMATCH  && dwSize<1000000);
	if (status == STATUS_SUCCESS)
	{
		pInfo = (PSYSTEM_PROCESS_INFORMATION)pBuffer;
		do
		{
			if (RtlCompareUnicodeString(&targetProcessName, &pInfo->ImageName, TRUE) == 0)
			{
				KdPrint(("找到目标进程\n"));
				KdPrint(("目标进程ID%d\n", pInfo->ProcessId));
				HANDLE hProcess = NULL;
				OBJECT_ATTRIBUTES ObjectAttributes;
				CLIENT_ID ClientId;
				ClientId.UniqueProcess = pInfo->ProcessId;
				ClientId.UniqueThread = 0;
				InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
				//通过进程ID获得进程句柄
				status = NtOpenProcess(&hProcess, PROCESS_ALL_ACCESS, &ObjectAttributes, &ClientId);
				if (status == STATUS_SUCCESS)
				{
					KdPrint(("获取进程句柄成功\n"));
					//通过进程句柄获得EPROCESS
					PEPROCESS pEprocess = NULL;
					status = ObReferenceObjectByHandle(hProcess, PROCESS_ALL_ACCESS, NULL, KernelMode, (PVOID*)&pEprocess, NULL);
					if (status == STATUS_SUCCESS && pEprocess != NULL)
					{
						KdPrint(("获取进程EPROCESS成功\n"));
						//附加进程
						if (checkProcess == 1)
						{
							ApcState = (PRKAPC_STATE)ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC_STATE), 'APC');
							if (ApcState)
							{
								KeStackAttachProcess(pEprocess, ApcState);
							}
						}
						//释放
						ObDereferenceObject(pEprocess);
					}
					//关闭句柄
					ZwClose(hProcess);
				}
				if (checkProcess == 1)
				{
					break;
				}
				checkProcess++;
			}
			//KdPrint(("%wZ\n", pInfo->ImageName));
			pInfo = (PSYSTEM_PROCESS_INFORMATION)((ULONG)pInfo + pInfo->NextEntryOffset);
		} while (pInfo->NextEntryOffset);
	}
	else
	{
		KdPrint(("获取进程信息失败"));
	}
	if (pBuffer != NULL)
	{
		ExFreePoolWithTag(pBuffer, '0123');
		pBuffer = NULL;
	}
	return ApcState;
}
3.HookNtUserCallTwoParam来达到一些不可告人的目的
有了ShadowSSDT表结构,那么就可以获得tUserCallTwoParam的地址,然后就可以在该函数头部做跳转,
在我们的中继函数中做判断,如果是某个进程调用,那么就直接返回它,不执行,而且调用这个函数的第一个
参数也必须是74h,这样判断之后就可以了。
中继函数代码:

__declspec(naked) void FuckNtUserCallTwoParam()
{
	__asm
	{
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		cmp dword ptr [esp + 0x10], 0x74
		jnz NOTFIND
		pushad
		pushfd
		call IsGame
		mov g_bGameProcessAccess, al
		popfd
		popad
		cmp g_bGameProcessAccess,1
		jnz NOTFIND
		pop ebp
		ret 0x14
	NOTFIND:
		jmp NtUserCallTwoParamRetAddr
	}
}
BOOLEAN IsGame()
{
	PEPROCESS pCurrentProcess = IoGetCurrentProcess();
	PUCHAR pszCurName = PsGetProcessImageFileName(pCurrentProcess);
	if (strstr("bluem2_ysmir2_cd.dat", (const char*)pszCurName) != NULL)
	{
		//KdPrint(("来自目标进程的调用\n"));
		return TRUE;
	}
	return FALSE;
}
我的目的是为了让某一个进程失去使用SetCursorPos的权利,那么通过上面的说明,你也可以让某一个进程失去使用任何
ShadowSSDT函数或者各种获得移动鼠标键盘函数的权利,这就是内核编程的强大,但也只是冰山一角,学海无涯,加油。



  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值