首页
社区
课程
招聘
[原创]从应用层进程中KiFastSystemCall接管进入内核的一切
发表于: 2014-7-6 11:06 14154

[原创]从应用层进程中KiFastSystemCall接管进入内核的一切

2014-7-6 11:06
14154
早期时候发过一个帖子 http://bbs.pediy.com/showthread.php?t=163658 介绍 HOOK KiFastSystemCall 这算是这帖子的延续 完整版.   

大致原理就是构造一个类似内核中SSDT表的HOOK数组存,当有函数通过KiFastSystemCall进入系统内核时 查找HOOK数组,看对应的Index中有无函数地址,有的话跳入新函数地址.  主要问题在于进入我们的函数时如果获取参数并且获取调用后函数返回!

DWORD	dwKiFastSystemCall;
DWORD	dwKiFastSystemCallReturn;

//HOOK后跳入的函数地址
DWORD dwHookSystemCall[0x2048*2];

//保存原始函数调用地址
DWORD *dwOrigSystemCall[0x2048*2];


dwHookSystemCall数组的组要目的就是为了保存被我们HOOK的函数新地址.类似SSDT表!

比如ZwAccessCheck 的index为1 那么查找dwHookSystemCall[1] 如果这地址不为空,那么就跳入这个新地址.

__declspec(naked) void KiFastSystemCallEx()
{
	__asm  {
		mov edx,esp
		__emit 0x0F
		__emit 0x34
		retn
	}
}
//EX SystemCall
__declspec(naked) void SystemCall()
{
	__asm  {
		__emit 0x90
		mov eax,0x11B2
		call KiFastSystemCallEx
		retn 0xFF
		__emit 0x90
	}
}


自己构造一个 KiFastSystemCall函数跟一个Zw原形,因为我们已经HOOK了系统的 KiFastSystemCall所以系统的函数我们不可能去调用必须自己构造.因为Shadow函数获取不到地址所以这我们必须自己先写个原形.

__declspec(naked) void KiFastSystemCall()
{
	
	__asm{
		pushad
			pushfd

			cmp         dword ptr [eax*4+dwHookSystemCall],0

			jz          Label
			popfd
			popad
			add         esp,4
			jmp         dword ptr [dwHookSystemCall+eax*4]

Label:
			popfd
			popad
			jmp         KiFastSystemCallEx

	}

}

这是我们的HOOK KiFastSystemCall后跳入的函数,KiFastSystemCall执行到这的时候EAX为函数INDEX ,判断INDEX 看我们的数组里是否存在 有的话就跳入我们的函数内.
add         esp,4

这个是整个HOOK中最重要的地方!
HOOK后正常流程: 调用Zw ->  Zw ->  MyKiFastSystemCall  ->MyZw ->OrgZw ->  OrgSystemCall 问题来了,Zw函数的参数传递到 MyZw的时候已经经过一次Zw了!正常直接获取是获取不到的!因此,为了让我们的函数可以正常获取到参数必须把ESP + 4  这样函数返回的时候是直接返回到"调用Zw"的地方,而不是NTDLL 中的ZW函数!即解决了函数返回的问题,也解决了MyZw获取参数的问题.



//初始化
BOOL HookSystemCall::Initialization()
{
	DWORD dwOldProtect;
	HMODULE hModule = GetModuleHandleA("NTDLL.dll");

	dwKiFastSystemCall = PtrToUlong(GetProcAddress(hModule, "KiFastSystemCall"));
	dwKiFastSystemCallReturn = dwKiFastSystemCall + 2;

	VirtualProtect(ULongToPtr(dwKiFastSystemCall - 0xA), 100, PAGE_EXECUTE_READWRITE, &dwOldProtect);

	//保存原始代码
	memcpy(szCode,(VOID*)(dwKiFastSystemCall - 6),0xF);

	//	Hook KiFastSystemCall
	*(PWORD)ULongToPtr(dwKiFastSystemCall) = 0xF9EB;
	*(PBYTE)ULongToPtr(dwKiFastSystemCall - 0x5) = 0xE9;
	*(PDWORD)ULongToPtr(dwKiFastSystemCall - 0x4) = PtrToUlong(KiFastSystemCall) - (dwKiFastSystemCall - 0x5) - 5;
	
	return 0;
}

这主要是为了初始化 跟 HOOK KiFastSystemCall ;KiFastSystemCall函数太短,小JMP 后再大JMP到我们的HOOK

//调用函数GetDllFuncAddr以便获得服务号
int HookSystemCall::GetSysCallIndex( PCHAR FuncName )
{
	DWORD          FuncAddr;    //函数地址
	int            SysCallIndex;//服务号
	FuncAddr = (DWORD)GetProcAddress(GetModuleHandleA("ntdll.dll"),FuncName);
	SysCallIndex = *( (WORD*)(FuncAddr + 1) );
	return SysCallIndex;
}

获取ZW函数index,Zw函数开头都是mov eax,1 之类的,刚好将地址+1就获得了Index! 某些软件直接HOOK Zw函数头五字节 防止冲突,可以从文件获取.


// 安装钩子
BOOL HookSystemCall::InstallHook(PCHAR FunName,		//NTAPI
								 DWORD pHookFunc,	//HOOK的函数
								 DWORD * pOrigFunc)	//返回的函数
{
	DWORD dwOldProtect;
	DWORD dwIndex = GetSysCallIndex(FunName);
	DWORD	dwFunadd =PtrToUlong(GetProcAddress(GetModuleHandleA("NTDLL.dll"), FunName));
	
	//保存各种信息
	dwHookSystemCall[dwIndex] = pHookFunc;
	dwOrigSystemCall[dwIndex] = (PDWORD)malloc(0x10);

	//将原本的ZW函数保存进去
	memcpy(dwOrigSystemCall[dwIndex],(PVOID)dwFunadd,0x10);
	
	//野猪改造开始
	VirtualProtect(ULongToPtr(dwOrigSystemCall[dwIndex]), 0x10, PAGE_EXECUTE_READWRITE, &dwOldProtect);

	*(PBYTE)((DWORD)dwOrigSystemCall[dwIndex]	+ 5)	=	 0xE8;
	*(PDWORD)((DWORD)dwOrigSystemCall[dwIndex] + 6)		=	 (DWORD)KiFastSystemCallEx - (DWORD)dwOrigSystemCall[dwIndex] -0xA;
	*(PWORD)((DWORD)dwOrigSystemCall[dwIndex]	+ 10)	=	 0x9090;

	* pOrigFunc = (DWORD)dwOrigSystemCall[dwIndex];
	
	return 0;
}

重新构造一个被我们HOOK的Zw函数,然后将
MOV EDX,7FFE0300
CALL DWORD PTR DS:[EDX]

修改为CALL KiFastSystemCallEx ;以便函数可以重新进入内核,实现我们函数内获取函数返回的功能.

BOOL HookSystemCall::InstallHookEx(DWORD dwIndex,		//NTAPI
								   WORD dwRetIndex,	//返回堆栈平衡
								   DWORD pHookFunc,		//HOOK的函数
								   DWORD * pOrigFunc)	//返回的函数
{
	DWORD dwOldProtect;

	//保存各种信息
	dwHookSystemCall[dwIndex] = pHookFunc;
	dwOrigSystemCall[dwIndex] = (PDWORD)malloc(0x10);

	//将原本的ZW函数保存进去
	memcpy(dwOrigSystemCall[dwIndex],(PVOID)SystemCall,0x10);

	//野猪改造开始
	VirtualProtect(ULongToPtr(dwOrigSystemCall[dwIndex]), 0x10, PAGE_EXECUTE_READWRITE, &dwOldProtect);

	*(PDWORD)((DWORD)dwOrigSystemCall[dwIndex] + 2)		=	 (DWORD)dwIndex;
	*(PDWORD)((DWORD)dwOrigSystemCall[dwIndex] + 7)		=	 (DWORD)KiFastSystemCallEx - (DWORD)dwOrigSystemCall[dwIndex] - 0xB;
	*(PWORD)((DWORD)dwOrigSystemCall[dwIndex]	+ 12)	=	 dwRetIndex;

	* pOrigFunc = (DWORD)dwOrigSystemCall[dwIndex];

	return 0;
}

这个主要是为了HOOK 一些不是NTDLL 导出的函数,比如NtUserFindWindowEx之类的函数,因为Shadow SSDT也是经由KiFastSystemCall进入内核,原理大概一致.
不过因为没办法直接获取函数INDEX所以必须根据系统版本自己确定,而且也无法获取函数地址,所以使用我们之前构造的函数原形来处理.ret的平衡也只能手动了!


代码到此就已经接管了从KiFastSystemCall进入内核的入口.

主要代码基本这些,剩下看附件看源码.WIN7 32位测试通过!
例子
typedef NTSTATUS (NTAPI *_ZwOpenProcess)(OUT     PHANDLE ProcessHandle,
										 IN      ACCESS_MASK DesiredAccess,
										 IN      POBJECT_ATTRIBUTES ObjectAttributes,
										 IN  PCLIENT_ID ClientId
										 );
_ZwOpenProcess ZwOpenProcess;
NTSTATUS NTAPI MyZwOpenProcess(_Out_	PHANDLE ProcessHandle,
							   _In_	ACCESS_MASK DesiredAccess,
							   _In_	POBJECT_ATTRIBUTES ObjectAttributes,
							   _In_	PCLIENT_ID ClientId)
{
	NTSTATUS ntStatus = ZwOpenProcess(ProcessHandle,DesiredAccess,ObjectAttributes,ClientId);
	return ntStatus;
}
HookSystemCall Hook;
Hook.Initialization();
Hook.InstallHook("ZwOpenProcess",(DWORD)MyZwOpenProcess,(PDWORD)&ZwOpenProcess);

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 3
支持
分享
最新回复 (9)
雪    币: 10
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
刚睡醒,占个楼...
2014-7-6 11:26
0
雪    币: 135
活跃值: (63)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
3
mark
2014-7-6 12:09
0
雪    币: 219
活跃值: (738)
能力值: (RANK:290 )
在线值:
发帖
回帖
粉丝
4
某些 调试器 也是应用这个,r3   r0  跳到自己的新函数,从而无视.缺点在于,很多杀毒软件 游戏都会检测这个地方
2014-7-6 12:32
0
雪    币: 228
活跃值: (115)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
5
一般不检测,主要是很少人会想到用这个地方HOOK 来监视进程!
2014-7-7 17:48
0
雪    币: 2664
活跃值: (3401)
能力值: ( LV13,RANK:1760 )
在线值:
发帖
回帖
粉丝
6
数字不是很早就用了吗?
2014-7-7 17:59
0
雪    币: 228
活跃值: (115)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
7
看清楚!R3下...NTDLL.DLL!!
2014-7-7 22:56
0
雪    币: 27
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
mark
2015-5-28 21:23
0
雪    币: 12
活跃值: (388)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
没试
WIN8 WIN10应该是不行的
2015-9-28 14:22
0
雪    币: 31
活跃值: (28)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
10
刚睡醒,占个楼...
2016-4-22 21:11
0
游客
登录 | 注册 方可回帖
返回
//