• IoAllocateMdl函数逆向分析


    0x00前言

    主要分析mdl结构体创建和应用

    0x01分析

    函数原型

    PMDL __stdcall IoAllocateMdl(
            PVOID VirtualAddress,//指向 MDL 要描述的缓冲区的基虚拟地址的指针。
            ULONG Length,//指定 MDL 要描述的缓冲区的长度(以字节为单位)
            BOOLEAN SecondaryBuffer,//指示缓冲区是主缓冲区还是辅助缓冲区
            BOOLEAN ChargeQuota,//预留给系统使用
            PIRP Irp)//指向要与 MDL 关联的 IRP 的指针

    IoAllocateMdl 返回指向 MDL 的指针;如果无法分配 MDL,则返回 NULL。

    PMDL的返回结构
    TYPEDEF struct _MDL{
    STRUCT _MDL *NEXT;//下一个节点_INT64
    short int  Size;//长度
    short int  MdlFlags;//flag
    int          Processor//进程环境
    int64     StartVa
    ulong     ByteCount
    ulong    ByteOffset
    }MDL,PMDL   

    Next:MDL可以连接成一个单链表,因此可以将分散的虚拟机地址串接起来
    Size:整个MDL列表的长度,MDL只是整个列表的头部,后面跟着一块内存,整个MDL列表则是对于一个缓冲区页面的描述。
    MdlFlags:很重要的字段,用于描述和操控虚拟地址的各种属性,指明Mdl的映射方式。
    Process:如果虚拟地址是某一进程的用户地址空间,那么MDL代表的这块虚拟地址必须是从属于某一个进程,这个成员指向从属进程的结构
    MappedSystemVa:该MDL结构对应的物理页面可能被映射到内核地址空间,这个成员代表这个内核地址空间下的虚拟地址。对MmBuildMdlForNonPagedPool的逆向表明,MappedSystemVa = StartVa +ByteOffset。这是因为这个函数的输入MDL,其StartVa是由ExAllocatePoolWithTag决定的,所以已经从内核空间到物理页面建立了映射,MappedSystemVa自然就可以这样算。 可以猜测,如果是调用MmProbeAndLockPages 返回,则MappedSystemVa不会与StartVa有这样的对应关系,因为此时对应的物理页面还没有被映射到内核空间。(此处未定,MmProbeAndLockPages 是否会到PDE与PTE中建立映射,未知。)
    StartVa:虚拟地址空间的首地址,当这块虚拟地址描述的是一个用户进程地址空间的一块时,这个地址从属于某一个进程。(页对齐)
    ByteCount:虚拟地址块的大小,字节数
    ByteOffset:业内的偏移StartVa+ByteCount等于缓冲区的开始地址

    PMDL __stdcall IoAllocateMdl(
            PVOID VirtualAddress,
            ULONG Length,
            BOOLEAN SecondaryBuffer,
            BOOLEAN ChargeQuota,
            PIRP Irp)
    {
      __int16 v5; // si
      __int16 v8; // r15
      unsigned __int64 v9; // rbx
      struct _KPRCB *CurrentPrcb; // r14
      _GENERAL_LOOKASIDE *P; // rbp
      PMDL result; // rax
      unsigned int Number; // ecx
      _GENERAL_LOOKASIDE *L; // rbp
      __int64 Size; // rdx
      void *(__fastcall *AllocateEx)(_POOL_TYPE, unsigned __int64, unsigned int, _LOOKASIDE_LIST_EX *); // rax
      __int64 Tag; // r8
      __int64 Type; // rcx
      unsigned int v19; // eax
      _MDL *MdlAddress; // rcx
      _MDL *i; // rdx
    
      v5 = (__int16)VirtualAddress;
      v8 = 0;
      v9 = (((unsigned __int16)VirtualAddress & 0xFFF) + (unsigned __int64)Length + 4095) >> 12;
      if ( (unsigned int)v9 > 0x11 )                // 大于就按正常大小申请
      {
        v19 = 8 * v9 + 48;
      }
      else
      {
        v8 = 8;
        CurrentPrcb = KeGetCurrentPrcb();
        P = CurrentPrcb->PPLookasideList[3].P;
        ++P->TotalAllocates;
        result = (PMDL)RtlpInterlockedPopEntrySList(&P->ListHead);
        if ( result )
          goto LABEL_3;
        ++P->AllocateMisses;
        L = CurrentPrcb->PPLookasideList[3].L;
        ++L->TotalAllocates;
        result = (PMDL)RtlpInterlockedPopEntrySList(&L->ListHead);
        if ( result
          || (Size = L->Size,
              AllocateEx = L->AllocateEx,
              Tag = L->Tag,
              Type = (unsigned int)L->Type,
              ++L->AllocateMisses,
              (result = (PMDL)((__int64 (__fastcall *)(__int64, __int64, __int64))AllocateEx)(Type, Size, Tag)) != 0i64) )
        {
    LABEL_3:
          LODWORD(result->Next) = CurrentPrcb->Number;
        }
        if ( result )
        {
          LOWORD(Number) = result->Next;
          goto LABEL_6;
        }
        v19 = 184;                                  // 小于0x11时实际大小
      }
      result = (PMDL)ExAllocatePoolWithTag(NonPagedPoolNx, v19, 0x206C644Du);// 申请内存
      if ( !result )
        return result;
      Number = KeGetPcr()->Prcb.Number;
    LABEL_6:
      result->AllocationProcessorNumber = Number;
      result->Next = 0i64;
      result->Size = 8 * (v9 + 6);
      result->StartVa = (void *)((unsigned __int64)VirtualAddress & 0xFFFFFFFFFFFFF000ui64);
      result->ByteOffset = v5 & 0xFFF;
      result->ByteCount = Length;
      result->MdlFlags = v8;
      if ( Irp )                                    // 返回irp值
      {
        if ( SecondaryBuffer )
        {
          MdlAddress = Irp->MdlAddress;
          for ( i = MdlAddress->Next; i; i = i->Next )
            MdlAddress = i;
          MdlAddress->Next = result;
        }
        else
        {
          Irp->MdlAddress = result;
        }
      }
      return result;
    }
     
  • 相关阅读:
    ffmpeg处理RTMP流媒体的命令大全
    人像摄影技巧——镜头差异可改变脸部印象
    windows操作系统自带的TCP端口转发
    IIS7.5如何限制某UserAgent 禁止访问
    JS显示上一周
    mysql主从复制(超简单)
    0001-BUGIFX-Magento-Zend-Framework-1-PHP5.6.patch
    Nginx启用Gzip压缩js无效的原因
    开启Nginx的gzip压缩功能详解
    Python 中的垃圾回收机制
  • 原文地址:https://www.cnblogs.com/feizianquan/p/16069071.html
Copyright © 2020-2023  润新知