Windows 2004 19041版本下SSDT函数的获取

在Windows10 高版本中 ,因为页表隔离补丁(?),__readmsr(0xC0000082) 返回KiSystemCall64Shadow,这玩意无法直接搜索到 KeServiceDescriptorTable,以前获取SystemServiceDescriptorTable的方法失效。

这里是新的,效果图。

在这里插入图片描述
代码抄的https://github.com/fIappy/infhook19041 嘤嘤嘤

核心代码如下:

NTSTATUS getKernelModuleByName(const char* moduleName, std::uintptr_t* moduleStart, std::size_t* moduleSize) {
	if (!moduleStart || !moduleSize)
		return STATUS_INVALID_PARAMETER;

	std::size_t size{};
	ZwQuerySystemInformation(0xB, nullptr, size, reinterpret_cast<PULONG>(&size));/* 0xB  SystemModuleInformation */

	const auto listHeader = ExAllocatePool(NonPagedPool, size);
	if (!listHeader)
		return STATUS_MEMORY_NOT_ALLOCATED;

	if (const auto status = ZwQuerySystemInformation(0xB, listHeader, size, reinterpret_cast<PULONG>(&size)))
		return status;

	auto currentModule = reinterpret_cast<PSYSTEM_MODULE_INFORMATION>(listHeader)->Module;
	for (std::size_t i{}; i < reinterpret_cast<PSYSTEM_MODULE_INFORMATION>(listHeader)->Count; ++i, ++currentModule) {
		const auto currentModuleName = reinterpret_cast<const char*>(currentModule->FullPathName + currentModule->OffsetToFileName);
		if (!strcmp(moduleName, currentModuleName)) {
			*moduleStart = reinterpret_cast<std::uintptr_t>(currentModule->ImageBase);
			*moduleSize = currentModule->ImageSize;
			return STATUS_SUCCESS;
		}
	}

	return STATUS_NOT_FOUND;
}

std::uintptr_t getImageSectionByName(const std::uintptr_t imageBase, const char* sectionName, std::size_t* sizeOut) {
	if (reinterpret_cast<PIMAGE_DOS_HEADER>(imageBase)->e_magic != 0x5A4D)
		return {};

	const auto ntHeader = reinterpret_cast<PIMAGE_NT_HEADERS64>(
		imageBase + reinterpret_cast<PIMAGE_DOS_HEADER>(imageBase)->e_lfanew);
	const auto sectionCount = ntHeader->FileHeader.NumberOfSections;

	auto sectionHeader = IMAGE_FIRST_SECTION(ntHeader);
	for (std::size_t i{}; i < sectionCount; ++i, ++sectionHeader) {
		if (!strcmp(sectionName, reinterpret_cast<const char*>(sectionHeader->Name))) {
			if (sizeOut)
				*sizeOut = sectionHeader->Misc.VirtualSize;
			return imageBase + sectionHeader->VirtualAddress;
		}
	}

	return {};
}

std::uintptr_t scanPattern(std::uint8_t* base, const std::size_t size, char* pattern, char* mask) {
	const auto patternSize = strlen(mask);

	for (std::size_t i = {}; i < size - patternSize; i++) {
		for (std::size_t j = {}; j < patternSize; j++) {
			if (mask[j] != '?' && *reinterpret_cast<std::uint8_t*>(base + i + j) != static_cast<std::uint8_t>(pattern[j]))
				break;

			if (j == patternSize - 1)
				return reinterpret_cast<std::uintptr_t>(base) + i;
		}
	}

	return {};
}

std::uintptr_t getServiceDescriptorTable() {
	std::uintptr_t ntoskrnlBase {};
	std::size_t ntoskrnlSize    {};
	if (!NT_SUCCESS(getKernelModuleByName("ntoskrnl.exe", &ntoskrnlBase, &ntoskrnlSize)))
		return {};

	std::size_t ntoskrnlTextSize {};
	const auto ntoskrnlText = getImageSectionByName(ntoskrnlBase, ".text", &ntoskrnlTextSize);
	if(!ntoskrnlText)
		return {};

	auto keServiceDescriptorTableShadow = scanPattern(reinterpret_cast<std::uint8_t*>(ntoskrnlText), ntoskrnlTextSize,
                                                               "\xC1\xEF\x07\x83\xE7\x20\x25\xFF\x0F", "xxxxxxxxx");

	if (!keServiceDescriptorTableShadow)
		return {};

	keServiceDescriptorTableShadow += 21;
	keServiceDescriptorTableShadow += *reinterpret_cast<std::int32_t*>(keServiceDescriptorTableShadow) + sizeof(std::int32_t);

	return keServiceDescriptorTableShadow;
}

std::uintptr_t GetSystemServiceDescriptorTableFunction(std::int32_t Index)
{
	if (keServiceDescriptorTable == NULL)
		keServiceDescriptorTable = getServiceDescriptorTable();
	const auto serviceTable = *reinterpret_cast<std::int32_t**>(keServiceDescriptorTable);
	return reinterpret_cast<std::uintptr_t>(serviceTable) + (serviceTable[Index & 0xFFF] >> 4);
}

完整工程下载地址

https://download.csdn.net/download/u011442768/13029151

本实例由VS2008开发,在提供了一套驱动开发框架的同时,又演示了如何获取Shadow SSDT表函数原始地址的办法。 主要函数:ULONG GetShadowSSDT_Function_OriAddr(ULONG index); 原理说明: 根据特征码搜索导出函数KeAddSystemServiceTable来获取Shadow SSDT基址,以及通过ZwQuerySystemInformation()函数获取win32k.sys基址,然后解析PE定位到Shadow SSDT在win32k.sys的偏移地址,并通过进一步计算来得到Shadow SSDT表函数的原始地址。 这里只测试了三个函数:(460)NtUserMessageCall、(475)NtUserPostMessage和(502)NtUserSendInput,具体使用时可以举一反三,网上完整的源代码实例并不太多,希望可以帮到真正有需要的朋友。 系统环境: 在WinXP SP3系统 + 瑞星杀毒软件 打印输出: [ LemonInfo : Loading Shadow SSDT Original Address Driver... ] [ LemonInfo : 创建“设备”值为:0 ] [ LemonInfo : 创建“设备”成功... ] [ LemonInfo : 创建“符号链接”状态值为:0 ] [ LemonInfo : 创建“符号链接”成功... ] [ LemonInfo : 驱动加载成功... ] [ LemonInfo : 派遣函数(DispatchRoutine) IRP 开始... ] [ LemonInfo : 派遣函数(DispatchRoutine) IRP Enter IRP_MJ_DEVICE_CONTROL... ] [ LemonInfo : 获取ShadowSSDT表 (460)NtUserMessageCall 函数的“当前地址”为:0xB83ECFC4,“起源地址”为:0xBF80EE6B ] [ LemonInfo : 获取ShadowSSDT表 (475)NtUserPostMessage 函数的“当前地址”为:0xB83ECFA3,“起源地址”为:0xBF8089B4 ] [ LemonInfo : 获取ShadowSSDT表 (502)NtUserSendInput 函数的“当前地址”为:0xBF8C31E7,“起源地址”为:0xBF8C31E7 ] [ LemonInfo : 派遣函数(DispatchRoutine) IRP_MJ_DEVICE_CONTROL 成功执行... ] [ LemonInfo : 派遣函数(DispatchRoutine) IRP 结束... ] [ LemonInfo : UnLoading Shadow SSDT Original Address Driver... ] [ LemonInfo : 删除“符号链接”成功... ] [ LemonInfo : 删除“设备”成功... ] [ LemonInfo : 驱动卸载成功... ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值