前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Windows Kernel-内核重载(NTOS)

Windows Kernel-内核重载(NTOS)

原创
作者头像
franket
发布于 2020-06-18 14:30:35
发布于 2020-06-18 14:30:35
20.7K00
代码可运行
举报
文章被收录于专栏:技术杂记技术杂记
运行总次数:0
代码可运行

取得NTOS原始的地址

这个可以通过遍历系统模块,找到第一个被加载的模块(NTOS),获得NTOS的路径,基地址,大小:

基本思路为:

1.ZwQuerySystemInformation查询到所有模块

2.获得NTOS的路径,基地址,大小

代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
NTSTATUS GetNtosModuleInfo(WCHAR *pNtosPath,ULONG nSize,
						   PULONG_PTR pNtosModBase,
						   PULONG_PTR pNtosModSize
						   )
{
	NTSTATUS						ntStatus = STATUS_UNSUCCESSFUL;
	PRTL_PROCESS_MODULES   			psmi = NULL;
	ULONG							ulSize = 0;
	ULONG						   ulIndex = 0;
 
	// 转换
	PCHAR						   pszNtosName = NULL;
	ANSI_STRING						Ansi_szNtosName;
	UNICODE_STRING				  Unicode_szNtosName;
 
	__try
	{
		do
		{
			ntStatus = ZwQuerySystemInformation(SystemModuleInformation, NULL, 0, &ulSize);
			if (STATUS_INFO_LENGTH_MISMATCH != ntStatus)
			{
				break;
			}
 
			psmi = (PRTL_PROCESS_MODULES)ExAllocatePoolWithTag(NonPagedPool, ulSize, '0YGH');
			if (NULL == psmi)
			{
				break;
			}
 
			ntStatus = ZwQuerySystemInformation(SystemModuleInformation,
				psmi, ulSize, &ulSize);
			if (STATUS_SUCCESS != ntStatus)
			{
				break;
			}
 
			//遍历打印:
			//for (ulIndex = 0; ulIndex<psmi->NumberOfModules; ulIndex++)
			//{
			//	KdPrint(("[ModInfo]-nIndex:%u--base:%p--size:%p--name:%s\n", ulIndex, psmi->Modules[ulIndex].ImageBase, psmi->Modules[ulIndex].ImageSize, psmi->Modules[ulIndex].FullPathName));
			//}
 
			if (pNtosPath)
			{
				memset(pNtosPath, 0, sizeof(WCHAR)*nSize);
				wcscpy(pNtosPath, L"\\SystemRoot\\system32\\");
				pszNtosName = psmi->Modules[0].FullPathName+psmi->Modules[0].OffsetToFileName;
				RtlInitAnsiString(&Ansi_szNtosName, pszNtosName);
				RtlAnsiStringToUnicodeString( &Unicode_szNtosName, &Ansi_szNtosName, TRUE);
				wcsncpy(pNtosPath+wcslen(pNtosPath), Unicode_szNtosName.Buffer,Unicode_szNtosName.Length);
				RtlFreeUnicodeString(&Unicode_szNtosName);
			}
 
			if (pNtosModBase
				&&MmIsAddressValid(pNtosModBase))
			{
				*pNtosModBase = psmi->Modules[0].ImageBase;
			}
 
			if (pNtosModSize
				&&MmIsAddressValid(pNtosModSize))
			{
				*pNtosModSize = psmi->Modules[0].ImageSize;
			}
 
		} while (FALSE);
 
	}
	__except(EXCEPTION_EXECUTE_HANDLER)
	{
 
	}
 
	if (NULL != psmi)
	{
		ExFreePool(psmi);
		psmi = NULL;
	}
 
	return ntStatus;
}

通过路径读取文件内容

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
NTSTATUS ReadFileToBuf(WCHAR *pFilePath, PVOID *ppBuf, PULONG_PTR pulSize)
{
	NTSTATUS						ntStatus = STATUS_UNSUCCESSFUL;
	HANDLE						  hFile = NULL;
	OBJECT_ATTRIBUTES			   obj;
	UNICODE_STRING					Unicode_FilePath;
	IO_STATUS_BLOCK				 iosb = {0};
	IO_STATUS_BLOCK				 io_readsb = {0};
	FILE_STANDARD_INFORMATION	   fInfo = {0};
	ULONG_PTR					   ulSize = 0;
	PVOID						   pBuf = NULL;
 
	do
	{
		RtlInitUnicodeString(&Unicode_FilePath, pFilePath);
		InitializeObjectAttributes(&obj, &Unicode_FilePath, OBJ_CASE_INSENSITIVE, NULL, NULL);
 
		ntStatus = ZwOpenFile(&hFile, SYNCHRONIZE, &obj, &iosb, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT);
		if (STATUS_SUCCESS != ntStatus)
		{
			break;
		}
 
		ntStatus = ZwQueryInformationFile(hFile,
			&iosb,
			&fInfo,
			sizeof(FILE_STANDARD_INFORMATION),
			FileStandardInformation
			);
		if (STATUS_SUCCESS != ntStatus)
		{
			break;
		}
 
		ulSize = fInfo.EndOfFile.LowPart;
		pBuf = ExAllocatePoolWithTag(PagedPool, ulSize+1024, '0YHG');
		if (NULL == pBuf)
		{
			break;
		}
 
		ntStatus = ZwReadFile(hFile,
			NULL,
			NULL,
			NULL,
			&io_readsb,
			pBuf,
			ulSize,
			0,
			NULL);
		if (STATUS_SUCCESS != ntStatus)
		{
			break;
		}
 
		if (io_readsb.Information != ulSize)
		{
			ntStatus = STATUS_UNSUCCESSFUL;
			break;
		}
 
		// 赋值
		if (pulSize)
		{
			*pulSize = ulSize;
		}
		if (ppBuf)
		{
			*ppBuf = pBuf;
		}
 
	} while (FALSE);
 
	if (hFile)
	{
		ZwClose(hFile);
		hFile = NULL;
	}
 
	if (STATUS_SUCCESS != ntStatus)
	{
		if (pBuf)
		{
			ExFreePool(pBuf);
			pBuf = NULL;
		}
	}
 
	return ntStatus;
}

按镜像大小分配内存

一般建议分配多一点,并映射MDL得到虚拟地址可读可写可执行

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
NTSTATUS MemoryMapMdl(PVOID pBase, ULONG ulSize, PMDL* ppMdl, PVOID* ppMapBase)
{
	NTSTATUS						ntStatus = STATUS_UNSUCCESSFUL;
	PMDL							pMdl = NULL;
	PVOID						   pMdlVA = NULL;
 
	do
	{
		pMdl = IoAllocateMdl(pBase, ulSize, FALSE, FALSE, NULL);
		if (NULL == pMdl)
		{
			break;
		}
 
		__try
		{
			// 锁住,避免被page out,直接会导致MmGetSystemAddressForMdl蓝屏
			MmProbeAndLockPages(pMdl, KernelMode, IoModifyAccess);
			//MmBuildMdlForNonPagedPool(pMdl);//如果是非分页内存,可以使用这个,使用这个就不需要MmUnmapLockedPages&MmUnlockPages了
		}
		__except(EXCEPTION_EXECUTE_HANDLER)
		{
			IoFreeMdl(pMdl);
			break;
		}
 
		pMdlVA = MmMapLockedPagesSpecifyCache(pMdl, KernelMode, MmCached, NULL, FALSE, NormalPagePriority);
		if (NULL == pMdlVA)
		{
			MmUnlockPages(pMdl);
			IoFreeMdl(pMdl);
			break;
		}
 
		ntStatus = MmProtectMdlSystemAddress(pMdl, PAGE_EXECUTE_READWRITE);
		if (STATUS_SUCCESS != ntStatus)
		{
			MmUnmapLockedPages(pMdlVA, pMdl);
			MmUnlockPages(pMdl);
			IoFreeMdl(pMdl);
			break;
		}
 
		// 赋值
		if (ppMapBase && MmIsAddressValid(ppMapBase))
		{
			*ppMapBase = pMdlVA;
		}
 
		if (ppMdl && MmIsAddressValid(ppMdl))
		{
			*ppMdl = pMdl;
		}
 
	} while (FALSE);
 
	return ntStatus;
}

复制section

对MDL映射出来的内存清0,再复制Header,复制section

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
NTSTATUS CopySections(PVOID pBase, PVOID pData, PIMAGE_NT_HEADERS pNtHdr)
{
	ULONG						   ulIndex = 0;
	PIMAGE_SECTION_HEADER			pSectionHdr = IMAGE_FIRST_SECTION(pNtHdr);
 
	for (ulIndex=0; ulIndex<pNtHdr->FileHeader.NumberOfSections; ulIndex++)
	{
		RtlCopyMemory((PUCHAR)pBase+pSectionHdr->VirtualAddress, (PUCHAR)pData+pSectionHdr->PointerToRawData, pSectionHdr->SizeOfRawData);
		pSectionHdr++;
	}
 
	return STATUS_SUCCESS;
}

修复IAT

1.像查找NTOS一样查找到依赖的dll的基地址

2.根据函数名搜索依赖的dll的导出表,找到函数地址,填充

3.在校验NTOS时,注意原始NTOS的导入表为init的,所以不存在了,需查看IAT表(12序号)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
NTSTATUS BuildNtosImportTable(PVOID pBase)
{
	PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pBase;
	PIMAGE_NT_HEADERS pNt = NULL;
	PIMAGE_IMPORT_DESCRIPTOR pImport = NULL;
	PIMAGE_THUNK_DATA pOrigThunk = NULL;
	PIMAGE_THUNK_DATA pFirstThunk = NULL;
	PIMAGE_IMPORT_BY_NAME pName = NULL;
	ULONG_PTR FunctionAddr = 0;
	ULONG_PTR ModBase = 0;
 
	if (NULL == pDos
		|| IMAGE_DOS_SIGNATURE != pDos->e_magic)
	{
		return STATUS_INVALID_IMAGE_FORMAT;
	}
 
	pNt = (PIMAGE_NT_HEADERS)((PUCHAR)pBase+pDos->e_lfanew);
	if (IMAGE_NT_SIGNATURE != pNt->Signature)
	{
		return STATUS_INVALID_IMAGE_FORMAT;
	}
 
	if (0 == pNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size)
	{
		return STATUS_SUCCESS;
	}
 
	pImport = (PIMAGE_IMPORT_DESCRIPTOR)((PUCHAR)pBase+pNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
 
	while (NULL !=pImport
		&& MmIsAddressValid(pImport)
		&&pImport->Name != 0)
	{
		// 获得模块基地址
		if (STATUS_SUCCESS != GetModuleInfo((PCHAR)((PUCHAR)pBase+pImport->Name), &ModBase))
		{
			return STATUS_UNSUCCESSFUL;
		}
		KdPrint(("[BuildNtosImportTable]-ModName:%s, ModBase:%p\n",(PCHAR)((PUCHAR)pBase+pImport->Name), ModBase));
 
		if (pImport->OriginalFirstThunk)
		{
			pOrigThunk = (PIMAGE_THUNK_DATA)((PUCHAR)pBase+pImport->OriginalFirstThunk);
			pFirstThunk = (PIMAGE_THUNK_DATA)((PUCHAR)pBase+pImport->FirstThunk);
		}
		else
		{
			pOrigThunk = (PIMAGE_THUNK_DATA)((PUCHAR)pBase+pImport->FirstThunk);
			pFirstThunk = (PIMAGE_THUNK_DATA)((PUCHAR)pBase+pImport->FirstThunk);
		}
 
		while (pOrigThunk->u1.Ordinal)
		{
			// 序号导入
			if (IMAGE_SNAP_BY_ORDINAL(pOrigThunk->u1.Ordinal))
			{
				FunctionAddr = GetExportFunAddr(ModBase,FALSE, NULL, pOrigThunk->u1.Ordinal& ~IMAGE_ORDINAL_FLAG32);
			}
			else
			{
				pName = (PIMAGE_IMPORT_BY_NAME)((PUCHAR)pBase+pOrigThunk->u1.Ordinal);
				FunctionAddr = GetExportFunAddr(ModBase, TRUE, pName->Name, 0);
				KdPrint(("[BuildNtosImportTable]-Mod:%s, Fun:%s[%p]\r\n",(PCHAR)((PUCHAR)pBase+pImport->Name), pName->Name, FunctionAddr));
			}
 
			if (FunctionAddr)
			{
				pFirstThunk->u1.Function = FunctionAddr;
			}
			else
			{
				KdPrint(("[BuildNtosImportTable]-Function fail\n"));
			}
 
			pOrigThunk++;
			pFirstThunk++;
		}
 
		pImport++;
	}
 
	return STATUS_SUCCESS;
}

修复重定位表

其目的是使用同一份全局变量,所以重定位差值一定要是原始NTOS-0X400000(OptionalHeader.ImageBase)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
NTSTATUS BuildNtosRelocTable(PVOID pBase,PVOID pSysBase)
{
	PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pBase;
	PIMAGE_NT_HEADERS pNt = NULL;
	PIMAGE_BASE_RELOCATION pBaseReloc = NULL;
 
	ULONG_PTR ulDiff = 0;
 
 
	if (NULL == pDos
		|| IMAGE_DOS_SIGNATURE != pDos->e_magic)
	{
		return STATUS_INVALID_IMAGE_FORMAT;
	}
 
	pNt = (PIMAGE_NT_HEADERS)((PUCHAR)pBase+pDos->e_lfanew);
	if (IMAGE_NT_SIGNATURE != pNt->Signature)
	{
		return STATUS_INVALID_IMAGE_FORMAT;
	}
 
	if (0 == pNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size)
	{
		return STATUS_SUCCESS;
	}
 
	pBaseReloc = (PIMAGE_BASE_RELOCATION)((PCHAR)pBase+pNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
	if (NULL == pBaseReloc)
	{
		return STATUS_SUCCESS;
	}
 
	ulDiff = (ULONG_PTR)pSysBase - (ULONG_PTR)pNt->OptionalHeader.ImageBase;
 
	if (pBaseReloc->SizeOfBlock>sizeof(IMAGE_BASE_RELOCATION))
	{
		do
		{
			ULONG ulCount = (pBaseReloc->SizeOfBlock-sizeof(IMAGE_BASE_RELOCATION))/sizeof(USHORT);
			PUSHORT pItem = (PUSHORT)((PCHAR)pBaseReloc+sizeof(IMAGE_BASE_RELOCATION));
			PULONG_PTR pRelocTarget = NULL;
			ULONG ulIndex = 0;
			for (ulIndex = 0; ulIndex<ulCount; ulIndex++)
			{
				//高四位类型:
				// IMAGE_REL_BASED_ABSOLUTE:无具体含义,仅是让每个段4字节对齐
				// IMAGE_REL_BASED_HIGHLOW:重定位指向的整个地址都要被修正,基本是这个情况
				// IMAGE_REL_BASED_DIR64:出现在64位PE文件中,对指向的整个地址修正.
				ULONG ulType = pItem[ulIndex]>>12;// 高4位
				ULONG ulOffset = pItem[ulIndex] & 0xFFF;// 低12位
				switch (ulType)
				{
				case IMAGE_REL_BASED_HIGHLOW:
				case IMAGE_REL_BASED_DIR64:
					{
						pRelocTarget = (PULONG_PTR)((PCHAR)pBase+ulOffset+pBaseReloc->VirtualAddress);
						*pRelocTarget += ulDiff;// 跳转到原始的全局变量
 
					}
					break;
 
				default:
					break;
				}
 
			}
 
			pBaseReloc = (PIMAGE_BASE_RELOCATION)((PCHAR)pBaseReloc+pBaseReloc->SizeOfBlock);
		} while (pBaseReloc->SizeOfBlock);//Vista的内核下,最后一个的VirtualAddress有可能不为0!
	}
 
	return STATUS_SUCCESS;
}

修复SSDT表(仅X86下适用)

这时可以用.reload /i 来再加载一份NT的pdb,可以看到,新的NT的SSDT对象内容全为0,所以需要重建:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 仅在X86下使用
void SetNewSSDT(PVOID pNewBase,PVOID pSysBase)
{
	//禁止写保护,不然蓝屏
 
	ULONG ulOffset = (ULONG)pNewBase - (ULONG)pSysBase;
	ULONG ulIndex = 0;
 
	DisablePageWriteProtection
	g_pNewSSDT = (PKSERVICE_TABLE_DESCRIPTOR)((PCHAR)KeServiceDescriptorTable+ulOffset);
	if (!MmIsAddressValid(g_pNewSSDT))
	{
		g_pNewSSDT = NULL;
		return;
	}
 
 
	g_pNewSSDT->TableSize = KeServiceDescriptorTable->TableSize;
	g_pNewSSDT->ServiceTableBase = (PULONG)((PCHAR)KeServiceDescriptorTable->ServiceTableBase+ulOffset);
	g_pNewSSDT->ArgumentTable = (PUCHAR)((PCHAR)KeServiceDescriptorTable->ArgumentTable+ulOffset);
	if (!MmIsAddressValid(g_pNewSSDT->ServiceTableBase)
		||!MmIsAddressValid(g_pNewSSDT->ArgumentTable))
	{
		g_pNewSSDT = NULL;
		return;
	}
 
	for (ulIndex=0; ulIndex<g_pNewSSDT->TableSize; ulIndex++)
	{
		// 函数偏移要变
		g_pNewSSDT->ServiceTableBase[ulIndex] += ulOffset;
	}
 
	// 参数不变
	memcpy(g_pNewSSDT->ArgumentTable, KeServiceDescriptorTable->ArgumentTable, KeServiceDescriptorTable->TableSize);
 
	//恢复写保护
	EnablePageWriteProtection
}

测试SSDT分发

hook管家的函数,实现SSDT分发

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ULONG __stdcall KiFastCallEntry_Filter(ULONG ulSyscallId,
									   ULONG ulSyscallAddr,
									   PULONG pulSyscallTable)
{
	ULONG ulRet = 0;
	pfn_KiFastCallEntry_Filter pfn = (pfn_KiFastCallEntry_Filter)QQHookZone;
	//KdPrint(("[KiFastCallEntry_Filter]-ulSyscallId:%d,ulSyscallAddr:0x%08x,pulSyscallTable:0x%08x\n",ulSyscallId, ulSyscallAddr, pulSyscallTable));
	ulRet = pfn(ulSyscallId, ulSyscallAddr, pulSyscallTable);
 
	if (pulSyscallTable == KeServiceDescriptorTable->ServiceTableBase)
	{
		if (g_pNewSSDT)
		{
			if (!_strnicmp((char*)PsGetCurrentProcess()+0x174,"cheatengine-", 10))
			{
				ulRet = g_pNewSSDT->ServiceTableBase[ulSyscallId];
			}
		}
	}
 
	return ulRet;
}

注意:比如只针对CE,那么 CE必须先关闭,再释放驱动,不然极可能蓝屏掉(蓝屏在重载 的NTOS中)

以下代码在装了QQ管家+CE下,可以查看被保护的内存(如NP)

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
作者已关闭评论
暂无评论
推荐阅读
编辑精选文章
换一批
驱动开发:内核远程线程实现DLL注入
在笔者上一篇文章《内核RIP劫持实现DLL注入》介绍了通过劫持RIP指针控制程序执行流实现插入DLL的目的,本章将继续探索全新的注入方式,通过NtCreateThreadEx这个内核函数实现注入DLL的目的,需要注意的是该函数在微软系统中未被导出使用时需要首先得到该函数的入口地址,NtCreateThreadEx函数最终会调用ZwCreateThread,本章在寻找函数的方式上有所不同,前一章通过内存定位的方法得到所需地址,本章则是通过解析导出表实现。
王 瑞
2023/06/25
5310
驱动开发:内核远程线程实现DLL注入
ring0下使用内核重载绕过杀软hook
首发于奇安信攻防社区: https://forum.butian.net/share/1423
红队蓝军
2022/05/17
6880
ring0下使用内核重载绕过杀软hook
ring0下使用内核重载绕过杀软hook
内核重载听起来是一个很高大上的概念,但其实跟PE的知识息息相关,那么为什么会有内核重载的出现呢?
红队蓝军
2022/04/07
6330
ring0下使用内核重载绕过杀软hook
二、驱动
二、驱动 2.1.hello world 1.创建项目 2.删除Driver Files里面的helloworld.inf文件 3.右键属性 Inf2Cat->General->Run Inf2Cat 改成否 Driver Settings->General->Traget OS VERSION和Target Platform改成对一个的平台 C/C++ -->常规->警告等级改为3,将警告视为错误改成否 C/C++ -->代码生成-->Spectre Mitigation改为Disabled 4.hell
zhang_derek
2022/09/21
6810
暴力搜索x64 ssdt 以及挂钩HOOK
IDA加载ntoskrnl.exe 微软符号,进入,jump by name,随便输入一个,比如zwwritefile,层层跟踪,进入,可以发现
战神伽罗
2019/07/24
2.5K0
8种HOOK技术[通俗易懂]
IAT是程序中存储导入函数地址的数据结构,如果HOOK了导入函数地址。就可以在函数调用的时候,将函数流程HOOK到我们指定的流程。但是我个人觉得这种方式最好要结合DLL注入的方式,如果单纯的使用HOOK,那么就需要将需要执行的操作的shellcode写入目标进程,如果操作复杂,可能需要的shellcode量特别大,所以我们需要借助DLL注入,这样就将我们需要执行的代码写入进程内部,在HOOK的Detour函数只需要实现LoadLibrary的操作。
全栈程序员站长
2022/09/01
3.6K0
驱动开发:Win10内核枚举SSDT表基址
三年前面朝黄土背朝天的我,写了一篇如何在Windows 7系统下枚举内核SSDT表的文章《驱动开发:内核读取SSDT表基址》三年过去了我还是个单身狗,开个玩笑,微软的Windows 10系统已经覆盖了大多数个人PC终端,以前的方法也该进行迭代更新了,或许在网上你能够找到类似的文章,但我可以百分百肯定都不能用,今天LyShark将带大家一起分析Win10 x64最新系统SSDT表的枚举实现。
王 瑞
2022/11/18
6720
驱动开发:Win10内核枚举SSDT表基址
如何找SSDT中精准的
我们可以通过枚举ntdll.dll的导出函数来间接枚举SSDT所有表项所对应的函数,因为所有的内核服务函数对应于ntdll.dll的同名函数都是这样开头的:
战神伽罗
2019/07/24
1.3K0
驱动开发:内核RIP劫持实现DLL注入
本章将探索内核级DLL模块注入实现原理,DLL模块注入在应用层中通常会使用CreateRemoteThread直接开启远程线程执行即可,驱动级别的注入有多种实现原理,而其中最简单的一种实现方式则是通过劫持EIP的方式实现,其实现原理可总结为,挂起目标进程,停止目标进程EIP的变换,在目标进程开启空间,并把相关的指令机器码和数据拷贝到里面去,然后直接修改目标进程EIP使其强行跳转到我们拷贝进去的相关机器码位置,执行相关代码后,然后再次跳转回来执行原始指令集。
王 瑞
2023/06/16
1K0
驱动开发:内核RIP劫持实现DLL注入
驱动开发:内核解析PE结构导出表
在笔者的上一篇文章《驱动开发:内核特征码扫描PE代码段》中LyShark带大家通过封装好的LySharkToolsUtilKernelBase函数实现了动态获取内核模块基址,并通过ntimage.h头文件中提供的系列函数解析了指定内核模块的PE节表参数,本章将继续延申这个话题,实现对PE文件导出表的解析任务,导出表无法动态获取,解析导出表则必须读入内核模块到内存才可继续解析,所以我们需要分两步走,首先读入内核磁盘文件到内存,然后再通过ntimage.h中的系列函数解析即可。
王 瑞
2023/05/31
3560
驱动开发:内核解析PE结构导出表
驱动开发:内核RIP劫持实现DLL注入
本章将探索内核级DLL模块注入实现原理,DLL模块注入在应用层中通常会使用CreateRemoteThread直接开启远程线程执行即可,驱动级别的注入有多种实现原理,而其中最简单的一种实现方式则是通过劫持EIP的方式实现,其实现原理可总结为,挂起目标进程,停止目标进程EIP的变换,在目标进程开启空间,并把相关的指令机器码和数据拷贝到里面去,然后直接修改目标进程EIP使其强行跳转到我们拷贝进去的相关机器码位置,执行相关代码后,然后再次跳转回来执行原始指令集。
王 瑞
2023/10/11
1.2K0
驱动开发:内核RIP劫持实现DLL注入
驱动开发:内核运用LoadImage屏蔽驱动
在笔者上一篇文章《驱动开发:内核监视LoadImage映像回调》中LyShark简单介绍了如何通过PsSetLoadImageNotifyRoutine函数注册回调来监视驱动模块的加载,注意我这里用的是监视而不是监控之所以是监视而不是监控那是因为PsSetLoadImageNotifyRoutine无法实现参数控制,而如果我们想要控制特定驱动的加载则需要自己做一些事情来实现,如下LyShark将解密如何实现屏蔽特定驱动的加载。
王 瑞
2022/11/14
1.4K0
驱动开发:内核运用LoadImage屏蔽驱动
驱动开发:挂接SSDT内核钩子
SSDT 中文名称为系统服务描述符表,该表的作用是将Ring3应用层与Ring0内核层,两者的API函数连接起来,起到承上启下的作用,SSDT并不仅仅只包含一个庞大的地址索引表,它还包含着一些其它有用的信息,诸如地址索引的基址、服务函数个数等,SSDT 通过修改此表的函数地址可以对常用 Windows 函数进行内核级的Hook,从而实现对一些核心的系统动作进行过滤、监控的目的,接下来将演示如何通过编写简单的驱动程序,来实现搜索 SSDT 函数的地址,并能够实现简单的内核 Hook 挂钩。
王 瑞
2022/12/20
8920
驱动开发:挂接SSDT内核钩子
进程管理器中隐藏进程
将其注入到进程管理器进程中,即可隐藏指定进程,当然在tasklist中依旧存在,win10 x86测试成功。用途可自行扩展。
鸿鹄实验室
2021/07/06
1.1K0
Windows x64内核下注入DLL姿势之一
用户10168639
2023/07/06
1.6K0
64位内核映射DLL获取Zw函数调用功能号
映射DLL其实很简单 在内核中使用4个函数即可映射. 而这方面网上资料也很多.这里推荐几个 也不再重复叙述了. 转载链接: 内核映射文件 简而言之只需要熟悉四个API即可. 而核心API其实就三个 分别为如下:
IBinary
2022/05/10
6610
64位内核映射DLL获取Zw函数调用功能号
SSDT-hook,IDT-hook原理
【详细过程】 这次主要说说核心层的hook。包括SSDT-hook,IDT-hook,sysenter-hook。欢迎讨论,指正!内核层需要驱动,有这方面的基础最好,如果不会,了解下其中的思路也可以的。 II. SSDT-hook,IDT-hook,sysenter-hook 一.SSDT-hook (一)一般思路: 1.先来了解一下,什么是SSDT SSDT既System Service Dispath Table。在了解他之前,我们先了解一下NT的基本组建。在 Windows NT 下,NT 的 executive(NTOSKRNL.EXE 的一部分)提供了核心系统服务。各种 Win32、OS/2 和 POSIX 的 APIs 都是以 DLL 的形式提供的。这些dll中的 APIs 转过来调用了 NT executive 提供的服务。尽管调用了相同的系统服务,但由于子系统不同,API 函数的函数名也不同。例如,要用Win32 API 打开一个文件,应用程序会调用 CreateFile(),而要用 POSIX API,则应用程序调用 open() 函数。这两种应用程序最终都会调用 NT executive 中的 NtCreateFile() 系统服务。
战神伽罗
2019/07/24
2K0
SSDT-hook,IDT-hook原理
五、句柄表
1.全局句柄表中只存储进程和线程对象,把PID/CID当作索引在全局句柄表中查找对应对象结构.
zhang_derek
2022/09/29
8770
五、句柄表
驱动开发:如何枚举所有SSDT表地址
在前面的博文《驱动开发:Win10内核枚举SSDT表基址》中已经教大家如何寻找SSDT表基地址了,找到后我们可根据序号获取到指定SSDT函数的原始地址,而如果需要输出所有SSDT表信息,则可以定义字符串列表,以此循环调用GetSSDTFunctionAddress()函数得到,当然在此之间也可以调用系统提供的MmGetSystemRoutineAddress()函数顺便把当前地址拿到,并通过循环方式得到完整的SSDT列表。
王 瑞
2023/10/11
3700
驱动开发:如何枚举所有SSDT表地址
驱动开发:内核枚举ShadowSSDT基址
在笔者上一篇文章《驱动开发:Win10枚举完整SSDT地址表》实现了针对SSDT表的枚举功能,本章继续实现对SSSDT表的枚举,ShadowSSDT中文名影子系统服务描述表,SSSDT其主要的作用是管理系统中的图形化界面,其Win32子系统的内核实现是Win32k.sys驱动,属于GUI线程的一部分,其自身没有导出表,枚举SSSDT表其与SSDT原理基本一致。
王 瑞
2022/11/18
6320
驱动开发:内核枚举ShadowSSDT基址
相关推荐
驱动开发:内核远程线程实现DLL注入
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验