#include <ntifs.h>
#include <ntimage.h>
typedef VOID(__stdcall *KEATTACHPROCESS)(IN PRKPROCESS Process);
KEATTACHPROCESS OldKeAttachProcess;
UCHAR *PsGetProcessImageFileName(IN PEPROCESS Process);
#define SystemModuleInformation 11
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef struct _SYSTEM_MODULE_INFORMATION // 系统模块信息
{
ULONG Reserved[2];
ULONG Base;
ULONG Size;
ULONG Flags;
USHORT Index;
USHORT Unknown;
USHORT LoadCount;
USHORT ModuleNameOffset;
CHAR ImageName[256];
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;
typedef struct _tagSysModuleList { //模块链结构
ULONG ulCount;
SYSTEM_MODULE_INFORMATION smi[1];
} MODULES, *PMODULES;
NTSTATUS __stdcall ZwQuerySystemInformation(
ULONG_PTR SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
);
VOID WPOFF()
{
__asm
{
cli
mov eax, cr0
and eax, not 10000h
mov cr0, eax
}
}
VOID WPON()
{
__asm
{
mov eax, cr0
or eax, 10000h
mov cr0, eax
sti
}
}
//作业:把驱动的卸载历程的代码补充,在卸载的时候,恢复EAThook
BOOLEAN GetKernelModuleInfo(ULONG *ulSysModuleBase, ULONG *ulSize)
{
NTSTATUS status;
ULONG NeededSize, i;
PMODULES pModuleList;
BOOLEAN bRet = FALSE;
pModuleList = NULL;
__try
{
status = ZwQuerySystemInformation(
SystemModuleInformation,
NULL,
0,
&NeededSize);
if (status != STATUS_INFO_LENGTH_MISMATCH)
{
return bRet;
}
pModuleList = (PMODULES)ExAllocatePool(NonPagedPool, NeededSize);
if (pModuleList)
{
status = ZwQuerySystemInformation(
SystemModuleInformation,
pModuleList,
NeededSize,
&NeededSize);
if (NT_SUCCESS(status))
{
__try
{
//ntoskrnl.exe总是第一个加载
*ulSysModuleBase = pModuleList->smi[0].Base;
*ulSize = pModuleList->smi[0].Size;
bRet = TRUE;
}
__except (EXCEPTION_EXECUTE_HANDLER){
}
}
ExFreePool(pModuleList);
pModuleList = NULL;
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
KdPrint(("%08x\r\n", GetExceptionCode()));
}
if (pModuleList)
ExFreePool(pModuleList);
return bRet;
}
//我们的过滤函数的声明,要跟微软原始函数一样
VOID __stdcall NewKeAttachProcess(IN PRKPROCESS Process)
{
//我们进行效验,看看传进来的进程对象,是否可以有效
if (Process && MmIsAddressValid(Process))
{
//我们对当前的执行级别进行判断
if (KeGetCurrentIrql() == PASSIVE_LEVEL){
//打印出来,是谁在附加谁
DbgPrint("%s attach to %s\r\n", PsGetProcessImageFileName(PsGetCurrentProcess()), PsGetProcessImageFileName(Process));
}
}
OldKeAttachProcess(Process);
return;
}
BOOLEAN EATTableHook(PVOID ulModuleBase, char *psz_func_name, ULONG_PTR ulong_new_func)
{
//变量的声明
PIMAGE_DOS_HEADER pDosHeader;
PIMAGE_NT_HEADERS NtDllHeader;
IMAGE_OPTIONAL_HEADER opthdr;
ULONG_PTR* arrayOfFunctionAddresses;
ULONG_PTR* arrayOfFunctionNames;
WORD* arrayOfFunctionOrdinals;
ULONG_PTR functionOrdinal;
ULONG_PTR Base, x;
IMAGE_EXPORT_DIRECTORY *pExportTable;
char *functionName;
//try可以捕获一些简单的异常,
__try
{
//获得dos的文件头结构体
pDosHeader = (PIMAGE_DOS_HEADER)ulModuleBase;
if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
{
DbgPrint("IMAGE_DOS_SIGNATURE failed\r\n");
return FALSE;
}
//获得NT 文件头的结构体
NtDllHeader = (PIMAGE_NT_HEADERS)(ULONG_PTR)((ULONG_PTR)pDosHeader + pDosHeader->e_lfanew);
if (NtDllHeader->Signature != IMAGE_NT_SIGNATURE)
{
DbgPrint("IMAGE_NT_SIGNATURE failed\r\n");
return FALSE;
}
//获得可选镜像头部结构
opthdr = NtDllHeader->OptionalHeader;
//获得导出表地址
pExportTable = (IMAGE_EXPORT_DIRECTORY*)((ULONG_PTR)ulModuleBase + opthdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); //得到导出表
//获得相对地址
arrayOfFunctionAddresses = (ULONG_PTR*)((ULONG_PTR)ulModuleBase + pExportTable->AddressOfFunctions); //地址表
arrayOfFunctionNames = (ULONG_PTR*)((BYTE*)ulModuleBase + pExportTable->AddressOfNames); //函数名表
arrayOfFunctionOrdinals = (WORD*)((BYTE*)ulModuleBase + pExportTable->AddressOfNameOrdinals);
//我们在这里获得导出表的起始地址
Base = pExportTable->Base;
//我们用一个结构,循环的打印,也就是列举
for (x = 0; x < pExportTable->NumberOfFunctions; x++) //在整个导出表里扫描
{
//得到函数名 = 内核模块的起始地址 + 相对地址
functionName = (char*)((BYTE*)ulModuleBase + arrayOfFunctionNames[x]);
functionOrdinal = arrayOfFunctionOrdinals[x] + Base - 1;
//对比,是否是我们要hook的函数
if (_stricmp(psz_func_name, functionName) == 0)
{
//我们要保存原始函数,
//为什么要保存:因为在你的过滤函数里面,还要调用原始函数
(PUCHAR)OldKeAttachProcess = (PUCHAR)ulModuleBase + arrayOfFunctionAddresses[functionOrdinal];
//禁止写保存
WPOFF();
//根据我们的计算公司: EAT表的[index] = 你的新函数 - 你要hook的模块的起始地址;
//通过这个计算公司,我们就完成了我们的eat hook
arrayOfFunctionAddresses[functionOrdinal] = (PCHAR)ulong_new_func - (PCHAR)ulModuleBase; //ntos的基址(起始地址)
//恢复写保护
WPON();
DbgPrint("%s:0x%08X\r\n", functionName, OldKeAttachProcess);
}
}
}
__except (EXCEPTION_EXECUTE_HANDLER){
}
return FALSE;
}
BOOLEAN EATTableUnHook(PVOID ulModuleBase, char *psz_func_name, ULONG_PTR ulong_new_func)
{
//变量的声明
PIMAGE_DOS_HEADER pDosHeader;
PIMAGE_NT_HEADERS NtDllHeader;
IMAGE_OPTIONAL_HEADER opthdr;
ULONG_PTR* arrayOfFunctionAddresses;
ULONG_PTR* arrayOfFunctionNames;
WORD* arrayOfFunctionOrdinals;
ULONG_PTR functionOrdinal;
ULONG_PTR Base, x;
IMAGE_EXPORT_DIRECTORY *pExportTable;
char *functionName;
//try可以捕获一些简单的异常,
__try
{
//获得dos的文件头结构体
pDosHeader = (PIMAGE_DOS_HEADER)ulModuleBase;
if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
{
DbgPrint("IMAGE_DOS_SIGNATURE failed\r\n");
return FALSE;
}
//获得NT 文件头的结构体
NtDllHeader = (PIMAGE_NT_HEADERS)(ULONG_PTR)((ULONG_PTR)pDosHeader + pDosHeader->e_lfanew);
if (NtDllHeader->Signature != IMAGE_NT_SIGNATURE)
{
DbgPrint("IMAGE_NT_SIGNATURE failed\r\n");
return FALSE;
}
//获得可选镜像头部结构
opthdr = NtDllHeader->OptionalHeader;
//获得导出表地址
pExportTable = (IMAGE_EXPORT_DIRECTORY*)((ULONG_PTR)ulModuleBase + opthdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); //得到导出表
//获得相对地址
arrayOfFunctionAddresses = (ULONG_PTR*)((ULONG_PTR)ulModuleBase + pExportTable->AddressOfFunctions); //地址表
arrayOfFunctionNames = (ULONG_PTR*)((BYTE*)ulModuleBase + pExportTable->AddressOfNames); //函数名表
arrayOfFunctionOrdinals = (WORD*)((BYTE*)ulModuleBase + pExportTable->AddressOfNameOrdinals);
//我们在这里获得导出表的起始地址
Base = pExportTable->Base;
//我们用一个结构,循环的打印,也就是列举
for (x = 0; x < pExportTable->NumberOfFunctions; x++) //在整个导出表里扫描
{
//得到函数名 = 内核模块的起始地址 + 相对地址
functionName = (char*)((BYTE*)ulModuleBase + arrayOfFunctionNames[x]);
functionOrdinal = arrayOfFunctionOrdinals[x] + Base - 1;
//对比,是否是我们要hook的函数
if (_stricmp(psz_func_name, functionName) == 0)
{
//我们要保存原始函数,
//为什么要保存:因为在你的过滤函数里面,还要调用原始函数
//(PUCHAR)OldKeAttachProcess = (PUCHAR)ulModuleBase + arrayOfFunctionAddresses[functionOrdinal];
//禁止写保存
WPOFF();
//根据我们的计算公司: EAT表的[index] = 你的新函数 - 你要hook的模块的起始地址;
//通过这个计算公司,我们就完成了我们的eat hook
arrayOfFunctionAddresses[functionOrdinal] = (PCHAR)OldKeAttachProcess - (PCHAR)ulModuleBase; //ntos的基址(起始地址)
//恢复写保护
WPON();
//DbgPrint("%s:0x%08X\r\n", functionName, OldKeAttachProcess);
}
}
}
__except (EXCEPTION_EXECUTE_HANDLER){
}
return FALSE;
}
VOID DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
ULONG_PTR ulong_kernel_base;
ULONG_PTR ulong_kernel_size;
if (GetKernelModuleInfo(&ulong_kernel_base, &ulong_kernel_size))
{
//开始hook,第一个参数就是内核模块的起始地址,就是我们要eat hook的函数名,就是我们的新过滤函数
EATTableUnHook((PVOID)ulong_kernel_base, "KeAttachProcess", (ULONG_PTR)NewKeAttachProcess);
}
DbgPrint("卸载完成!\n");
}
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
//声明两个变量,一个是内核模块的地址,一个是大小 ULONG_PTR 是编译器自动识别,如果是32位驱动,就是ULONG,如果是64位驱动,就是ULONG_PTR
ULONG_PTR ulong_kernel_base;
ULONG_PTR ulong_kernel_size;
//就是驱动的卸载历程
DriverObject->DriverUnload = DriverUnload;
//keattachprocess,是在ntoskrnl.exe 这个内核导出
if (GetKernelModuleInfo(&ulong_kernel_base, &ulong_kernel_size))
{
//开始hook,第一个参数就是内核模块的起始地址,就是我们要eat hook的函数名,就是我们的新过滤函数
EATTableHook((PVOID)ulong_kernel_base, "KeAttachProcess", (ULONG_PTR)NewKeAttachProcess);
}
return STATUS_SUCCESS;
}