Loading

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

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



#pragma pack(1)
typedef struct ServiceDescriptorEntry {
	unsigned int *ServiceTableBase;
	unsigned int *ServiceCounterTableBase; 
	unsigned int NumberOfServices;
	unsigned char *ParamTableBase;
} ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t;
#pragma pack()

/* 从内核中导入的变量,定义后里面就有值,感觉很新颖的写法 */
__declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable;

ServiceDescriptorTableEntry_t	*pNewSSDT;
ULONG							h_org_NtOpenProcess;
ULONG							addr_hookaddr=0;
ULONG							jmp_ret;
ULONG							OrigImage=0x804d8000;		//硬编码地址,要确定自己的nt内核地址 

/*
kd> lm nt
start    end        module name
804d8000 806d0480   nt       ntkrnlpa.exe Mon Apr 14 02:31:06 2008 (4802516A)
*/

typedef
	NTSTATUS (*NTOPENPROCESS) (
	__out PHANDLE ProcessHandle,
	__in ACCESS_MASK DesiredAccess,
	__in POBJECT_ATTRIBUTES ObjectAttributes,
	__in_opt PCLIENT_ID ClientId
	);

void PageProtectOn()
{
	__asm{//恢复内存保护  
		mov  eax,cr0
			or   eax,10000h
			mov  cr0,eax
			sti
	}
}
void PageProtectOff()
{
	__asm{//去掉内存保护
		cli
			mov  eax,cr0
			and  eax,not 10000h
			mov  cr0,eax
	}
}

/*
	ServiceTableBase:	SSDT指针
	FuncIndex:			当前函数在SSDT中的索引
	OrigFuncAddress:	原函数地址,ebx中
*/
ULONG display(ULONG ServiceTableBase,ULONG FuncIndex,ULONG OrigFuncAddress)
{
	if (ServiceTableBase==(ULONG)KeServiceDescriptorTable.ServiceTableBase)
	{//比较当前调用的进程是不是ce
	
	/* 
	reloadKernel!display+0x21:
	f8963071 0574010000      add     eax,174h
	kd> p
	reloadKernel!display+0x26:
	f8963076 8945f8          mov     dword ptr [ebp-8],eax
	kd> db eax
	824af534  76 6d 74 6f 6f 6c 73 64-2e 65 78 65 00 00 00 00  vmtoolsd.exe....	
	*/
		if (!strcmp((char*)PsGetCurrentProcess()+0x174,"cheatengine-i38"))
		{
			return pNewSSDT->ServiceTableBase[FuncIndex];
		}
	}
	return OrigFuncAddress;
}

/*
	调用display函数
*/
__declspec(naked)
	void MyKiFastCallEntry()
{
	__asm
	{
		pushad
			pushfd
			push	ebx			//原函数地址
			push	eax			//SSDT index
			push	edi			//SSDT指针
			call	display							
			mov		[esp+0x14],eax					//改EBX
			popfd
			popad									//改EBX
			//恢复以前的代码,以便内核正常运行
			sub esp,ecx
			shr ecx,2
			jmp jmp_ret
	}
}

/*
	hook KiFastCallEntry函数 跳到 MyKiFastCallEntry
*/
void hook_KiFastCallEntry()
{
	UCHAR jmp_code[5];
	jmp_code[0]=0xe9;
	//计算jmp_code
	*(ULONG *)&jmp_code[1]=(ULONG)MyKiFastCallEntry-5-addr_hookaddr;
	//计算返回jmp
	jmp_ret = addr_hookaddr + 5;
	PageProtectOff();
	//inline hook
	RtlCopyMemory((PVOID)addr_hookaddr,jmp_code,5);
	PageProtectOn();
}



NTSTATUS h_NtOpenProcess (
	__out PHANDLE ProcessHandle,
	__in ACCESS_MASK DesiredAccess,
	__in POBJECT_ATTRIBUTES ObjectAttributes,
	__in_opt PCLIENT_ID ClientId
	)
{

	ULONG retaddr;
	UCHAR *p=NULL;
	int i=0;

	/* 驱动程序保存为.c文件时,变量不能随处定义 */
	KdPrint(("h_NtOpenProcess函数被调用\n"));
	
	__asm
	{
		pushad
		mov eax,[ebp+0x04]
		mov retaddr,eax
		popad
	}
	p=(UCHAR *)retaddr;			//获取kifsatcallentry对SSDT的调用
	
	/*
	reloadKernel!h_NtOpenProcess+0x27:
	f8a2b1a7 8b4504          mov     eax,dword ptr [ebp+4]
	kd> r eax
	eax=8053e638
	
	kd> ub eax
	nt!KiFastCallEntry+0xde:
	8053e61e 8b1c87          mov     ebx,dword ptr [edi+eax*4]
	8053e621 2be1            sub     esp,ecx
	8053e623 c1e902          shr     ecx,2
	8053e626 8bfc            mov     edi,esp
	8053e628 3b35d4995580    cmp     esi,dword ptr [nt!MmUserProbeAddress (805599d4)]
	8053e62e 0f83a8010000    jae     nt!KiSystemCallExit2+0x9f (8053e7dc)
	8053e634 f3a5            rep movs dword ptr es:[edi],dword ptr [esi]
	8053e636 ffd3            call    ebx
	*/
	KdPrint(("h_NtOpenProcess函数  retaddr: %x\n",retaddr));
	
	/* 
	向前搜索字节码,找到这里,记下这个地址用于hook KiFastCallEntry
	
	8053e621 2be1            sub     esp,ecx
	8053e623 c1e902          shr     ecx,2
	
	*/
	for(i=0;i<100;i++)
	{			
		if(*p==0x2b&&*(p+1)==0xe1&&*(p+2)==0xc1&&*(p+3)==0xe9&&*(p+4)==0x02)
		{
			addr_hookaddr=(ULONG)p;
			break;
		}
		else
		{
			p--;
		}
	}
	if(addr_hookaddr==0)
	{
		KdPrint(("%x",retaddr));
		KdPrint(("Find addr_hookaddr failed!"));
	}
	else
	{
		KdPrint(("You Have Find The Addr_hookaddr!"));
		PageProtectOff();
		KeServiceDescriptorTable.ServiceTableBase[122] =(unsigned int ) h_org_NtOpenProcess;	//去掉老内核对h_org_NtOpenProcess的hook
		PageProtectOn();
		hook_KiFastCallEntry();			//改为hook KiFastCallEntry
	}
	return ((NTOPENPROCESS)h_org_NtOpenProcess)(ProcessHandle,DesiredAccess,ObjectAttributes,ClientId);
}



void Hook_NtOpenProcess()
{
	h_org_NtOpenProcess = KeServiceDescriptorTable.ServiceTableBase[122];
	PageProtectOff();
	KeServiceDescriptorTable.ServiceTableBase[122] = (unsigned int)h_NtOpenProcess;		//hook 老内核的NtOpenProcess,再调用NtOpenProcess函数时,进入我们的h_NtOpenProcess函数
	/*  注意KdPrint使用双括号 */
	KdPrint(("[+] h_NtOpenProcess函数地址: %x \n",  KeServiceDescriptorTable.ServiceTableBase[122]));
	PageProtectOn();
}

/*
	解除KiFastCallEntry的hook
*/
void UnHook_KiFastCallEntry()
{
	UCHAR org_code[]={0x2b,0xe1,0xc1,0xe9,0x2};
	if(addr_hookaddr!=0)
	{
		PageProtectOff();
		RtlCopyMemory((PVOID)addr_hookaddr,org_code,5);
		PageProtectOn();
	}
}
void UnHookNtOpenProcess()
{
	if(addr_hookaddr)
		return;
	PageProtectOff();
	KeServiceDescriptorTable.ServiceTableBase[122]=(unsigned int )h_org_NtOpenProcess;
	PageProtectOn();
}

VOID SetNewSSDT(PVOID pNewImage)
{
	ULONG							uIndex;
	ULONG							uNewKernelInc,uOffset;
	//新内核地址-老内核地址,得到相对偏移
	uNewKernelInc = (ULONG)pNewImage -OrigImage;
	//老内核的ssdt指针加上相对偏移,得到新内核的ssdt指针
	pNewSSDT = (ServiceDescriptorTableEntry_t *)((ULONG)&KeServiceDescriptorTable + uNewKernelInc);
		
	KdPrint(("%x\n",&KeServiceDescriptorTable));		//打印老内核SSDT指针,输出80553fa0
	/*
	kd> dd nt!KeServiceDescriptorTable
	80553fa0  80502b8c 00000000 0000011c 80503000
	*/
	
	if (!MmIsAddressValid(pNewSSDT))
	{
		KdPrint(("pNewSSDT is unaviable!"));
		return;
	}
	//由于数量是一个数值,因此不必作相对偏移
	pNewSSDT->NumberOfServices = KeServiceDescriptorTable.NumberOfServices;
	//计算相对函数地址
	uOffset = (ULONG)KeServiceDescriptorTable.ServiceTableBase -OrigImage;
	//得到新的ssdt函数表地址
	pNewSSDT->ServiceTableBase = (unsigned int*)((ULONG)pNewImage + uOffset);
	if (!MmIsAddressValid(pNewSSDT->ServiceTableBase))
	{
		KdPrint(("pNewSSDT->ServiceTableBase: %X",pNewSSDT->ServiceTableBase));
		return;
	}
	//依次遍历
	for (uIndex = 0;uIndex<pNewSSDT->NumberOfServices;uIndex++)
	{//新的函数地址再加上相对加载地址,得到现在的ssdt函数地址
		pNewSSDT->ServiceTableBase[uIndex] += uNewKernelInc;
	}
}

void FixBaseRelocTable(PVOID pNewImage)
{

	ULONG					uIndex;
	ULONG					uRelocTableSize;
	ULONG					OriginalImageBase;
	ULONG					Type;
	ULONG 					*uRelocAddress;
	PIMAGE_DOS_HEADER		pImageDosHeader;
	PIMAGE_NT_HEADERS		pImageNtHeader;
	IMAGE_DATA_DIRECTORY	ImageDataDirectory;
	IMAGE_BASE_RELOCATION	*pImageBaseRelocation;
	//将新内核地址作为一个PE文件头,依次向下,目的是寻找重定位表结构
	pImageDosHeader=(PIMAGE_DOS_HEADER)pNewImage;
	//定位到IMAGE_NT_HEADER
	pImageNtHeader=(PIMAGE_NT_HEADERS)((ULONG)pNewImage+pImageDosHeader->e_lfanew);
	//获取内核文件的imagebase,以便后面做偏移修改。
	OriginalImageBase=pImageNtHeader->OptionalHeader.ImageBase;
	//定位到数据目录
	ImageDataDirectory = pImageNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
	//定位到重定位表结构
	pImageBaseRelocation = (PIMAGE_BASE_RELOCATION)(ImageDataDirectory.VirtualAddress + (ULONG)pNewImage);
	if (pImageBaseRelocation==NULL)
	{
		return;  
	}
	while (pImageBaseRelocation->SizeOfBlock)
	{   //计算需要修改的地址的个数
		uRelocTableSize=(pImageBaseRelocation->SizeOfBlock-8)/2;
		//循环遍历
		for (uIndex=0;uIndex<uRelocTableSize;uIndex++)
		{//判断高4位是否等于3
			Type=pImageBaseRelocation->TypeOffset[uIndex]>>12;
			if (Type==3)
			{
				//修改地址,相对地址加上一个新内核地址,使其成为一个实际地址
				uRelocAddress=(ULONG *)((ULONG)(pImageBaseRelocation->TypeOffset[uIndex]&0x0fff)+pImageBaseRelocation->VirtualAddress+(ULONG)pNewImage);
				//再加上内核首地址到imagebase的偏移
				*uRelocAddress=*uRelocAddress+(OrigImage-OriginalImageBase);
			}
		}
		//进行下一个重定位表的修改
		pImageBaseRelocation=(IMAGE_BASE_RELOCATION *)((ULONG)pImageBaseRelocation+pImageBaseRelocation->SizeOfBlock);
	}
}

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 = ZwReadFile(hFile,\
			NULL,\
			NULL,\
			NULL,\
			&IoStatusBlock,\
			(PVOID)((ULONG)lpVirtualPointer+SectionVirtualAddress),\
			SectionSize,\
			&FileOffset,\
			0);
		if(!NT_SUCCESS(status))
		{
			KdPrint(("SectionData Read Failed!"));
			ExFreePool(lpImageSectionHeader);
			ExFreePool(lpVirtualPointer);
			ZwClose(hFile);
			return;
		}
	}
	ExFreePool(lpImageSectionHeader);//释放区段内存空间
	KdPrint(("lpVirtualPointer: %X\n",lpVirtualPointer));
	FixBaseRelocTable(lpVirtualPointer);
	SetNewSSDT(lpVirtualPointer);
	ZwClose(hFile);//关闭句柄
}

void DriverUnload(PDRIVER_OBJECT pDriverObject)
{
	UnHook_KiFastCallEntry();
	UnHookNtOpenProcess();
	DbgPrint("Driver Unload Success !\n");
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,PUNICODE_STRING pRegsiterPath)
{
	DbgPrint("This is My First Driver!\n");
	LoadKernel();
	Hook_NtOpenProcess();
	pDriverObject->DriverUnload = DriverUnload;
	return STATUS_SUCCESS;
}
posted @ 2016-04-19 13:08  Lnju  阅读(805)  评论(1编辑  收藏  举报