17.系统调用(SSDT_HOOK)

测试环境Win7 x86

实现原理系统调用分析

1.重新加载一份按照PE格式拉伸后的内核文件到内存(避免当前内核已经被挂钩).

2.通过导出表获取HOOK函数系统服务号.

3.利用导出KeServiceDescriptorTable结构定位系统服务表实现替换函数(类似IAT_HOOK).

代码如下:

#include <ntifs.h>
#include <ntimage.h>
#include <ntstrsafe.h>

//获取系统目录
PWCHAR GetSystemFullPath();

//内核文件按照PE拉伸后格式映射到内存
PUCHAR FileMaping(PWCHAR SystemPath);

//释放文件映射
VOID UnFileMaping(PVOID mapBase);

//通过函数名查找导出函数
ULONG64 GetFuntionAddressByExportTableName(PUCHAR ImageBuffer, PUCHAR FunctionName);

//导出未文档化函数
NTSTATUS MmCreateSection(
	__deref_out PVOID* SectionObject,
	__in ACCESS_MASK DesiredAccess,
	__in_opt POBJECT_ATTRIBUTES ObjectAttributes,
	__in PLARGE_INTEGER InputMaximumSize,
	__in ULONG SectionPageProtection,
	__in ULONG AllocationAttributes,
	__in_opt HANDLE FileHandle,
	__in_opt PFILE_OBJECT FileObject
);


// 系统服务表
typedef struct _KSYSTEM_SERVICE_TABLE
{
	PULONG ServiceTableBase;			// 函数地址表(SSDT)
	PULONG ServiceCounterTableBase;		// SSDT 函数被调用的次数
	ULONG NumberOfService;				// 函数个数
	PULONG ParamTableBase;				// 函数参数表(SSPT)
} KSYSTEM_SERVICE_TABLE, * PKSYSTEM_SERVICE_TABLE;

typedef struct _KSERVICE_TABLE_DESCRIPTOR
{
	KSYSTEM_SERVICE_TABLE ntoskrnl;		// 内核函数
	KSYSTEM_SERVICE_TABLE win32k;		// win32k.sys 函数
	KSYSTEM_SERVICE_TABLE unUsed1;
	KSYSTEM_SERVICE_TABLE unUsed2;
} KSERVICE_TABLE_DESCRIPTOR, * PKSERVICE_TABLE_DESCRIPTOR;

extern PKSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable;

PUCHAR G_MapNtdll = NULL;

//拷贝SSDT表
BOOLEAN SSDT_Init();

//释放SSDT表
VOID SSDT_Destroy();

//获取函数系统服务号
ULONG SSDT_GetFunIndex(PUCHAR szFunctionName);

//SSDTHOOK
ULONG_PTR SSDT_Hook(PUCHAR szFunctionName, ULONG_PTR FunctionAddr);

//关闭写保护以及中断
ULONG wpOff()
{
	ULONG cr0 = __readcr0();
	_disable();
	__writecr0(cr0 & (~0x10000));
	return cr0;
}

//恢复CR0默认数据
VOID wpOn(ULONG value)
{
	__writecr0(value);
	_enable();
}

//恢复HOOK时用到
ULONG G_OldFunAddr = NULL;

//函数指针
typedef NTSTATUS(NTAPI* OpenProcessProc)(_Out_ PHANDLE ProcessHandle, _In_ ACCESS_MASK DesiredAccess, _In_ POBJECT_ATTRIBUTES ObjectAttributes, _In_opt_ PCLIENT_ID ClientId);

//替换函数
NTSTATUS NTAPI MyOpenProcess(_Out_ PHANDLE ProcessHandle, _In_ ACCESS_MASK DesiredAccess, _In_ POBJECT_ATTRIBUTES ObjectAttributes, _In_opt_ PCLIENT_ID ClientId)
{
	PUCHAR pEprocess = (PUCHAR)IoGetCurrentProcess();
	DbgPrint("进程ID: [%d] 调用OpenProcess \r\n", *(PULONG)(pEprocess + 0xb4));

	//TODO:
	//获取参数,监控,修改返回值....

	return ((OpenProcessProc)G_OldFunAddr)(ProcessHandle, DesiredAccess, ObjectAttributes, ClientId);
}

NTSTATUS DriverUnload(PDRIVER_OBJECT pDriver)
{
	DbgPrint("Driver Exit \r\n");

	//恢复钩子
	if (G_OldFunAddr)
	{
		SSDT_Hook("ZwOpenProcess", G_OldFunAddr);
	}

	//释放后延迟避免有进程还在执行我们函数释放导致蓝屏
	SSDT_Destroy();

	//延时
	LARGE_INTEGER inTime = { 0 };
	inTime.QuadPart = -10000 * 3000;
	KeDelayExecutionThread(KernelMode, FALSE, &inTime);

}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg)
{
	DbgPrint("Driver Load \r\n");
	pDriver->DriverUnload = DriverUnload;
	
	if (SSDT_Init())
	{
		G_OldFunAddr = SSDT_Hook("ZwOpenProcess", MyOpenProcess);
	}

	return STATUS_SUCCESS;
}

PWCHAR GetSystemFullPath()
{
	//申请路径缓冲区
	PWCHAR SystemPath = ExAllocatePool(PagedPool, PAGE_SIZE);
	if (!SystemPath)
	{
		return NULL;
	}
	memset(SystemPath, 0, PAGE_SIZE);

	//初始化路径
	RtlStringCbPrintfW(SystemPath, PAGE_SIZE, L"\\??\\%s\\System32\\ntdll.dll", SharedUserData->NtSystemRoot);
	DbgPrint("SystemPath -> [%ws] \r\n", SystemPath);
	
	return SystemPath;
}

PUCHAR FileMaping(PWCHAR SystemPath)
{
	//Initialize UnicodeString
	UNICODE_STRING FileName = { 0 };
	RtlInitUnicodeString(&FileName, SystemPath);

	//Initialize ObjectAttribute
	OBJECT_ATTRIBUTES objectFile = { 0 };
	InitializeObjectAttributes(&objectFile, &FileName, OBJ_CASE_INSENSITIVE, NULL, NULL);

	//CreateFile
	HANDLE hFile = NULL;
	IO_STACK_LOCATION iostacklocation = { 0 };
	NTSTATUS ntstatus = ZwCreateFile(&hFile, GENERIC_READ, &objectFile, &iostacklocation, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, NULL);
	if (!NT_SUCCESS(ntstatus))
	{
		DbgPrint("FileMaping ZwCreateFile Filed \r\n");
		return NULL;
	}

	//Create Section
	OBJECT_ATTRIBUTES objectSection = { 0 };
	InitializeObjectAttributes(&objectSection, NULL, OBJ_CASE_INSENSITIVE, NULL, NULL);

	PVOID pSection = NULL;
	LARGE_INTEGER InputMaximumSize = { 0 };
	ntstatus = MmCreateSection(&pSection, SECTION_ALL_ACCESS, &objectSection, &InputMaximumSize, PAGE_EXECUTE_READWRITE, 0x1000000, hFile, NULL);
	if (!NT_SUCCESS(ntstatus))
	{
		DbgPrint("FileMaping MmCreateSection Filed \r\n");
		ZwClose(hFile);
		return NULL;
	}

	PVOID pMapBase = NULL;
	SIZE_T ViewSize = 0;
	ntstatus = MmMapViewInSystemSpace(pSection, &pMapBase, &ViewSize);
	ObDereferenceObject(pSection);
	ZwClose(hFile);

	if (NT_SUCCESS(ntstatus))
	{
		return pMapBase;
	}

	return NULL;
}

VOID UnFileMaping(PVOID pImage)
{
	if (pImage)
	{
		MmUnmapViewInSystemSpace(pImage);
	}
}

ULONG64 GetFuntionAddressByExportTableName(PUCHAR ImageBuffer, PUCHAR FunctionName)
{
	//Headers
	PIMAGE_DOS_HEADER    pDos = (PIMAGE_DOS_HEADER)ImageBuffer;
	if (*(PUSHORT)pDos != IMAGE_DOS_SIGNATURE)
	{
		DbgPrint("Not PeFile \r\n");
		return NULL;
	}

	PIMAGE_NT_HEADERS    pNts = (PIMAGE_NT_HEADERS)(ImageBuffer + pDos->e_lfanew);
	if (*(PULONG)pNts != IMAGE_NT_SIGNATURE)
	{
		DbgPrint("Not PeFile \r\n");
		return NULL;
	}

	PIMAGE_FILE_HEADER      pFil = (PIMAGE_FILE_HEADER)((ULONG)pNts + 0x4);
	PIMAGE_OPTIONAL_HEADER  pOpt = (PIMAGE_OPTIONAL_HEADER)((ULONG)pFil + IMAGE_SIZEOF_FILE_HEADER);
	PIMAGE_EXPORT_DIRECTORY pExp = (PIMAGE_EXPORT_DIRECTORY)(ImageBuffer + pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);

	//遍历导出表
	ULONG64 FunctionAddr = NULL;
	for (int i = 0; i < pExp->NumberOfNames; i++)
	{
		PULONG  pAddressOfFuntion	= ImageBuffer + pExp->AddressOfFunctions;
		PULONG  pAddressOfNames		= ImageBuffer + pExp->AddressOfNames;
		PUSHORT pAddressOfOrd		= ImageBuffer + pExp->AddressOfNameOrdinals;
		PUCHAR  CurrentFunctionName = ImageBuffer + pAddressOfNames[i];

		ULONG uIndex = -1;

		if (strcmp(CurrentFunctionName, FunctionName) == 0)
		{
			uIndex = pAddressOfOrd[i];
		}

		if (uIndex != -1)
		{
			FunctionAddr = ImageBuffer + pAddressOfFuntion[uIndex];
			break;
		}

	}

	if (FunctionAddr)
	{
		DbgPrint("FindFunctionAddress FunName[%s] Addr[%p] \r\n", FunctionName, FunctionAddr);
	}
	else
	{
		DbgPrint("FindFunctionAddress Error FunName[%s] \r\n", FunctionName);
	}

	return FunctionAddr;
}

BOOLEAN SSDT_Init()
{
	if (G_MapNtdll)
	{
		return TRUE;
	}

	PWCHAR szPath = GetSystemFullPath();
	if (szPath == NULL)
	{
		return FALSE;
	}

	G_MapNtdll = FileMaping(szPath);
	if (G_MapNtdll == NULL)
	{
		ExFreePool(szPath);
		return FALSE;
	}

	ExFreePool(szPath);
	return TRUE;
}

VOID SSDT_Destroy()
{
	if (G_MapNtdll)
	{
		UnFileMaping(G_MapNtdll);
		G_MapNtdll = NULL;
	}
}

ULONG SSDT_GetFunIndex(PUCHAR szFunctionName)
{
	//获取函数地址
	PUCHAR pFunAddr = (PUCHAR)GetFuntionAddressByExportTableName(G_MapNtdll, szFunctionName);
	if (pFunAddr == NULL)
	{
		return -1;
	}

	//获取函数系统服务号
	return *(PULONG)(pFunAddr + 1);
}

ULONG_PTR SSDT_Hook(PUCHAR szFunctionName, ULONG_PTR FunctionAddr)
{
	ULONG uIndex = SSDT_GetFunIndex(szFunctionName);
	if (uIndex == -1)
	{
		return NULL;
	}

	//备份旧的地址
	ULONG OldFuncAddr = KeServiceDescriptorTable->ntoskrnl.ServiceTableBase[uIndex];

	//替换SSDT表中函数
	ULONG cr0 = wpOff();
	KeServiceDescriptorTable->ntoskrnl.ServiceTableBase[uIndex] = FunctionAddr;
	wpOn(cr0);

	return OldFuncAddr;
}


上一篇:lvs_nat服务搭建


下一篇:hook