• Ps回调函数.拦截驱动模块原理+实现.


    一丶简介

    主要是讲解.内核中如何拦截模块加载的. 需要熟悉.内核回调的设置
    PE知识. ShellCode

    二丶原理

    1.原理

    原理是通过回调函数. 回调函数中有 ImageBase. 使用PE解析ImageBase 得到OEP. OEP位置写入 ret等ShellCode

    如何判断 是加载DLL 还是加载Sys. 可以看回调的第二个参数.(ProcessId) 如果ProcessId == 0. 则是加载Sys

    PS: 在内核中解析PE需要用到 ntImage.h头文件来进行解析.

    2.代码实现

    #include <ntimage.h>
    #include <ntddk.h>
    
    #include <wdm.h>
    
    ULONG_PTR g_LoadPtr = 0;
    
    
    void WPONx64(KIRQL irql)
    {
    	UINT64 cr0 = __readcr0();
    	cr0 |= 0x10000;
    	_enable();
    	__writecr0(cr0);
    	KeLowerIrql(irql);
    }
    
    
    
    KIRQL WPOFFx64()
    {
    	KIRQL irql = KeRaiseIrqlToDpcLevel();
    	UINT64 cr0 = __readcr0();
    	cr0 &= 0xfffffffffffeffff;
    	__writecr0(cr0);
    	_disable();
    	return irql;
    
    }
    
    
    BOOLEAN Fuck(PVOID pOep)
    {
    	KIRQL kirql;
    
    	if (NULL == pOep)
    		return FALSE;
    
    	//写入字节.
    	
    	UCHAR FuckCode[] = { "xB8x22x00x00xC0xC3" };
    	kirql = WPOFFx64();
    	KdBreakPoint();
    	memcpy(pOep, FuckCode, sizeof(FuckCode) / sizeof(FuckCode[0])); //开头写入拒绝访问错误码让其无法加载即可.
    	WPONx64(kirql);
    	return TRUE;
    }
    //根据ImageBase来获取加载模块的入口点
    PVOID GetImageOep(PVOID ImageBase)
    {
    
    	PVOID pAddressOfEntryPoint = NULL;
    	PIMAGE_DOS_HEADER pDosHead = NULL;
    	PIMAGE_NT_HEADERS pNtHead = NULL;
    	PIMAGE_FILE_HEADER pFileHead = NULL;
    	PIMAGE_OPTIONAL_HEADER pOptHead = NULL;
    
    	//开始解析
    	if (ImageBase == NULL)
    		return NULL;
    
    	pDosHead = (PIMAGE_DOS_HEADER)ImageBase;
    	pNtHead = (PIMAGE_NT_HEADERS)(pDosHead->e_lfanew + (char *)ImageBase);
    	pFileHead = (PIMAGE_FILE_HEADER)&pNtHead->FileHeader;
    	pOptHead = (PIMAGE_OPTIONAL_HEADER)&pNtHead->OptionalHeader;
    
    	//判断是否是PE头
    	if (pDosHead->e_magic != 0x5A4D && pNtHead->Signature != 0x5045)
    		return NULL;
    	pAddressOfEntryPoint = pOptHead->AddressOfEntryPoint + (char *)ImageBase;
    
    	return pAddressOfEntryPoint;
    }
    
    char * MyWideUnicodeStringToMutilString(PUNICODE_STRING uString)
    {
    	ANSI_STRING asStr;
    	char *Buffer = NULL; ;
    	RtlUnicodeStringToAnsiString(&asStr, uString, TRUE);
    	Buffer = ExAllocatePoolWithTag(NonPagedPool, uString->MaximumLength * sizeof(wchar_t), 0);
    	if (Buffer == NULL)
    		return NULL;
    	RtlCopyMemory(Buffer, asStr.Buffer, asStr.Length);
    	return Buffer;
    }
    VOID pSfFilterModule(
    	_In_opt_ PUNICODE_STRING FullImageName,
    	_In_ HANDLE ProcessId,                // pid into which image is being mapped
    	_In_ PIMAGE_INFO ImageInfo
    )
    {
    	/*
    	模块拦截思路:
    	1.通过 PIMAGE_INFO->ImageBase 得到模块的ImageBase
    	2.解析PE头.
    	3.可选头的OEP + ImageBase = 程序运行位置
    	4.在程序开头写入 ret.
    	5.通过参数一,判断是不是我们想要拦截的模块.然后进行1 2 3 4步
    	6.如何判断加载驱动模块还是DLL 根据参数2.ProcessId高低位判断即可. == 0加载驱动模块.否则加载DLL
    	*/
    
    	
    	
    	PVOID pDriverOep = NULL;
    	char *ComPareString = NULL;
    	if (MmIsAddressValid(FullImageName))
    	{
    		
    		if (ProcessId == 0)
    		{
    			//代表拦截驱动模块
    
    			
    
    			//判断名字是否是你想要拦截的.
    			KdBreakPoint();
    			
    			ComPareString = MyWideUnicodeStringToMutilString(FullImageName);
    			if (ComPareString == NULL)
    				return;
    
    			if (strstr(ComPareString,"1.sys"))
    			{
    				KdBreakPoint();
    				KdPrint(("你要拦截的驱动模块名字为: %wZ 
    ", FullImageName));
    				pDriverOep = GetImageOep(ImageInfo->ImageBase);
    
    				//判断拦截的名字是否是你想要拦截的
    				if (pDriverOep != NULL)
    				{
    					Fuck(pDriverOep);
    				}
    			}
    			
    		}
    		//输出调试
    		
    	}
    	
    }
    
    NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pRegPath)
    {
    	ULONG iCount = 0;
    	NTSTATUS ntStatus;
    	pDriverObj->DriverUnload = DriverUnLoad;
    	ntStatus = InitDeviceAnSybolicLinkName(pDriverObj);
    	if (!NT_SUCCESS(ntStatus))
    	{
    		return ntStatus;
    	}
    
    	ntStatus = InitDisPatchFunction(pDriverObj);
    	if (!NT_SUCCESS(ntStatus))
    	{
    		return ntStatus;
    	}
    
    
    	PsSetLoadImageNotifyRoutine(pSfFilterModule);
    	return STATUS_SUCCESS;
    }
    
    
    
    
    

    3.效果

    win7 64 sp1 下测试.

  • 相关阅读:
    Activity
    日志
    StringBuffer
    内部类
    接口
    多态
    final关键字
    abstract关键字
    对象初始化
    继承
  • 原文地址:https://www.cnblogs.com/iBinary/p/11483446.html
Copyright © 2020-2023  润新知