一份内核重载代码的学习笔记

 0x00 前言

参考文章:
https://blog.csdn.net/whatday/article/details/14160875

https://blog.csdn.net/pjz969/article/details/8615085

  首先重载内核不是什么新技术,对于绕过HOOK是一种一刀切的做法,不过对于我这样初探内核的小白还是很有总结意义的。
本篇涉及的知识点:0环和3环通信,PE结构(除了基础的头外还有重定位表),用到了两种HOOK(SSDT HOOK,Inline HOOK),API函数调用(逆了一个函数KiFastCallEntry)。
流程:
1)按照字节对齐把文件中的PE结构在内存里展开
2)利用重定位表修改全局变量
3)COPY自己的SSDT表
4)函数调用时换成新的内核(HOOK KiFastCallEntry)

0x01 展开PE结构

因为我的环境是win7 32位,所以要把ntkrnlpa.exe文件在内存里展开.
1. 首先,在内核里使用RtlInitUnicodeString创建对象,打开文件使用ZwCreateFile,并且要初始化InitializeObjectAttributes。
2. 通过PE结构的知识,DOS头,PE头,节表,是紧挨在一起的无需扩展,只需确定在文件中的偏移和大小利用ZwReadFile即可获取: 
     1)DOS头的偏移就是0,大小为sizeof(IMAGE_DOS_HEADER);
     2)PE头的偏移由DOS最后一个成员确定ImageDosHeader.e_lfanew,大小为sizeof(IMAGE_NT_HEADER);
     3)节表的偏移为+= sizeof(IMAGE_NT_HEADERS),因为节表里HEADER的数量不确定,所以需要到
           IMAGE_NT_HEADER->IMAGE_FILE_HEADER.NumberOfSection确定节的数目,所以大小为 sizeof(IMAGE_SECTION_HEADER) * 前者。
      4)每个节的偏移由
           IMAGE_SCTION_HEADER->SectionHeader[i].VirTualAddress(相对于文件开头),
           节的大小需要判断:比较SectionHeader[i].Misc.VirTualSize(实际的大小)和SectionHeader[i].SizeOfRawData(按字节对齐            时文件中的大小),因为全局变量的关系,所以两者大小不一定,取大的那个。
3. 第三,就是用RtlCopyMemory一段一段COPY DOS头,PE头,节表,和每个节。

void LoadKernel()
{
	NTSTATUS					status;
	UNICODE_STRING				uFileName;
	HANDLE						hFile;
	OBJECT_ATTRIBUTES			ObjAttr;
	IO_STATUS_BLOCK				IoStatusBlock;
	LARGE_INTEGER				FileOffset;
	ULONG						retsize;
	PVOID						lpVirtualPointer;
	ULONG						uLoop;
	ULONG						SectionVirtualAddress, SectionSize;
	IMAGE_DOS_HEADER			ImageDosHeader;
	IMAGE_NT_HEADERS			ImageNtHeader;
	IMAGE_SECTION_HEADER* lpImageSectionHeader;

	InitializeObjectAttributes(&ObjAttr, \
		& uFileName, \
		OBJ_CASE_INSENSITIVE, \
		NULL, \
		NULL);
	RtlInitUnicodeString(&uFileName, L"\\??\\C:\\WINDOWS\\system32\\ntkrnlpa.exe");
	//打开文件
	status = ZwCreateFile(\
		& hFile, \
		FILE_ALL_ACCESS, \
		& ObjAttr, \
		& IoStatusBlock, \
		0, \
		FILE_ATTRIBUTE_NORMAL, \
		FILE_SHARE_READ, \
		FILE_OPEN, \
		FILE_NON_DIRECTORY_FILE, \
		NULL, \
		0);
	if (!NT_SUCCESS(status))
	{
		KdPrint(("CreateFile Failed!"));
		return;
	}
	//读取DOS头
	FileOffset.QuadPart = 0;
	status = ZwReadFile(hFile, \
		NULL, \
		NULL, \
		NULL, \
		& IoStatusBlock, \
		& ImageDosHeader, \
		sizeof(IMAGE_DOS_HEADER), \
		& FileOffset, \
		0);
	if (!NT_SUCCESS(status))
	{
		KdPrint(("Read ImageDosHeader Failed!"));
		ZwClose(hFile);
		return;
	}
	//读取NT头
	FileOffset.QuadPart = ImageDosHeader.e_lfanew;
	status = ZwReadFile(hFile, \
		NULL, \
		NULL, \
		NULL, \
		& IoStatusBlock, \
		& ImageNtHeader, \
		sizeof(IMAGE_NT_HEADERS), \
		& FileOffset, \
		0);
	if (!NT_SUCCESS(status))
	{
		KdPrint(("Read ImageNtHeaders Failed!"));
		ZwClose(hFile);
		return;
	}
	//读取节表
	lpImageSectionHeader = (IMAGE_SECTION_HEADER*)ExAllocatePool(NonPagedPool, \
		sizeof(IMAGE_SECTION_HEADER) * ImageNtHeader.FileHeader.NumberOfSections);
	FileOffset.QuadPart += sizeof(IMAGE_NT_HEADERS);
	status = ZwReadFile(hFile, \
		NULL, \
		NULL, \
		NULL, \
		& IoStatusBlock, \
		lpImageSectionHeader, \
		sizeof(IMAGE_SECTION_HEADER) * ImageNtHeader.FileHeader.NumberOfSections, \
		& FileOffset, \
		0);
	if (!NT_SUCCESS(status))
	{
		KdPrint(("Read ImageSectionHeader Failed!"));
		ExFreePool(lpImageSectionHeader);
		ZwClose(hFile);
		return;
	}
	//COPY数据到内存
	lpVirtualPointer = ExAllocatePool(NonPagedPool, \
		ImageNtHeader.OptionalHeader.SizeOfImage);
	if (lpVirtualPointer == 0)
	{
		KdPrint(("lpVirtualPointer Alloc space Failed!"));
		ZwClose(hFile);
		return;
	}
	memset(lpVirtualPointer, 0, ImageNtHeader.OptionalHeader.SizeOfImage);
	//COPY DOS头
	RtlCopyMemory(lpVirtualPointer, \
		& ImageDosHeader, \
		sizeof(IMAGE_DOS_HEADER));
	//COPY NT头
	RtlCopyMemory((PVOID)((ULONG)lpVirtualPointer + ImageDosHeader.e_lfanew), \
		& ImageNtHeader, \
		sizeof(IMAGE_NT_HEADERS));
	//COPY 区表
	RtlCopyMemory((PVOID)((ULONG)lpVirtualPointer + ImageDosHeader.e_lfanew + sizeof(IMAGE_NT_HEADERS)), \
		lpImageSectionHeader, \
		sizeof(IMAGE_SECTION_HEADER) * ImageNtHeader.FileHeader.NumberOfSections);
	//依次COPY 各区段数据
	for (uLoop = 0;uLoop < ImageNtHeader.FileHeader.NumberOfSections;uLoop++)
	{
		SectionVirtualAddress = lpImageSectionHeader[uLoop].VirtualAddress;//对应区段相对偏移
		if (lpImageSectionHeader[uLoop].Misc.VirtualSize > lpImageSectionHeader[uLoop].SizeOfRawData)
			SectionSize = lpImageSectionHeader[uLoop].Misc.VirtualSize;//取最大的占用空间
		else
			SectionSize = lpImageSectionHeader[uLoop].SizeOfRawData;
		FileOffset.QuadPart = lpImageSectionHeader[uLoop].PointerToRawData;//对应区段的超始地址
		status 
  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值