• 驱动开发:内核CR3切换读写内存


    首先CR3是什么,CR3是一个寄存器,该寄存器内保存有页目录表物理地址(PDBR地址),其实CR3内部存放的就是页目录表的内存基地址,运用CR3切换可实现对特定进程内存地址的强制读写操作,此类读写属于有痕读写,多数驱动保护都会将这个地址改为无效,此时CR3读写就失效了,当然如果能找到CR3的正确地址,此方式也是靠谱的一种读写机制。

    在读写进程之前需要先找到进程的PEPROCESS结构,查找结构的方法也很简单,依次遍历进程并对比进程名称即可得到。

    #include 
    #include 
    #include 
    
    NTKERNELAPI NTSTATUS PsLookupProcessByProcessId(HANDLE ProcessId, PEPROCESS *Process);
    NTKERNELAPI CHAR* PsGetProcessImageFileName(PEPROCESS Process);
    
    // 定义全局EProcess结构
    PEPROCESS Global_Peprocess = NULL;
    
    // 根据进程名获得EPROCESS结构
    NTSTATUS GetProcessObjectByName(char *name)
    {
    	NTSTATUS Status = STATUS_UNSUCCESSFUL;
    	SIZE_T i;
    
    	__try
    	{
    		for (i = 100; i<20000; i += 4)
    		{
    			NTSTATUS st;
    			PEPROCESS ep;
    			st = PsLookupProcessByProcessId((HANDLE)i, &ep);
    			if (NT_SUCCESS(st))
    			{
    				char *pn = PsGetProcessImageFileName(ep);
    				if (_stricmp(pn, name) == 0)
    				{
    					Global_Peprocess = ep;
    				}
    			}
    		}
    	}
    	__except (EXCEPTION_EXECUTE_HANDLER)
    	{
    		return Status;
    	}
    	return Status;
    }
    
    VOID UnDriver(PDRIVER_OBJECT driver)
    {
    	DbgPrint(("Uninstall Driver Is OK \n"));
    }
    
    NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
    {
    	DbgPrint("hello lyshark \n");
    
    	NTSTATUS nt = GetProcessObjectByName("Tutorial-i386.exe");
    
    	if (NT_SUCCESS(nt))
    	{
    		DbgPrint("[+] eprocess = %x \n", Global_Peprocess);
    	}
    
    	Driver->DriverUnload = UnDriver;
    	return STATUS_SUCCESS;
    }
    

    以打开Tutorial-i386.exe为例,打开后即可返回他的Proces,当然也可以直接传入进程PID同样可以得到进程Process结构地址。

    // 根据PID打开进程
    PEPROCESS Peprocess = NULL;
    DWORD PID = 6672;
    NTSTATUS nt = PsLookupProcessByProcessId((HANDLE)PID, &Peprocess);
    

    通过CR3读取内存实现代码如下,我们读取Tutorial-i386.exe里面的0x0009EDC8这段内存,读出长度是4字节,代码如下。

    #include 
    #include 
    #include 
    
    #define DIRECTORY_TABLE_BASE 0x028
    
    #pragma  intrinsic(_disable)
    #pragma  intrinsic(_enable)
    
    NTKERNELAPI NTSTATUS PsLookupProcessByProcessId(HANDLE ProcessId, PEPROCESS *Process);
    NTKERNELAPI CHAR* PsGetProcessImageFileName(PEPROCESS Process);
    
    // 关闭写保护
    KIRQL Open()
    {
    	KIRQL irql = KeRaiseIrqlToDpcLevel();
    	UINT64 cr0 = __readcr0();
    	cr0 &= 0xfffffffffffeffff;
    	__writecr0(cr0);
    	_disable();
    	return irql;
    }
    
    // 开启写保护
    void Close(KIRQL irql)
    {
    	UINT64 cr0 = __readcr0();
    	cr0 |= 0x10000;
    	_enable();
    	__writecr0(cr0);
    	KeLowerIrql(irql);
    }
    
    // 检查内存
    ULONG64 CheckAddressVal(PVOID p)
    {
    	if (MmIsAddressValid(p) == FALSE)
    		return 0;
    	return *(PULONG64)p;
    }
    
    // CR3 寄存器读内存
    BOOLEAN CR3_ReadProcessMemory(IN PEPROCESS Process, IN PVOID Address, IN UINT32 Length, OUT PVOID Buffer)
    {
    	ULONG64 pDTB = 0, OldCr3 = 0, vAddr = 0;
    	pDTB = CheckAddressVal((UCHAR*)Process + DIRECTORY_TABLE_BASE);
    	if (pDTB == 0)
    	{
    		return FALSE;
    	}
    
    	_disable();
    	OldCr3 = __readcr3();
    	__writecr3(pDTB);
    	_enable();
    
    	if (MmIsAddressValid(Address))
    	{
    		RtlCopyMemory(Buffer, Address, Length);
    		DbgPrint("读入数据: %ld", *(PDWORD)Buffer);
    		return TRUE;
    	}
    
    	_disable();
    	__writecr3(OldCr3);
    	_enable();
    	return FALSE;
    }
    
    VOID UnDriver(PDRIVER_OBJECT driver)
    {
    	DbgPrint(("Uninstall Driver Is OK \n"));
    }
    
    NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
    {
    	DbgPrint("hello lyshark \n");
    
    	// 根据PID打开进程
    	PEPROCESS Peprocess = NULL;
    	DWORD PID = 6672;
    	NTSTATUS nt = PsLookupProcessByProcessId((HANDLE)PID, &Peprocess);
    
    	DWORD buffer = 0;
    
    	BOOLEAN bl = CR3_ReadProcessMemory(Peprocess, (PVOID)0x0009EDC8, 4, &buffer);
    
    	DbgPrint("readbuf = %x \n", buffer);
    	DbgPrint("readbuf = %d \n", buffer);
    
    	Driver->DriverUnload = UnDriver;
    	return STATUS_SUCCESS;
    }
    

    读出后输出效果如下:

    写出内存与读取基本一致,代码如下。

    #include 
    #include 
    #include 
    
    #define DIRECTORY_TABLE_BASE 0x028
    
    #pragma  intrinsic(_disable)
    #pragma  intrinsic(_enable)
    
    NTKERNELAPI NTSTATUS PsLookupProcessByProcessId(HANDLE ProcessId, PEPROCESS *Process);
    NTKERNELAPI CHAR* PsGetProcessImageFileName(PEPROCESS Process);
    
    // 关闭写保护
    KIRQL Open()
    {
    	KIRQL irql = KeRaiseIrqlToDpcLevel();
    	UINT64 cr0 = __readcr0();
    	cr0 &= 0xfffffffffffeffff;
    	__writecr0(cr0);
    	_disable();
    	return irql;
    }
    
    // 开启写保护
    void Close(KIRQL irql)
    {
    	UINT64 cr0 = __readcr0();
    	cr0 |= 0x10000;
    	_enable();
    	__writecr0(cr0);
    	KeLowerIrql(irql);
    }
    
    // 检查内存
    ULONG64 CheckAddressVal(PVOID p)
    {
    	if (MmIsAddressValid(p) == FALSE)
    		return 0;
    	return *(PULONG64)p;
    }
    
    // CR3 寄存器写内存
    BOOLEAN CR3_WriteProcessMemory(IN PEPROCESS Process, IN PVOID Address, IN UINT32 Length, IN PVOID Buffer)
    {
    	ULONG64 pDTB = 0, OldCr3 = 0, vAddr = 0;
    
    	// 检查内存
    	pDTB = CheckAddressVal((UCHAR*)Process + DIRECTORY_TABLE_BASE);
    	if (pDTB == 0)
    	{
    		return FALSE;
    	}
    
    	_disable();
    
    	// 读取CR3
    	OldCr3 = __readcr3();
    
    	// 写CR3
    	__writecr3(pDTB);
    	_enable();
    
    	// 验证并拷贝内存
    	if (MmIsAddressValid(Address))
    	{
    		RtlCopyMemory(Address, Buffer, Length);
    		return TRUE;
    	}
    	_disable();
    
    	// 恢复CR3
    	__writecr3(OldCr3);
    	_enable();
    	return FALSE;
    }
    
    VOID UnDriver(PDRIVER_OBJECT driver)
    {
    	DbgPrint(("Uninstall Driver Is OK \n"));
    }
    
    NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
    {
    	DbgPrint("hello lyshark \n");
    
    	// 根据PID打开进程
    	PEPROCESS Peprocess = NULL;
    	DWORD PID = 6672;
    	NTSTATUS nt = PsLookupProcessByProcessId((HANDLE)PID, &Peprocess);
    
    	DWORD buffer = 999;
    
    	BOOLEAN bl = CR3_WriteProcessMemory(Peprocess, (PVOID)0x0009EDC8, 4, &buffer);
    	DbgPrint("写出状态: %d \n", bl);
    
    	Driver->DriverUnload = UnDriver;
    	return STATUS_SUCCESS;
    }
    

    写出后效果如下:

  • 相关阅读:
    leetcode:LCP 42. 玩具套圈【数据范围优化模拟集合题】
    BGP联邦综合实验
    基于STM32的DHT11温湿度测量
    selenium简单常见操作(部分WebdriverAPI)
    如果C盘满了怎么办
    Spring Boot之容器功能
    B/S架构,java源码,医院绩效管理系统,覆盖了医院绩效管理工作“PDCA”循环的全过程,支持二次开发
    【软件与系统安全】AFL模糊测试实验
    One-Hot 编码/哑变量所做的就是将类别型数据
    C#实现高斯模糊(图像处理)
  • 原文地址:https://www.cnblogs.com/LyShark/p/16727379.html