A forum for reverse engineering, OS internals and malware analysis 

Forum for discussion about kernel-mode development.
 #26945  by myid
 Wed Oct 14, 2015 4:53 pm
Hi, I use WINDBG to study VAD structure on WIN10X86, but I found MMVAD.Subsection is an Invalid value.
lkd> !process 0 0
**** NT ACTIVE PROCESS DUMP ****
Unable to get LeftChild of nt!_MMVAD_SHORT at a863a408 //WINDBG display
failed to count VADs
PROCESS a3d8a240 SessionId: 1 Cid: 1708 Peb: 7ffd3000 ParentCid: 0b20
DirBase: 7fff05e0 ObjectTable: a5dfbbc0 HandleCount: <Data Not Accessible>
Image: Dbgview.exe

lkd> dt_eprocess
nt!_EPROCESS
+0x000 Pcb : _KPROCESS
...
+0x284 VadRoot : _RTL_AVL_TREE
...
+0x37c DefaultCpuSetsIndirect : Ptr32 Uint4B

lkd> dt _RTL_AVL_TREE a3d8a240+284
nt!_RTL_AVL_TREE
+0x000 Root : 0xa863a408 _RTL_BALANCED_NODE

lkd> dt_RTL_BALANCED_NODE 0xa863a408
nt!_RTL_BALANCED_NODE
+0x000 Children : [2] 0xa3d67958 _RTL_BALANCED_NODE
+0x000 Left : 0xa3d67958 _RTL_BALANCED_NODE
+0x004 Right : 0xa3489338 _RTL_BALANCED_NODE
+0x008 Red : 0y1
+0x008 Balance : 0y01
+0x008 ParentValue : 1

lkd> dt_mmvad 0xa3d67958
nt!_MMVAD
+0x000 Core : _MMVAD_SHORT
+0x028 u2 : <unnamed-tag>
+0x02c Subsection : 0x52777445 _SUBSECTION //the value is invalid
+0x030 FirstPrototypePte : (null)
+0x034 LastContiguousPte : 0x00000074 _MMPTE
+0x038 ViewLinks : _LIST_ENTRY [ 0x6c - 0x948a5140 ]
+0x040 VadsProcess : 0xa865c580 _EPROCESS
+0x044 u4 : <unnamed-tag>
+0x048 FileObject : 0x00000001 _FILE_OBJECT
How to get the real value of Subsection?
 #26947  by Vrtule
 Wed Oct 14, 2015 6:56 pm
Is that VAD really the medium/long one? There are multiple fields that do not look initialized, ViewLinks for example. Unfortunately, it is a few years I was doing some research about VADs, so I do not remember much about this. My findings are published but in Czech only so they won't be too useful for you I expect.
 #26948  by myid
 Wed Oct 14, 2015 7:05 pm
Vrtule wrote:Is that VAD really the medium/long one? There are multiple fields that do not look initialized, ViewLinks for example. Unfortunately, it is a few years I was doing some research about VADs, so I do not remember much about this. My findings are published but in Czech only so they won't be too useful for you I expect.
Thanks. Do you have some good way to read VAD?
I found that sometimes I cannot read VAD (get the wrong data), but sometimes is OK.
Direct read, or use MDL APIs to read, is not useful.
 #26949  by Vrtule
 Wed Oct 14, 2015 7:58 pm
Hello,

I used a driver to read process VADs. I always read the whole VAD tree of a given process. First, I found process' VadRoot (hardcoded offset into then EPROCESS structure) and just walked the tree. So, it was the direct read method; no MDLs, no APIs. I think I even did not locked the tree since I never planned to give my VAD displayer as "an utility for everyone".

I used the following procedure to determine type of a VAD:
Code: Select all
VAD_STRUCTURE_TYPE VDGetVadStructureType(PVOID Vad)
{
  MMVAD_FLAGS VadFlags;
  MMVAD_FLAGS2 VadFlags2;
  VAD_STRUCTURE_TYPE Ret = VadStructureUnknown;
  KdPrint(("vad-def.c: VDGetVadStructureType(Vad=0x%p)\n", Vad));

  VadFlags = VDGetVadFlags(Vad);
  Ret = (VadFlags.PrivateMemory == 0 || VadFlags.NoChange == 1) ? VadStructureNormal : VadStructureShort;
  if (Ret == VadStructureNormal) {
    VadFlags2 = VDGetVadFlags2(Vad);
    Ret = (VadFlags2.LongVad == 1) ? VadStructureLong : VadStructureNormal;
  }

  KdPrint(("vad-def.c: VDGetVadStructureType(-):%u\n", Ret));
  return Ret;
}
As I am looking to my code now, I experimented with VADs only up to Windows 7 so I can't give you any information about how these things work on later systems.
 #26954  by myid
 Thu Oct 15, 2015 12:55 am
Vrtule wrote:Hello,

I used a driver to read process VADs. I always read the whole VAD tree of a given process. First, I found process' VadRoot (hardcoded offset into then EPROCESS structure) and just walked the tree. So, it was the direct read method; no MDLs, no APIs. I think I even did not locked the tree since I never planned to give my VAD displayer as "an utility for everyone".

I used the following procedure to determine type of a VAD:
Code: Select all
VAD_STRUCTURE_TYPE VDGetVadStructureType(PVOID Vad)
{
  MMVAD_FLAGS VadFlags;
  MMVAD_FLAGS2 VadFlags2;
  VAD_STRUCTURE_TYPE Ret = VadStructureUnknown;
  KdPrint(("vad-def.c: VDGetVadStructureType(Vad=0x%p)\n", Vad));

  VadFlags = VDGetVadFlags(Vad);
  Ret = (VadFlags.PrivateMemory == 0 || VadFlags.NoChange == 1) ? VadStructureNormal : VadStructureShort;
  if (Ret == VadStructureNormal) {
    VadFlags2 = VDGetVadFlags2(Vad);
    Ret = (VadFlags2.LongVad == 1) ? VadStructureLong : VadStructureNormal;
  }

  KdPrint(("vad-def.c: VDGetVadStructureType(-):%u\n", Ret));
  return Ret;
}
As I am looking to my code now, I experimented with VADs only up to Windows 7 so I can't give you any information about how these things work on later systems.
Thanks, could you give me more tips? I don't know how to use your code.
 #26956  by Brock
 Thu Oct 15, 2015 6:40 am
@myid

You can lock the process' address space with EProcess->AddressCreationLock before you copy or walk the VAD, make sure to release the lock when finished
 #26958  by myid
 Thu Oct 15, 2015 8:33 am
Brock wrote:@myid

You can lock the process' address space with EProcess->AddressCreationLock before you copy or walk the VAD, make sure to release the lock when finished
How to lock it? Could you give me more tips?
 #26961  by Brock
 Thu Oct 15, 2015 12:07 pm
IIRC <= XP you'd use KeAcquireFastMutex and on 2k3+ you'd use KeAcquireGuardedMutex on the "AddressCreationLock". According to WRK v1.2 LOCK_ADDRESS_SPACE is a macro which does this
Code: Select all
#define LOCK_ADDRESS_SPACE(PROCESS)                                  \
            KeAcquireGuardedMutex (&((PROCESS)->AddressCreationLock));
 #26963  by myid
 Thu Oct 15, 2015 3:01 pm
Brock wrote:IIRC <= XP you'd use KeAcquireFastMutex and on 2k3+ you'd use KeAcquireGuardedMutex on the "AddressCreationLock". According to WRK v1.2 LOCK_ADDRESS_SPACE is a macro which does this
Code: Select all
#define LOCK_ADDRESS_SPACE(PROCESS)                                  \
            KeAcquireGuardedMutex (&((PROCESS)->AddressCreationLock));
Thanks. But I use this API (and try to lock process address space) on WIN10, it cause BSOD. :oops: