多核环境hook高并发函数

SwapContext函数调用频繁,我们就hook它

思路

1.首先我们需要找到SwapContext函数的地址 可通过特征码搜索,也可以通过windbg直接查看
2.需要一个执行我们xx操作的函数
3.需要关闭写保护,因为我们要操作内核文件
4.操作完我们的函数后需要返回SwapContext中正常执行

去除写保护

VOID  RemoveWProtect()
{
	__asm
	{
		cli
		push eax
		mov eax,cr0
		and eax,not 0x10000
		mov cr0,eax
		pop eax
	}
	return;
}

VOID  SetWProtect()
{
	__asm
	{
		push eax
		mov eax, cr0
		or eax, 0x10000
		mov cr0, eax
		pop eax
		sti
	}
	return;
}

我们自己的函数

void  _declspec(naked) HookSwapContextFunction()
{
	_asm
	{
		mov dword ptr[CurrentThread], edi
		mov dword ptr[NextThread], esi
	}
	_asm
	{
		pushad
		pushfd
	}

	DbgPrint("当前线程为:%x\t\t下一个线程为:%x\n", CurrentThread, NextThread);

	_asm
	{
		popfd
		popad
		mov byte ptr es:[esi + 2Dh],0x2
		ret
	}
}

特征码搜索SwapContext函数地址

		//特征码搜索SwapContext函数的地址
		UINT32 shellcode[] = {
		0xc626c90a,0x9c022d46,0xbb830b8b,0x00000994,
		0x850f5100,0x00000134,0x310c3d83,0x0f008056,
		0x0000fe85,0xc5200f00,0x4e8ad58b,0x504b882c
		};


		UINT32 shellcodeLength = sizeof(shellcode);

		UINT32 base = NULL;
		UINT32 baseSize = NULL;
		UNICODE_STRING baseName;


		LIST_ENTRY* current_entry = (LIST_ENTRY*)pDriver->DriverSection;

		UNICODE_STRING ntName;
		RtlInitUnicodeString(&ntName, L"ntoskrnl.exe");

		do {
			base = *(UINT32*)((UINT32)current_entry + 0x18);
			baseSize = *(UINT32*)((UINT32)current_entry + 0x20);
			baseName = *(PUNICODE_STRING)((UINT32)current_entry + 0x2c);
			if (RtlCompareUnicodeString(&ntName, &baseName, TRUE) == 0)
			{
				for (int i = base; i < base + baseSize - shellcodeLength; i++)
				{
					if (RtlCompareMemory(shellcode, i, shellcodeLength) == shellcodeLength)
					{
						SwapContext = i + 2;
						break;
					}
				}
				break;
			}
			current_entry = current_entry->Blink;

		} while (1);

		//判断函数地址找到没有
		if (SwapContext == NULL)
		{
			DbgPrint("SwapContext func addr is not find \n");
			return STATUS_ABANDONED;
		}

驱动代码


#include <ntifs.h>
#include <ntddk.h>


//操作码:0x0-0x7FF 被保留,0x800-0xFFF 可用
#define ADDR_HOOK CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define ADDR_UNHOOK CTL_CODE(FILE_DEVICE_UNKNOWN,0x801,METHOD_BUFFERED,FILE_ANY_ACCESS)


//设备对象
PDEVICE_OBJECT devObj;
//符号链接
UNICODE_STRING symbolLink;
//SwapContext的地址
UINT32 SwapContext = NULL;
//当前线程
UINT32 CurrentThread = NULL;
//下一个线程
UINT32 NextThread = NULL;
//原字节
UINT32 lowData,highData,oldLowData, oldHighData;


NTSTATUS DEVICE_CONTROL_Dispatch(PDEVICE_OBJECT pDevObj, PIRP pIrp);
NTSTATUS DEVICE_CREATE_Dispatch(PDEVICE_OBJECT pDevObj, PIRP pIrp);
NTSTATUS DEVICE_CLOSE_Dispatch(PDEVICE_OBJECT pDevObj, PIRP pIrp);

VOID  RemoveWProtect()
{
	__asm
	{
		cli
		push eax
		mov eax,cr0
		and eax,not 0x10000
		mov cr0,eax
		pop eax
	}
	return;
}

VOID  SetWProtect()
{
	__asm
	{
		push eax
		mov eax, cr0
		or eax, 0x10000
		mov cr0, eax
		pop eax
		sti
	}
	return;
}

void  _declspec(naked) HookSwapContextFunction()
{
	_asm
	{
		mov dword ptr[CurrentThread], edi
		mov dword ptr[NextThread], esi
	}
	_asm
	{
		pushad
		pushfd
	}

	DbgPrint("当前线程为:%x\t\t下一个线程为:%x\n", CurrentThread, NextThread);

	_asm
	{
		popfd
		popad
		mov byte ptr es:[esi + 2Dh],0x2
		ret
	}
}


VOID DriverUnload(PDRIVER_OBJECT pDriver)
{

	//删除符号链接
	IoDeleteSymbolicLink(&symbolLink);
	//删除设备
	IoDeleteDevice(devObj);
	DbgPrint("卸载成功!!!\n");
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pRegPath)
{

	try {
		//unload
		pDriver->DriverUnload = DriverUnload;



		//创建设备和3环通信
		UNICODE_STRING deviceName;
		RtlInitUnicodeString(&deviceName,L"\\Device\\firstDevice");
		NTSTATUS status = IoCreateDevice(
			pDriver,
			0,
			&deviceName,
			FILE_DEVICE_UNKNOWN,
			FILE_DEVICE_SECURE_OPEN,
			FALSE,
			&devObj
		);

		DbgPrint("创建设备 : %d~~\n", status);
		

		//创建符号链接 (3环需要这个符号链接才可以找到)
		RtlInitUnicodeString(&symbolLink,L"\\??\\HOOKTOOL");
		IoCreateSymbolicLink(&symbolLink,&deviceName);

		//设置通信方式
		pDriver->Flags |= DO_BUFFERED_IO;

		//设置派遣函数
		pDriver->MajorFunction[IRP_MJ_CREATE] = DEVICE_CREATE_Dispatch;
		pDriver->MajorFunction[IRP_MJ_CLOSE] = DEVICE_CLOSE_Dispatch;
		pDriver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DEVICE_CONTROL_Dispatch;


		//特征码搜索SwapContext函数的地址
		UINT32 shellcode[] = {
		0xc626c90a,0x9c022d46,0xbb830b8b,0x00000994,
		0x850f5100,0x00000134,0x310c3d83,0x0f008056,
		0x0000fe85,0xc5200f00,0x4e8ad58b,0x504b882c
		};


		UINT32 shellcodeLength = sizeof(shellcode);

		UINT32 base = NULL;
		UINT32 baseSize = NULL;
		UNICODE_STRING baseName;
		
		LIST_ENTRY* current_entry = (LIST_ENTRY*)pDriver->DriverSection;

		UNICODE_STRING ntName;
		RtlInitUnicodeString(&ntName, L"ntoskrnl.exe");

		do {
			base = *(UINT32*)((UINT32)current_entry + 0x18);
			baseSize = *(UINT32*)((UINT32)current_entry + 0x20);
			baseName = *(PUNICODE_STRING)((UINT32)current_entry + 0x2c);
			if (RtlCompareUnicodeString(&ntName, &baseName, TRUE) == 0)
			{
				for (int i = base; i < base + baseSize - shellcodeLength; i++)
				{
					if (RtlCompareMemory(shellcode, i, shellcodeLength) == shellcodeLength)
					{
						SwapContext = i + 2;
						break;
					}
				}
				break;
			}
			current_entry = current_entry->Blink;

		} while (1);

		//判断函数地址找到没有
		if (SwapContext == NULL)
		{
			DbgPrint("SwapContext func addr is not find \n");
			return STATUS_ABANDONED;
		}

		DbgPrint("dllbase : %08x\n", base);
		DbgPrint("SwapContext func addr is  : %08x\n", SwapContext);

		UINT32 callAddr = (UINT32)HookSwapContextFunction - SwapContext - 5;
		//这里不懂的,可以去看看E8 call 的硬编码知识,不难
		lowData = (callAddr << 8) + 0xE8;
		highData = (callAddr >> 24) + 0x0b8b9c00;

	} __except(EXCEPTION_EXECUTE_HANDLER) {
		DbgPrint("run error~~\n");
		return STATUS_SUCCESS;
	}
	return STATUS_SUCCESS;
}


NTSTATUS DEVICE_CONTROL_Dispatch(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{

	//NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
	NTSTATUS status = STATUS_SUCCESS;
	//获取PIRP的数据
	PIO_STACK_LOCATION psLocation = IoGetCurrentIrpStackLocation(pIrp);
	//获取控制码
	ULONG code = psLocation->Parameters.DeviceIoControl.IoControlCode;
	//获取缓冲区地址(输入和输出都是同一个)
	PVOID bufferAddress = pIrp->AssociatedIrp.SystemBuffer;
	//3环发送的数据字节数
	ULONG threeLength = psLocation->Parameters.DeviceIoControl.InputBufferLength;
	//0环发送的数据字节数
	ULONG zeroLength = psLocation->Parameters.DeviceIoControl.OutputBufferLength;
	//PEPROCESS
	//PETHREAD peprocess;
	PEPROCESS peprocess1;
	PEPROCESS peprocess2;



	switch (code) 
	{
	case ADDR_HOOK :
		//去除写保护
		RemoveWProtect();
		__asm
		{
			pushad
			pushfd

			mov edi, SwapContext

			mov edx, [edi+4]
			mov eax, [edi]
			mov dword ptr oldHighData, edx
			mov dword ptr oldLowData, eax

			mov ecx, highData
			mov ebx, lowData

			lock CMPXCHG8B qword ptr [edi]
			
			/*
			* cmpxchg8b mem64 指令的工作如下:
				比较 mem64 和 EDX:EAX
				如果相等,那么把 ECX:EBX 存储到 mem64
				如果不相等,那么把 mem64 存储到 EDX:EAX
				我们要一次性改8字节内存,用的是相等的情况,先把要写入的内容放到 ECX:EBX ,然后调用 cmpxchg8b 指令即可
			*/

			popfd
			popad
		}
		//设置写保护
		SetWProtect();
		DbgPrint("Hook success ~~\n");
		break;
	case ADDR_UNHOOK :
		//去除写保护
		RemoveWProtect();
		__asm
		{
			pushad
			pushfd

			mov edi, SwapContext

			mov edx, [edi + 4]
			mov eax, [edi]
			

			mov ecx, oldHighData
			mov ebx, oldLowData

			lock CMPXCHG8B qword ptr[edi]


			popfd
			popad
		}
		//设置写保护
		SetWProtect();
		DbgPrint("UnHook success ~~\n");
		break;
	default:
		status = STATUS_INVALID_DEVICE_REQUEST;
		break;
	}


	DbgPrint("3环发送的数据长度 %d~~\n", threeLength);
	DbgPrint("0环发送的数据长度 %d~~\n", zeroLength);

	//设置返回状态,默认是失败的哦
	pIrp->IoStatus.Status = status;
	//返回给3环多少字节数据,没有填0
	pIrp->IoStatus.Information = 8;
	//
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);
	return STATUS_SUCCESS;

}


NTSTATUS DEVICE_CREATE_Dispatch(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
	DbgPrint("CREATE  SUCCESS~~\n");

	//设置返回状态
	pIrp->IoStatus.Status = STATUS_SUCCESS;
	//返回给3环多少字节数据,没有填0
	pIrp->IoStatus.Information = 0;
	IoCompleteRequest(pIrp,IO_NO_INCREMENT);
	return STATUS_SUCCESS;
}


NTSTATUS DEVICE_CLOSE_Dispatch(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
	DbgPrint("CLOSE  SUCCESS~~\n");

	//设置返回状态
	pIrp->IoStatus.Status = STATUS_SUCCESS;
	//返回给3环多少字节数据,没有填0
	pIrp->IoStatus.Information = 0;
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);
	return STATUS_SUCCESS;
}

3环代码

#include "stdafx.h"
#include <windows.h>
#include <stdlib.h>
#include <winioctl.h>

#define symbolLinkName L"\\\\.\\HOOKTOOL"
//操作码:0x0-0x7FF 被保留,0x800-0xFFF 可用
#define ADDR_HOOK CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define ADDR_UNHOOK CTL_CODE(FILE_DEVICE_UNKNOWN,0x801,METHOD_BUFFERED,FILE_ANY_ACCESS)

int main(int argc, char* argv[])
{
	
	//create device link
	HANDLE device = CreateFileW(
		symbolLinkName,//创建或打开的文件或设备的名称
		GENERIC_READ | GENERIC_WRITE,//请求对文件或设备的访问权限
		0,//文件或设备请求的共享模式,参数为零且 CreateFile 成功,则文件或设备无法共享,并且无法在文件或设备的句柄关闭之前再次打开
		0,//确定返回的句柄是否可以由子进程继承
		OPEN_EXISTING,//仅当文件或设备存在时,才打开该文件或设备
		FILE_ATTRIBUTE_NORMAL,
		NULL);


	if (device == INVALID_HANDLE_VALUE)
	{
		printf("device open error ......");
		system("pause");
		return 0;
	}

	DWORD pid;
    DWORD outBuffer;
	DWORD lbret;//actually out buffer size


	if (DeviceIoControl(device,ADDR_HOOK,&pid,sizeof(pid),&outBuffer,sizeof(outBuffer),&lbret,NULL))
	{
		printf("ADDR_HOOK success , please test......\n");
	}
	system("pause");
	if (DeviceIoControl(device,ADDR_UNHOOK,&pid,sizeof(pid),&outBuffer,sizeof(outBuffer),&lbret,NULL))
	{
		printf("ADDR_UNHOOK success , please test......\n");
	}
	system("pause");
	CloseHandle(device);
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值