打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
另一种读写进程内存空间的方法
标 题: 【原创】另一种读写进程内存空间的方法
作 者: NetRoc
时 间: 2008-05-16,17:16
链 接: http://bbs.pediy.com/showthread.php?t=64938

cc682
http://netroc682.spaces.live.com/
    丢一个比较难防的读写其他进程内存空间的方法出来,嘿嘿。貌似我还没想到什么好办法可以防住的。
    内存空间不能跨进程访问的原因主要在于不同进程都有自己的页目录和页表。进程切换的很大一块也就是切换掉页目录。
    Windows自己的ReadProcessMemory最终也是通过KeStackAttachProcess附加到目标进程空间执行拷贝的。但是中间的N个内核函数调用现在被很多保护系统Hook掉并保护起来了,所以要通过这层层关卡读到东西还是不那么简单的。Unhook?自己实现内核函数?都很麻烦。
    其实,仅仅是需要拿到目标进程的页目录,然后直接从目标地址拷贝出来而已,完全可以用简单得多的办法来达到这个目的。
    所有的XXAttachProcess函数最终都通过_KiSwapProcess切换进程环境,_KiSwapProcess中会将目标进程的页目录指针放入CR3。这个过程我们可以自己来实现,唯一需要的就是拿到目标进程的EPROCESS而已,而这有无数种方法可以达到。整个过程基本上没有能当作非正常访问的证据以阻止掉的。
    首先来看一下几个内核结构:
    每个进程都有一个内核里面的进程结构_EPROCESS,前面几个字段如下:
代码:
typedef struct _EPROCESS {    KPROCESS Pcb;    EX_PUSH_LOCK ProcessLock;……
Pcb中就包含我们需要的页目录地址:
代码:
typedef struct _KPROCESS {    DISPATCHER_HEADER Header;    LIST_ENTRY ProfileListHead;    ULONG_PTR DirectoryTableBase[2];……
    系统一般只使用DirectoryTableBase[0],DirectoryTableBase[1]是用于hyperspace的。我们只需要拿到目标进程里面的DirectoryTableBase[0]值并直接设置到CR3中就可以读取了。
    假设要读取PID为1000的进程从0x400000开始的100个字节,只需要按下面的步骤实现:
1、  获取PID=1000的进程的_EPROCESS,读取_EPROCESS::Pcb::DirectoryTableBase[0]
2、  将页目录的值mov到cr3中。
3、  直接将0x400000的地址memcpy到内核空间地址中
4、  恢复cr3的值。
    下面是我测试使用的代码片断,图方便使用了PsLookupProcessByProcessId来获取EPROCESS,实际上这个函数多半被处理过的,所以很可能拿不到。解决的方法之一是可以通过PsSetCreateProcessNotifyRoutine挂一个回调,在里面通过PsLookupProcessByProcessId获取每个进程的EPROCESS地址并缓存起来后面使用。
这是DispatchIoCtrl里面的
代码:
switch(irpStack->Parameters.DeviceIoControl.IoControlCode)  {  case IOCTL_READMEM:    pstReadInfo = Irp->AssociatedIrp.SystemBuffer;    ntStatus = STATUS_SUCCESS;    if ( pstReadInfo->ulLen > 1000 ||       irpStack->Parameters.DeviceIoControl.InputBufferLength < pstReadInfo->ulLen ||      pstReadInfo->ulStart >= (PVOID)0x80000000 ||      (ULONG)pstReadInfo->ulStart + pstReadInfo->ulLen >= 0x80000000)    {      DbgPrint( "Read range invalid\r\n");      ntStatus = STATUS_UNSUCCESSFUL;      break;    }    __try    {                        if (PsLookupProcessByProcessId((HANDLE)(pstReadInfo->ulPid),&pstEProcess) == STATUS_SUCCESS)      {        pbyBuff = (PUCHAR)ExAllocatePoolWithTag( NonPagedPool, pstReadInfo->ulLen, 'PMRD');        ASSERT( pbyBuff);      }      else      {        DbgPrint( "PsLookupProcessByProcessId fail\r\n");        ntStatus = STATUS_UNSUCCESSFUL;        break;      }      ntStatus = ReadProcessMemory( pstEProcess, pbyBuff, pstReadInfo->ulStart, pstReadInfo->ulLen);      if ( ntStatus == STATUS_SUCCESS)      {        RtlCopyMemory( pstReadInfo, pbyBuff, pstReadInfo->ulLen);      }      else      {        ntStatus = STATUS_UNSUCCESSFUL;        break;      }      ExFreePool( pbyBuff);      pbyBuff = NULL;    }    __except(1)    {      ntStatus=STATUS_UNSUCCESSFUL;    }    break;……
这是读取内存的:
代码:
NTSTATUS ReadProcessMemory( PEPROCESS pstEProcess, PUCHAR pucBuff, PVOID pStart, ULONG ulLen){  PKPROCESS pstKProcess = NULL;  PEPROCESS pstCurrent = NULL;  ULONG ulPDT = 0;   ULONG ulOldCr3 = 0;  pstKProcess = &pstEProcess->Pcb;  ulPDT = pstKProcess->DirectoryTableBase[0];  //load cr3  _asm  {    cli;    mov eax, cr3;    mov ulOldCr3, eax;    mov eax, ulPDT;    mov cr3,eax  }  _asm sti;  RtlCopyMemory( pucBuff, pStart, ulLen); //直接复制内存  _asm cli;  _asm  {    mov eax, ulOldCr3;    mov cr3,eax;    sti;  }  return STATUS_SUCCESS;}
    这个代码有些细节并没有处理,只是尝试了一下新的访问进程内存的方式。除了拿EPROCESS之外,中间没有使用任何系统函数,所以常规办法基本上是没有办法挡住的。进程保护技术看来实现起来难度还是很大啊。还是那句话,一点突破,满盘皆输。   
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
NT 内核的进程调度分析笔记
不HOOK任何函数,让任务管理器、XueTr、360进程管理器无法结束保护进程
利用伪造内核文件来绕过IceSword的检测
【Delphi】驱动绕过360的KiFastCallEntry钩子
内核编程之SSDTHook(2)Hook NtOpenProcess实现进程保护
_EPROCESS对象和_KPROCESS对象之间有什么区别
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服