由枚举模块到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

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

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

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 = ;
ULONG ulRet = ;
#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 = ;
//改变PreviousMode
PETHREAD EThread = PsGetCurrentThread();
CHAR PreMode = ChangePreMode(EThread); //KernelMode
do
{
MEMORY_BASIC_INFORMATION mbi = {};
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 = {};
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
**** NT ACTIVE PROCESS DUMP ****
PROCESS 87b73cf8 SessionId: Cid: 0dd8 Peb: 7ffdf000 ParentCid: 07f4
DirBase: 7f3455e0 ObjectTable: HandleCount: .
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 :
+0x010 EndingVpn :

注意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 :
+0x010 UnusedPtes :
+0x010 GlobalPerSessionHead : (null)
+0x014 u : <unnamed-tag>
+0x018 StartingSector :
+0x01c NumberOfFullSectors :
kd> dt _CONTROL_AREA 0x880a33c0
nt!_CONTROL_AREA
+0x000 Segment : 0x961b6998 _SEGMENT
+0x004 DereferenceList : _LIST_ENTRY [ 0x0 - 0x880d7104 ]
+0x00c NumberOfSectionReferences :
+0x010 NumberOfPfnReferences : 0x86
+0x014 NumberOfMappedViews :
+0x018 NumberOfUserReferences :
+0x01c u : <unnamed-tag>
+0x020 FlushInProgressCount :
+0x024 FilePointer : _EX_FAST_REF //关联的文件对象就在这个结构里面了
+0x028 ControlAreaLock : 0n0
+0x02c ModifiedWriteCount :
+0x02c StartingFrame :
+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: PointerCount:
Directory Object: 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
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 0F push offset stru_450F18
PAGE:0063F249 E8 D2 4F E1 FF call __SEH_prolog4
PAGE:0063F24E F6 xor esi, esi
PAGE:0063F250 E4 mov [ebp+var_1C??Attached], esi
PAGE:0063F253 DC mov [ebp+var_24], esi
PAGE:0063F256 8B mov eax, [ebp+MemoryInformationClass]
PAGE:0063F259 2B C6 sub eax, esi ; Handler MemoryBasicInformation
PAGE:0063F25B jz short Handler_MemoryBasicInformation
PAGE:0063F25D dec eax ; Handler MemoryWorkingSetList
PAGE:0063F25E 1F jz short Handler_MemoryWorkingSetList
PAGE:0063F260 dec eax
PAGE:0063F261 jz short loc_63F295 ; Handler_MemoryMappedFilenameInformation
PAGE:0063F263 dec eax
PAGE:0063F264 jz short loc_63F279
PAGE:0063F266 dec eax
PAGE:0063F267 0A jz short loc_63F273
PAGE:0063F269 B8 C0 mov eax, 0C0000003h
PAGE:0063F26E E9 D6 jmp loc_63F949
PAGE:0063F273 ; ---------------------------------------------------------------------------
PAGE:0063F273
PAGE:0063F273 loc_63F273: ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+25j
PAGE:0063F273 7D cmp [ebp+MemoryInformationLength],
PAGE:0063F277 EB jmp short loc_63F289
PAGE:0063F279 ; ---------------------------------------------------------------------------
PAGE:0063F279
PAGE:0063F279 loc_63F279: ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+22j
PAGE:0063F279 7D 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 7D cmp [ebp+MemoryInformationLength],
PAGE:0063F283 EB 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 7D 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 0A jnb short loc_63F295
PAGE:0063F28B B8 C0 mov eax, 0C0000004h
PAGE:0063F290 E9 B4 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 8B 1D +mov ebx, large fs:124h ; Handler_MemoryMappedFilenameInformation
PAGE:0063F29C 8A 3A mov al, [ebx+13Ah] ; FS寄存器指向当前CPU的KPCR KPCR+0x124指向当前线程对象
PAGE:0063F29C ; +0x13A获取先前的调用模式<KernelMode/UserMode>
PAGE:0063F2A2 D0 mov [ebp+AccessMode], al
PAGE:0063F2A5 C0 test al, al ; KernelMode=0,UserMode=1
PAGE:0063F2A7 jz short loc_63F2F9
PAGE:0063F2A9 FC mov [ebp+ms_exc.registration.TryLevel], esi ; 很明显的异常处理,与我们分析无关,忽略
PAGE:0063F2AC 6A push ; Alignment
PAGE:0063F2AC ; UserMode
PAGE:0063F2AE FF push [ebp+MemoryInformationLength] ; Length
PAGE:0063F2B1 8B 7D mov edi, [ebp+MemoryInformation]
PAGE:0063F2B4 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 0F jz short loc_63F2D0 ; ReturnLength==0则跳转
PAGE:0063F2C1 A1 mov eax, ds:_MmUserProbeAddress ; 检查此地址是否高于用户边界地址,
PAGE:0063F2C1 ; _MmUserProbeAddress == 7fff0000
PAGE:0063F2C6 3B C8 cmp ecx, eax
PAGE:0063F2C8 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 mov eax, [ecx]
PAGE:0063F2CE mov [ecx], eax
PAGE:0063F2D0
PAGE:0063F2D0 loc_63F2D0: ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+7Dj
PAGE:0063F2D0 C7 FC FE FF FF+mov [ebp+ms_exc.registration.TryLevel], 0FFFFFFFEh ; 很明显的SEH处理,
PAGE:0063F2D0 FF ; 改变TryLevel,忽略
PAGE:0063F2D7 EB jmp short loc_63F2FC ; 一般参数没问题,直接跳转
PAGE:0063F2D9 ; ---------------------------------------------------------------------------
PAGE:0063F2D9
PAGE:0063F2D9 loc_63F2D9: ; DATA XREF: .text:stru_450F18o
PAGE:0063F2D9 8B EC mov eax, [ebp+ms_exc.exc_ptr] ; 很明显,如果参数有问题,就直接返回了
PAGE:0063F2DC 8B mov eax, [eax]
PAGE:0063F2DE 8B mov eax, [eax]
PAGE:0063F2E0 D4 mov [ebp+var_2C], eax
PAGE:0063F2E3 C0 xor eax, eax
PAGE:0063F2E5 inc eax
PAGE:0063F2E6 C3 retn
PAGE:0063F2E7 ; ---------------------------------------------------------------------------
PAGE:0063F2E7
PAGE:0063F2E7 loc_63F2E7: ; DATA XREF: .text:stru_450F18o
PAGE:0063F2E7 8B E8 mov esp, [ebp+ms_exc.old_esp] ; Exception handler 0 for function 63F242
PAGE:0063F2EA 8B 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 FC FE FF FF+mov [ebp+ms_exc.registration.TryLevel], 0FFFFFFFEh
PAGE:0063F2F4 E9 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 mov edi, [ebp+MemoryInformation] ; KernelMode
PAGE:0063F2FC
PAGE:0063F2FC loc_63F2FC: ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+95j
PAGE:0063F2FC 8B 0C mov eax, [ebp+BaseAddress] ; 还是参数的校验,我们要查询的虚拟地址
PAGE:0063F2FF 8B 0D FC mov ecx, ds:_MmHighestUserAddress ; MmHighestUserAddress==0x7ffeffff
PAGE:0063F2FF ; (这是用户空间可以访问的最高地址,
PAGE:0063F2FF ; 逻辑上的而已,上面还有个64K的禁区(飞地)就到内核空间了)
PAGE:0063F305 3B C1 cmp eax, ecx
PAGE:0063F307 0A jbe short loc_63F313
PAGE:0063F309 B8 0D C0 mov eax, 0C000000Dh ; Status的返回值 STATUS_INVALID_PARAMETER(参数无效)
PAGE:0063F30E E9 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 FF FF lea esi, [ecx-10000h] ; esi==0x7ffdffff
PAGE:0063F319 D8 mov [ebp+var_28], esi ; 保存允许查询的最高地址,作为查询的虚拟地址的终结点
PAGE:0063F31C BA F0 FF FF mov edx, 0FFFFF000h
PAGE:0063F321 3B C6 cmp eax, esi ; 判断查询的虚拟地址是否高于终结点
PAGE:0063F323 0F A6 ja loc_63F8CF ; 高于,跳转,等会再看具体处理
PAGE:0063F329 mov [ebp+MemoryInformation], eax ; 将地址保存
PAGE:0063F32C and [ebp+MemoryInformation], edx ; edi==0FFFFF000h 取整得到虚拟地址的内存页首地址
PAGE:0063F32F 7D FE+cmp [ebp+MemoryInformation], 7FFE0000h ; 判断地址是否大于SharedUserData
PAGE:0063F32F 7F ; 也就是说SharedUserData为最后一个合法的用户边界
PAGE:0063F336 0F jz loc_63F8CF
PAGE:0063F33C 7D FF cmp [ebp+ProcessHandle], 0FFFFFFFFh
PAGE:0063F340 jnz short loc_63F34A ; 不是本身的进程就跳转
PAGE:0063F342 8B mov esi, [ebx+50h] ; ebx为线程对象,+0x50就为进程对象
PAGE:0063F345 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 push ; HandleInformation
PAGE:0063F34C 8D CC lea eax, [ebp+Object]
PAGE:0063F34F push eax ; Object
PAGE:0063F350 FF D0 push dword ptr [ebp+AccessMode] ; AccessMode
PAGE:0063F353 FF 2C push ds:_PsProcessType ; ObjectType
PAGE:0063F359 push 400h ; DesiredAccess
PAGE:0063F35E FF push [ebp+ProcessHandle] ; Handle
PAGE:0063F361 E8 F6 D0 FB FF call _ObReferenceObjectByHandle@24 ; ObReferenceObjectByHandle(x,x,x,x,x,x)
PAGE:0063F366 8B CC mov esi, [ebp+Object]
PAGE:0063F369 E0 mov [ebp+EProcess], esi
PAGE:0063F36C C0 test eax, eax
PAGE:0063F36E 0F 8C D5 jl loc_63F949
PAGE:0063F374
PAGE:0063F374 loc_63F374: ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+106j
PAGE:0063F374 7D cmp [ebp+MemoryInformationClass], ; MemoryRegionInformation方式查询
PAGE:0063F378 4D jnz short loc_63F3C7
PAGE:0063F37A push esi
PAGE:0063F37B 8B 5D mov ebx, [ebp+MemoryInformationLength]
PAGE:0063F37E 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 7D FF cmp [ebp+ProcessHandle], 0FFFFFFFFh
PAGE:0063F38C jz short loc_63F395
PAGE:0063F38E 8B CE mov ecx, esi ; Object
PAGE:0063F390 E8 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 FF test edi, edi
PAGE:0063F397 7D jge short loc_63F3A0
PAGE:0063F399 8B C7 mov eax, edi
PAGE:0063F39B E9 A9 jmp loc_63F949
PAGE:0063F3A0 ; ---------------------------------------------------------------------------
PAGE:0063F3A0
PAGE:0063F3A0 loc_63F3A0: ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+155j
PAGE:0063F3A0 C7 FC +mov [ebp+ms_exc.registration.TryLevel],
PAGE:0063F3A7 8B 1C mov eax, [ebp+ReturnLength]
PAGE:0063F3AA C0 test eax, eax
PAGE:0063F3AC 0B jz short loc_63F3B9
PAGE:0063F3AE mov [eax], ebx
PAGE:0063F3B0 EB jmp short loc_63F3B9
PAGE:0063F3B2 ; ---------------------------------------------------------------------------
PAGE:0063F3B2
PAGE:0063F3B2 loc_63F3B2: ; DATA XREF: .text:stru_450F18o
PAGE:0063F3B2 C0 xor eax, eax ; Exception filter 2 for function 63F242
PAGE:0063F3B4 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 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 FC FE FF FF+mov [ebp+ms_exc.registration.TryLevel], 0FFFFFFFEh
PAGE:0063F3C0 C0 xor eax, eax
PAGE:0063F3C2 E9 jmp loc_63F949
PAGE:0063F3C7 ; ---------------------------------------------------------------------------
PAGE:0063F3C7
PAGE:0063F3C7 loc_63F3C7: ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+136j
PAGE:0063F3C7 7D cmp [ebp+MemoryInformationClass],
PAGE:0063F3CB jnz short loc_63F410
PAGE:0063F3CD push esi ; BugCheckParameter1
PAGE:0063F3CE FF push [ebp+MemoryInformationLength] ; int
PAGE:0063F3D1 8B CF mov ecx, edi
PAGE:0063F3D3 E8 A3 E7 FF call _MiGetWorkingSetInfo@12 ; MiGetWorkingSetInfo(x,x,x)
PAGE:0063F3D8 8B D8 mov ebx, eax
PAGE:0063F3DA 7D FF cmp [ebp+ProcessHandle], 0FFFFFFFFh
PAGE:0063F3DE jz short loc_63F3E7
PAGE:0063F3E0 8B CE mov ecx, esi ; Object
PAGE:0063F3E2 E8 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 DB test ebx, ebx
PAGE:0063F3E9 0F 8C jl loc_63F947
PAGE:0063F3EF C7 FC +mov [ebp+ms_exc.registration.TryLevel],
PAGE:0063F3F6 8B 1C mov eax, [ebp+ReturnLength]
PAGE:0063F3F9 C0 test eax, eax
PAGE:0063F3FB BC jz short loc_63F3B9
PAGE:0063F3FD 8B 0F mov ecx, [edi]
PAGE:0063F3FF 8D 0C 8D +lea ecx, ds:[ecx*]
PAGE:0063F406 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 C0 xor eax, eax ; Exception filter 3 for function 63F242
PAGE:0063F40C 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 7D FF cmp [ebp+ProcessHandle], 0FFFFFFFFh
PAGE:0063F414 jz short loc_63F427 ; 如果不是自己进程本身就靠挂到其他进程空间
PAGE:0063F416 8D A0 lea eax, [ebp+ApcState]
PAGE:0063F419 push eax ; ApcState
PAGE:0063F41A push esi ; Process
PAGE:0063F41B E8 7A E2 FF call _KeStackAttachProcess@8 ; KeStackAttachProcess(x,x)
PAGE:0063F420 C7 E4 +mov [ebp+var_1C??Attached],
PAGE:0063F427
PAGE:0063F427 loc_63F427: ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+1D2j
PAGE:0063F427 FF 8B +dec word ptr [ebx+86h] ; ????
PAGE:0063F42E 8D lea eax, [esi+100h] ; +0x100 AddressCreationLock : _EX_PUSH_LOCK
PAGE:0063F42E ; 获取进程的地址空间锁,因为涉及到遍历地址空间,
PAGE:0063F42E ; 就不可以在遍历的时候地址空间发生变化
PAGE:0063F434 6A push 11h
PAGE:0063F436 pop ecx ; ???应该是原子锁的问题,不是很清楚
PAGE:0063F437 8B D0 mov edx, eax
PAGE:0063F439 C0 xor eax, eax
PAGE:0063F43B F0 0F B1 0A lock cmpxchg [edx], ecx
PAGE:0063F43F C0 test eax, eax
PAGE:0063F441 0B jz short loc_63F44E
PAGE:0063F443 8D 8E lea ecx, [esi+100h]
PAGE:0063F449 E8 C7 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 8B +or byte ptr [ebx+289h], ; ???
PAGE:0063F44E ; +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 +test byte ptr [esi+270h], 20h ; ???判断此进程的空间是否准备删除,EPROCESS->VmDeleted,如果删除就返回了
PAGE:0063F455 ; +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 jz short loc_63F4C5 ; 正常流程跳转
PAGE:0063F45E C9 xor ecx, ecx ; 肯定是如果准备删除了这里会需要处理资源
PAGE:0063F460 8D lea eax, [esi+100h]
PAGE:0063F466 8B D0 mov edx, eax
PAGE:0063F468 6A push 11h
PAGE:0063F46A pop eax
PAGE:0063F46B F0 0F B1 0A lock cmpxchg [edx], ecx
PAGE:0063F46F F8 cmp eax, 11h
PAGE:0063F472 0B jz short loc_63F47F
PAGE:0063F474 8D 8E lea ecx, [esi+100h]
PAGE:0063F47A E8 7B E4 FF call @ExfReleasePushLockShared@4 ; //释放锁
PAGE:0063F47F
PAGE:0063F47F loc_63F47F: ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+230j
PAGE:0063F47F A3 +and byte ptr [ebx+289h], 0FBh
PAGE:0063F486 FF +inc word ptr [ebx+86h]
PAGE:0063F48D 0F B7 +movzx eax, word ptr [ebx+86h]
PAGE:0063F494 C0 test ax, ax
PAGE:0063F497 0C jnz short loc_63F4A5
PAGE:0063F499 C3 add ebx, 40h
PAGE:0063F49C 1B cmp [ebx], ebx
PAGE:0063F49E 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 E4 test byte ptr [ebp+var_1C??Attached],
PAGE:0063F4A9 jz short loc_63F4BB
PAGE:0063F4AB 8D A0 lea eax, [ebp+ApcState]
PAGE:0063F4AE push eax
PAGE:0063F4AF E8 9E E2 FF call _KeUnstackDetachProcess@4 ; KeUnstackDetachProcess(x)
PAGE:0063F4B4 8B CE mov ecx, esi ; Object
PAGE:0063F4B6 E8 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 C0 mov eax, 0C000010Ah ; STATUS_PROCESS_IS_TERMINATING
PAGE:0063F4C0 E9 jmp loc_63F949
PAGE:0063F4C5 ; ---------------------------------------------------------------------------
PAGE:0063F4C5
PAGE:0063F4C5 loc_63F4C5: ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+21Aj
PAGE:0063F4C5 F7 8C +test dword ptr [esi+28Ch], 0FFFFFF00h ; esi==Process
PAGE:0063F4C5 FF FF FF ; +0x28c实际+0x014 NumberGenericTableElements : Pos 8, 24 Bits
PAGE:0063F4C5 ; 判断节点数量
PAGE:0063F4CF 3D jz short loc_63F50E
PAGE:0063F4D1 8B E0 mov eax, [ebp+EProcess]
PAGE:0063F4D4 8B B0 mov esi, [eax+280h] ; esi == Process->VadRoot->RightChild
PAGE:0063F4DA 8B 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 0C mov edx, [esi+0Ch] ; 遍历AVL树
PAGE:0063F4E7 3B CA cmp ecx, edx
PAGE:0063F4E9 jb short loc_63F4F4
PAGE:0063F4EB 3B 4E cmp ecx, [esi+10h]
PAGE:0063F4EE jbe short loc_63F508 ; ???
PAGE:0063F4F0 3B CA cmp ecx, edx
PAGE:0063F4F2 jnb short loc_63F4F9
PAGE:0063F4F4
PAGE:0063F4F4 loc_63F4F4: ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+2A7j
PAGE:0063F4F4 8B mov edx, [esi+]
PAGE:0063F4F7 EB 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 mov edx, [esi+]
PAGE:0063F4FC
PAGE:0063F4FC loc_63F4FC: ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+2B5j
PAGE:0063F4FC D2 test edx, edx
PAGE:0063F4FE 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 F6 test esi, esi ; 判断子节点是否有效
PAGE:0063F504 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 4D E4 or [ebp+var_1C??Attached], ; 如果之前有靠挂,Attached为1,此时or 2 ,Attached==3
PAGE:0063F508 ; 如果没有靠挂,此时Attached = 2
PAGE:0063F50C EB jmp short loc_63F515
PAGE:0063F50E ; ---------------------------------------------------------------------------
PAGE:0063F50E
PAGE:0063F50E loc_63F50E: ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+28Dj
PAGE:0063F50E F6 xor esi, esi
PAGE:0063F510 C9 xor ecx, ecx
PAGE:0063F512 8B 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 E4 test byte ptr [ebp+var_1C??Attached], ; 一般情况此时Attached=3,跳转发生
PAGE:0063F519 0F 0D jnz loc_63F62C
PAGE:0063F51F F6 test esi, esi
PAGE:0063F521 jnz short loc_63F52C
PAGE:0063F523
PAGE:0063F523 loc_63F523: ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+2FAj
PAGE:0063F523 8B D8 mov esi, [ebp+var_28]
PAGE:0063F526 2B sub esi, [ebp+MemoryInformation]
PAGE:0063F529 inc esi
PAGE:0063F52A EB 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 0C mov eax, [esi+0Ch]
PAGE:0063F52F 3B C1 cmp eax, ecx
PAGE:0063F531 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 C0 test eax, eax
PAGE:0063F53C E5 jz short loc_63F523
PAGE:0063F53E 8B 0C mov esi, [eax+0Ch]
PAGE:0063F541 C1 E6 0C shl esi, 0Ch
PAGE:0063F544 2B sub esi, [ebp+MemoryInformation]
PAGE:0063F547 EB 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 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 C9 xor ecx, ecx
PAGE:0063F553 8B E0 mov eax, [ebp+EProcess]
PAGE:0063F556 add eax, 100h
PAGE:0063F55B 8B D0 mov edx, eax
PAGE:0063F55D 6A push 11h
PAGE:0063F55F pop eax
PAGE:0063F560 F0 0F B1 0A lock cmpxchg [edx], ecx
PAGE:0063F564 F8 cmp eax, 11h
PAGE:0063F567 0E jz short loc_63F577
PAGE:0063F569 8B 4D E0 mov ecx, [ebp+EProcess]
PAGE:0063F56C C1 add ecx, 100h
PAGE:0063F572 E8 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 A3 +and byte ptr [ebx+289h], 0FBh
PAGE:0063F57E FF +inc word ptr [ebx+86h]
PAGE:0063F585 0F B7 +movzx eax, word ptr [ebx+86h]
PAGE:0063F58C C0 test ax, ax
PAGE:0063F58F 0C jnz short loc_63F59D
PAGE:0063F591 C3 add ebx, 40h
PAGE:0063F594 1B cmp [ebx], ebx
PAGE:0063F596 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 E4 test byte ptr [ebp+var_1C??Attached],
PAGE:0063F5A1 jz short loc_63F5B4
PAGE:0063F5A3 8D A0 lea eax, [ebp+ApcState]
PAGE:0063F5A6 push eax
PAGE:0063F5A7 E8 A6 E2 FF call _KeUnstackDetachProcess@4 ; KeUnstackDetachProcess(x)
PAGE:0063F5AC 8B 4D E0 mov ecx, [ebp+EProcess] ; Object
PAGE:0063F5AF E8 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 C9 xor ecx, ecx
PAGE:0063F5B6 4D cmp [ebp+MemoryInformationClass], ecx
PAGE:0063F5B9 jnz short loc_63F622
PAGE:0063F5BB E4 FD and [ebp+var_1C??Attached], 0FFFFFFFDh
PAGE:0063F5BF C7 FC +mov [ebp+ms_exc.registration.TryLevel],
PAGE:0063F5C6 4F mov [edi+], ecx
PAGE:0063F5C9 4F mov [edi+], ecx
PAGE:0063F5CC 8B mov eax, [ebp+MemoryInformation]
PAGE:0063F5CF mov [edi], eax
PAGE:0063F5D1 0C mov [edi+0Ch], esi
PAGE:0063F5D4 C7 +mov dword ptr [edi+10h], 10000h
PAGE:0063F5DB C7 +mov dword ptr [edi+14h],
PAGE:0063F5E2 4F mov [edi+18h], ecx
PAGE:0063F5E5 4D E4 or [ebp+var_1C??Attached],
PAGE:0063F5E9 8B 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 C5 FD FF FF jz loc_63F3B9
PAGE:0063F5F4 C7 1C 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 EC mov eax, [ebp+ms_exc.exc_ptr] ; Exception filter 4 for function 63F242
PAGE:0063F602 8B mov eax, [eax]
PAGE:0063F604 8B mov eax, [eax]
PAGE:0063F606 C8 mov [ebp+var_38], eax
PAGE:0063F609 C0 xor eax, eax
PAGE:0063F60B inc eax
PAGE:0063F60C C3 retn
PAGE:0063F60D ; ---------------------------------------------------------------------------
PAGE:0063F60D
PAGE:0063F60D loc_63F60D: ; DATA XREF: .text:stru_450F18o
PAGE:0063F60D 8B E8 mov esp, [ebp+ms_exc.old_esp] ; Exception handler 4 for function 63F242
PAGE:0063F610 F6 E4 test byte ptr [ebp+var_1C??Attached],
PAGE:0063F614 0F 9F FD FF FF jnz loc_63F3B9
PAGE:0063F61A 8B 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 C0 mov eax, 0C0000141h
PAGE:0063F627 E9 1D jmp loc_63F949
PAGE:0063F62C ; ---------------------------------------------------------------------------
PAGE:0063F62C
PAGE:0063F62C loc_63F62C: ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+2D7j
PAGE:0063F62C F0 FF FF and eax, 0FFFFF000h ; eax == BaseAddress,这里取BaseAddress的虚拟内存页的首地址
PAGE:0063F631 0C mov [ebp+BaseAddress], eax
PAGE:0063F634 mov [ebp+var_7C], eax
PAGE:0063F637 8B 0C mov eax, [esi+0Ch] ; 取得此子节点的起始编号 MMVAD->StartingVpn
PAGE:0063F63A C1 E0 0C shl eax, 0Ch ; 左移12位,取得虚拟内存页的页首地址
PAGE:0063F63D mov [ebp+var_78], eax
PAGE:0063F640 8B mov eax, [esi+14h] ; 取得MMVAD->u 其实是此节点的内存描述信息,
PAGE:0063F640 ; u是一个联合体,表示一个Flags
PAGE:0063F643 8B C8 mov ecx, eax ; ???对Flag进行某种运算
PAGE:0063F645 C1 E9 shr ecx, 18h
PAGE:0063F648 E1 1F and ecx, 1Fh
PAGE:0063F64B 8B 0C 8D E8 1E +mov ecx, ds:_MmProtectToValue[ecx*] ; 很明显是取数组中的元素,
PAGE:0063F64B ; 可以在Windbg中kd> dd MmProtectToValue查看
PAGE:0063F64B ; 其实MmProtectToValue就是一个数组,保存内存页的保护属性,
PAGE:0063F64B ; 前面的Flags其实就是得到数组的下标,然后从中取出值
PAGE:0063F652 4D 8C mov [ebp+var_74], ecx ; 保存查询地址的内存页属性
PAGE:0063F655 C0 test eax, eax
PAGE:0063F657 jns short loc_63F662
PAGE:0063F659 C7 9C +mov [ebp+var_64], 20000h
PAGE:0063F660 EB jmp short loc_63F6C3
PAGE:0063F662 ; ---------------------------------------------------------------------------
PAGE:0063F662
PAGE:0063F662 loc_63F662: ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+415j
PAGE:0063F662 and eax, (offset loc_6FFFFD+) ; ????
PAGE:0063F667 2D sub eax, 200000h
PAGE:0063F66C F7 D8 neg eax ; ????指令不懂
PAGE:0063F66E 1B C0 sbb eax, eax
PAGE:0063F670 FF and eax, 0FF040000h
PAGE:0063F675 add eax, 1000000h
PAGE:0063F67A 9C mov [ebp+var_64], eax ; 之前就是对Flag进行某种运算,再保存
PAGE:0063F67D 7D cmp [ebp+MemoryInformationClass], ; 我们就是2
PAGE:0063F681 jnz short loc_63F6C3
PAGE:0063F683 8B mov eax, [esi+24h] ; MMVAD->Subsection->ControlArea
PAGE:0063F686 cmp dword ptr [eax], ; 判断CONTROL_AREA->Segment 是否有效
PAGE:0063F689 2B jz short loc_63F6B6 ; 无效则跳转
PAGE:0063F68B 8B mov eax, [eax]
PAGE:0063F68D mov [ebp+ProcessHandle], eax ; 取出来,保存
PAGE:0063F690 8B mov eax, [eax+24h] ; CONTROL_AREA->FilePointer 结构类型_EX_FAST_REF
PAGE:0063F693 E0 F8 and eax, 0FFFFFFF8h ; 去除标志,只要是CONTROL_AREA下的文件指针,
PAGE:0063F693 ; 全部都要这样去除标志,得到文件对象
PAGE:0063F696 DC mov [ebp+var_24], eax ; 保存这块虚拟内存的文件对象FilePointer
PAGE:0063F699 1B jz short loc_63F6B6
PAGE:0063F69B 8B mov eax, [ebp+ProcessHandle]
PAGE:0063F69E C0 add eax, 24h ; PEX_FAST_REF结构
PAGE:0063F6A1 push eax
PAGE:0063F6A2 E8 5F F5 E1 FF call @ObFastReferenceObject@4 ; 快速引用一个对象
PAGE:0063F6A7 C0 test eax, eax ; 判断文件对象是否有效
PAGE:0063F6A9 jnz short loc_63F6B3 ; 有效跳转
PAGE:0063F6AB FF push [ebp+ProcessHandle]
PAGE:0063F6AE E8 A3 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 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 7D DC cmp [ebp+var_24], ; 判断对象引用是否成功
PAGE:0063F6BA jnz short loc_63F6C3 ; 引用成功则跳转
PAGE:0063F6BC C7 DC +mov [ebp+var_24],
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 7D cmp [ebp+MemoryInformationClass], ; 我们的方式是2
PAGE:0063F6C7 0F D5 jnz loc_63F7A2 ; 不为 3 就跳转
PAGE:0063F6CD 8B 4E mov ecx, [esi+10h]
PAGE:0063F6D0 2B 4E 0C sub ecx, [esi+0Ch]
PAGE:0063F6D3 inc ecx
PAGE:0063F6D4 C1 E1 0C shl ecx, 0Ch
PAGE:0063F6D7 4D mov [ebp+MemoryInformationClass], ecx
PAGE:0063F6DA D2 xor edx, edx
PAGE:0063F6DC 8B E0 mov eax, [ebp+EProcess]
PAGE:0063F6DF add eax, 100h
PAGE:0063F6E4 8B F0 mov esi, eax
PAGE:0063F6E6 6A push 11h
PAGE:0063F6E8 pop eax
PAGE:0063F6E9 F0 0F B1 lock cmpxchg [esi], edx
PAGE:0063F6ED F8 cmp eax, 11h
PAGE:0063F6F0 jz short loc_63F703
PAGE:0063F6F2 8B 4D E0 mov ecx, [ebp+EProcess]
PAGE:0063F6F5 C1 add ecx, 100h
PAGE:0063F6FB E8 FA E4 FF call @ExfReleasePushLockShared@4 ; ExfReleasePushLockShared(x)
PAGE:0063F700 8B 4D mov ecx, [ebp+MemoryInformationClass]
PAGE:0063F703
PAGE:0063F703 loc_63F703: ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+4AEj
PAGE:0063F703 A3 +and byte ptr [ebx+289h], 0FBh
PAGE:0063F70A FF +inc word ptr [ebx+86h]
PAGE:0063F711 0F B7 +movzx eax, word ptr [ebx+86h]
PAGE:0063F718 C0 test ax, ax
PAGE:0063F71B 0F jnz short loc_63F72C
PAGE:0063F71D C3 add ebx, 40h
PAGE:0063F720 1B cmp [ebx], ebx
PAGE:0063F722 jz short loc_63F72C
PAGE:0063F724 E8 4E DC DE FF call _KiCheckForKernelApcDelivery@0 ; KiCheckForKernelApcDelivery()
PAGE:0063F729 8B 4D 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 E4 test byte ptr [ebp+var_1C??Attached],
PAGE:0063F730 jz short loc_63F746
PAGE:0063F732 8D A0 lea eax, [ebp+ApcState]
PAGE:0063F735 push eax
PAGE:0063F736 E8 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 mov ecx, [ebp+MemoryInformationClass]
PAGE:0063F746
PAGE:0063F746 loc_63F746: ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+4EEj
PAGE:0063F746 E4 FD and [ebp+var_1C??Attached], 0FFFFFFFDh
PAGE:0063F74A C7 FC +mov [ebp+ms_exc.registration.TryLevel],
PAGE:0063F751 8B mov eax, [ebp+var_78]
PAGE:0063F754 mov [edi], eax
PAGE:0063F756 8B 8C mov eax, [ebp+var_74]
PAGE:0063F759 mov [edi+], eax
PAGE:0063F75C 8B 9C mov eax, [ebp+var_64]
PAGE:0063F75F mov [edi+], eax
PAGE:0063F762 4F 0C mov [edi+0Ch], ecx
PAGE:0063F765 4D E4 or [ebp+var_1C??Attached],
PAGE:0063F769 8B 1C mov eax, [ebp+ReturnLength]
PAGE:0063F76C C0 test eax, eax
PAGE:0063F76E 0F FC FF FF jz loc_63F3B9
PAGE:0063F774 C7 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 EC mov eax, [ebp+ms_exc.exc_ptr] ; Exception filter 5 for function 63F242
PAGE:0063F782 8B mov eax, [eax]
PAGE:0063F784 8B mov eax, [eax]
PAGE:0063F786 C4 mov [ebp+var_3C], eax
PAGE:0063F789 C0 xor eax, eax
PAGE:0063F78B inc eax
PAGE:0063F78C C3 retn
PAGE:0063F78D ; ---------------------------------------------------------------------------
PAGE:0063F78D
PAGE:0063F78D loc_63F78D: ; DATA XREF: .text:stru_450F18o
PAGE:0063F78D 8B E8 mov esp, [ebp+ms_exc.old_esp] ; Exception handler 5 for function 63F242
PAGE:0063F790 F6 E4 test byte ptr [ebp+var_1C??Attached],
PAGE:0063F794 0F 1F FC FF FF jnz loc_63F3B9
PAGE:0063F79A 8B 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 7D cmp [ebp+MemoryInformationClass], ; 我们是2,继续跳转
PAGE:0063F7A6 jnz short loc_63F7BA
PAGE:0063F7A8 push esi
PAGE:0063F7A9 FF 0C push [ebp+BaseAddress]
PAGE:0063F7AC 8D lea eax, [ebp+var_7C]
PAGE:0063F7AF E8 7E B2 E4 FF call _MiQueryAddressSpan@12 ; MiQueryAddressSpan(x,x,x)
PAGE:0063F7B4 2B sub eax, [ebp+var_7C]
PAGE:0063F7B7 mov [ebp+var_70], eax
PAGE:0063F7BA
PAGE:0063F7BA loc_63F7BA: ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+564j
PAGE:0063F7BA C9 xor ecx, ecx
PAGE:0063F7BC 8B E0 mov eax, [ebp+EProcess]
PAGE:0063F7BF add eax, 100h ; +0x100 AddressCreationLock : _EX_PUSH_LOCK
PAGE:0063F7BF ; 地址空间锁
PAGE:0063F7C4 8B D0 mov edx, eax
PAGE:0063F7C6 6A push 11h
PAGE:0063F7C8 pop eax
PAGE:0063F7C9 F0 0F B1 0A lock cmpxchg [edx], ecx
PAGE:0063F7CD F8 cmp eax, 11h
PAGE:0063F7D0 0E jz short loc_63F7E0
PAGE:0063F7D2 8B 4D E0 mov ecx, [ebp+EProcess]
PAGE:0063F7D5 C1 add ecx, 100h
PAGE:0063F7DB E8 1A 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 A3 +and byte ptr [ebx+289h], 0FBh
PAGE:0063F7E7 FF +inc word ptr [ebx+86h]
PAGE:0063F7EE 0F B7 +movzx eax, word ptr [ebx+86h]
PAGE:0063F7F5 C0 test ax, ax
PAGE:0063F7F8 0C jnz short loc_63F806
PAGE:0063F7FA C3 add ebx, 40h
PAGE:0063F7FD 1B cmp [ebx], ebx
PAGE:0063F7FF jz short loc_63F806
PAGE:0063F801 E8 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 E4 test byte ptr [ebp+var_1C??Attached], ; 判断进程是否靠挂
PAGE:0063F80A jz short loc_63F81D
PAGE:0063F80C 8D A0 lea eax, [ebp+ApcState]
PAGE:0063F80F push eax
PAGE:0063F810 E8 3D E2 FF call _KeUnstackDetachProcess@4 ; KeUnstackDetachProcess(x)
PAGE:0063F815 8B 4D E0 mov ecx, [ebp+EProcess] ; Object
PAGE:0063F818 E8 6C E1 FF call @ObfDereferenceObject@4 ; 解除对进程对象的引用
PAGE:0063F81D
PAGE:0063F81D loc_63F81D: ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+5C8j
PAGE:0063F81D 7D cmp [ebp+MemoryInformationClass],
PAGE:0063F821 jnz short loc_63F867
PAGE:0063F823 E4 FD and [ebp+var_1C??Attached], 0FFFFFFFDh
PAGE:0063F827 C7 FC +mov [ebp+ms_exc.registration.TryLevel],
PAGE:0063F82E 6A push
PAGE:0063F830 pop ecx
PAGE:0063F831 8D lea esi, [ebp+var_7C]
PAGE:0063F834 F3 A5 rep movsd
PAGE:0063F836 4D E4 or [ebp+var_1C??Attached],
PAGE:0063F83A 8B 1C mov eax, [ebp+ReturnLength]
PAGE:0063F83D 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 EC mov eax, [ebp+ms_exc.exc_ptr] ; Exception filter 6 for function 63F242
PAGE:0063F847 8B mov eax, [eax]
PAGE:0063F849 8B mov eax, [eax]
PAGE:0063F84B C0 mov [ebp+var_40], eax
PAGE:0063F84E C0 xor eax, eax
PAGE:0063F850 inc eax
PAGE:0063F851 C3 retn
PAGE:0063F852 ; ---------------------------------------------------------------------------
PAGE:0063F852
PAGE:0063F852 loc_63F852: ; DATA XREF: .text:stru_450F18o
PAGE:0063F852 8B E8 mov esp, [ebp+ms_exc.old_esp] ; Exception handler 6 for function 63F242
PAGE:0063F855 F6 E4 test byte ptr [ebp+var_1C??Attached],
PAGE:0063F859 0F 5A FB FF FF jnz loc_63F3B9
PAGE:0063F85F 8B C0 mov eax, [ebp+var_40]
PAGE:0063F862 E9 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 7D DC cmp [ebp+var_24], ; 又是对文件对象的判断
PAGE:0063F86B 0F B1 FD FF FF jz loc_63F622 ; 为NULL,跳转
PAGE:0063F871 7D DC cmp [ebp+var_24],
PAGE:0063F875 0A jnz short loc_63F881 ; 有效,则跳转
PAGE:0063F877 B8 C0 mov eax, 0C0000098h ; STATUS_FILE_INVALID 错误码
PAGE:0063F87C E9 C8 jmp loc_63F949
PAGE:0063F881 ; ---------------------------------------------------------------------------
PAGE:0063F881
PAGE:0063F881 loc_63F881: ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+633j
PAGE:0063F881 8D BC lea eax, [ebp+var_44]
PAGE:0063F884 push eax ; ReturnLength
PAGE:0063F885 FF push [ebp+MemoryInformationLength] ; Length
PAGE:0063F888 push edi ; ObjectNameInfo
PAGE:0063F889 FF DC push [ebp+var_24] ; Object
PAGE:0063F88C E8 0D 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 6B E1 FF call @ObfDereferenceObject@4 ; 释放对文件对象的引用
PAGE:0063F89B 8B 1C mov eax, [ebp+ReturnLength] ; 判断传入的返回值是否为NULL
PAGE:0063F89E C0 test eax, eax
PAGE:0063F8A0 jz short loc_63F8CB ; 为NULL,则跳转
PAGE:0063F8A2 C7 FC +mov [ebp+ms_exc.registration.TryLevel],
PAGE:0063F8A9 8B 4D BC mov ecx, [ebp+var_44] ; 实际字符串的长度
PAGE:0063F8AC mov [eax], ecx ; 返回实际字符串的长度
PAGE:0063F8AE EB jmp short loc_63F8C4
PAGE:0063F8B0 ; ---------------------------------------------------------------------------
PAGE:0063F8B0
PAGE:0063F8B0 loc_63F8B0: ; DATA XREF: .text:stru_450F18o
PAGE:0063F8B0 8B EC mov eax, [ebp+ms_exc.exc_ptr] ; Exception filter 7 for function 63F242
PAGE:0063F8B3 8B mov eax, [eax]
PAGE:0063F8B5 8B mov eax, [eax]
PAGE:0063F8B7 B8 mov [ebp+var_48], eax
PAGE:0063F8BA C0 xor eax, eax
PAGE:0063F8BC inc eax
PAGE:0063F8BD C3 retn
PAGE:0063F8BE ; ---------------------------------------------------------------------------
PAGE:0063F8BE
PAGE:0063F8BE loc_63F8BE: ; DATA XREF: .text:stru_450F18o
PAGE:0063F8BE 8B E8 mov esp, [ebp+ms_exc.old_esp] ; Exception handler 7 for function 63F242
PAGE:0063F8C1 8B 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 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 C0 mov ebx, 0C0000141h
PAGE:0063F8D4 7D cmp [ebp+MemoryInformationClass],
PAGE:0063F8D8 6D jnz short loc_63F947
PAGE:0063F8DA C7 FC +mov [ebp+ms_exc.registration.TryLevel],
PAGE:0063F8E1 inc esi
PAGE:0063F8E2 mov [edi+], esi
PAGE:0063F8E5 6A push
PAGE:0063F8E7 5B pop ebx
PAGE:0063F8E8 5F mov [edi+], ebx
PAGE:0063F8EB 8B F0 mov esi, eax
PAGE:0063F8ED F2 and esi, edx
PAGE:0063F8EF mov [edi], esi
PAGE:0063F8F1 C2 and eax, edx
PAGE:0063F8F3 2B C8 sub ecx, eax
PAGE:0063F8F5 inc ecx
PAGE:0063F8F6 4F 0C mov [edi+0Ch], ecx
PAGE:0063F8F9 C7 +mov dword ptr [edi+10h], 2000h
PAGE:0063F900 C7 +mov dword ptr [edi+14h],
PAGE:0063F907 C7 +mov dword ptr [edi+18h], 20000h
PAGE:0063F90E 8B 1C mov eax, [ebp+ReturnLength]
PAGE:0063F911 C0 test eax, eax
PAGE:0063F913 jz short loc_63F91B
PAGE:0063F915 C7 1C mov dword ptr [eax], 1Ch
PAGE:0063F91B
PAGE:0063F91B loc_63F91B: ; CODE XREF: NtQueryVirtualMemory(x,x,x,x,x,x)+6D1j
PAGE:0063F91B B8 FE 7F mov eax, 7FFE0000h
PAGE:0063F920 3B F0 cmp esi, eax
PAGE:0063F922 1A jnz short loc_63F93E
PAGE:0063F924 mov [edi+], eax
PAGE:0063F927 5F mov [edi+14h], ebx
PAGE:0063F92A B8 mov eax, 1000h
PAGE:0063F92F 0C mov [edi+0Ch], eax
PAGE:0063F932 mov [edi+10h], eax
PAGE:0063F935 EB jmp short loc_63F93E
PAGE:0063F937 ; ---------------------------------------------------------------------------
PAGE:0063F937
PAGE:0063F937 loc_63F937: ; DATA XREF: .text:stru_450F18o
PAGE:0063F937 C0 xor eax, eax ; Exception filter 1 for function 63F242
PAGE:0063F939 inc eax
PAGE:0063F93A C3 retn
PAGE:0063F93B ; ---------------------------------------------------------------------------
PAGE:0063F93B
PAGE:0063F93B loc_63F93B: ; DATA XREF: .text:stru_450F18o
PAGE:0063F93B 8B 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 FC FE FF FF+mov [ebp+ms_exc.registration.TryLevel], 0FFFFFFFEh
PAGE:0063F945 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 E1 FF call __SEH_epilog4
PAGE:0063F94E C2 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 - );
}
else {
HighestUserAddress = (PVOID) ((ULONG_PTR)_2gb - X64K - );
} 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 + ;
((PMEMORY_BASIC_INFORMATION)MemoryInformation)->AllocationProtect =
PAGE_READONLY;
((PMEMORY_BASIC_INFORMATION)MemoryInformation)->BaseAddress =
PAGE_ALIGN(BaseAddress);
((PMEMORY_BASIC_INFORMATION)MemoryInformation)->RegionSize =
((PCHAR)HighestUserAddress + ) -
(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 - ) *
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 != ) { 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 = ;
} 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 + ) -
(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 + ) -
(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 = ;
BasicInfo->BaseAddress = PAGE_ALIGN(BaseAddress);
BasicInfo->RegionSize = TheRegionSize;
BasicInfo->State = MEM_FREE;
BasicInfo->Protect = PAGE_NOACCESS;
BasicInfo->Type = ; 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);
}
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 + );
} 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)) {
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:;
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,);
ULONG RetLen=;
if(!Str||!Root)
return ;
RtlZeroMemory(Str,);//递归要节省堆栈资源,不要大量使用局部变量
__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>>)<<);
if(MmIsAddressValid(pFileObj))
{
NTSTATUS Status=ObQueryNameString(pFileObj,Str,,&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()
{
DbgPrint("Invalid Address!\n");
}
ExFreePool(Str);
__try
{
if(MmIsAddressValid(Root->LeftChild))
PrintTree(Root->LeftChild);
if(MmIsAddressValid(Root->RightChild))
PrintTree(Root->RightChild);
}
__except()
{
DbgPrint("Exception!");
return;
} } VOID ShowProcessModule(ULONG Pid)
{
#ifdef _DBG
_asm int
#endif
PMMAVL_TABLE Table;
PEPROCESS Epr=;
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();
}
}
上一篇:Java垃圾回收(GC)与引用的种类


下一篇:About GAC