[转](70)内核重载 xp sp3 x86 单核

 

一、项目说明

这次项目是这样设计的,首先 inline hook NtTerminateProcess 函数,使其他进程不能关闭受保护的进程,这里选择记事本。

然后编写一个普通的程序,调用 TerminateProcess 函数关闭记事本,如无意外是关不掉的。

然后编写驱动,从文件系统中加载一份新内核到内存,拉伸PE,修复重定位表,IAT表,SSDT表;HOOK KiFastCallEntry 函数,让我们的程序系统调用走新内核,这样就可以关掉记事本了。

二、前置任务

首先把保护记事本和关闭记事本的程序给出,这两个没什么难度,不想解释。

效果就是加载保护驱动后,无法 TerminateProcess 关闭记事本。

调用 TerminateProcess 关闭记事本的程序

// KillNotepad.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <Windows.h>

// 提权函数:提升为DEBUG权限
BOOL EnableDebugPrivilege()
{
	HANDLE hToken;
	BOOL fOk=FALSE;
	if(OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&hToken))
	{
		TOKEN_PRIVILEGES tp;
		tp.PrivilegeCount=1;
		LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&tp.Privileges[0].Luid);

		tp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;
		AdjustTokenPrivileges(hToken,FALSE,&tp,sizeof(tp),NULL,NULL);

		fOk=(GetLastError()==ERROR_SUCCESS);
		CloseHandle(hToken);
	}
	return fOk;
}


int _tmain(int argc, _TCHAR* argv[])
{
	EnableDebugPrivilege();
	HWND hWnd = FindWindowA(NULL, "无标题 - 记事本");
	DWORD dwPid = -1;
	GetWindowThreadProcessId(hWnd, &dwPid);
	HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);

	TerminateProcess(hProcess,0);
	return 0;
}



保护记事本的驱动

//#include <ntddk.h>
#include <ntifs.h>
#include <ntimage.h>


//-----------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------


typedef struct _LDR_DATA_TABLE_ENTRY
{
	LIST_ENTRY InLoadOrderLinks;
	LIST_ENTRY InMemoryOrderLinks;
	LIST_ENTRY InInitializationOrderLinks;
	PVOID DllBase;
	PVOID EntryPoint;
	ULONG SizeOfImage;
	UNICODE_STRING FullDllName;
	UNICODE_STRING BaseDllName;
	ULONG Flags;
	UINT16 LoadCount;
	UINT16 TlsIndex;
	LIST_ENTRY HashLinks;
	PVOID SectionPointer;
	ULONG CheckSum;
	ULONG TimeDateStamp;
	PVOID LoadedImports;
	PVOID EntryPointActivationContext;
	PVOID PatchInformation;
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;

typedef NTSTATUS (*NTTERMINATEPROCESS) (HANDLE ProcessHandle, NTSTATUS ExitStatus);

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

// SSDT表
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;

//-----------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------

NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path);
VOID DriverUnload(PDRIVER_OBJECT driver);
VOID PageProtectOff();
VOID PageProtectOn();
VOID GetKernelBase(PDRIVER_OBJECT driver, PVOID *pKrnlBase, PULONG uKrnlImageSize);
PVOID MemorySearch(PVOID bytecode, ULONG bytecodeLen, PVOID pBeginAddress, PVOID pEndAddress);
VOID HookNtTerminateProcess();
VOID UnhookNtTerminateProcess();
VOID HbgNtTerminateProcess(HANDLE ProcessHandle, NTSTATUS ExitStatus);

//-----------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------

PDRIVER_OBJECT g_Driver;
extern PKSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable; // 内核导出的全局变量

PVOID pNtTerminateProcess;
PVOID pNtTerminateProcessHookRet;

// NtTerminateProcess 系统调用号
#define NTTERMINATEPROCESS_INDEX 0x101

//-----------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------

NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path)
{	
	g_Driver = driver;
	driver->DriverUnload = DriverUnload;

	HookNtTerminateProcess();

	return STATUS_SUCCESS;
}

// 卸载驱动
VOID DriverUnload(PDRIVER_OBJECT driver)
{
	UnhookNtTerminateProcess();
	DbgPrint("Kernel Unload Successfully.\n");
}

// 关闭页保护
VOID PageProtectOff()
{
	__asm
	{
		cli; // 关闭中断
		mov eax, cr0;
		and eax, not 0x10000; // WP位置0
		mov cr0, eax;
	}
}

// 开启页保护
VOID PageProtectOn()
{
	__asm
	{
		mov eax, cr0;
		or eax, 0x10000; // WP位置1
		mov cr0, eax;
		sti; // 恢复中断
	}
}

// 获取内核基址,大小
VOID GetKernelBase(PDRIVER_OBJECT driver, PVOID *pKrnlBase, PULONG uKrnlImageSize)
{
	PLDR_DATA_TABLE_ENTRY pLdteHead; // 内核模块链表头
	PLDR_DATA_TABLE_ENTRY pLdteCur; // 遍历指针
	UNICODE_STRING usKrnlBaseDllName; // 内核模块名

	RtlInitUnicodeString(&usKrnlBaseDllName,L"ntoskrnl.exe");
	pLdteHead = (PLDR_DATA_TABLE_ENTRY)driver->DriverSection;
	pLdteCur = pLdteHead;
	do 
	{
		PLDR_DATA_TABLE_ENTRY pLdte = CONTAINING_RECORD(pLdteCur, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
		//DbgPrint("DllBase: %p, SizeOfImage: %08X %wZ\n", pLdteCur->DllBase, pLdteCur->SizeOfImage, &(pLdteCur->FullDllName));
		if (RtlCompareUnicodeString(&pLdteCur->BaseDllName, &usKrnlBaseDllName, TRUE) == 0)
		{
			*pKrnlBase = pLdteCur->DllBase;
			*uKrnlImageSize = pLdteCur->SizeOfImage;
			return;
		}
		pLdteCur = (PLDR_DATA_TABLE_ENTRY)pLdteCur->InLoadOrderLinks.Flink;
	} while (pLdteHead != pLdteCur);
	return;
}

// 特征码搜索
PVOID MemorySearch(PVOID bytecode, ULONG bytecodeLen, PVOID pBeginAddress, PVOID pEndAddress)
{
	PVOID pCur = pBeginAddress;
	while (pCur != pEndAddress)
	{
		if (RtlCompareMemory(bytecode,pCur,bytecodeLen) == bytecodeLen)
		{
			return pCur;
		}
		((ULONG)pCur)++;
	}
	return 0;
}

// hook NtTerminateProcess
VOID HookNtTerminateProcess()
{	
	pNtTerminateProcess = (PVOID)KeServiceDescriptorTable->ntoskrnl.ServiceTableBase[NTTERMINATEPROCESS_INDEX];
	PageProtectOff();
	// hook NtTerminateProcess ,采取短跳+长跳的方式
	*(PUCHAR)((ULONG)pNtTerminateProcess - 5) = 0xE9;
	*(PULONG)((ULONG)pNtTerminateProcess - 4) = (ULONG)HbgNtTerminateProcess - (ULONG)pNtTerminateProcess;
	*(PUSHORT)pNtTerminateProcess = (USHORT)0xF9EB;
	PageProtectOn();
}

// unhook NtTerminateProcess
VOID UnhookNtTerminateProcess()
{
	*(PUSHORT)pNtTerminateProcess = (USHORT)0xFF8B;
	*(PUCHAR)((ULONG)pNtTerminateProcess - 5) = 0xCC;
	*(PULONG)((ULONG)pNtTerminateProcess - 4) = 0xCCCCCCCC;
}

// 被修改的 NtTerminateProcess 函数,简单打印参数
__declspec(naked) VOID HbgNtTerminateProcess(HANDLE ProcessHandle, NTSTATUS ExitStatus)
{
	PEPROCESS pEprocess;
	NTSTATUS status;
	PCHAR ImageFileName;

	__asm
	{
		mov edi,edi;
		push ebp;
		mov ebp,esp;

		pushad;
		pushfd;
		sub esp,0x20;
	}

	status = ObReferenceObjectByHandle(ProcessHandle,FILE_ANY_ACCESS,*PsProcessType,KernelMode,&pEprocess,NULL);
	if (!NT_SUCCESS(status))
	{
		goto ReturnToNtTerminateProcess;
	}
	// 根据镜像文件名判断是不是要保护的进程,字符串最大长度是16,超过就会截断,所以不用担心越界
	ImageFileName = (PCHAR)pEprocess + 0x174;
	if (strcmp(ImageFileName, "notepad.exe") == 0)
	{
		if (ProcessHandle == (HANDLE)0xFFFFFFFF)
		{
			// 通过关闭按钮关闭
			goto ReturnToNtTerminateProcess;			
		}
		else
		{
			// 通过任务管理器或其他进程调用TerminateProcess关闭
			//DbgPrint("Terminate denied. %s: NtTerminateProcess(%x, %x)\n", ImageFileName, ProcessHandle, ExitStatus);
			goto ReturnAccessDenied;
		}
	}
ReturnToNtTerminateProcess:
	pNtTerminateProcessHookRet = (PVOID)((ULONG)pNtTerminateProcess + 5);
	__asm
	{
		add esp,0x20;
		popfd;
		popad;
		jmp pNtTerminateProcessHookRet;
	}
ReturnAccessDenied:
	__asm
	{				
		add esp,0x20;
		popfd;
		popad;
		leave;
		mov eax,0xC0000022; // STATUS_ACCESS_DENIED
		retn 0x08;
	}
}


三、内核重载

写不出来,一是能力不足,二是动机不足。

动机方面,后面会学自建调用框架,完美替代内核重载。

能力方面,目前主要存在以下疑问:

  • MDL 是什么,不清楚,ExAllocatePool 申请出来的内存似乎还不能执行?
  • 修复 IAT 的方式?是否从当前内核内存镜像中复制过来?
  • 修复重定位的方式?用老办法修复,还是从当前内核镜像中拷贝?是否必须共用一份全局变量?
  • 修复SSDT表,是否是拷贝现有的SSDT表,然后减去新旧内核镜像的地址差?

下面给出目前唯一的成果,0环读写文件的API。

// 读取文件到内存中,返回读取的字节数;读取失败返回0
ULONG FileToMemory(LPCWSTR lpszFile, PVOID *pFileBuffer)
{
	OBJECT_ATTRIBUTES objectAttributes;
	IO_STATUS_BLOCK iostatus;
	HANDLE hfile;
	UNICODE_STRING KernelFileUnicodeString;
	NTSTATUS ntStatus;
	FILE_STANDARD_INFORMATION fsi;
	PUCHAR pBuffer;

	//初始化UNICODE_STRING字符串
	//RtlInitUnicodeString( &KernelFileUnicodeString, L"\\??\\C:\\Windows\\System32\\ntkrnlpa.exe");
	RtlInitUnicodeString( &KernelFileUnicodeString, lpszFile);

	//初始化objectAttributes
	InitializeObjectAttributes(&objectAttributes, 
		&KernelFileUnicodeString,
		OBJ_CASE_INSENSITIVE, 
		NULL, 
		NULL );

	//创建文件
	ntStatus = ZwOpenFile( &hfile, 
		GENERIC_ALL,
		&objectAttributes, 
		&iostatus, 
		FILE_SHARE_READ|FILE_SHARE_WRITE,
		FILE_SYNCHRONOUS_IO_NONALERT);

	if (!NT_SUCCESS(ntStatus))
	{
		KdPrint(("The file is not exist!\n"));
		return 0;
	}
	
	//读取文件长度
	ntStatus = ZwQueryInformationFile(hfile,
		&iostatus,
		&fsi,
		sizeof(FILE_STANDARD_INFORMATION),
		FileStandardInformation);

	//KdPrint(("The program want to read %d bytes\n",fsi.EndOfFile.QuadPart));

	//为读取的文件分配缓冲区
	pBuffer = (PUCHAR)ExAllocatePool(PagedPool,
		(LONG)fsi.EndOfFile.QuadPart);

	//读取文件
	ZwReadFile(hfile,NULL,
		NULL,NULL,
		&iostatus,
		pBuffer,
		(LONG)fsi.EndOfFile.QuadPart,
		NULL,NULL);
	//KdPrint(("The program really read %d bytes\n",iostatus.Information));

	//释放缓冲区
	//ExFreePool(pBuffer);

	*pFileBuffer = pBuffer;

	//关闭文件句柄
	ZwClose(hfile);
	return (ULONG)fsi.EndOfFile.QuadPart;
}

// 内存数据写入文件
VOID MemoryToFile(PVOID pMemBuffer, ULONG ulSize, LPCWSTR lpszFile) 
{
	OBJECT_ATTRIBUTES objectAttributes;
	IO_STATUS_BLOCK iostatus;
	HANDLE hfile;
	UNICODE_STRING logFileUnicodeString;
	NTSTATUS ntStatus;

	//初始化UNICODE_STRING字符串
	RtlInitUnicodeString( &logFileUnicodeString, lpszFile);

	//初始化objectAttributes
	InitializeObjectAttributes(&objectAttributes,
		&logFileUnicodeString,
		OBJ_CASE_INSENSITIVE,//对大小写敏感 
		NULL, 
		NULL );

	//创建文件
	ntStatus = ZwCreateFile( &hfile, 
		GENERIC_WRITE,
		&objectAttributes, 
		&iostatus, 
		NULL,
		FILE_ATTRIBUTE_NORMAL, 
		FILE_SHARE_WRITE,
		FILE_OPEN_IF,//即使存在该文件,也创建 
		FILE_SYNCHRONOUS_IO_NONALERT, 
		NULL, 
		0 );

	ZwWriteFile(hfile,NULL,NULL,NULL,&iostatus,pMemBuffer,ulSize,NULL,NULL);
	KdPrint(("The program really wrote %d bytes\n",iostatus.Information));

	//关闭文件句柄
	ZwClose(hfile);

}


---------------------
作者:hambaga
来源:CSDN
原文:https://blog.csdn.net/Kwansy/article/details/110072446
版权声明:本文为作者原创文章,转载请附上博文链接!
内容解析By:CSDN,CNBLOG博客文章一键转载插件

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值