由枚举模块到ring0内存结构 (分析NtQueryVirtualMemory)

是由获得进程模块而引发的一系列的问题,首先,在ring3层下枚举进程模块有ToolHelp,Psapi,还可以通过在ntdll中获得ZwQuerySystemInformation的函数地址来枚举,其中ZwQueryInformationProcess相当于是调用系统服务函数,其内部实现就是遍历PEB中的Moudle链表,

kd> dt _PEB

+0x00c Ldr              : Ptr32 _PEB_LDR_DATA   

kd> dt _PEB_LDR_DATA 

nt!_PEB_LDR_DATA

   +0x000 Length           : Uint4B

   +0x004 Initialized         : UChar

   +0x008 SsHandle         : Ptr32 Void

   +0x00c InLoadOrderModuleList : _LIST_ENTRY        //按模块的加载顺序

   +0x014 InMemoryOrderModuleList : _LIST_ENTRY     //按模块在内存中的地址顺序

   +0x01c InInitializationOrderModuleList : _LIST_ENTRY  //按初始化顺序

   +0x024 EntryInProgress  : Ptr32 Void

   +0x028 ShutdownInProgress : UChar

   +0x02c ShutdownThreadId : Ptr32 Void

整个链的结构就是下面这张图

   

typedef struct _PEB_LDR_DATA32   //xp sp3 x86
{
    ULONG Length;                              0x00
    BOOLEAN Initialized;                        0x04
    HANDLE SsHandle;                            0x08
    LIST_ENTRY InLoadOrderModuleList;           0x0c        //按模块的加载顺序
    LIST_ENTRY InMemoryOrderModuleList;        0x14        //按模块在内存中的地址顺序
    LIST_ENTRY InInitializationOrderModuleList;  0x1c        //按初始化顺序
    PVOID EntryInProgress;                       0x24
} PEB_LDR_DATA32, *PPEB_LDR_DATA32;

typedef struct _PEB_LDR_DATA64  //win7 sp1 x64
{
    ULONG Length;
    BOOLEAN Initialized;
    HANDLE SsHandle;
    LIST_ENTRY64 InLoadOrderModuleList;
    LIST_ENTRY64 InMemoryOrderModuleList;
    LIST_ENTRY64 InInitializationOrderModuleList;
    PVOID EntryInProgress;
    BOOLEAN  ShutdownInProgress;
    PVOID    ShutdownThreadId;
} PEB_LDR_DATA64, *PPEB_LDR_DATA64;


图中所示的_LDR_MOUDLE的结构如下:
typedef struct _LDR_DATA_TABLE_ENTRY32 { //xp sp3 x86
    LIST_ENTRY InLoadOrderLinks;
    LIST_ENTRY InMemoryOrderLinks;
    LIST_ENTRY InInitializationOrderLinks;
    PVOID DllBase;
    PVOID EntryPoint;
    ULONG SizeOfImage;
    UNICODE_STRING FullDllName;
    UNICODE_STRING BaseDllName;
    ULONG Flags;
    USHORT LoadCount;
    USHORT TlsIndex;
    union {
        LIST_ENTRY HashLinks;
        struct {
            PVOID SectionPointer;
            ULONG CheckSum;
        };
    };
    union {
        struct {
            ULONG TimeDateStamp;
        };
        struct {
            PVOID LoadedImports;
        };
    };
} LDR_DATA_TABLE_ENTRY32,*PLDR_DATA_TABLE_ENTRY32;


typedef struct _LDR_DATA_TABLE_ENTRY64    //win7 sp1 x64
{
    LIST_ENTRY64    InLoadOrderLinks;
    LIST_ENTRY64    InMemoryOrderLinks;
    LIST_ENTRY64    InInitializationOrderLinks;
    PVOID            DllBase;
    PVOID            EntryPoint;
    ULONG            SizeOfImage;
    UNICODE_STRING    FullDllName;
    UNICODE_STRING     BaseDllName;
    ULONG            Flags;
    USHORT            LoadCount;
    USHORT            TlsIndex;
    PVOID            SectionPointer;
    ULONG            CheckSum;
    PVOID            LoadedImports;
    PVOID            EntryPointActivationContext;
    PVOID            PatchInformation;
    LIST_ENTRY64    ForwarderLinks;
    LIST_ENTRY64    ServiceTagLinks;
    LIST_ENTRY64    StaticLinks;
    PVOID            ContextInformation;
    ULONG64            OriginalBase;
    LARGE_INTEGER    LoadTime;
} LDR_DATA_TABLE_ENTRY64, *PLDR_DATA_TABLE_ENTRY64;

 

很清晰的结构,只要遍历链表就能获得所有的模块的信息,具体的代码就不给出了。问题产生了,就像利用ActiveList来遍历进程一样,存在被断链的可能,如果被断链了,遍历Ldr的方法就失效了,模块也就被隐藏了。

那针对断链的隐藏进程有没有好的方法呢,答案是肯定的,这就利用到了进程中的内存管理。

我们知道Windows对于可执行映像都是采用内存映射文件的方式,而映射区对象(SectioinObject)中会存有与之关联的FileObject的指针,而文件对象中的域

+0x030 FileName         : _UNICODE_STRING   

存放的就是整个映像文件的路径,所以我们可以来暴力搜索进程内存来得到进程模块,这里我们可以借助一个SSDT的函数,NtQueryVirtualMemory() 来枚举进程空间内的所有内存的信息,怎么获得NtQueryVirtualMemory函数地址我就不赘述了,

函数原型:

typedef NTSTATUS
(*pfnNtQueryVirtualMemory)(HANDLE ProcessHandle,PVOID BaseAddress,
    MEMORY_INFORMATION_CLASS MemoryInformationClass,
    PVOID MemoryInformation,
    SIZE_T MemoryInformationLength,
    PSIZE_T ReturnLength);

 

其中的MEMORY_INFORMATION_CLASS 是一个枚举量,来表示查询的是哪种信息

Wrk中搜的枚举类型

typedef enum _MEMORY_INFORMATION_CLASS {
    MemoryBasicInformation
#if DEVL
    ,MemoryWorkingSetInformation
#endif
    ,MemoryMappedFilenameInformation
    ,MemoryRegionInformation
    ,MemoryWorkingSetExInformation
} MEMORY_INFORMATION_CLASS;

而我自己一般用的就是下面的简化版

typedef enum _MEMORY_INFORMATION_CLASS
{
    MemoryBasicInformation,  //内存基本信息
    MemoryWorkingSetList,
    MemorySectionName        //内存映射文件名信息  
}MEMORY_INFORMATION_CLASS;

 当我们使用MemoryBasicInformation 来查询时,MemoryInformation结构如下

typedef struct _MEMORY_BASIC_INFORMATION {  
    PVOID       BaseAddress;           //查询内存块所占的第一个页面基地址
    PVOID       AllocationBase;        //内存块所占的第一块区域基地址,小于等于BaseAddress,
    DWORD       AllocationProtect;     //区域被初次保留时赋予的保护属性
    SIZE_T      RegionSize;            //从BaseAddress开始,具有相同属性的页面的大小,
    DWORD       State;                 //页面的状态,有三种可能值MEM_COMMIT、MEM_FREE和MEM_RESERVE
    DWORD       Protect;               //页面的属性,其可能的取值与AllocationProtect相同
    DWORD       Type;                  //该内存块的类型,有三种可能值:MEM_IMAGE、MEM_MAPPED和MEM_PRIVATE
} MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION;

State指示虚拟内存的状态
MEM_COMMIT    指明已分配物理内存或者系统页文件。
MEM_RESERVE   指明页面被保留,但是没有分配任何物理内存。
MEM_FREE         空闲状态。该区域的虚拟地址没有分配任务物理内存

Type是指示物理存储器的类型

MEM_IMAGE   指明该区域的虚拟地址原先受内存映射的映像文件(如.exe或DLL文件)的支持,但也许不再受映像文件的支持。
         例如,当写入模块映像中的全局变量时,“写入时拷贝”的机制将由页文件来支持特定的页面,而不是受原始映像文件的支持。
MEM_MAPPED   该区域的虚拟地址原先是受内存映射的数据文件的支持,但也许不再受数据文件的支持。
         例如,数据文件可以使用“写入时拷贝”的保护属性来映射。对文件的任何写入操作都将导致页文件而不是原始数据支持特定的页面。
MEM_PRIVATE   指明该内存区域是私有的。不被其他进程共享。

 用MemorySectionName 查询时MemoryInformation结构如下

typedef struct _MEMORY_SECTION_NAME  {  
    UNICODE_STRING Name;  
    WCHAR     Buffer[_MAX_OBJECT_NAME];  
}MEMORY_SECTION_NAME,*PMEMORY_SECTION_NAME;

下面给出主要代码,思路就是调用NtQueryVirtualMemory来暴力遍历进程的所有内存

NTSTATUS EnumMoudleByNtQueryVirtualMemory(ULONG ProcessId)
{
    NTSTATUS Status;
    PEPROCESS  EProcess = NULL;
    HANDLE    hProcess = NULL;
    ULONG_PTR HighUserAddress  = 0;
    ULONG ulRet = 0;
#ifdef _WIN64
    HighUserAddress = 0x80000000000;
#else
    HighUserAddress = 0x80000000;
#endif

    if (ProcessId)
    {
        Status = PsLookupProcessByProcessId((HANDLE)ProcessId, &EProcess);
        if (!NT_SUCCESS(Status))
        {
            return Status;
        }    
    }
    if (IsRealProcess(EProcess))   //判断是否为僵尸进程,我只是判断了对象类型和句柄表是否存在
    {
        ObfDereferenceObject(EProcess);
        Status = ObOpenObjectByPointer(EProcess, 
            OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, 
            NULL, 
            GENERIC_ALL, 
            *PsProcessType, 
            KernelMode, 
            &hProcess
            );
        if (NT_SUCCESS(Status))
        {
            ULONG_PTR ulBase = 0;
            //改变PreviousMode
            PETHREAD EThread = PsGetCurrentThread();
            CHAR PreMode     = ChangePreMode(EThread);   //KernelMode
            do 
            {
                MEMORY_BASIC_INFORMATION mbi = {0};
                Status = NtQueryVirtualMemory(hProcess, 
                    (PVOID)ulBase, 
                    MemoryBasicInformation, 
                    &mbi, 
                    sizeof(MEMORY_BASIC_INFORMATION), 
                    &ulRet);
                if (NT_SUCCESS(Status))
                {    
                    //如果是Image 再查询SectionName,即FileObject Name
                    if (mbi.Type==MEM_IMAGE)
                    {
                        MEMORY_SECTION_NAME msn = {0};
                        Status = NtQueryVirtualMemory(hProcess,
                            (PVOID)ulBase,
                            MemorySectionName,
                            &msn,
                            sizeof(MEMORY_SECTION_NAME),
                            &ulRet);
                        if (NT_SUCCESS(Status)) 
                        {
                            UNICODE_STRING DosName;
                            DbgPrint("SectionName:%wZ\r\n",&(msn.SectionFileName));
                        //    DbgPrint("MoudleName:%S\r\n",msn.SectionFileName);        
                            RtlVolumeDeviceToDosName_(&(msn.SectionFileName),&DosName);
                            DbgPrint("SectionName:%wZ\r\n",&(DosName));
                        }
                    }
                    ulBase += mbi.RegionSize;
                }
                else ulBase += PAGE_SIZE;    
            } while (ulBase < (ULONG_PTR)HighUserAddress);
            NtClose(hProcess);
            RecoverPreMode(EThread,PreMode);
        }
    }
    return Status;
}
    

然后我们进一步探索NtQueryVirtualMemory的内部实现原理,先重点关注NtQueryVirtualMemory关于MemorySectionName==2 方式的处理流程,这里只以Win7 x86 Sp1为例列出我们要用到的几个结构,如果对于Windows 底层的内存管理想要深入了解,可以阅读《Windows内核原理及实现》和《Windows内核情景分析》中内存管理的相关章节。

 我们可以看到EProcess进程体的VadRoot

kd> dt _eprocess
+0x278 VadRoot          : _MM_AVL_TABLE
kd> dt _MMADDRESS_NODE
nt!_MMADDRESS_NODE
   +0x000 u1                 : <unnamed-tag>
   +0x004 LeftChild          : Ptr32 _MMADDRESS_NODE
   +0x008 RightChild         : Ptr32 _MMADDRESS_NODE
   +0x00c StartingVpn        : Uint4B
   +0x010 EndingVpn          : Uint4B

 可以看到Win 7Sp1 下的两种结构非常简单,提供不了太多有效的信息,我们再来看看xp sp3下的结构

kd> dt _eprocess
+0x11c VadRoot          : Ptr32 Void

 只是一个32位的指针,但是我们知道这个指针是指向_MMVAD结构,形成一颗二叉树结构

kd> dt _mmvad
nt!_MMVAD
   +0x000 StartingVpn         : Uint4B
   +0x004 EndingVpn           : Uint4B
   +0x008 Parent              : Ptr32 _MMVAD
   +0x00c LeftChild           : Ptr32 _MMVAD
   +0x010 RightChild          : Ptr32 _MMVAD
   +0x014 u                   : __unnamed
   +0x018 ControlArea         : Ptr32 _CONTROL_AREA
   +0x01c FirstPrototypePte   : Ptr32 _MMPTE
   +0x020 LastContiguousPte   : Ptr32 _MMPTE
   +0x024 u2                  : __unnamed

 

 然后尝试着在Win 7下输入 dt _MMVAD

kd> dt _mmvad
nt!_MMVAD
   +0x000 StartingVpn         : Uint4B
   +0x004 EndingVpn           : Uint4B
   +0x008 Parent              : Ptr32 _MMVAD
   +0x00c LeftChild           : Ptr32 _MMVAD
   +0x010 RightChild          : Ptr32 _MMVAD
   +0x014 u                   : __unnamed
   +0x018 ControlArea         : Ptr32 _CONTROL_AREA
   +0x01c FirstPrototypePte   : Ptr32 _MMPTE
   +0x020 LastContiguousPte   : Ptr32 _MMPTE
   +0x024 u2                  : __unnamed

 

 对比两个结构,发现了什么,没错,_MMADRESS_NODE只是_MMVAD结构体的前一部分,真正的内存块的节点还是_MMVAD结构

  我们可以以calc.exe为例来体验一下整个流程 Win7 x86 sp1

kd> !process 0 0
**** NT ACTIVE PROCESS DUMP ****
PROCESS 87b73cf8  SessionId: 1  Cid: 0dd8    Peb: 7ffdf000  ParentCid: 07f4
    DirBase: 7f3455e0  ObjectTable: 97934428  HandleCount:  79.
    Image: calc.exe
kd> dt _eprocess 87b73cf8
 +0x278 VadRoot          : _MM_AVL_TABLE

 

kd> dt _MM_AVL_TABLE 87b73cf8+0x278
nt!_MM_AVL_TABLE
   +0x000 BalancedRoot     : _MMADDRESS_NODE
   +0x014 DepthOfTree      : 0y01001 (0x9)
   +0x014 Unused           : 0y000
   +0x014 NumberGenericTableElements : 0y000000000000000010011111 (0x9f)
   +0x018 NodeHint         : 0x876c4ec8 Void
   +0x01c NodeFreeHint     : (null) 
kd> dt _MMADDRESS_NODE 87b73cf8+0x278
nt!_MMADDRESS_NODE
   +0x000 u1               : <unnamed-tag>
   +0x004 LeftChild        : (null) 
   +0x008 RightChild       : 0x87c327e0 _MMADDRESS_NODE
   +0x00c StartingVpn      : 0
   +0x010 EndingVpn        : 0

 

 注意Win 7下的根结点只利用了右子树,想当与跟节点的右子树才是真正意义上的AVL树的根节点,继续跟入:

kd> dt _MMVAD 0x87c327e0
nt!_MMVAD
   +0x000 u1               : <unnamed-tag>
   +0x004 LeftChild        : 0x87ac3248 _MMVAD
   +0x008 RightChild       : 0x87c2b3b8 _MMVAD
   +0x00c StartingVpn      : 0xd80
   +0x010 EndingVpn        : 0xe3f
   +0x014 u                : <unnamed-tag>
   +0x018 PushLock         : _EX_PUSH_LOCK
   +0x01c u5               : <unnamed-tag>
   +0x020 u2               : <unnamed-tag>
   +0x024 Subsection       : 0x880a3410 _SUBSECTION //我们接下来要跟的就是这个结构
   +0x024 MappedSubsection : 0x880a3410 _MSUBSECTION
   +0x028 FirstPrototypePte : 0x961b69c8 _MMPTE
   +0x02c LastContiguousPte : 0xfffffffc _MMPTE
   +0x030 ViewLinks        : _LIST_ENTRY [ 0x880a3408 - 0x880a3408 ]
   +0x038 VadsProcess      : 0x87b73cf9 _EPROCESS
kd> dt _SUBSECTION 0x880a3410
nt!_SUBSECTION
   +0x000 ControlArea      : 0x880a33c0 _CONTROL_AREA    //跟这个结构
   +0x004 SubsectionBase   : 0x961b69c8 _MMPTE
   +0x008 NextSubsection   : 0x880a3430 _SUBSECTION
   +0x00c PtesInSubsection : 1
   +0x010 UnusedPtes       : 0
   +0x010 GlobalPerSessionHead : (null) 
   +0x014 u                : <unnamed-tag>
   +0x018 StartingSector   : 0
   +0x01c NumberOfFullSectors : 2
kd> dt _CONTROL_AREA 0x880a33c0
nt!_CONTROL_AREA
   +0x000 Segment          : 0x961b6998 _SEGMENT
   +0x004 DereferenceList  : _LIST_ENTRY [ 0x0 - 0x880d7104 ]
   +0x00c NumberOfSectionReferences : 1
   +0x010 NumberOfPfnReferences : 0x86
   +0x014 NumberOfMappedViews : 1
   +0x018 NumberOfUserReferences : 2
   +0x01c u                : <unnamed-tag>
   +0x020 FlushInProgressCount : 0
   +0x024 FilePointer      : _EX_FAST_REF   //关联的文件对象就在这个结构里面了
   +0x028 ControlAreaLock  : 0n0
   +0x02c ModifiedWriteCount : 0
   +0x02c StartingFrame    : 0
   +0x030 WaitingForDeletion : (null) 
   +0x034 u2               : <unnamed-tag>
   +0x040 LockedPages      : 0n1
   +0x048 ViewList         : _LIST_ENTRY [ 0x87c32810 - 0x87c32810 ]
kd> dt _EX_FAST_REF 0x880a33c0+0x24
nt!_EX_FAST_REF
   +0x000 Object           : 0x880a1b43 Void  //关联的文件对象
   +0x000 RefCnt           : 0y011
   +0x000 Value            : 0x880a1b43

 

 注意,这里关联的文件对象要&0x0FFFFFFF8(最后三位清零)才是正真的文件对象

kd> !object 0x880a1b43&0x0fffffff8
Object: 880a1b40  Type: (863ff650) File
    ObjectHeader: 880a1b28 (new version)
    HandleCount: 0  PointerCount: 4
    Directory Object: 00000000  Name: \Windows\System32\calc.exe {HarddiskVolume1}  //文件对象名,完整路径

 

 

 了解了这些结构体之后,再看NtQueryVirtualMemory函数关于MemorySectionName的处理流程,贴出ida分析的过程,只分析了我们关注的MemorySectionName的方式,wrk中也有源码

PAGE:0063F242                   ; NTSTATUS __stdcall NtQueryVirtualMemory(HANDLE ProcessHandle, PVOID BaseAddress, MEMORY_INFORMATION_CLASS MemoryInformationClass, PVOID MemoryInformation, ULONG MemoryInformationLength, PULONG ReturnLength)
PAGE:0063F242                   _NtQueryVirtualMemory@24 proc near
PAGE:0063F242                                                 ; DATA XREF: .text:0045CB68o
PAGE:0063F242
PAGE:0063F242                   var_7C= dword ptr -7Ch
PAGE:0063F242                   var_78= dword ptr -78h
PAGE:0063F242                   var_74= dword ptr -74h
PAGE:0063F242                   var_70= dword ptr -70h
PAGE:0063F242                   var_64= dword ptr -64h
PAGE:0063F242                   ApcState= dword ptr -60h
PAGE:0063F242                   var_48= dword ptr -48h
PAGE:0063F242                   var_44= dword ptr -44h
PAGE:0063F242                   var_40= dword ptr -40h
PAGE:0063F242                   var_3C= dword ptr -3Ch
PAGE:0063F242                   var_38= dword ptr -38h
PAGE:0063F242                   Object= dword ptr -34h
PAGE:0063F242                   AccessMode= byte ptr -30h
PAGE:0063F242                   var_2C= dword ptr -2Ch
PAGE:0063F242                   var_28= dword ptr -28h
PAGE:0063F242                   var_24= dword ptr -24h
PAGE:0063F242                   EProcess= dword ptr -20h
PAGE:0063F242                   var_1C??Attached= dword ptr -1Ch
PAGE:0063F242                   ms_exc= CPPEH_RECORD ptr -18h
PAGE:0063F242                   ProcessHandle= dword ptr  8
PAGE:0063F242                   BaseAddress= dword ptr  0Ch
PAGE:0063F242                   MemoryInformationClass= dword ptr  10h
PAGE:0063F242                   MemoryInformation= dword ptr  14h
PAGE:0063F242                   MemoryInformationLength= dword ptr  18h
PAGE:0063F242                   ReturnLength= dword ptr  1Ch
PAGE:0063F242
PAGE:0063F242 6A 6C             push    6Ch
PAGE:0063F244 68 18 0F 45 00    push    offset stru_450F18
PAGE:0063F249 E8 D2 4F E1 FF    call    __SEH_prolog4
PAGE:0063F24E 33 F6             xor     esi, esi
PAGE:0063F250 89 75 E4          mov     [ebp+var_1C??Attached], esi
PAGE:0063F253 89 75 DC          mov     [ebp+var_24], esi
PAGE:0063F256 8B 45 10          mov     eax, [ebp+MemoryInformationClass]
PAGE:0063F259 2B C6             sub     eax, esi              ; Handler MemoryBasicInformation
PAGE:0063F25B 74 28             jz      short Handler_MemoryBasicInformation
PAGE:0063F25D 48                dec     eax                   ; Handler MemoryWorkingSetList
PAGE:0063F25E 74 1F             jz      short Handler_MemoryWorkingSetList
PAGE:0063F260 48                dec     eax
PAGE:0063F261 74 32             jz      short loc_63F295      ; Handler_MemoryMappedFilenameInformation
PAGE:0063F263 48                dec     eax
PAGE:0063F264 74 13             jz      short loc_63F279
PAGE:0063F266 48                dec     eax
PAGE:0063F267 74 0A             jz      short loc_63F273
PAGE:0063F269 B8 03 00 00 C0    mov     eax, 0C0000003h
PAGE:0063F26E E9 D6 06 00 00    jmp     loc_63F949
PAGE:0063F273                   ; ---------------------------------------------------------------------------
PAGE:0063F273
PAGE:0063F273                   loc_63F273:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+25j
PAGE:0063F273 83 7D 18 08       cmp     [ebp+MemoryInformationLength], 8
PAGE:0063F277 EB 10             jmp     short loc_63F289
PAGE:0063F279                   ; ---------------------------------------------------------------------------
PAGE:0063F279
PAGE:0063F279                   loc_63F279:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+22j
PAGE:0063F279 83 7D 18 10       cmp     [ebp+MemoryInformationLength], 10h
PAGE:0063F27D EB 0A             jmp     short loc_63F289
PAGE:0063F27F                   ; ---------------------------------------------------------------------------
PAGE:0063F27F
PAGE:0063F27F                   Handler_MemoryWorkingSetList: ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+1Cj
PAGE:0063F27F 83 7D 18 04       cmp     [ebp+MemoryInformationLength], 4
PAGE:0063F283 EB 04             jmp     short loc_63F289
PAGE:0063F285                   ; ---------------------------------------------------------------------------
PAGE:0063F285
PAGE:0063F285                   Handler_MemoryBasicInformation:
PAGE:0063F285                                                 ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+19j
PAGE:0063F285 83 7D 18 1C       cmp     [ebp+MemoryInformationLength], 1Ch
PAGE:0063F289
PAGE:0063F289                   loc_63F289:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+35j
PAGE:0063F289                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x)+3Bj
PAGE:0063F289                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x)+41j
PAGE:0063F289 73 0A             jnb     short loc_63F295
PAGE:0063F28B B8 04 00 00 C0    mov     eax, 0C0000004h
PAGE:0063F290 E9 B4 06 00 00    jmp     loc_63F949
PAGE:0063F295                   ; ---------------------------------------------------------------------------
PAGE:0063F295
PAGE:0063F295                   loc_63F295:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+1Fj
PAGE:0063F295                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x):loc_63F289j
PAGE:0063F295 64 8B 1D 24 01 00+mov     ebx, large fs:124h    ; Handler_MemoryMappedFilenameInformation
PAGE:0063F29C 8A 83 3A 01 00 00 mov     al, [ebx+13Ah]        ; FS寄存器指向当前CPU的KPCR   KPCR+0x124指向当前线程对象
PAGE:0063F29C                                                 ; +0x13A获取先前的调用模式<KernelMode/UserMode>
PAGE:0063F2A2 88 45 D0          mov     [ebp+AccessMode], al
PAGE:0063F2A5 84 C0             test    al, al                ; KernelMode=0,UserMode=1
PAGE:0063F2A7 74 50             jz      short loc_63F2F9
PAGE:0063F2A9 89 75 FC          mov     [ebp+ms_exc.registration.TryLevel], esi ; 很明显的异常处理,与我们分析无关,忽略
PAGE:0063F2AC 6A 04             push    4                     ; Alignment
PAGE:0063F2AC                                                 ; UserMode
PAGE:0063F2AE FF 75 18          push    [ebp+MemoryInformationLength] ; Length
PAGE:0063F2B1 8B 7D 14          mov     edi, [ebp+MemoryInformation]
PAGE:0063F2B4 57                push    edi                   ; Address
PAGE:0063F2B5 E8 B3 E0 FB FF    call    _ProbeForWrite@12     ; 查看用户态内存是否可写
PAGE:0063F2BA 8B 4D 1C          mov     ecx, [ebp+ReturnLength]
PAGE:0063F2BD 3B CE             cmp     ecx, esi              ; 此时的esi=0,即比较ReturnLength是否为0
PAGE:0063F2BF 74 0F             jz      short loc_63F2D0      ; ReturnLength==0则跳转
PAGE:0063F2C1 A1 04 07 56 00    mov     eax, ds:_MmUserProbeAddress ; 检查此地址是否高于用户边界地址,
PAGE:0063F2C1                                                 ; _MmUserProbeAddress == 7fff0000
PAGE:0063F2C6 3B C8             cmp     ecx, eax
PAGE:0063F2C8 72 02             jb      short loc_63F2CC      ; 低于的话则跳转,正常来讲一定会跳
PAGE:0063F2CA 8B C8             mov     ecx, eax              ; 异常处理,忽略
PAGE:0063F2CC
PAGE:0063F2CC                   loc_63F2CC:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+86j
PAGE:0063F2CC 8B 01             mov     eax, [ecx]
PAGE:0063F2CE 89 01             mov     [ecx], eax
PAGE:0063F2D0
PAGE:0063F2D0                   loc_63F2D0:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+7Dj
PAGE:0063F2D0 C7 45 FC FE FF FF+mov     [ebp+ms_exc.registration.TryLevel], 0FFFFFFFEh ; 很明显的SEH处理,
PAGE:0063F2D0 FF                                              ; 改变TryLevel,忽略
PAGE:0063F2D7 EB 23             jmp     short loc_63F2FC      ; 一般参数没问题,直接跳转
PAGE:0063F2D9                   ; ---------------------------------------------------------------------------
PAGE:0063F2D9
PAGE:0063F2D9                   loc_63F2D9:                   ; DATA XREF: .text:stru_450F18o
PAGE:0063F2D9 8B 45 EC          mov     eax, [ebp+ms_exc.exc_ptr] ; 很明显,如果参数有问题,就直接返回了
PAGE:0063F2DC 8B 00             mov     eax, [eax]
PAGE:0063F2DE 8B 00             mov     eax, [eax]
PAGE:0063F2E0 89 45 D4          mov     [ebp+var_2C], eax
PAGE:0063F2E3 33 C0             xor     eax, eax
PAGE:0063F2E5 40                inc     eax
PAGE:0063F2E6 C3                retn
PAGE:0063F2E7                   ; ---------------------------------------------------------------------------
PAGE:0063F2E7
PAGE:0063F2E7                   loc_63F2E7:                   ; DATA XREF: .text:stru_450F18o
PAGE:0063F2E7 8B 65 E8          mov     esp, [ebp+ms_exc.old_esp] ; Exception handler 0 for function 63F242
PAGE:0063F2EA 8B 45 D4          mov     eax, [ebp+var_2C]
PAGE:0063F2ED
PAGE:0063F2ED                   loc_63F2ED:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+3DBj
PAGE:0063F2ED                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x)+55Bj
PAGE:0063F2ED                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x)+620j
PAGE:0063F2ED C7 45 FC FE FF FF+mov     [ebp+ms_exc.registration.TryLevel], 0FFFFFFFEh
PAGE:0063F2F4 E9 50 06 00 00    jmp     loc_63F949
PAGE:0063F2F9                   ; ---------------------------------------------------------------------------
PAGE:0063F2F9
PAGE:0063F2F9                   loc_63F2F9:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+65j
PAGE:0063F2F9 8B 7D 14          mov     edi, [ebp+MemoryInformation] ; KernelMode
PAGE:0063F2FC
PAGE:0063F2FC                   loc_63F2FC:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+95j
PAGE:0063F2FC 8B 45 0C          mov     eax, [ebp+BaseAddress] ; 还是参数的校验,我们要查询的虚拟地址
PAGE:0063F2FF 8B 0D FC 06 56 00 mov     ecx, ds:_MmHighestUserAddress ; MmHighestUserAddress==0x7ffeffff
PAGE:0063F2FF                                                 ; (这是用户空间可以访问的最高地址,
PAGE:0063F2FF                                                 ; 逻辑上的而已,上面还有个64K的禁区(飞地)就到内核空间了)
PAGE:0063F305 3B C1             cmp     eax, ecx
PAGE:0063F307 76 0A             jbe     short loc_63F313
PAGE:0063F309 B8 0D 00 00 C0    mov     eax, 0C000000Dh       ; Status的返回值 STATUS_INVALID_PARAMETER(参数无效)
PAGE:0063F30E E9 36 06 00 00    jmp     loc_63F949            ; 返回
PAGE:0063F313                   ; ---------------------------------------------------------------------------
PAGE:0063F313
PAGE:0063F313                   loc_63F313:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+C5j
PAGE:0063F313 8D B1 00 00 FF FF lea     esi, [ecx-10000h]     ; esi==0x7ffdffff
PAGE:0063F319 89 75 D8          mov     [ebp+var_28], esi     ; 保存允许查询的最高地址,作为查询的虚拟地址的终结点
PAGE:0063F31C BA 00 F0 FF FF    mov     edx, 0FFFFF000h
PAGE:0063F321 3B C6             cmp     eax, esi              ; 判断查询的虚拟地址是否高于终结点
PAGE:0063F323 0F 87 A6 05 00 00 ja      loc_63F8CF            ; 高于,跳转,等会再看具体处理
PAGE:0063F329 89 45 14          mov     [ebp+MemoryInformation], eax ; 将地址保存
PAGE:0063F32C 21 55 14          and     [ebp+MemoryInformation], edx ; edi==0FFFFF000h 取整得到虚拟地址的内存页首地址
PAGE:0063F32F 81 7D 14 00 00 FE+cmp     [ebp+MemoryInformation], 7FFE0000h ; 判断地址是否大于SharedUserData
PAGE:0063F32F 7F                                              ; 也就是说SharedUserData为最后一个合法的用户边界
PAGE:0063F336 0F 84 93 05 00 00 jz      loc_63F8CF
PAGE:0063F33C 83 7D 08 FF       cmp     [ebp+ProcessHandle], 0FFFFFFFFh
PAGE:0063F340 75 08             jnz     short loc_63F34A      ; 不是本身的进程就跳转
PAGE:0063F342 8B 73 50          mov     esi, [ebx+50h]        ; ebx为线程对象,+0x50就为进程对象
PAGE:0063F345 89 75 E0          mov     [ebp+EProcess], esi
PAGE:0063F348 EB 2A             jmp     short loc_63F374
PAGE:0063F34A                   ; ---------------------------------------------------------------------------
PAGE:0063F34A
PAGE:0063F34A                   loc_63F34A:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+FEj
PAGE:0063F34A 6A 00             push    0                     ; HandleInformation
PAGE:0063F34C 8D 45 CC          lea     eax, [ebp+Object]
PAGE:0063F34F 50                push    eax                   ; Object
PAGE:0063F350 FF 75 D0          push    dword ptr [ebp+AccessMode] ; AccessMode
PAGE:0063F353 FF 35 2C 00 56 00 push    ds:_PsProcessType     ; ObjectType
PAGE:0063F359 68 00 04 00 00    push    400h                  ; DesiredAccess
PAGE:0063F35E FF 75 08          push    [ebp+ProcessHandle]   ; Handle
PAGE:0063F361 E8 F6 D0 FB FF    call    _ObReferenceObjectByHandle@24 ; ObReferenceObjectByHandle(x,x,x,x,x,x)
PAGE:0063F366 8B 75 CC          mov     esi, [ebp+Object]
PAGE:0063F369 89 75 E0          mov     [ebp+EProcess], esi
PAGE:0063F36C 85 C0             test    eax, eax
PAGE:0063F36E 0F 8C D5 05 00 00 jl      loc_63F949
PAGE:0063F374
PAGE:0063F374                   loc_63F374:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+106j
PAGE:0063F374 83 7D 10 04       cmp     [ebp+MemoryInformationClass], 4 ; MemoryRegionInformation方式查询
PAGE:0063F378 75 4D             jnz     short loc_63F3C7
PAGE:0063F37A 56                push    esi
PAGE:0063F37B 8B 5D 18          mov     ebx, [ebp+MemoryInformationLength]
PAGE:0063F37E 53                push    ebx
PAGE:0063F37F 8B CF             mov     ecx, edi
PAGE:0063F381 E8 FF B8 DE FF    call    _MiGetWorkingSetInfoList@12 ; MiGetWorkingSetInfoList(x,x,x)
PAGE:0063F386 8B F8             mov     edi, eax
PAGE:0063F388 83 7D 08 FF       cmp     [ebp+ProcessHandle], 0FFFFFFFFh
PAGE:0063F38C 74 07             jz      short loc_63F395
PAGE:0063F38E 8B CE             mov     ecx, esi              ; Object
PAGE:0063F390 E8 98 70 E1 FF    call    @ObfDereferenceObject@4 ; ObfDereferenceObject(x)
PAGE:0063F395
PAGE:0063F395                   loc_63F395:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+14Aj
PAGE:0063F395 85 FF             test    edi, edi
PAGE:0063F397 7D 07             jge     short loc_63F3A0
PAGE:0063F399 8B C7             mov     eax, edi
PAGE:0063F39B E9 A9 05 00 00    jmp     loc_63F949
PAGE:0063F3A0                   ; ---------------------------------------------------------------------------
PAGE:0063F3A0
PAGE:0063F3A0                   loc_63F3A0:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+155j
PAGE:0063F3A0 C7 45 FC 02 00 00+mov     [ebp+ms_exc.registration.TryLevel], 2
PAGE:0063F3A7 8B 45 1C          mov     eax, [ebp+ReturnLength]
PAGE:0063F3AA 85 C0             test    eax, eax
PAGE:0063F3AC 74 0B             jz      short loc_63F3B9
PAGE:0063F3AE 89 18             mov     [eax], ebx
PAGE:0063F3B0 EB 07             jmp     short loc_63F3B9
PAGE:0063F3B2                   ; ---------------------------------------------------------------------------
PAGE:0063F3B2
PAGE:0063F3B2                   loc_63F3B2:                   ; DATA XREF: .text:stru_450F18o
PAGE:0063F3B2 33 C0             xor     eax, eax              ; Exception filter 2 for function 63F242
PAGE:0063F3B4 40                inc     eax
PAGE:0063F3B5 C3                retn
PAGE:0063F3B6                   ; ---------------------------------------------------------------------------
PAGE:0063F3B6
PAGE:0063F3B6                   loc_63F3B6:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x):loc_63F40Ej
PAGE:0063F3B6                                                 ; DATA XREF: .text:stru_450F18o
PAGE:0063F3B6 8B 65 E8          mov     esp, [ebp+ms_exc.old_esp] ; Exception handler 2 for function 63F242
PAGE:0063F3B9
PAGE:0063F3B9                   loc_63F3B9:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+16Aj
PAGE:0063F3B9                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x)+16Ej
PAGE:0063F3B9                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x)+1B9j
PAGE:0063F3B9                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x)+1C6j
PAGE:0063F3B9                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x):loc_63F5EEj
PAGE:0063F3B9                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x)+3B8j
PAGE:0063F3B9                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x)+3D2j
PAGE:0063F3B9                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x)+52Cj
PAGE:0063F3B9                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x)+538j
PAGE:0063F3B9                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x)+552j
PAGE:0063F3B9                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x)+617j
PAGE:0063F3B9 C7 45 FC FE FF FF+mov     [ebp+ms_exc.registration.TryLevel], 0FFFFFFFEh
PAGE:0063F3C0 33 C0             xor     eax, eax
PAGE:0063F3C2 E9 82 05 00 00    jmp     loc_63F949
PAGE:0063F3C7                   ; ---------------------------------------------------------------------------
PAGE:0063F3C7
PAGE:0063F3C7                   loc_63F3C7:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+136j
PAGE:0063F3C7 83 7D 10 01       cmp     [ebp+MemoryInformationClass], 1
PAGE:0063F3CB 75 43             jnz     short loc_63F410
PAGE:0063F3CD 56                push    esi                   ; BugCheckParameter1
PAGE:0063F3CE FF 75 18          push    [ebp+MemoryInformationLength] ; int
PAGE:0063F3D1 8B CF             mov     ecx, edi
PAGE:0063F3D3 E8 A3 96 E7 FF    call    _MiGetWorkingSetInfo@12 ; MiGetWorkingSetInfo(x,x,x)
PAGE:0063F3D8 8B D8             mov     ebx, eax
PAGE:0063F3DA 83 7D 08 FF       cmp     [ebp+ProcessHandle], 0FFFFFFFFh
PAGE:0063F3DE 74 07             jz      short loc_63F3E7
PAGE:0063F3E0 8B CE             mov     ecx, esi              ; Object
PAGE:0063F3E2 E8 46 70 E1 FF    call    @ObfDereferenceObject@4 ; ObfDereferenceObject(x)
PAGE:0063F3E7
PAGE:0063F3E7                   loc_63F3E7:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+19Cj
PAGE:0063F3E7 85 DB             test    ebx, ebx
PAGE:0063F3E9 0F 8C 58 05 00 00 jl      loc_63F947
PAGE:0063F3EF C7 45 FC 03 00 00+mov     [ebp+ms_exc.registration.TryLevel], 3
PAGE:0063F3F6 8B 45 1C          mov     eax, [ebp+ReturnLength]
PAGE:0063F3F9 85 C0             test    eax, eax
PAGE:0063F3FB 74 BC             jz      short loc_63F3B9
PAGE:0063F3FD 8B 0F             mov     ecx, [edi]
PAGE:0063F3FF 8D 0C 8D 04 00 00+lea     ecx, ds:4[ecx*4]
PAGE:0063F406 89 08             mov     [eax], ecx
PAGE:0063F408 EB AF             jmp     short loc_63F3B9
PAGE:0063F40A                   ; ---------------------------------------------------------------------------
PAGE:0063F40A
PAGE:0063F40A                   loc_63F40A:                   ; DATA XREF: .text:stru_450F18o
PAGE:0063F40A 33 C0             xor     eax, eax              ; Exception filter 3 for function 63F242
PAGE:0063F40C 40                inc     eax
PAGE:0063F40D C3                retn
PAGE:0063F40E                   ; ---------------------------------------------------------------------------
PAGE:0063F40E
PAGE:0063F40E                   loc_63F40E:                   ; DATA XREF: .text:stru_450F18o
PAGE:0063F40E EB A6             jmp     short loc_63F3B6      ; Exception handler 3 for function 63F242
PAGE:0063F410                   ; ---------------------------------------------------------------------------
PAGE:0063F410
PAGE:0063F410                   loc_63F410:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+189j
PAGE:0063F410 83 7D 08 FF       cmp     [ebp+ProcessHandle], 0FFFFFFFFh
PAGE:0063F414 74 11             jz      short loc_63F427      ; 如果不是自己进程本身就靠挂到其他进程空间
PAGE:0063F416 8D 45 A0          lea     eax, [ebp+ApcState]
PAGE:0063F419 50                push    eax                   ; ApcState
PAGE:0063F41A 56                push    esi                   ; Process
PAGE:0063F41B E8 7A 36 E2 FF    call    _KeStackAttachProcess@8 ; KeStackAttachProcess(x,x)
PAGE:0063F420 C7 45 E4 01 00 00+mov     [ebp+var_1C??Attached], 1
PAGE:0063F427
PAGE:0063F427                   loc_63F427:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+1D2j
PAGE:0063F427 66 FF 8B 86 00 00+dec     word ptr [ebx+86h]    ; ????
PAGE:0063F42E 8D 86 00 01 00 00 lea     eax, [esi+100h]       ; +0x100 AddressCreationLock : _EX_PUSH_LOCK
PAGE:0063F42E                                                 ; 获取进程的地址空间锁,因为涉及到遍历地址空间,
PAGE:0063F42E                                                 ; 就不可以在遍历的时候地址空间发生变化
PAGE:0063F434 6A 11             push    11h
PAGE:0063F436 59                pop     ecx                   ; ???应该是原子锁的问题,不是很清楚
PAGE:0063F437 8B D0             mov     edx, eax
PAGE:0063F439 33 C0             xor     eax, eax
PAGE:0063F43B F0 0F B1 0A       lock cmpxchg [edx], ecx
PAGE:0063F43F 85 C0             test    eax, eax
PAGE:0063F441 74 0B             jz      short loc_63F44E
PAGE:0063F443 8D 8E 00 01 00 00 lea     ecx, [esi+100h]
PAGE:0063F449 E8 C7 79 E4 FF    call    @ExfAcquirePushLockShared@4 ; ExfAcquirePushLockShared(x)
PAGE:0063F44E
PAGE:0063F44E                   loc_63F44E:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+1FFj
PAGE:0063F44E 80 8B 89 02 00 00+or      byte ptr [ebx+289h], 4 ; ???
PAGE:0063F44E 04                                              ;    +0x289 OwnsSessionWorkingSetShared : Pos 0, 1 Bit
PAGE:0063F44E                                                 ;    +0x289 OwnsProcessAddressSpaceExclusive : Pos 1, 1 Bit
PAGE:0063F44E                                                 ;    +0x289 OwnsProcessAddressSpaceShared : Pos 2, 1 Bit
PAGE:0063F44E                                                 ;    +0x289 SuppressSymbolLoad : Pos 3, 1 Bit
PAGE:0063F44E                                                 ;    +0x289 Prefetching      : Pos 4, 1 Bit
PAGE:0063F44E                                                 ;    +0x289 OwnsDynamicMemoryShared : Pos 5, 1 Bit
PAGE:0063F44E                                                 ;    +0x289 OwnsChangeControlAreaExclusive : Pos 6, 1 Bit
PAGE:0063F44E                                                 ;    +0x289 OwnsChangeControlAreaShared : Pos 7, 1 Bi
PAGE:0063F455 F6 86 70 02 00 00+test    byte ptr [esi+270h], 20h ; ???判断此进程的空间是否准备删除,EPROCESS->VmDeleted,如果删除就返回了
PAGE:0063F455 20                                              ; +0x270 Flags            : Uint4B
PAGE:0063F455                                                 ;    +0x270 CreateReported   : Pos 0, 1 Bit
PAGE:0063F455                                                 ;    +0x270 NoDebugInherit   : Pos 1, 1 Bit
PAGE:0063F455                                                 ;    +0x270 ProcessExiting   : Pos 2, 1 Bit
PAGE:0063F455                                                 ;    +0x270 ProcessDelete    : Pos 3, 1 Bit
PAGE:0063F455                                                 ;    +0x270 Wow64SplitPages  : Pos 4, 1 Bit
PAGE:0063F455                                                 ;    +0x270 VmDeleted        : Pos 5, 1 Bit
PAGE:0063F455                                                 ;    +0x270 OutswapEnabled   : Pos 6, 1 Bit
PAGE:0063F455                                                 ;    +0x270 Outswapped       : Pos 7, 1 Bit
PAGE:0063F455                                                 ;    +0x270 ForkFailed       : Pos 8, 1 Bit
PAGE:0063F455                                                 ;    +0x270 Wow64VaSpace4Gb  : Pos 9, 1 Bit
PAGE:0063F455                                                 ;    +0x270 AddressSpaceInitialized : Pos 10, 2 Bits
PAGE:0063F455                                                 ;    +0x270 SetTimerResolution : Pos 12, 1 Bit
PAGE:0063F455                                                 ;    +0x270 BreakOnTermination : Pos 13, 1 Bit
PAGE:0063F455                                                 ;    +0x270 DeprioritizeViews : Pos 14, 1 Bit
PAGE:0063F455                                                 ;    +0x270 WriteWatch       : Pos 15, 1 Bit
PAGE:0063F455                                                 ;    +0x270 ProcessInSession : Pos 16, 1 Bit
PAGE:0063F455                                                 ;    +0x270 OverrideAddressSpace : Pos 17, 1 Bit
PAGE:0063F455                                                 ;    +0x270 HasAddressSpace  : Pos 18, 1 Bit
PAGE:0063F455                                                 ;    +0x270 LaunchPrefetched : Pos 19, 1 Bit
PAGE:0063F455                                                 ;    +0x270 InjectInpageErrors : Pos 20, 1 Bit
PAGE:0063F455                                                 ;    +0x270 VmTopDown        : Pos 21, 1 Bit
PAGE:0063F455                                                 ;    +0x2
PAGE:0063F45C 74 67             jz      short loc_63F4C5      ; 正常流程跳转
PAGE:0063F45E 33 C9             xor     ecx, ecx              ; 肯定是如果准备删除了这里会需要处理资源
PAGE:0063F460 8D 86 00 01 00 00 lea     eax, [esi+100h]
PAGE:0063F466 8B D0             mov     edx, eax
PAGE:0063F468 6A 11             push    11h
PAGE:0063F46A 58                pop     eax
PAGE:0063F46B F0 0F B1 0A       lock cmpxchg [edx], ecx
PAGE:0063F46F 83 F8 11          cmp     eax, 11h
PAGE:0063F472 74 0B             jz      short loc_63F47F
PAGE:0063F474 8D 8E 00 01 00 00 lea     ecx, [esi+100h]
PAGE:0063F47A E8 7B 78 E4 FF    call    @ExfReleasePushLockShared@4 ; //释放锁
PAGE:0063F47F
PAGE:0063F47F                   loc_63F47F:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+230j
PAGE:0063F47F 80 A3 89 02 00 00+and     byte ptr [ebx+289h], 0FBh
PAGE:0063F486 66 FF 83 86 00 00+inc     word ptr [ebx+86h]
PAGE:0063F48D 0F B7 83 86 00 00+movzx   eax, word ptr [ebx+86h]
PAGE:0063F494 66 85 C0          test    ax, ax
PAGE:0063F497 75 0C             jnz     short loc_63F4A5
PAGE:0063F499 83 C3 40          add     ebx, 40h
PAGE:0063F49C 39 1B             cmp     [ebx], ebx
PAGE:0063F49E 74 05             jz      short loc_63F4A5
PAGE:0063F4A0 E8 D2 DE DE FF    call    _KiCheckForKernelApcDelivery@0 ; KiCheckForKernelApcDelivery()
PAGE:0063F4A5
PAGE:0063F4A5                   loc_63F4A5:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+255j
PAGE:0063F4A5                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x)+25Cj
PAGE:0063F4A5 F6 45 E4 01       test    byte ptr [ebp+var_1C??Attached], 1
PAGE:0063F4A9 74 10             jz      short loc_63F4BB
PAGE:0063F4AB 8D 45 A0          lea     eax, [ebp+ApcState]
PAGE:0063F4AE 50                push    eax
PAGE:0063F4AF E8 9E 37 E2 FF    call    _KeUnstackDetachProcess@4 ; KeUnstackDetachProcess(x)
PAGE:0063F4B4 8B CE             mov     ecx, esi              ; Object
PAGE:0063F4B6 E8 72 6F E1 FF    call    @ObfDereferenceObject@4 ; ObfDereferenceObject(x)
PAGE:0063F4BB
PAGE:0063F4BB                   loc_63F4BB:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+267j
PAGE:0063F4BB B8 0A 01 00 C0    mov     eax, 0C000010Ah       ; STATUS_PROCESS_IS_TERMINATING
PAGE:0063F4C0 E9 84 04 00 00    jmp     loc_63F949
PAGE:0063F4C5                   ; ---------------------------------------------------------------------------
PAGE:0063F4C5
PAGE:0063F4C5                   loc_63F4C5:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+21Aj
PAGE:0063F4C5 F7 86 8C 02 00 00+test    dword ptr [esi+28Ch], 0FFFFFF00h ; esi==Process
PAGE:0063F4C5 00 FF FF FF                                     ; +0x28c实际+0x014 NumberGenericTableElements : Pos 8, 24 Bits
PAGE:0063F4C5                                                 ; 判断节点数量
PAGE:0063F4CF 74 3D             jz      short loc_63F50E
PAGE:0063F4D1 8B 45 E0          mov     eax, [ebp+EProcess]
PAGE:0063F4D4 8B B0 80 02 00 00 mov     esi, [eax+280h]       ; esi == Process->VadRoot->RightChild
PAGE:0063F4DA 8B 45 0C          mov     eax, [ebp+BaseAddress]
PAGE:0063F4DD 8B C8             mov     ecx, eax
PAGE:0063F4DF C1 E9 0C          shr     ecx, 0Ch              ; 右移12位,取得高20位,获得页帧编号
PAGE:0063F4DF                                                 ; ecx == 查询地址的页帧编号
PAGE:0063F4E2 EB 1E             jmp     short loc_63F502
PAGE:0063F4E4                   ; ---------------------------------------------------------------------------
PAGE:0063F4E4
PAGE:0063F4E4                   loc_63F4E4:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+2C2j
PAGE:0063F4E4 8B 56 0C          mov     edx, [esi+0Ch]        ; 遍历AVL树
PAGE:0063F4E7 3B CA             cmp     ecx, edx
PAGE:0063F4E9 72 09             jb      short loc_63F4F4
PAGE:0063F4EB 3B 4E 10          cmp     ecx, [esi+10h]
PAGE:0063F4EE 76 18             jbe     short loc_63F508      ; ???
PAGE:0063F4F0 3B CA             cmp     ecx, edx
PAGE:0063F4F2 73 05             jnb     short loc_63F4F9
PAGE:0063F4F4
PAGE:0063F4F4                   loc_63F4F4:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+2A7j
PAGE:0063F4F4 8B 56 04          mov     edx, [esi+4]
PAGE:0063F4F7 EB 03             jmp     short loc_63F4FC
PAGE:0063F4F9                   ; ---------------------------------------------------------------------------
PAGE:0063F4F9
PAGE:0063F4F9                   loc_63F4F9:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+2B0j
PAGE:0063F4F9 8B 56 08          mov     edx, [esi+8]
PAGE:0063F4FC
PAGE:0063F4FC                   loc_63F4FC:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+2B5j
PAGE:0063F4FC 85 D2             test    edx, edx
PAGE:0063F4FE 74 15             jz      short loc_63F515
PAGE:0063F500 8B F2             mov     esi, edx
PAGE:0063F502
PAGE:0063F502                   loc_63F502:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+2A0j
PAGE:0063F502 85 F6             test    esi, esi              ; 判断子节点是否有效
PAGE:0063F504 75 DE             jnz     short loc_63F4E4      ; 如果有效就跳转,遍历AVL树
PAGE:0063F506 EB 0D             jmp     short loc_63F515      ; 退出循环
PAGE:0063F508                   ; ---------------------------------------------------------------------------
PAGE:0063F508
PAGE:0063F508                   loc_63F508:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+2ACj
PAGE:0063F508 83 4D E4 02       or      [ebp+var_1C??Attached], 2 ; 如果之前有靠挂,Attached为1,此时or 2 ,Attached==3
PAGE:0063F508                                                 ; 如果没有靠挂,此时Attached = 2
PAGE:0063F50C EB 07             jmp     short loc_63F515
PAGE:0063F50E                   ; ---------------------------------------------------------------------------
PAGE:0063F50E
PAGE:0063F50E                   loc_63F50E:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+28Dj
PAGE:0063F50E 33 F6             xor     esi, esi
PAGE:0063F510 33 C9             xor     ecx, ecx
PAGE:0063F512 8B 45 0C          mov     eax, [ebp+BaseAddress]
PAGE:0063F515
PAGE:0063F515                   loc_63F515:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+2BCj
PAGE:0063F515                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x)+2C4j
PAGE:0063F515                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x)+2CAj
PAGE:0063F515 F6 45 E4 02       test    byte ptr [ebp+var_1C??Attached], 2 ; 一般情况此时Attached=3,跳转发生
PAGE:0063F519 0F 85 0D 01 00 00 jnz     loc_63F62C
PAGE:0063F51F 85 F6             test    esi, esi
PAGE:0063F521 75 09             jnz     short loc_63F52C
PAGE:0063F523
PAGE:0063F523                   loc_63F523:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+2FAj
PAGE:0063F523 8B 75 D8          mov     esi, [ebp+var_28]
PAGE:0063F526 2B 75 14          sub     esi, [ebp+MemoryInformation]
PAGE:0063F529 46                inc     esi
PAGE:0063F52A EB 25             jmp     short loc_63F551
PAGE:0063F52C                   ; ---------------------------------------------------------------------------
PAGE:0063F52C
PAGE:0063F52C                   loc_63F52C:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+2DFj
PAGE:0063F52C 8B 46 0C          mov     eax, [esi+0Ch]
PAGE:0063F52F 3B C1             cmp     eax, ecx
PAGE:0063F531 73 16             jnb     short loc_63F549
PAGE:0063F533 8B CE             mov     ecx, esi
PAGE:0063F535 E8 E2 8D E4 FF    call    @MiGetNextNode@4      ; MiGetNextNode(x)
PAGE:0063F53A 85 C0             test    eax, eax
PAGE:0063F53C 74 E5             jz      short loc_63F523
PAGE:0063F53E 8B 70 0C          mov     esi, [eax+0Ch]
PAGE:0063F541 C1 E6 0C          shl     esi, 0Ch
PAGE:0063F544 2B 75 14          sub     esi, [ebp+MemoryInformation]
PAGE:0063F547 EB 08             jmp     short loc_63F551
PAGE:0063F549                   ; ---------------------------------------------------------------------------
PAGE:0063F549
PAGE:0063F549                   loc_63F549:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+2EFj
PAGE:0063F549 C1 E0 0C          shl     eax, 0Ch
PAGE:0063F54C 2B 45 14          sub     eax, [ebp+MemoryInformation]
PAGE:0063F54F 8B F0             mov     esi, eax
PAGE:0063F551
PAGE:0063F551                   loc_63F551:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+2E8j
PAGE:0063F551                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x)+305j
PAGE:0063F551 33 C9             xor     ecx, ecx
PAGE:0063F553 8B 45 E0          mov     eax, [ebp+EProcess]
PAGE:0063F556 05 00 01 00 00    add     eax, 100h
PAGE:0063F55B 8B D0             mov     edx, eax
PAGE:0063F55D 6A 11             push    11h
PAGE:0063F55F 58                pop     eax
PAGE:0063F560 F0 0F B1 0A       lock cmpxchg [edx], ecx
PAGE:0063F564 83 F8 11          cmp     eax, 11h
PAGE:0063F567 74 0E             jz      short loc_63F577
PAGE:0063F569 8B 4D E0          mov     ecx, [ebp+EProcess]
PAGE:0063F56C 81 C1 00 01 00 00 add     ecx, 100h
PAGE:0063F572 E8 83 77 E4 FF    call    @ExfReleasePushLockShared@4 ; ExfReleasePushLockShared(x)
PAGE:0063F577
PAGE:0063F577                   loc_63F577:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+325j
PAGE:0063F577 80 A3 89 02 00 00+and     byte ptr [ebx+289h], 0FBh
PAGE:0063F57E 66 FF 83 86 00 00+inc     word ptr [ebx+86h]
PAGE:0063F585 0F B7 83 86 00 00+movzx   eax, word ptr [ebx+86h]
PAGE:0063F58C 66 85 C0          test    ax, ax
PAGE:0063F58F 75 0C             jnz     short loc_63F59D
PAGE:0063F591 83 C3 40          add     ebx, 40h
PAGE:0063F594 39 1B             cmp     [ebx], ebx
PAGE:0063F596 74 05             jz      short loc_63F59D
PAGE:0063F598 E8 DA DD DE FF    call    _KiCheckForKernelApcDelivery@0 ; KiCheckForKernelApcDelivery()
PAGE:0063F59D
PAGE:0063F59D                   loc_63F59D:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+34Dj
PAGE:0063F59D                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x)+354j
PAGE:0063F59D F6 45 E4 01       test    byte ptr [ebp+var_1C??Attached], 1
PAGE:0063F5A1 74 11             jz      short loc_63F5B4
PAGE:0063F5A3 8D 45 A0          lea     eax, [ebp+ApcState]
PAGE:0063F5A6 50                push    eax
PAGE:0063F5A7 E8 A6 36 E2 FF    call    _KeUnstackDetachProcess@4 ; KeUnstackDetachProcess(x)
PAGE:0063F5AC 8B 4D E0          mov     ecx, [ebp+EProcess]   ; Object
PAGE:0063F5AF E8 79 6E E1 FF    call    @ObfDereferenceObject@4 ; ObfDereferenceObject(x)
PAGE:0063F5B4
PAGE:0063F5B4                   loc_63F5B4:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+35Fj
PAGE:0063F5B4 33 C9             xor     ecx, ecx
PAGE:0063F5B6 39 4D 10          cmp     [ebp+MemoryInformationClass], ecx
PAGE:0063F5B9 75 67             jnz     short loc_63F622
PAGE:0063F5BB 83 65 E4 FD       and     [ebp+var_1C??Attached], 0FFFFFFFDh
PAGE:0063F5BF C7 45 FC 04 00 00+mov     [ebp+ms_exc.registration.TryLevel], 4
PAGE:0063F5C6 89 4F 04          mov     [edi+4], ecx
PAGE:0063F5C9 89 4F 08          mov     [edi+8], ecx
PAGE:0063F5CC 8B 45 14          mov     eax, [ebp+MemoryInformation]
PAGE:0063F5CF 89 07             mov     [edi], eax
PAGE:0063F5D1 89 77 0C          mov     [edi+0Ch], esi
PAGE:0063F5D4 C7 47 10 00 00 01+mov     dword ptr [edi+10h], 10000h
PAGE:0063F5DB C7 47 14 01 00 00+mov     dword ptr [edi+14h], 1
PAGE:0063F5E2 89 4F 18          mov     [edi+18h], ecx
PAGE:0063F5E5 83 4D E4 02       or      [ebp+var_1C??Attached], 2
PAGE:0063F5E9 8B 45 1C          mov     eax, [ebp+ReturnLength]
PAGE:0063F5EC 3B C1             cmp     eax, ecx
PAGE:0063F5EE
PAGE:0063F5EE                   loc_63F5EE:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+5FDj
PAGE:0063F5EE 0F 84 C5 FD FF FF jz      loc_63F3B9
PAGE:0063F5F4 C7 00 1C 00 00 00 mov     dword ptr [eax], 1Ch
PAGE:0063F5FA E9 BA FD FF FF    jmp     loc_63F3B9
PAGE:0063F5FF                   ; ---------------------------------------------------------------------------
PAGE:0063F5FF
PAGE:0063F5FF                   loc_63F5FF:                   ; DATA XREF: .text:stru_450F18o
PAGE:0063F5FF 8B 45 EC          mov     eax, [ebp+ms_exc.exc_ptr] ; Exception filter 4 for function 63F242
PAGE:0063F602 8B 00             mov     eax, [eax]
PAGE:0063F604 8B 00             mov     eax, [eax]
PAGE:0063F606 89 45 C8          mov     [ebp+var_38], eax
PAGE:0063F609 33 C0             xor     eax, eax
PAGE:0063F60B 40                inc     eax
PAGE:0063F60C C3                retn
PAGE:0063F60D                   ; ---------------------------------------------------------------------------
PAGE:0063F60D
PAGE:0063F60D                   loc_63F60D:                   ; DATA XREF: .text:stru_450F18o
PAGE:0063F60D 8B 65 E8          mov     esp, [ebp+ms_exc.old_esp] ; Exception handler 4 for function 63F242
PAGE:0063F610 F6 45 E4 02       test    byte ptr [ebp+var_1C??Attached], 2
PAGE:0063F614 0F 85 9F FD FF FF jnz     loc_63F3B9
PAGE:0063F61A 8B 45 C8          mov     eax, [ebp+var_38]
PAGE:0063F61D E9 CB FC FF FF    jmp     loc_63F2ED
PAGE:0063F622                   ; ---------------------------------------------------------------------------
PAGE:0063F622
PAGE:0063F622                   loc_63F622:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+377j
PAGE:0063F622                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x)+629j
PAGE:0063F622 B8 41 01 00 C0    mov     eax, 0C0000141h
PAGE:0063F627 E9 1D 03 00 00    jmp     loc_63F949
PAGE:0063F62C                   ; ---------------------------------------------------------------------------
PAGE:0063F62C
PAGE:0063F62C                   loc_63F62C:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+2D7j
PAGE:0063F62C 25 00 F0 FF FF    and     eax, 0FFFFF000h       ; eax == BaseAddress,这里取BaseAddress的虚拟内存页的首地址
PAGE:0063F631 89 45 0C          mov     [ebp+BaseAddress], eax
PAGE:0063F634 89 45 84          mov     [ebp+var_7C], eax
PAGE:0063F637 8B 46 0C          mov     eax, [esi+0Ch]        ; 取得此子节点的起始编号 MMVAD->StartingVpn
PAGE:0063F63A C1 E0 0C          shl     eax, 0Ch              ; 左移12位,取得虚拟内存页的页首地址
PAGE:0063F63D 89 45 88          mov     [ebp+var_78], eax
PAGE:0063F640 8B 46 14          mov     eax, [esi+14h]        ; 取得MMVAD->u 其实是此节点的内存描述信息,
PAGE:0063F640                                                 ; u是一个联合体,表示一个Flags
PAGE:0063F643 8B C8             mov     ecx, eax              ; ???对Flag进行某种运算
PAGE:0063F645 C1 E9 18          shr     ecx, 18h
PAGE:0063F648 83 E1 1F          and     ecx, 1Fh
PAGE:0063F64B 8B 0C 8D E8 1E 44+mov     ecx, ds:_MmProtectToValue[ecx*4] ; 很明显是取数组中的元素,
PAGE:0063F64B 00                                              ; 可以在Windbg中kd> dd MmProtectToValue查看
PAGE:0063F64B                                                 ; 其实MmProtectToValue就是一个数组,保存内存页的保护属性,
PAGE:0063F64B                                                 ; 前面的Flags其实就是得到数组的下标,然后从中取出值
PAGE:0063F652 89 4D 8C          mov     [ebp+var_74], ecx     ; 保存查询地址的内存页属性
PAGE:0063F655 85 C0             test    eax, eax
PAGE:0063F657 79 09             jns     short loc_63F662
PAGE:0063F659 C7 45 9C 00 00 02+mov     [ebp+var_64], 20000h
PAGE:0063F660 EB 61             jmp     short loc_63F6C3
PAGE:0063F662                   ; ---------------------------------------------------------------------------
PAGE:0063F662
PAGE:0063F662                   loc_63F662:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+415j
PAGE:0063F662 25 00 00 70 00    and     eax, (offset loc_6FFFFD+3) ; ????
PAGE:0063F667 2D 00 00 20 00    sub     eax, 200000h
PAGE:0063F66C F7 D8             neg     eax                   ; ????指令不懂
PAGE:0063F66E 1B C0             sbb     eax, eax
PAGE:0063F670 25 00 00 04 FF    and     eax, 0FF040000h
PAGE:0063F675 05 00 00 00 01    add     eax, 1000000h
PAGE:0063F67A 89 45 9C          mov     [ebp+var_64], eax     ; 之前就是对Flag进行某种运算,再保存
PAGE:0063F67D 83 7D 10 02       cmp     [ebp+MemoryInformationClass], 2 ; 我们就是2
PAGE:0063F681 75 40             jnz     short loc_63F6C3
PAGE:0063F683 8B 46 24          mov     eax, [esi+24h]        ; MMVAD->Subsection->ControlArea
PAGE:0063F686 83 38 00          cmp     dword ptr [eax], 0    ; 判断CONTROL_AREA->Segment 是否有效
PAGE:0063F689 74 2B             jz      short loc_63F6B6      ; 无效则跳转
PAGE:0063F68B 8B 00             mov     eax, [eax]
PAGE:0063F68D 89 45 08          mov     [ebp+ProcessHandle], eax ; 取出来,保存
PAGE:0063F690 8B 40 24          mov     eax, [eax+24h]        ; CONTROL_AREA->FilePointer 结构类型_EX_FAST_REF
PAGE:0063F693 83 E0 F8          and     eax, 0FFFFFFF8h       ; 去除标志,只要是CONTROL_AREA下的文件指针,
PAGE:0063F693                                                 ; 全部都要这样去除标志,得到文件对象
PAGE:0063F696 89 45 DC          mov     [ebp+var_24], eax     ; 保存这块虚拟内存的文件对象FilePointer
PAGE:0063F699 74 1B             jz      short loc_63F6B6
PAGE:0063F69B 8B 45 08          mov     eax, [ebp+ProcessHandle]
PAGE:0063F69E 83 C0 24          add     eax, 24h              ; PEX_FAST_REF结构
PAGE:0063F6A1 50                push    eax
PAGE:0063F6A2 E8 5F F5 E1 FF    call    @ObFastReferenceObject@4 ; 快速引用一个对象
PAGE:0063F6A7 85 C0             test    eax, eax              ; 判断文件对象是否有效
PAGE:0063F6A9 75 08             jnz     short loc_63F6B3      ; 有效跳转
PAGE:0063F6AB FF 75 08          push    [ebp+ProcessHandle]
PAGE:0063F6AE E8 A3 93 E5 FF    call    _MiReferenceControlAreaFile@4 ; MiReferenceControlAreaFile(x)
PAGE:0063F6B3
PAGE:0063F6B3                   loc_63F6B3:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+467j
PAGE:0063F6B3 89 45 DC          mov     [ebp+var_24], eax     ; 保存_File_Object
PAGE:0063F6B6
PAGE:0063F6B6                   loc_63F6B6:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+447j
PAGE:0063F6B6                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x)+457j
PAGE:0063F6B6 83 7D DC 00       cmp     [ebp+var_24], 0       ; 判断对象引用是否成功
PAGE:0063F6BA 75 07             jnz     short loc_63F6C3      ; 引用成功则跳转
PAGE:0063F6BC C7 45 DC 01 00 00+mov     [ebp+var_24], 1
PAGE:0063F6C3
PAGE:0063F6C3                   loc_63F6C3:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+41Ej
PAGE:0063F6C3                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x)+43Fj
PAGE:0063F6C3                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x)+478j
PAGE:0063F6C3 83 7D 10 03       cmp     [ebp+MemoryInformationClass], 3 ; 我们的方式是2
PAGE:0063F6C7 0F 85 D5 00 00 00 jnz     loc_63F7A2            ; 不为 3 就跳转
PAGE:0063F6CD 8B 4E 10          mov     ecx, [esi+10h]
PAGE:0063F6D0 2B 4E 0C          sub     ecx, [esi+0Ch]
PAGE:0063F6D3 41                inc     ecx
PAGE:0063F6D4 C1 E1 0C          shl     ecx, 0Ch
PAGE:0063F6D7 89 4D 10          mov     [ebp+MemoryInformationClass], ecx
PAGE:0063F6DA 33 D2             xor     edx, edx
PAGE:0063F6DC 8B 45 E0          mov     eax, [ebp+EProcess]
PAGE:0063F6DF 05 00 01 00 00    add     eax, 100h
PAGE:0063F6E4 8B F0             mov     esi, eax
PAGE:0063F6E6 6A 11             push    11h
PAGE:0063F6E8 58                pop     eax
PAGE:0063F6E9 F0 0F B1 16       lock cmpxchg [esi], edx
PAGE:0063F6ED 83 F8 11          cmp     eax, 11h
PAGE:0063F6F0 74 11             jz      short loc_63F703
PAGE:0063F6F2 8B 4D E0          mov     ecx, [ebp+EProcess]
PAGE:0063F6F5 81 C1 00 01 00 00 add     ecx, 100h
PAGE:0063F6FB E8 FA 75 E4 FF    call    @ExfReleasePushLockShared@4 ; ExfReleasePushLockShared(x)
PAGE:0063F700 8B 4D 10          mov     ecx, [ebp+MemoryInformationClass]
PAGE:0063F703
PAGE:0063F703                   loc_63F703:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+4AEj
PAGE:0063F703 80 A3 89 02 00 00+and     byte ptr [ebx+289h], 0FBh
PAGE:0063F70A 66 FF 83 86 00 00+inc     word ptr [ebx+86h]
PAGE:0063F711 0F B7 83 86 00 00+movzx   eax, word ptr [ebx+86h]
PAGE:0063F718 66 85 C0          test    ax, ax
PAGE:0063F71B 75 0F             jnz     short loc_63F72C
PAGE:0063F71D 83 C3 40          add     ebx, 40h
PAGE:0063F720 39 1B             cmp     [ebx], ebx
PAGE:0063F722 74 08             jz      short loc_63F72C
PAGE:0063F724 E8 4E DC DE FF    call    _KiCheckForKernelApcDelivery@0 ; KiCheckForKernelApcDelivery()
PAGE:0063F729 8B 4D 10          mov     ecx, [ebp+MemoryInformationClass]
PAGE:0063F72C
PAGE:0063F72C                   loc_63F72C:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+4D9j
PAGE:0063F72C                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x)+4E0j
PAGE:0063F72C F6 45 E4 01       test    byte ptr [ebp+var_1C??Attached], 1
PAGE:0063F730 74 14             jz      short loc_63F746
PAGE:0063F732 8D 45 A0          lea     eax, [ebp+ApcState]
PAGE:0063F735 50                push    eax
PAGE:0063F736 E8 17 35 E2 FF    call    _KeUnstackDetachProcess@4 ; KeUnstackDetachProcess(x)
PAGE:0063F73B 8B 4D E0          mov     ecx, [ebp+EProcess]   ; Object
PAGE:0063F73E E8 EA 6C E1 FF    call    @ObfDereferenceObject@4 ; ObfDereferenceObject(x)
PAGE:0063F743 8B 4D 10          mov     ecx, [ebp+MemoryInformationClass]
PAGE:0063F746
PAGE:0063F746                   loc_63F746:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+4EEj
PAGE:0063F746 83 65 E4 FD       and     [ebp+var_1C??Attached], 0FFFFFFFDh
PAGE:0063F74A C7 45 FC 05 00 00+mov     [ebp+ms_exc.registration.TryLevel], 5
PAGE:0063F751 8B 45 88          mov     eax, [ebp+var_78]
PAGE:0063F754 89 07             mov     [edi], eax
PAGE:0063F756 8B 45 8C          mov     eax, [ebp+var_74]
PAGE:0063F759 89 47 04          mov     [edi+4], eax
PAGE:0063F75C 8B 45 9C          mov     eax, [ebp+var_64]
PAGE:0063F75F 89 47 08          mov     [edi+8], eax
PAGE:0063F762 89 4F 0C          mov     [edi+0Ch], ecx
PAGE:0063F765 83 4D E4 02       or      [ebp+var_1C??Attached], 2
PAGE:0063F769 8B 45 1C          mov     eax, [ebp+ReturnLength]
PAGE:0063F76C 85 C0             test    eax, eax
PAGE:0063F76E 0F 84 45 FC FF FF jz      loc_63F3B9
PAGE:0063F774 C7 00 10 00 00 00 mov     dword ptr [eax], 10h
PAGE:0063F77A E9 3A FC FF FF    jmp     loc_63F3B9
PAGE:0063F77F                   ; ---------------------------------------------------------------------------
PAGE:0063F77F
PAGE:0063F77F                   loc_63F77F:                   ; DATA XREF: .text:stru_450F18o
PAGE:0063F77F 8B 45 EC          mov     eax, [ebp+ms_exc.exc_ptr] ; Exception filter 5 for function 63F242
PAGE:0063F782 8B 00             mov     eax, [eax]
PAGE:0063F784 8B 00             mov     eax, [eax]
PAGE:0063F786 89 45 C4          mov     [ebp+var_3C], eax
PAGE:0063F789 33 C0             xor     eax, eax
PAGE:0063F78B 40                inc     eax
PAGE:0063F78C C3                retn
PAGE:0063F78D                   ; ---------------------------------------------------------------------------
PAGE:0063F78D
PAGE:0063F78D                   loc_63F78D:                   ; DATA XREF: .text:stru_450F18o
PAGE:0063F78D 8B 65 E8          mov     esp, [ebp+ms_exc.old_esp] ; Exception handler 5 for function 63F242
PAGE:0063F790 F6 45 E4 02       test    byte ptr [ebp+var_1C??Attached], 2
PAGE:0063F794 0F 85 1F FC FF FF jnz     loc_63F3B9
PAGE:0063F79A 8B 45 C4          mov     eax, [ebp+var_3C]
PAGE:0063F79D E9 4B FB FF FF    jmp     loc_63F2ED
PAGE:0063F7A2                   ; ---------------------------------------------------------------------------
PAGE:0063F7A2
PAGE:0063F7A2                   loc_63F7A2:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+485j
PAGE:0063F7A2 83 7D 10 00       cmp     [ebp+MemoryInformationClass], 0 ; 我们是2,继续跳转
PAGE:0063F7A6 75 12             jnz     short loc_63F7BA
PAGE:0063F7A8 56                push    esi
PAGE:0063F7A9 FF 75 0C          push    [ebp+BaseAddress]
PAGE:0063F7AC 8D 45 84          lea     eax, [ebp+var_7C]
PAGE:0063F7AF E8 7E B2 E4 FF    call    _MiQueryAddressSpan@12 ; MiQueryAddressSpan(x,x,x)
PAGE:0063F7B4 2B 45 84          sub     eax, [ebp+var_7C]
PAGE:0063F7B7 89 45 90          mov     [ebp+var_70], eax
PAGE:0063F7BA
PAGE:0063F7BA                   loc_63F7BA:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+564j
PAGE:0063F7BA 33 C9             xor     ecx, ecx
PAGE:0063F7BC 8B 45 E0          mov     eax, [ebp+EProcess]
PAGE:0063F7BF 05 00 01 00 00    add     eax, 100h             ; +0x100 AddressCreationLock : _EX_PUSH_LOCK
PAGE:0063F7BF                                                 ; 地址空间锁
PAGE:0063F7C4 8B D0             mov     edx, eax
PAGE:0063F7C6 6A 11             push    11h
PAGE:0063F7C8 58                pop     eax
PAGE:0063F7C9 F0 0F B1 0A       lock cmpxchg [edx], ecx
PAGE:0063F7CD 83 F8 11          cmp     eax, 11h
PAGE:0063F7D0 74 0E             jz      short loc_63F7E0
PAGE:0063F7D2 8B 4D E0          mov     ecx, [ebp+EProcess]
PAGE:0063F7D5 81 C1 00 01 00 00 add     ecx, 100h
PAGE:0063F7DB E8 1A 75 E4 FF    call    @ExfReleasePushLockShared@4 ; ExfReleasePushLockShared(x)
PAGE:0063F7E0
PAGE:0063F7E0                   loc_63F7E0:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+58Ej
PAGE:0063F7E0 80 A3 89 02 00 00+and     byte ptr [ebx+289h], 0FBh
PAGE:0063F7E7 66 FF 83 86 00 00+inc     word ptr [ebx+86h]
PAGE:0063F7EE 0F B7 83 86 00 00+movzx   eax, word ptr [ebx+86h]
PAGE:0063F7F5 66 85 C0          test    ax, ax
PAGE:0063F7F8 75 0C             jnz     short loc_63F806
PAGE:0063F7FA 83 C3 40          add     ebx, 40h
PAGE:0063F7FD 39 1B             cmp     [ebx], ebx
PAGE:0063F7FF 74 05             jz      short loc_63F806
PAGE:0063F801 E8 71 DB DE FF    call    _KiCheckForKernelApcDelivery@0 ; KiCheckForKernelApcDelivery()
PAGE:0063F806
PAGE:0063F806                   loc_63F806:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+5B6j
PAGE:0063F806                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x)+5BDj
PAGE:0063F806 F6 45 E4 01       test    byte ptr [ebp+var_1C??Attached], 1 ; 判断进程是否靠挂
PAGE:0063F80A 74 11             jz      short loc_63F81D
PAGE:0063F80C 8D 45 A0          lea     eax, [ebp+ApcState]
PAGE:0063F80F 50                push    eax
PAGE:0063F810 E8 3D 34 E2 FF    call    _KeUnstackDetachProcess@4 ; KeUnstackDetachProcess(x)
PAGE:0063F815 8B 4D E0          mov     ecx, [ebp+EProcess]   ; Object
PAGE:0063F818 E8 10 6C E1 FF    call    @ObfDereferenceObject@4 ; 解除对进程对象的引用
PAGE:0063F81D
PAGE:0063F81D                   loc_63F81D:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+5C8j
PAGE:0063F81D 83 7D 10 00       cmp     [ebp+MemoryInformationClass], 0
PAGE:0063F821 75 44             jnz     short loc_63F867
PAGE:0063F823 83 65 E4 FD       and     [ebp+var_1C??Attached], 0FFFFFFFDh
PAGE:0063F827 C7 45 FC 06 00 00+mov     [ebp+ms_exc.registration.TryLevel], 6
PAGE:0063F82E 6A 07             push    7
PAGE:0063F830 59                pop     ecx
PAGE:0063F831 8D 75 84          lea     esi, [ebp+var_7C]
PAGE:0063F834 F3 A5             rep movsd
PAGE:0063F836 83 4D E4 02       or      [ebp+var_1C??Attached], 2
PAGE:0063F83A 8B 45 1C          mov     eax, [ebp+ReturnLength]
PAGE:0063F83D 85 C0             test    eax, eax
PAGE:0063F83F E9 AA FD FF FF    jmp     loc_63F5EE
PAGE:0063F844                   ; ---------------------------------------------------------------------------
PAGE:0063F844
PAGE:0063F844                   loc_63F844:                   ; DATA XREF: .text:stru_450F18o
PAGE:0063F844 8B 45 EC          mov     eax, [ebp+ms_exc.exc_ptr] ; Exception filter 6 for function 63F242
PAGE:0063F847 8B 00             mov     eax, [eax]
PAGE:0063F849 8B 00             mov     eax, [eax]
PAGE:0063F84B 89 45 C0          mov     [ebp+var_40], eax
PAGE:0063F84E 33 C0             xor     eax, eax
PAGE:0063F850 40                inc     eax
PAGE:0063F851 C3                retn
PAGE:0063F852                   ; ---------------------------------------------------------------------------
PAGE:0063F852
PAGE:0063F852                   loc_63F852:                   ; DATA XREF: .text:stru_450F18o
PAGE:0063F852 8B 65 E8          mov     esp, [ebp+ms_exc.old_esp] ; Exception handler 6 for function 63F242
PAGE:0063F855 F6 45 E4 02       test    byte ptr [ebp+var_1C??Attached], 2
PAGE:0063F859 0F 85 5A FB FF FF jnz     loc_63F3B9
PAGE:0063F85F 8B 45 C0          mov     eax, [ebp+var_40]
PAGE:0063F862 E9 86 FA FF FF    jmp     loc_63F2ED
PAGE:0063F867                   ; ---------------------------------------------------------------------------
PAGE:0063F867
PAGE:0063F867                   loc_63F867:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+5DFj
PAGE:0063F867 83 7D DC 00       cmp     [ebp+var_24], 0       ; 又是对文件对象的判断
PAGE:0063F86B 0F 84 B1 FD FF FF jz      loc_63F622            ; 为NULL,跳转
PAGE:0063F871 83 7D DC 01       cmp     [ebp+var_24], 1
PAGE:0063F875 75 0A             jnz     short loc_63F881      ; 有效,则跳转
PAGE:0063F877 B8 98 00 00 C0    mov     eax, 0C0000098h       ; STATUS_FILE_INVALID 错误码
PAGE:0063F87C E9 C8 00 00 00    jmp     loc_63F949
PAGE:0063F881                   ; ---------------------------------------------------------------------------
PAGE:0063F881
PAGE:0063F881                   loc_63F881:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+633j
PAGE:0063F881 8D 45 BC          lea     eax, [ebp+var_44]
PAGE:0063F884 50                push    eax                   ; ReturnLength
PAGE:0063F885 FF 75 18          push    [ebp+MemoryInformationLength] ; Length
PAGE:0063F888 57                push    edi                   ; ObjectNameInfo
PAGE:0063F889 FF 75 DC          push    [ebp+var_24]          ; Object
PAGE:0063F88C E8 0D 10 FE FF    call    _ObQueryNameString@16 ; 在wrk中搜函数原型
PAGE:0063F891 8B F0             mov     esi, eax
PAGE:0063F893 8B 4D DC          mov     ecx, [ebp+var_24]     ; Object
PAGE:0063F896 E8 92 6B E1 FF    call    @ObfDereferenceObject@4 ; 释放对文件对象的引用
PAGE:0063F89B 8B 45 1C          mov     eax, [ebp+ReturnLength] ; 判断传入的返回值是否为NULL
PAGE:0063F89E 85 C0             test    eax, eax
PAGE:0063F8A0 74 29             jz      short loc_63F8CB      ; 为NULL,则跳转
PAGE:0063F8A2 C7 45 FC 07 00 00+mov     [ebp+ms_exc.registration.TryLevel], 7
PAGE:0063F8A9 8B 4D BC          mov     ecx, [ebp+var_44]     ; 实际字符串的长度
PAGE:0063F8AC 89 08             mov     [eax], ecx            ; 返回实际字符串的长度
PAGE:0063F8AE EB 14             jmp     short loc_63F8C4
PAGE:0063F8B0                   ; ---------------------------------------------------------------------------
PAGE:0063F8B0
PAGE:0063F8B0                   loc_63F8B0:                   ; DATA XREF: .text:stru_450F18o
PAGE:0063F8B0 8B 45 EC          mov     eax, [ebp+ms_exc.exc_ptr] ; Exception filter 7 for function 63F242
PAGE:0063F8B3 8B 00             mov     eax, [eax]
PAGE:0063F8B5 8B 00             mov     eax, [eax]
PAGE:0063F8B7 89 45 B8          mov     [ebp+var_48], eax
PAGE:0063F8BA 33 C0             xor     eax, eax
PAGE:0063F8BC 40                inc     eax
PAGE:0063F8BD C3                retn
PAGE:0063F8BE                   ; ---------------------------------------------------------------------------
PAGE:0063F8BE
PAGE:0063F8BE                   loc_63F8BE:                   ; DATA XREF: .text:stru_450F18o
PAGE:0063F8BE 8B 65 E8          mov     esp, [ebp+ms_exc.old_esp] ; Exception handler 7 for function 63F242
PAGE:0063F8C1 8B 75 B8          mov     esi, [ebp+var_48]
PAGE:0063F8C4
PAGE:0063F8C4                   loc_63F8C4:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+66Cj
PAGE:0063F8C4 C7 45 FC FE FF FF+mov     [ebp+ms_exc.registration.TryLevel], 0FFFFFFFEh
PAGE:0063F8CB
PAGE:0063F8CB                   loc_63F8CB:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+65Ej
PAGE:0063F8CB 8B C6             mov     eax, esi              ; ObQueryNameString 返回的status
PAGE:0063F8CD EB 7A             jmp     short loc_63F949
PAGE:0063F8CF                   ; ---------------------------------------------------------------------------
PAGE:0063F8CF
PAGE:0063F8CF                   loc_63F8CF:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+E1j
PAGE:0063F8CF                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x)+F4j
PAGE:0063F8CF BB 41 01 00 C0    mov     ebx, 0C0000141h
PAGE:0063F8D4 83 7D 10 00       cmp     [ebp+MemoryInformationClass], 0
PAGE:0063F8D8 75 6D             jnz     short loc_63F947
PAGE:0063F8DA C7 45 FC 01 00 00+mov     [ebp+ms_exc.registration.TryLevel], 1
PAGE:0063F8E1 46                inc     esi
PAGE:0063F8E2 89 77 04          mov     [edi+4], esi
PAGE:0063F8E5 6A 02             push    2
PAGE:0063F8E7 5B                pop     ebx
PAGE:0063F8E8 89 5F 08          mov     [edi+8], ebx
PAGE:0063F8EB 8B F0             mov     esi, eax
PAGE:0063F8ED 23 F2             and     esi, edx
PAGE:0063F8EF 89 37             mov     [edi], esi
PAGE:0063F8F1 23 C2             and     eax, edx
PAGE:0063F8F3 2B C8             sub     ecx, eax
PAGE:0063F8F5 41                inc     ecx
PAGE:0063F8F6 89 4F 0C          mov     [edi+0Ch], ecx
PAGE:0063F8F9 C7 47 10 00 20 00+mov     dword ptr [edi+10h], 2000h
PAGE:0063F900 C7 47 14 01 00 00+mov     dword ptr [edi+14h], 1
PAGE:0063F907 C7 47 18 00 00 02+mov     dword ptr [edi+18h], 20000h
PAGE:0063F90E 8B 45 1C          mov     eax, [ebp+ReturnLength]
PAGE:0063F911 85 C0             test    eax, eax
PAGE:0063F913 74 06             jz      short loc_63F91B
PAGE:0063F915 C7 00 1C 00 00 00 mov     dword ptr [eax], 1Ch
PAGE:0063F91B
PAGE:0063F91B                   loc_63F91B:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+6D1j
PAGE:0063F91B B8 00 00 FE 7F    mov     eax, 7FFE0000h
PAGE:0063F920 3B F0             cmp     esi, eax
PAGE:0063F922 75 1A             jnz     short loc_63F93E
PAGE:0063F924 89 47 04          mov     [edi+4], eax
PAGE:0063F927 89 5F 14          mov     [edi+14h], ebx
PAGE:0063F92A B8 00 10 00 00    mov     eax, 1000h
PAGE:0063F92F 89 47 0C          mov     [edi+0Ch], eax
PAGE:0063F932 89 47 10          mov     [edi+10h], eax
PAGE:0063F935 EB 07             jmp     short loc_63F93E
PAGE:0063F937                   ; ---------------------------------------------------------------------------
PAGE:0063F937
PAGE:0063F937                   loc_63F937:                   ; DATA XREF: .text:stru_450F18o
PAGE:0063F937 33 C0             xor     eax, eax              ; Exception filter 1 for function 63F242
PAGE:0063F939 40                inc     eax
PAGE:0063F93A C3                retn
PAGE:0063F93B                   ; ---------------------------------------------------------------------------
PAGE:0063F93B
PAGE:0063F93B                   loc_63F93B:                   ; DATA XREF: .text:stru_450F18o
PAGE:0063F93B 8B 65 E8          mov     esp, [ebp+ms_exc.old_esp] ; Exception handler 1 for function 63F242
PAGE:0063F93E
PAGE:0063F93E                   loc_63F93E:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+6E0j
PAGE:0063F93E                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x)+6F3j
PAGE:0063F93E C7 45 FC FE FF FF+mov     [ebp+ms_exc.registration.TryLevel], 0FFFFFFFEh
PAGE:0063F945 33 DB             xor     ebx, ebx
PAGE:0063F947
PAGE:0063F947                   loc_63F947:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+1A7j
PAGE:0063F947                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x)+696j
PAGE:0063F947 8B C3             mov     eax, ebx
PAGE:0063F949
PAGE:0063F949                   loc_63F949:                   ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+2Cj
PAGE:0063F949                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x)+4Ej
PAGE:0063F949                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x)+B2j
PAGE:0063F949                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x)+CCj
PAGE:0063F949                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x)+12Cj
PAGE:0063F949                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x)+159j
PAGE:0063F949                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x)+180j
PAGE:0063F949                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x)+27Ej
PAGE:0063F949                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x)+3E5j
PAGE:0063F949                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x)+63Aj
PAGE:0063F949                                                 ; NtQueryVirtualMemory(x,x,x,x,x,x)+68Bj
PAGE:0063F949 E8 17 49 E1 FF    call    __SEH_epilog4
PAGE:0063F94E C2 18 00          retn    18h
PAGE:0063F94E                   _NtQueryVirtualMemory@24 endp
PAGE:0063F94E

 下面是wrk中的源代码

NTSTATUS
NtQueryVirtualMemory(
    __in HANDLE ProcessHandle,
    __in PVOID BaseAddress,
    __in MEMORY_INFORMATION_CLASS MemoryInformationClass,
    __out_bcount(MemoryInformationLength) PVOID MemoryInformation,
    __in SIZE_T MemoryInformationLength,
    __out_opt PSIZE_T ReturnLength
    )

/*++

Routine Description:

    This function provides the capability to determine the state,
    protection, and type of a region of pages within the virtual address
    space of the subject process.

    The state of the first page within the region is determined and then
    subsequent entries in the process address map are scanned from the
    base address upward until either the entire range of pages has been
    scanned or until a page with a nonmatching set of attributes is
    encountered. The region attributes, the length of the region of pages
    with matching attributes, and an appropriate status value are
    returned.

    If the entire region of pages does not have a matching set of
    attributes, then the returned length parameter value can be used to
    calculate the address and length of the region of pages that was not
    scanned.

Arguments:


    ProcessHandle - An open handle to a process object.

    BaseAddress - The base address of the region of pages to be
                  queried. This value is rounded down to the next host-page-
                  address boundary.

    MemoryInformationClass - The memory information class about which
                             to retrieve information.

    MemoryInformation - A pointer to a buffer that receives the specified
                        information.  The format and content of the buffer
                        depend on the specified information class.


        MemoryBasicInformation - Data type is PMEMORY_BASIC_INFORMATION.

            MEMORY_BASIC_INFORMATION Structure


            ULONG RegionSize - The size of the region in bytes beginning at
                               the base address in which all pages have
                               identical attributes.

            ULONG State - The state of the pages within the region.

                State Values

                MEM_COMMIT - The state of the pages within the region
                             is committed.

                MEM_FREE - The state of the pages within the region
                           is free.

                MEM_RESERVE - The state of the pages within the
                              region is reserved.

            ULONG Protect - The protection of the pages within the region.

                Protect Values

                PAGE_NOACCESS - No access to the region of pages is allowed.
                                An attempt to read, write, or execute within
                                the region results in an access violation.

                PAGE_EXECUTE - Execute access to the region of pages
                               is allowed. An attempt to read or write within
                               the region results in an access violation.

                PAGE_READONLY - Read-only and execute access to the region
                                of pages is allowed. An attempt to write within
                                the region results in an access violation.

                PAGE_READWRITE - Read, write, and execute access to the region
                                 of pages is allowed. If write access to the
                                 underlying section is allowed, then a single
                                 copy of the pages are shared. Otherwise,
                                 the pages are shared read-only/copy-on-write.

                PAGE_GUARD - Read, write, and execute access to the
                             region of pages is allowed; however, access to
                             the region causes a "guard region entered"
                             condition to be raised in the subject process.

                PAGE_NOCACHE - Disable the placement of committed
                               pages into the data cache.

                PAGE_WRITECOMBINE - Disable the placement of committed
                                    pages into the data cache, combine the
                                    writes as well.

            ULONG Type - The type of pages within the region.

                Type Values

                MEM_PRIVATE - The pages within the region are private.

                MEM_MAPPED - The pages within the region are mapped
                             into the view of a section.

                MEM_IMAGE - The pages within the region are mapped
                            into the view of an image section.

    MemoryInformationLength - Specifies the length in bytes of
                              the memory information buffer.

    ReturnLength - An optional pointer which, if specified, receives the
                   number of bytes placed in the process information buffer.

Return Value:

    NTSTATUS.

Environment:

    Kernel mode.

--*/

{
    ULONG LocalReturnLength;
    KPROCESSOR_MODE PreviousMode;
    PEPROCESS TargetProcess;
    PETHREAD Thread;
    NTSTATUS Status;
    PMMVAD Vad;
    PVOID Va;
    PVOID NextVaToQuery;
    LOGICAL Found;
    SIZE_T TheRegionSize;
    ULONG NewProtect;
    ULONG NewState;
    PVOID FilePointer;
    ULONG_PTR BaseVpn;
    MEMORY_BASIC_INFORMATION Info;
    PMEMORY_BASIC_INFORMATION BasicInfo;
    LOGICAL Attached;
    LOGICAL Leaped;
    ULONG MemoryInformationLengthUlong;
    KAPC_STATE ApcState;
    PETHREAD CurrentThread;
    PVOID HighestVadAddress;
    PVOID HighestUserAddress;

    Found = FALSE;
    Leaped = TRUE;
    FilePointer = NULL;

    //
    // Make sure the user's buffer is large enough for the requested operation.
    //
    // Check argument validity.
    //

    switch (MemoryInformationClass) {
        case MemoryBasicInformation:
            if (MemoryInformationLength < sizeof(MEMORY_BASIC_INFORMATION)) {
                return STATUS_INFO_LENGTH_MISMATCH;
            }
            break;

        case MemoryWorkingSetInformation:
            if (MemoryInformationLength < sizeof(ULONG_PTR)) {
                return STATUS_INFO_LENGTH_MISMATCH;
            }
            break;

        case MemoryWorkingSetExInformation:
            if (MemoryInformationLength < sizeof (MEMORY_WORKING_SET_EX_INFORMATION)) {
                return STATUS_INFO_LENGTH_MISMATCH;
            }
            break;

        case MemoryMappedFilenameInformation:
            break;

        default:
            return STATUS_INVALID_INFO_CLASS;
    }

    CurrentThread = PsGetCurrentThread ();
    PreviousMode = KeGetPreviousModeByThread(&CurrentThread->Tcb);

    if (PreviousMode != KernelMode) {

        //
        // Check arguments.
        //

        try {

            ProbeForWrite(MemoryInformation,
                          MemoryInformationLength,
                          sizeof(ULONG_PTR));

            if (ARGUMENT_PRESENT(ReturnLength)) {
                ProbeForWriteUlong_ptr(ReturnLength);
            }

        } except (EXCEPTION_EXECUTE_HANDLER) {

            //
            // If an exception occurs during the probe or capture
            // of the initial values, then handle the exception and
            // return the exception code as the status value.
            //

            return GetExceptionCode();
        }
    }

    if (BaseAddress > MM_HIGHEST_USER_ADDRESS) {
        return STATUS_INVALID_PARAMETER;
    }

    HighestUserAddress = MM_HIGHEST_USER_ADDRESS;
    HighestVadAddress  = (PCHAR) MM_HIGHEST_VAD_ADDRESS;

#if defined(_WIN64)

    if (ProcessHandle == NtCurrentProcess()) {
        TargetProcess = PsGetCurrentProcessByThread(CurrentThread);
    }
    else {
        Status = ObReferenceObjectByHandle (ProcessHandle,
                                            PROCESS_QUERY_INFORMATION,
                                            PsProcessType,
                                            PreviousMode,
                                            (PVOID *)&TargetProcess,
                                            NULL);

        if (!NT_SUCCESS(Status)) {
            return Status;
        }
    }

    //
    // If this is a wow64 process, then return the appropriate highest
    // user address depending on whether the process has been started with
    // a 2GB or a 4GB address space.
    //

    if (TargetProcess->Wow64Process != NULL) {

        if (TargetProcess->Flags & PS_PROCESS_FLAGS_WOW64_4GB_VA_SPACE) {
            HighestUserAddress = (PVOID) ((ULONG_PTR)_4gb - X64K - 1);
        }
        else {
            HighestUserAddress = (PVOID) ((ULONG_PTR)_2gb - X64K - 1);
        }

        HighestVadAddress  = (PCHAR)HighestUserAddress - X64K;

        if (BaseAddress > HighestUserAddress) {

            if (ProcessHandle != NtCurrentProcess()) {
                ObDereferenceObject (TargetProcess);
            }
            return STATUS_INVALID_PARAMETER;
        }
    }

#endif

    if ((BaseAddress > HighestVadAddress) ||
        (PAGE_ALIGN(BaseAddress) == (PVOID)MM_SHARED_USER_DATA_VA)) {

        //
        // Indicate a reserved area from this point on.
        //

        Status = STATUS_INVALID_ADDRESS;

        if (MemoryInformationClass == MemoryBasicInformation) {

            try {
                ((PMEMORY_BASIC_INFORMATION)MemoryInformation)->AllocationBase =
                                      (PCHAR) HighestVadAddress + 1;
                ((PMEMORY_BASIC_INFORMATION)MemoryInformation)->AllocationProtect =
                                                                      PAGE_READONLY;
                ((PMEMORY_BASIC_INFORMATION)MemoryInformation)->BaseAddress =
                                                       PAGE_ALIGN(BaseAddress);
                ((PMEMORY_BASIC_INFORMATION)MemoryInformation)->RegionSize =
                                    ((PCHAR)HighestUserAddress + 1) -
                                                (PCHAR)PAGE_ALIGN(BaseAddress);
                ((PMEMORY_BASIC_INFORMATION)MemoryInformation)->State = MEM_RESERVE;
                ((PMEMORY_BASIC_INFORMATION)MemoryInformation)->Protect = PAGE_NOACCESS;
                ((PMEMORY_BASIC_INFORMATION)MemoryInformation)->Type = MEM_PRIVATE;

                if (ARGUMENT_PRESENT(ReturnLength)) {
                    *ReturnLength = sizeof(MEMORY_BASIC_INFORMATION);
                }

                if (PAGE_ALIGN(BaseAddress) == (PVOID)MM_SHARED_USER_DATA_VA) {

                    //
                    // This is the page that is double mapped between
                    // user mode and kernel mode.
                    //

                    ((PMEMORY_BASIC_INFORMATION)MemoryInformation)->AllocationBase =
                                (PVOID)MM_SHARED_USER_DATA_VA;
                    ((PMEMORY_BASIC_INFORMATION)MemoryInformation)->Protect =
                                                                 PAGE_READONLY;
                    ((PMEMORY_BASIC_INFORMATION)MemoryInformation)->RegionSize =
                                                                 PAGE_SIZE;
                    ((PMEMORY_BASIC_INFORMATION)MemoryInformation)->State =
                                                                 MEM_COMMIT;
                }

            } except (EXCEPTION_EXECUTE_HANDLER) {

                //
                // Just return success.
                //

                NOTHING;
            }

            Status = STATUS_SUCCESS;
        }
            
#if defined(_WIN64)
        if (ProcessHandle != NtCurrentProcess()) {
            ObDereferenceObject (TargetProcess);
        }
#endif
            
        return Status;
    }

#if !defined(_WIN64)

    if (ProcessHandle == NtCurrentProcess()) {
        TargetProcess = PsGetCurrentProcessByThread(CurrentThread);
    }
    else {
        Status = ObReferenceObjectByHandle (ProcessHandle,
                                            PROCESS_QUERY_INFORMATION,
                                            PsProcessType,
                                            PreviousMode,
                                            (PVOID *)&TargetProcess,
                                            NULL);

        if (!NT_SUCCESS(Status)) {
            return Status;
        }
    }

#endif

    if (MemoryInformationClass == MemoryWorkingSetExInformation) {

        Status = MiGetWorkingSetInfoList (
                            (PMEMORY_WORKING_SET_EX_INFORMATION) MemoryInformation,
                            MemoryInformationLength,
                            TargetProcess);

        if (ProcessHandle != NtCurrentProcess()) {
            ObDereferenceObject (TargetProcess);
        }

        //
        // If MiGetWorkingSetInfoList failed then inform the caller.
        //

        if (!NT_SUCCESS(Status)) {
            return Status;
        }

        try {

            if (ARGUMENT_PRESENT (ReturnLength)) {
                *ReturnLength = MemoryInformationLength;
            }

        } except (EXCEPTION_EXECUTE_HANDLER) {
            NOTHING;
        }

        return STATUS_SUCCESS;
    }

    if (MemoryInformationClass == MemoryWorkingSetInformation) {

        Status = MiGetWorkingSetInfo (
                            (PMEMORY_WORKING_SET_INFORMATION) MemoryInformation,
                            MemoryInformationLength,
                            TargetProcess);

        if (ProcessHandle != NtCurrentProcess()) {
            ObDereferenceObject (TargetProcess);
        }

        //
        // If MiGetWorkingSetInfo failed then inform the caller.
        //

        if (!NT_SUCCESS(Status)) {
            return Status;
        }

        try {

            if (ARGUMENT_PRESENT(ReturnLength)) {
                *ReturnLength = ((((PMEMORY_WORKING_SET_INFORMATION)
                                    MemoryInformation)->NumberOfEntries - 1) *
                                        sizeof(ULONG_PTR)) +
                                        sizeof(MEMORY_WORKING_SET_INFORMATION);
            }

        } except (EXCEPTION_EXECUTE_HANDLER) {
        }

        return STATUS_SUCCESS;
    }

    //
    // If the specified process is not the current process, attach
    // to the specified process.
    //

    if (ProcessHandle != NtCurrentProcess()) {
        KeStackAttachProcess (&TargetProcess->Pcb, &ApcState);
        Attached = TRUE;
    }
    else {
        Attached = FALSE;
    }

    //
    // Get working set mutex and block APCs.
    //

    LOCK_ADDRESS_SPACE (TargetProcess);

    //
    // Make sure the address space was not deleted, if so, return an error.
    //

    if (TargetProcess->Flags & PS_PROCESS_FLAGS_VM_DELETED) {
        UNLOCK_ADDRESS_SPACE (TargetProcess);
        if (Attached == TRUE) {
            KeUnstackDetachProcess (&ApcState);
            ObDereferenceObject (TargetProcess);
        }
        return STATUS_PROCESS_IS_TERMINATING;
    }

    //
    // Locate the VAD that contains the base address or the VAD
    // which follows the base address.
    //

    if (TargetProcess->VadRoot.NumberGenericTableElements != 0) {

        Vad = (PMMVAD) TargetProcess->VadRoot.BalancedRoot.RightChild;
        BaseVpn = MI_VA_TO_VPN (BaseAddress);

        while (TRUE) {

            if (Vad == NULL) {
                break;
            }

            if ((BaseVpn >= Vad->StartingVpn) &&
                (BaseVpn <= Vad->EndingVpn)) {
                Found = TRUE;
                break;
            }

            if (BaseVpn < Vad->StartingVpn) {
                if (Vad->LeftChild == NULL) {
                    break;
                }
                Vad = Vad->LeftChild;
            }
            else {
                ASSERT (BaseVpn > Vad->EndingVpn);

                if (Vad->RightChild == NULL) {
                    break;
                }

                Vad = Vad->RightChild;
            }
        }
    }
    else {
        Vad = NULL;
        BaseVpn = 0;
    }

    if (!Found) {

        //
        // There is no virtual address allocated at the base
        // address.  Return the size of the hole starting at
        // the base address.
        //

        if (Vad == NULL) {
            TheRegionSize = (((PCHAR)HighestVadAddress + 1) - 
                                         (PCHAR)PAGE_ALIGN(BaseAddress));
        }
        else {
            if (Vad->StartingVpn < BaseVpn) {

                //
                // We are looking at the Vad which occupies the range
                // just before the desired range.  Get the next Vad.
                //

                Vad = MiGetNextVad (Vad);
                if (Vad == NULL) {
                    TheRegionSize = (((PCHAR)HighestVadAddress + 1) - 
                                                (PCHAR)PAGE_ALIGN(BaseAddress));
                }
                else {
                    TheRegionSize = (PCHAR)MI_VPN_TO_VA (Vad->StartingVpn) -
                                                (PCHAR)PAGE_ALIGN(BaseAddress);
                }
            }
            else {
                TheRegionSize = (PCHAR)MI_VPN_TO_VA (Vad->StartingVpn) -
                                                (PCHAR)PAGE_ALIGN(BaseAddress);
            }
        }

        UNLOCK_ADDRESS_SPACE (TargetProcess);

        if (Attached == TRUE) {
            KeUnstackDetachProcess (&ApcState);
            ObDereferenceObject (TargetProcess);
        }

        //
        // Establish an exception handler and write the information and
        // returned length.
        //

        if (MemoryInformationClass == MemoryBasicInformation) {
            BasicInfo = (PMEMORY_BASIC_INFORMATION) MemoryInformation;
            Found = FALSE;
            try {

                BasicInfo->AllocationBase = NULL;
                BasicInfo->AllocationProtect = 0;
                BasicInfo->BaseAddress = PAGE_ALIGN(BaseAddress);
                BasicInfo->RegionSize = TheRegionSize;
                BasicInfo->State = MEM_FREE;
                BasicInfo->Protect = PAGE_NOACCESS;
                BasicInfo->Type = 0;

                Found = TRUE;
                if (ARGUMENT_PRESENT(ReturnLength)) {
                    *ReturnLength = sizeof(MEMORY_BASIC_INFORMATION);
                }

            } except (EXCEPTION_EXECUTE_HANDLER) {

                //
                // Just return success if the BasicInfo was successfully
                // filled in.
                //
                
                if (Found == FALSE) {
                    return GetExceptionCode ();
                }
            }

            return STATUS_SUCCESS;
        }
        return STATUS_INVALID_ADDRESS;
    }

    //
    // Found a VAD.
    //
   
    Va = PAGE_ALIGN(BaseAddress);
    Info.BaseAddress = Va;
    Info.AllocationBase = MI_VPN_TO_VA (Vad->StartingVpn);
    Info.AllocationProtect = MI_CONVERT_FROM_PTE_PROTECTION (
                                             Vad->u.VadFlags.Protection);
    
    //
    // There is a page mapped at the base address.
    //
    
    if ((Vad->u.VadFlags.PrivateMemory) || 
        (Vad->u.VadFlags.VadType == VadRotatePhysical)) {

        Info.Type = MEM_PRIVATE;
    }
    else {
        if (Vad->u.VadFlags.VadType == VadImageMap) {
            Info.Type = MEM_IMAGE;
        }
        else {
            Info.Type = MEM_MAPPED;
        }

        if (MemoryInformationClass == MemoryMappedFilenameInformation) {

            if (Vad->ControlArea != NULL) {
                FilePointer = Vad->ControlArea->FilePointer;
            }
            if (FilePointer == NULL) {
                FilePointer = (PVOID)1;
            }
            else {
                ObReferenceObject (FilePointer);
            }
        } 
    }

    Thread = PsGetCurrentThread ();

    LOCK_WS_SHARED (Thread, TargetProcess);

    Info.State = MiQueryAddressState (Va,
                                      Vad,
                                      TargetProcess,
                                      &Info.Protect,
                                      &NextVaToQuery);

    Va = NextVaToQuery;

    while (MI_VA_TO_VPN (Va) <= Vad->EndingVpn) {

        NewState = MiQueryAddressState (Va,
                                        Vad,
                                        TargetProcess,
                                        &NewProtect,
                                        &NextVaToQuery);

        if ((NewState != Info.State) || (NewProtect != Info.Protect)) {

            //
            // The state for this address does not match, calculate
            // size and return.
            //

            Leaped = FALSE;
            break;
        }
        Va = NextVaToQuery;
    }

    UNLOCK_WS_SHARED (Thread, TargetProcess);    

    //
    // We may have aggressively leaped past the end of the VAD.  Shorten the
    // Va here if we did.
    //

    if (Leaped == TRUE) {
        Va = MI_VPN_TO_VA (Vad->EndingVpn + 1);
    }

    Info.RegionSize = ((PCHAR)Va - (PCHAR)Info.BaseAddress);

    //
    // A range has been found, release the mutexes, detach from the
    // target process and return the information.
    //

    UNLOCK_ADDRESS_SPACE (TargetProcess);

    if (Attached == TRUE) {
        KeUnstackDetachProcess (&ApcState);
        ObDereferenceObject (TargetProcess);
    }

    if (MemoryInformationClass == MemoryBasicInformation) {
        Found = FALSE;
        try {

            *(PMEMORY_BASIC_INFORMATION)MemoryInformation = Info;

            Found = TRUE;
            if (ARGUMENT_PRESENT(ReturnLength)) {
                *ReturnLength = sizeof(MEMORY_BASIC_INFORMATION);
            }

        } except (EXCEPTION_EXECUTE_HANDLER) {

            //
            // Just return success if the BasicInfo was successfully
            // filled in.
            //
                
            if (Found == FALSE) {
                return GetExceptionCode ();
            }
        }
        return STATUS_SUCCESS;
    }

    //
    // Try to return the name of the file that is mapped.
    //

    if (FilePointer == NULL) {
        return STATUS_INVALID_ADDRESS;
    }

    if (FilePointer == (PVOID)1) {
        return STATUS_FILE_INVALID;
    }

    MemoryInformationLengthUlong = (ULONG)MemoryInformationLength;

    if ((SIZE_T)MemoryInformationLengthUlong < MemoryInformationLength) {
        return STATUS_INVALID_PARAMETER_5;
    }
    
    //
    // We have a referenced pointer to the file.  Call ObQueryNameString
    // and get the file name.
    //

    Status = ObQueryNameString (FilePointer,
                                (POBJECT_NAME_INFORMATION) MemoryInformation,
                                 MemoryInformationLengthUlong,
                                 &LocalReturnLength);

    ObDereferenceObject (FilePointer);

    if (ARGUMENT_PRESENT (ReturnLength)) {
        try {
            *ReturnLength = LocalReturnLength;
        } except (EXCEPTION_EXECUTE_HANDLER) {
            Status = GetExceptionCode ();
        }
    }

    return Status;
}
Wrk NtQueryVirtualMemory

 

所以,我们也可以自己来遍历二叉树来获得进程的所有模块,而不用NtQueryVirtualMemory函数,就是一个AVL树的遍历,主要代码如下

typedef struct _MMADDRESS_NODE              // 0x14
{
    union  u1{ULONG u1;};                    // +0x0(0x4)
    struct _MMADDRESS_NODE* LeftChild;       // +0x4(0x4)
    struct _MMADDRESS_NODE* RightChild;      // +0x8(0x4)
    ULONG StartingVpn;                       // +0xc(0x4)
    ULONG EndingVpn;                         // +0x10(0x4)
}MMADDRESS_NODE,*PMMADDRESS_NODE;

#pragma pack(push,1)

typedef struct _EX_FAST_REF
{
    union
    {
        PVOID Object;
        ULONG_PTR RefCnt:3;
        ULONG_PTR Value;
    };
} EX_FAST_REF, *PEX_FAST_REF;
#pragma pack(pop)

struct _SEGMENT                                // 0x38
{
    struct _CONTROL_AREA* ControlArea;        // +0x0(0x4)
    ULONG TotalNumberOfPtes;                  // +0x4(0x4)
    ULONG SegmentFlags;                       // +0x8(0x4)
    ULONG NumberOfCommittedPages;             // +0xc(0x4)
    ULONGLONG SizeOfSegment;                  // +0x10(0x8)
    union
    {
        struct _MMEXTEND_INFO* ExtendInfo;     // +0x18(0x4)
        void* BasedAddress;                    // +0x18(0x4)
    };
    EX_PUSH_LOCK SegmentLock;                  // +0x1c(0x4)
    ULONG u1;                                  // +0x20(0x4)
    ULONG u2;                                  // +0x24(0x4)
    struct _MMPTE* PrototypePte;               // +0x28(0x4)
    //ULONGLONG ThePtes[0x1];                  // +0x30(0x8)
};
struct _CONTROL_AREA                           // 0x50
{
    struct _SEGMENT* Segment;                  // +0x0(0x4)
    struct _LIST_ENTRY DereferenceList;        // +0x4(0x8)
    ULONG NumberOfSectionReferences;           // +0xc(0x4)
    ULONG NumberOfPfnReferences;               // +0x10(0x4)
    ULONG NumberOfMappedViews;                 // +0x14(0x4)
    ULONG NumberOfUserReferences;              // +0x18(0x4)
    ULONG  u;                                  // +0x1c(0x4)
    ULONG FlushInProgressCount;                // +0x20(0x4)
    struct _EX_FAST_REF FilePointer;           // +0x24(0x4)   
};
struct _SUBSECTION                             // 0x20
{
    struct _CONTROL_AREA* ControlArea;          // +0x0(0x4)
    struct _MMPTE* SubsectionBase;              // +0x4(0x4)
    struct _SUBSECTION* NextSubsection;         // +0x8(0x4)
    ULONG PtesInSubsection;                     // +0xc(0x4)
    ULONG UnusedPtes;                           // +0x10(0x4)
    struct _MM_AVL_TABLE* GlobalPerSessionHead; // +0x10(0x4)
    union u{ULONG u;};                          // +0x14(0x4)
    ULONG StartingSector;                       // +0x18(0x4)
    ULONG NumberOfFullSectors;                  // +0x1c(0x4)
};
typedef struct _MMVAD                           // 0x3c
{
    ULONG u1;                                   // +0x0(0x4)
    struct _MMVAD* LeftChild;                   // +0x4(0x4)
    struct _MMVAD* RightChild;                  // +0x8(0x4)
    ULONG StartingVpn;                          // +0xc(0x4)
    ULONG EndingVpn;                            // +0x10(0x4)
    ULONG u;                                    // +0x14(0x4)
    EX_PUSH_LOCK PushLock;                      // +0x18(0x4)
    ULONG u5;                                   // +0x1c(0x4)
    ULONG u2;                                   // +0x20(0x4)
    struct _SUBSECTION* Subsection;             // +0x24(0x4)
    struct _MSUBSECTION* MappedSubsection;      // +0x24(0x4)
    struct _MMPTE* FirstPrototypePte;           // +0x28(0x4)
    struct _MMPTE* LastContiguousPte;           // +0x2c(0x4)
    struct _LIST_ENTRY ViewLinks;               // +0x30(0x8)
    struct _EPROCESS* VadsProcess;              // +0x38(0x4)
}MMVAD;

typedef struct   _MM_AVL_TABLE                   // 0x20
{
    struct _MMADDRESS_NODE BalancedRoot;         // +0x0(0x14)
    ULONG DepthOfTree;                           // +0x14(0x4)
    ULONG Unused;                                // +0x14(0x4)
    ULONG NumberGenericTableElements;            // +0x14(0x4)
    void* NodeHint;                              // +0x18(0x4)
    void* NodeFreeHint;                          // +0x1c(0x4)
}MM_AVL_TABLE,*PMMAVL_TABLE;


#define GetVadRoot(eprocess)  ((PVOID)((char*)eprocess+0x278))


VOID PrintTree(MMVAD
* Root) { POBJECT_NAME_INFORMATION Str=(POBJECT_NAME_INFORMATION )ExAllocatePool(PagedPool,800); ULONG RetLen=0; if(!Str||!Root) return ; RtlZeroMemory(Str,800);//递归要节省堆栈资源,不要大量使用局部变量 __try { if(MmIsAddressValid(Root->Subsection)&&MmIsAddressValid(Root->Subsection->ControlArea)) { if(MmIsAddressValid((PVOID)Root->Subsection->ControlArea->FilePointer.Value)) { //最后三位清零 PFILE_OBJECT pFileObj=(PFILE_OBJECT)((Root->Subsection->ControlArea->FilePointer.Value>>3)<<3); if(MmIsAddressValid(pFileObj)) { NTSTATUS Status=ObQueryNameString(pFileObj,Str,800,&RetLen); if(NT_SUCCESS(Status)) { DbgPrint("Base:%08X Size:%dKb Name:%wZ\r\n",Root->Subsection->ControlArea->Segment->BasedAddress,\ (Root->Subsection->ControlArea->Segment->SizeOfSegment)/0x1000, \ (PUNICODE_STRING)(&(Str->Name))); } else { DbgPrint("不能获取到对象!%08X\n",Status); } } } } } __except(1) { DbgPrint("Invalid Address!\n"); } ExFreePool(Str); __try { if(MmIsAddressValid(Root->LeftChild)) PrintTree(Root->LeftChild); if(MmIsAddressValid(Root->RightChild)) PrintTree(Root->RightChild); } __except(1) { DbgPrint("Exception!"); return; } } VOID ShowProcessModule(ULONG Pid) { #ifdef _DBG _asm int 3 #endif PMMAVL_TABLE Table; PEPROCESS Epr=0; if(NT_SUCCESS(PsLookupProcessByProcessId((HANDLE)Pid,&Epr))) { KeAttachProcess(Epr); Table=(PMMAVL_TABLE)GetVadRoot(Epr); if(Table->BalancedRoot.LeftChild) PrintTree((MMVAD*)Table->BalancedRoot.LeftChild); if(Table->BalancedRoot.RightChild) PrintTree((MMVAD*)Table->BalancedRoot.RightChild); KeDetachProcess(); } }

posted on 2015-07-23 19:33  _懒人  阅读(6736)  评论(0编辑  收藏  举报

导航