HOOK集合----SSDT Hook Anti(X86 win7)

介绍:

  前段时间写了SSDT  Hook,没来得及写SSDT Hook 的ANTI策略,今天来写一下。

  其实,ANTI SSDT Hook 也很简单,无非就是对比一下内存中加载的SSDT 表中的函数地址和原文件(ntkrnlpa.exe)中的SSDT表中函数地址是否一致即可。

(一)

⚪ 获取ntkrnlpa.exe模块的完整路径

⚪将文件读取到当前内存空间中

⚪将RVA转化为FOA,找到原文件读取到内存中的SSDT表位置。

⚪判断内存加载的SSDT表中的函数地址和原文件中的SSDT表中函数地址是否一致

⚪关闭写保护,覆盖FakeFunction函数地址。

⚪开启写保护,ANTI完成。

 

这些步骤当中其实还涉及到一些小细节去要介绍一下,比如说SSDT表中的存放的函数地址,都是Nt系列函数,那是如何找到的目标函数地址呢?这就要从Zw函数调用开始说起了,当你调用Zw函数的时候,Zw函数代码中会传入一个序列号,这个序列号就是Zw对应的Nt系列函数在SSDT表中的下标,所以我们在Zw函数中可以找到对应的序列号。

        2: kd> u 0x8485acd8
            nt!ZwOpenProcess:
            8485acd8 b8 be000000      mov     eax,0BEh
            8485acdd 8d542404        lea     edx,[esp+4]
            8485ace1 9c              pushfd
            8485ace2 6a08            push    8
            8485ace4 e8d5190000      call    nt!KiSystemService (8485c6be)
            8485ace9 c21000          ret     10h
            nt!ZwOpenProcessToken:
            8485acec b8bf000000      mov     eax,0BFh
            8485acf1 8d542404        lea     edx,[esp+4]

注意红色部分!!!!

在我通过Windbg中找出ZwOpenProcess函数的反汇编的时候,有一个0BEh的序列号传入,这就是我们要找的东西。具体为什么是这样,可以看我之前些的Zw和Nt系列函数的区别

 

(二)

#pragma once
#include<fltKernel.h>
#include"Common.h"
#include"SystemHelper.h"
#include<ntimage.h>

NTSTATUS SSDTHookANTI();
ULONG GetRawOffset(IN PVOID ImageBase, IN ULONG TableRVA, OUT PULONG FileImageBase);

VOID OnEnableWrite();   //关闭写保护 
VOID OnDisableWrite();  //开启写保护

#include"SSDTHook-ANTI.h"

extern PVOID __KernelModuleBase ;
extern ULONG __KernelModuleSize;
extern UNICODE_STRING __KernelModulePath ;
extern PSYSTEM_SERVICE_DESCRIPTOR_TABLE KeServiceDescriptorTable;


#define SSDT_INDEX(ZwFunctionAddress) * (PULONG)((PUCHAR)ZwFunctionAddress +1)
NTSTATUS SSDTHookANTI()
{
	NTSTATUS Status = STATUS_UNSUCCESSFUL;
	HANDLE FileHandle = NULL;
	OBJECT_ATTRIBUTES ObjectAttributes;
	IO_STATUS_BLOCK IoStatusBlock;
	FILE_STANDARD_INFORMATION FileStandardInfo;
	char * BufferData = NULL;
	ULONG RawOffset = 0;
	UNICODE_STRING v1;
	LARGE_INTEGER Offset;
	ULONG FileImageBase = 0;  //优先加载地址
	ULONG SSDTRva = 0;
	PUCHAR ZwOpenProcessAddress = NULL;

	Status = MaGetKernelModuleInfo();
	if (!NT_SUCCESS(Status))
	{
		return Status;
	}


	RtlInitUnicodeString(&v1, L"ZwOpenProcess");

	
	ZwOpenProcessAddress = (PUCHAR)MmGetSystemRoutineAddress(&v1);




	InitializeObjectAttributes(&ObjectAttributes, &__KernelModulePath, OBJ_CASE_INSENSITIVE, NULL, NULL);
	Status = ZwCreateFile(&FileHandle,
		SYNCHRONIZE,
		&ObjectAttributes,
		&IoStatusBlock,
		NULL,
		FILE_ATTRIBUTE_NORMAL,
		FILE_SHARE_READ,
		FILE_OPEN,
		FILE_SYNCHRONOUS_IO_NONALERT,
		NULL,
		0);
	if (!NT_SUCCESS(Status))
	{
		return Status;
	}
	Status = ZwQueryInformationFile(FileHandle,
		&IoStatusBlock,
		&FileStandardInfo,
		sizeof(FILE_STANDARD_INFORMATION),
		FileStandardInformation);
	if (!NT_SUCCESS(Status))
	{
		ZwClose(FileHandle);
		return Status;
	}
	BufferData = ExAllocatePool(PagedPool, FileStandardInfo.EndOfFile.LowPart);
	if (BufferData == NULL)
	{
				
		ZwClose(FileHandle);
		return STATUS_INSUFFICIENT_RESOURCES;
	}
	Status = ZwReadFile(FileHandle,
		NULL,
		NULL,
		NULL,
		&IoStatusBlock,
		BufferData,
		FileStandardInfo.EndOfFile.LowPart,
		&Offset,
		NULL);
	if (!NT_SUCCESS(Status))
	{
		ExFreePool(BufferData);
		ZwClose(FileHandle);
		return STATUS_UNSUCCESSFUL;
	}
	//SSDT表在内存的偏移   内存粒度0x1000对齐的
	SSDTRva = (ULONG_PTR)(KeServiceDescriptorTable->ServiceTableBase) - (ULONG)__KernelModuleBase;
	//SSDT表在文件中的偏移 内存粒度0x200对齐的
	RawOffset = GetRawOffset(BufferData, SSDTRva, &FileImageBase);

	//判断是否HOOK

	if (((PULONG_PTR)(KeServiceDescriptorTable->ServiceTableBase))[SSDT_INDEX(ZwOpenProcessAddress)] !=
		(((PULONG_PTR)(RawOffset + (ULONG_PTR)BufferData))[SSDT_INDEX(ZwOpenProcessAddress)]
			- (ULONG_PTR)FileImageBase + (ULONG_PTR)__KernelModuleBase))
	{
		OnEnableWrite();

		((PULONG_PTR)(KeServiceDescriptorTable->ServiceTableBase))[SSDT_INDEX(ZwOpenProcessAddress)] =
			((PULONG_PTR)(RawOffset+(ULONG_PTR)BufferData))[SSDT_INDEX(ZwOpenProcessAddress)] -
			(ULONG_PTR)FileImageBase + (ULONG_PTR)__KernelModuleBase;

		OnDisableWrite();

	}

	if (FileHandle != NULL)
	{
		ZwClose(FileHandle);
		FileHandle = NULL;
	}
	if (BufferData != NULL)
	{
		ExFreePool(BufferData);
		BufferData = NULL;
	}
	RtlFreeUnicodeString(&__KernelModulePath);
	return Status;
}

ULONG GetRawOffset(IN PVOID ImageBase, IN ULONG TableRVA, OUT PULONG FileImageBase)
{
	PIMAGE_DOS_HEADER ImageDosHeader = NULL;
	PIMAGE_NT_HEADERS ImageNtHeader = NULL;
	PIMAGE_FILE_HEADER ImageFileHeader = NULL;
	PIMAGE_SECTION_HEADER ImageSectionHeader = NULL;
	PIMAGE_OPTIONAL_HEADER ImageOptionHeader = NULL;
	ULONG SectionNumber = 0;
	ULONG RawOffset = 0;
	ULONG i;


	ImageDosHeader = (PIMAGE_DOS_HEADER)ImageBase;
	ImageNtHeader = ImageDosHeader->e_lfanew + (ULONG_PTR)ImageDosHeader;
	ImageFileHeader = &ImageNtHeader->FileHeader;
	ImageOptionHeader = &ImageNtHeader->OptionalHeader;
	ImageSectionHeader = (PIMAGE_SECTION_HEADER)((PUCHAR)ImageNtHeader+sizeof(ULONG)+sizeof(IMAGE_FILE_HEADER)+
		ImageFileHeader->SizeOfOptionalHeader);

	//预先加载的位置
	*FileImageBase = ImageOptionHeader->ImageBase;
	SectionNumber = ImageFileHeader->NumberOfSections;

	for (i = 0;i < SectionNumber;i++, ImageSectionHeader++)
	{
		if (TableRVA > ImageSectionHeader->VirtualAddress &&
			TableRVA < ImageSectionHeader->VirtualAddress + ImageSectionHeader->SizeOfRawData)
		{
			RawOffset = TableRVA - ImageSectionHeader->VirtualAddress + ImageSectionHeader->PointerToRawData;

			//RawOffset = (ULONG)ImageBase + RawOffset;
			return (ULONG)RawOffset;
		}
	}
	return 0;
}

VOID OnEnableWrite()
{
	__try
	{
		_asm
		{
			cli   //禁止中断发生
			mov eax,cr0
			and eax,not 10000h //cr0寄存器中第17位 WP位
			mov cr0,eax
	    }
	}
	__except (1)
	{
		
	}
}

VOID OnDisableWrite()
{
	__try
	{
		_asm
		{
		
			mov eax, cr0
			or eax, 10000h  //cr0寄存器中第17位 WP位
			mov cr0, eax

			sti        //恢复中断屏蔽
		} 
	}
	__except (1)
	{

	}
}

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值