zoukankan      html  css  js  c++  java
  • 重载内核的一份代码的学习

    #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;
    }
    
  • 相关阅读:
    结巴分词 0.14 版发布,Python 中文分词库
    Lazarus 1.0.2 发布,Pascal 集成开发环境
    Android全屏 去除标题栏和状态栏
    服务器日志现 Android 4.2 传将添多项新特性
    Percona XtraBackup 2.0.3 发布
    长平狐 Android 强制设置横屏或竖屏 设置全屏
    NetBeans 7.3 Beta 发布,全新的 HTML5 支持
    CppDepend现在已经支持Linux
    GromJS 1.7.18 发布,服务器端的 JavaScript
    Apache OpenWebBeans 1.1.6 发布
  • 原文地址:https://www.cnblogs.com/Lnju/p/5407804.html
Copyright © 2011-2022 走看看