首页
社区
课程
招聘
[求助]用驱动写内存,代码段无法写
发表于: 2011-12-6 00:01 9759

[求助]用驱动写内存,代码段无法写

2011-12-6 00:01
9759
是不是要去掉内存保护,刚学驱动,是下面这个代码,自己实现了ntWriteMemory

NTSTATUS MyWriteMemory(IN HANDLE hProcess,OUT PVOID BaseAddress,IN PVOID Pbuff,IN ULONG BufferSize)
{
	KdPrint(("MyWriteMemory参数检查\nhProcess:%X\nBaseAddress:%X\nPbuff:%X\n缓冲内容:%s\nBufferSize:%d\n检查结束\n",hProcess,BaseAddress,Pbuff,(char*)Pbuff,BufferSize));
	if(hProcess==NULL)
	{
		KdPrint(("失败:1\n"));
		return STATUS_UNSUCCESSFUL;
	}
	NTSTATUS status=STATUS_UNSUCCESSFUL;

	PEPROCESS EProcess; 
	KAPC_STATE ApcState;
	PVOID writebuffer=NULL;
	
	status = ObReferenceObjectByHandle(
		hProcess,
		PROCESS_VM_WRITE|PROCESS_VM_READ,
		NULL,
		KernelMode,
		(VOID**)&EProcess,
		NULL
		);
	
	if(!NT_SUCCESS(status))
	{
		ObDereferenceObject(EProcess);
		KdPrint(("失败:2\n"));
		return STATUS_UNSUCCESSFUL;
	}
	writebuffer = ExAllocatePoolWithTag (NonPagedPool, BufferSize, 'Sys');
	
	if(writebuffer==NULL)
	{
		ObDereferenceObject(EProcess);
		ExFreePool (writebuffer);
		KdPrint(("失败:3\n"));
		return STATUS_UNSUCCESSFUL;
	}
	*(ULONG*)writebuffer=(ULONG)0x1;
	
	if (MmIsAddressValid(Pbuff))
	{
		__try
		{
			ProbeForRead ((CONST PVOID)Pbuff, BufferSize, sizeof(CHAR));
			RtlCopyMemory (writebuffer, Pbuff, BufferSize);
		}
		__except(EXCEPTION_EXECUTE_HANDLER)
		{
			KdPrint(("失败:4\n"));
			status = STATUS_UNSUCCESSFUL;
		}
	}
	else
	{
		KdPrint(("失败:5\n"));
		status = STATUS_UNSUCCESSFUL;
	}
	
	if (NT_SUCCESS(status))
	{
		KeStackAttachProcess (EProcess, &ApcState);
		if (MmIsAddressValid(BaseAddress))
		{
			__try
			{
				ProbeForWrite ((CONST PVOID)BaseAddress, BufferSize, sizeof(CHAR));
				RtlCopyMemory (BaseAddress,writebuffer, BufferSize);
			}
			__except(EXCEPTION_EXECUTE_HANDLER)
			{
				KdPrint(("失败:6\n"));
				status = STATUS_UNSUCCESSFUL;
			}
		}
		else
		{
			KdPrint(("失败:7\n"));
			status = STATUS_UNSUCCESSFUL;
		}
		KeUnstackDetachProcess (&ApcState);
	}
	
	ObDereferenceObject(EProcess);
	ExFreePool (writebuffer);

	KdPrint(("结束\n"));
	return status;
}


读目标内存、写内存段都可以,就是无法写代码段,知道的朋友指点下 !

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 0
支持
分享
最新回复 (13)
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
2
我晕啊,原因很简单啊,就是代码段具有写保护属性,写入的时候会受到CPU的保护,如果强行写入的话,系统会崩溃的,解决的办法有三个:
1。关闭CPU的写保护,也就是设置CR0寄存器(直接更改CPU写保护状态,容易和别的软件冲突,不推荐)

2 用NTAPI改变对应地址的保护属性,在属性里面加入写属性(Zw*系列函数)(函数没有在内核导出,但是已经在NTDLL.DLL中导出了,比较难,但是使用具有很强的稳定性)

3 创建一个内存描述符 也就是创建对应地址的MDL (使用 MmCreateMdl 或者 IoCreateMdl),然后通过内存描述符取得一个内核地址,这个地址是你要写入的地址在内核的映射,并且这个内核地址你在取得时,通过加入写属性(API调用的时候默认已经加入),让这个内核地址可写就可以了(比较容易,并且稳定,推荐使用)
2011-12-6 01:40
0
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
3
给你两个函数,功能是把一个不可写,但可读的地址,映射为一个内核可读可写的内核地址的函数,但是这个函数要求同一个上下文

PMDL NTAPI IoCreateWriteMdlForAddress(PVOID InAddress,PVOID *OutAddress,size_t Size)
{
        PMDL pMdl=NULL;
        if(Size>0)
        {
        if((InAddress==NULL)|(Size==0))
                return NULL;
//        if(!MmIsAddressValid(InAddress))
//                return NULL;
        if(OutAddress==NULL)
                return NULL;
        if(!MmIsAddressValid(OutAddress))
                return NULL;
        }
        else
        {
                return NULL;
        }
        pMdl=MmCreateMdl(NULL,InAddress,Size);
        if(pMdl==NULL)
        {
                return NULL;
        }
        MmBuildMdlForNonPagedPool(pMdl);
//        My_Mdl->MdlFlags = My_Mdl->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA;
        if(!FlagOn(pMdl->MdlFlags,MDL_MAPPED_TO_SYSTEM_VA))
                SetFlag(pMdl->MdlFlags,MDL_MAPPED_TO_SYSTEM_VA);
                        *OutAddress=MmMapLockedPages(pMdl, KernelMode);
return pMdl;
}
VOID NTAPI IoFreeMdlForAddress(PVOID Address,PMDL pMdl)
{
                        MmUnmapLockedPages(Address,pMdl);
                IoFreeMdl(pMdl);
}

我看你的代码,太简陋了吧!只能读取本进程的内存的,不能读取别的进程(原因很简单,你没有切换进程上下文),下次麻烦你写这样的程序的时候,去看一下微软的2000系统的源代码,还有微软的2003的源代码(2003内核源代码是公开的),他们写的内存复制函数没有你那么简陋的

本来想现在帮你更改的,但是时间不够了,今天晚上先了。
2011-12-6 02:03
0
雪    币: 204
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
偶的问题木有高人这么热心呢  可能台简单了吧

另外问问  if (MmIsAddressValid(Pbuff))
      ProbeForRead ((CONST PVOID)Pbuff, BufferSize, sizeof(CHAR));
这2个函数都是连用啊。偶经常就是不知道该用哪个  结果楼主2个同时用  偶豁然开朗啊
2011-12-6 08:50
0
雪    币: 228
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
pak
5
不清楚这段话是你自己总结的,还是网上查到的。第2点说的根本就是错的,误导人!
ntdll.dll是ring3层的模块,导不导出函数也都是给ring3调用的,只是ring3进入ring0的接口,除此之外,跟内核调用没有任何直接联系。修改页属性的常规方法就是在ring0使用第1和3两个方法。
2011-12-6 09:23
0
雪    币: 256
活跃值: (41)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
试了第一种方法
   //关保护
    __asm
    {
        push    eax
        mov        eax, CR0
        and        eax, 0FFFEFFFFh
        mov        CR0, eax
        pop        eax
    }
   //开保护
    __asm
    {
        push    eax
        mov        eax, CR0
        or        eax, NOT 0FFFEFFFFh
        mov        CR0, eax
        pop        eax
    }

分别加在写内存函数的前后,不过还是写不了
我是想读目标进程里面的代码段,不是自己进程里的代码段 !
2011-12-6 14:05
0
雪    币: 204
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
楼主要读别的进程 这种方式肯定不奏效了哦。楼上大牛都说了

要进行进程上下文context的切换 至于如何切换 呵呵  

我也没搞过  静观其变了 哈哈
2011-12-6 14:45
0
雪    币: 256
活跃值: (41)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
谢谢czcqq的提示和你的代码
用第三种方法成功了,继续研究
2011-12-6 20:56
0
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
9
5楼的, 这么简单的问题,你都不知道?通过查找NTDLL.DLL中的Zw系列函数的开头的一条指令
例如 mov eax,101 的函数序列号,就可以在SSDT表中找到NT下对应的函数的内核函数地址
2011-12-6 21:01
0
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
10
楼主,你在开关写保护的时候,你写入失败是因为你没有切换到目标进程的上下文环境中
2011-12-6 21:03
0
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
11
使用这个函数KeAttachProcess 就可以了
2011-12-6 21:14
0
雪    币: 256
活跃值: (41)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
第三种方法是成功了,不过在目标进程写入代码之后,关掉进程在打开这个进程,那个地址的代码还是关掉之前写入之后的样子。怎么取消这个映射呢
2011-12-6 22:50
0
雪    币: 228
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
pak
13
首先,第2条和你现在说的跟修改页属性(LZ所问)没有任何联系,答非所问。
再者,你既然知道这个原理,何不在ring0通过ntoskrnl.exe导出的Zw*来获取Nt*在SSDT中的索引号?ring3获得了有啥意义,不一样还得传到ring0?多此一举~
2011-12-7 14:38
0
雪    币: 121
活跃值: (11)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
14
请教一下 映射问题解决了么?
2012-11-12 14:13
0
游客
登录 | 注册 方可回帖
返回
//