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


    #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函数被调用
    "));
    	
    	__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
    ",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 
    ",  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
    ",&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
    ",lpVirtualPointer));
    	FixBaseRelocTable(lpVirtualPointer);
    	SetNewSSDT(lpVirtualPointer);
    	ZwClose(hFile);//关闭句柄
    }
    
    void DriverUnload(PDRIVER_OBJECT pDriverObject)
    {
    	UnHook_KiFastCallEntry();
    	UnHookNtOpenProcess();
    	DbgPrint("Driver Unload Success !
    ");
    }
    
    NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,PUNICODE_STRING pRegsiterPath)
    {
    	DbgPrint("This is My First Driver!
    ");
    	LoadKernel();
    	Hook_NtOpenProcess();
    	pDriverObject->DriverUnload = DriverUnload;
    	return STATUS_SUCCESS;
    }
    
  • 相关阅读:
    分布式文档存储数据库 MongoDB
    MongoDB运行状态、性能监控,分析
    Mongodb在Linux下的安装和启动和配置
    mongodb 状态监控命令详解
    Asp.net Core 入门实战 2.请求流程
    Asp.net Core 入门实战
    前后端分离之CORS和WebApi
    2.CLI标准
    JavaScript的引入方式
    CSS选择器的优先级
  • 原文地址:https://www.cnblogs.com/Lnju/p/5407804.html
Copyright © 2020-2023  润新知