On a clean Windows XP SP2 installation running inside a VirtualBox VM, when doing a snapshot with vboxmangage debugvm --dumpguestcore and analyzing it in Volatility, I always find 9 VADs with PAGE_EXECUTE_READWRITE permissions in winlogon.exe process and 1 VAD with the same permission in csrss.exe process. Sometimes there is one in explorer.exe process as well.

This is the same for two different Machines one with VirtualBox tools installed and one without.

Where do these come from? What are the write permission useful for? Any help is mostly appreciated, thank you!

  • Relocations? I don't know for sure, so just guessing. – 0xC0000022L Jan 11 '14 at 18:53

All the statements below are xp-sp3 based

windbg can also be used to parse for RWX pages in VadTree
Copy paste following lines to **.txt and run the script $$>a< path to **.txt

script contents needs grep in path for text parsing

aS  proc        @#Process ;
aS  procname    @@c++( (char *)(((nt!_EPROCESS *) @#Process ))->ImageFileName )  ;
aS  procvad     @@c++( (((nt!_EPROCESS *) @#Process ))->VadRoot )  ;
.block { !for_each_process ".printf \"%20ma\t%p\t%p\n\n\",${procname}, ${proc} , ${procvad}; .echo \n;.shell  -ci  \"!vad ${procvad}\"  grep  \"EXECUTE_READWRITE\"" } ;
ad *

and then set the process context to approriate process and examine the memory from StartVpn to EndVpn

iirc Winlogon and csrss always had a few RWX pages
the csrss RWX page always seemed to contain lots of initialization _UNICODE_STRING
most of the pages wont be available for viewing you may need to live debug in Phase1Init Stage

sxe ibp;.reboot  

on reboot set bp NtCreateProcessEx until csrss is about to be created
bc * ; gu ;!vad on csrss _EPROCESS csrss process at this point wont have the RWX page
only 4 vads will exist in csrss VadTree
you may need to follow from here and catch the allocation / writes and executions

           csrss.exe    86acebe0    86d62660  
86d39250 ( 4) 7f6f0 7f7ef 0 Mapped       EXECUTE_READWRITE  Pagefile-backed section

this oneliner will fetch you most of the strings in that page

.foreach (place { s -[1]b 7f6f0000 l?7000 0x7f } ) { r $t0 = place ; dS @$t0-7}

output of the above line

7f6f2170  "C:\WINDOWS"
7f6f2190  "C:\WINDOWS\system32"
7f6f21c0  "\BaseNamedObjects"
7f6f2208  ".罯...罯"
7f6f22b0  ".罯...罯"
7f6f221c  "Autorun.inf"
7f6f2300  ".罯02.罯Software\Microsoft\Clock"
7f6f226c  "DoesNotExist"
7f6f2260  ".罯"
7f6f2368  "ヘ罯...罯.罯"
7f6f22c4  "Clock.ini"
7f6f23d8  ".罯68.罯Control Panel\Color Scheme"
7f6f2418  "s"
7f6f230c  "Software\Microsoft\Clock"

the winlogon RWX pages will contain Executble code most of them will start with push cx push ax sequence and end with an indirect call to somehwre via jmp eax and some intermediate calls to unviewable / non existing locations may need live analysis

never observed rwx pages in clean explorer / iexplore / services.exe processos they exist only if some antivirus etc are installed

see below for an Avasted RWX page in explorer.exe patching RtlSetCurrentDirectory_U and loading snxhk.dll using LdrLoadDll() this same patch can also be observed in iexplore.exe

.shell dir /b scan*vad*
lkd> $$>a< scanvad4rwx.txt
              System    86fc6830    86fbfa90     
            smss.exe    86b0e020    86dfd008      
           csrss.exe    86acebe0    86f4e4d0  
86d39250 ( 4) 7f6f0 7f7ef 0 Mapped EXECUTE_READWRITE  Pagefile-backed section    
        winlogon.exe    86d7b918    86d58930  
86ae8ee0 ( 8)       9550     9553         4 Private      EXECUTE_READWRITE 
86340690 ( 7)      29c90    29c93         4 Private      EXECUTE_READWRITE 
86f370d0 ( 6)      2a4f0    2a4f3         4 Private      EXECUTE_READWRITE 
86b13a38 ( 5)      46580    46583         4 Private      EXECUTE_READWRITE 
86da2a00 ( 6)      497c0    497c3         4 Private      EXECUTE_READWRITE 
        services.exe    86b0a020    86ec15c8  
86da7c20 (12)        380      380         1 Private      EXECUTE_READWRITE 
               lsass.exe    86b2a6b8    86b21110  
        explorer.exe    86241260    86b86768  
86b13d28 (13)         90       90         1 Private      EXECUTE_READWRITE 
86545e50 (11)        2b0      2b0         1 Private      EXECUTE_READWRITE 
86aa6878 (12)        2c0      2ca        11 Private      EXECUTE_READWRITE 
86b056a0 (10)        2d0      2da        11 Private      EXECUTE_READWRITE 
86b3b9c8 (12)        2e0      2ea        11 Private      EXECUTE_READWRITE 
             AvastUI.exe    86315a00    860fc008  
        iexplore.exe    86aaf020    861b3f00  
862ae9f8 (16)        150      150         1 Private      EXECUTE_READWRITE 

on rereading i noticed the below output is from a differnt session so splitting

and examine the memory  using  lkd> .process /p /r 862543e8 &   lkd> uf 150000
00150000 50              push    eax
00150001 60              pushad
00150002 bd42001500      mov     ebp,150042h
00150007 8b7d10          mov     edi,dword ptr [ebp+10h]
0015000a 8b4518          mov     eax,dword ptr [ebp+18h]
0015000d 8b5d1c          mov     ebx,dword ptr [ebp+1Ch]
00150010 8907            mov     dword ptr [edi],eax
00150012 895f04          mov     dword ptr [edi+4],ebx
00150015 897c2420        mov     dword ptr [esp+20h],edi
00150019 8d454c          lea     eax,[ebp+4Ch]
0015001c 50              push    eax
0015001d ff7548          push    dword ptr [ebp+48h]
00150020 8d4550          lea     eax,[ebp+50h]
00150023 50              push    eax
00150024 8d4540          lea     eax,[ebp+40h]
00150027 50              push    eax
00150028 6aff            push    0FFFFFFFFh
0015002a ff5508          call    dword ptr [ebp+8]
0015002d 85c0            test    eax,eax
0015002f 750f            jne     00150040    
00150031 33c9            xor     ecx,ecx
00150033 8d4538          lea     eax,[ebp+38h]
00150036 50              push    eax
00150037 8d4528          lea     eax,[ebp+28h]
0015003a 50              push    eax
0015003b 51              push    ecx
0015003c 51              push    ecx
0015003d ff5500          call    dword ptr [ebp]    
00150040 61              popad
00150041 c3              ret

put the commands in one line

? @$t1+10 ; ? poi(@$t1+10) ; ln poi(@$t1+10); db (@$t1+18) l8; u (@$t1+18)  l3;
? poi(@$t1+4c) ; ? poi(@$t1+48) ; ? poi(@$t1+50) ;? poi(@$t1+40) ;  lm m ntdll* ;
ln poi(@$t1+8) ; ? poi(@$t1+38); db  (@$t1+28) l8; du /c 40 poi(@$t1+2c) ;
? poi(@$t1); ln poi(@$t1);.echo patches RtlSetCurwith pattern and sets return 
address    [esp+20]to patched instruction calls ntvirtproct for a pagein ntdll 
on successloads a dll using LdrLoadDll;   

Evaluate expression: 1376338 = 00150052
Evaluate expression: 2089936810 = 7c91e7aa
(7c91e7aa)       Exact matches: ntdll!RtlSetCurrentDirectory_U
0015005a  6a 6c 68 78 e9 91 7c e8                          jlhx..|.
0015005a 6a6c            push    6Ch
0015005c 6878e9917c      push    offset ntdll!`string'+0x34 (7c91e978)
00150061 e81501ffff      call    0014017b
Evaluate expression: 64 = 00000040
Evaluate expression: 32 = 00000020
Evaluate expression: 4096 = 00001000
Evaluate expression: 2089934848 = 7c91e000
start    end        module name
7c900000 7c9b2000   ntdll      (pdb symbols)          f:\symbols\ntdll.pdb
(7c90d6ee)   Exact matches: ntdll!NtProtectVirtualMemory
Evaluate expression: 1691353088 = 64d00000
0015006a  60 00 60 00 9a 00 15 00                          `.`.....
0015009a  "C:\Program Files\Alwil Software\Avast5\snxhk.dll"
Evaluate expression: 2089903043 = 7c9163c3
(7c9163c3)      Exact matches:    ntdll!LdrLoadDll = <no type information>
patches RtlSetCurwith pattern and sets return address    
[esp+20] to patched instruction calls ntvirtproct for     
a page in ntdll on success loads a dll using LdrLoadDll


the rwx page in csrss.exe is being created during CSRSRV initialization seems to be heap

i set a conditional break after csrss.exe is created on NtAllocateVirtualMemory to print the VadTree on every allocation
and i see that the rwx page is inserted while CSRSRV init and a CreateSharedSection is observed in call stack

sxe ibp;.reboot

on reboot bp NtCreateprocessEx and hit g;kb till csrss.exe is about to be created
you can glean the process being created by looking at the unicode_string passed to RtlCreateUserProcess api in the callstack printed
dS should print ........................../csrss.exe
enter gu go up to allow the process to be created
!process 0 1 csrss.exe save eprocess to scratch pad
!vad VadRoot
you should observe 4 vads in csrss vad tree

now set this conditional breakpoint (substitute the saved eprocess inplace of 0x81160020 note use 0x notation )

bp nt!NtAllocateVirtualMemory "!vad @@c++(((nt!_EPROCESS *) 0x81160020)->VadRoot);kb;.echo \n;dd poi(@esp+8);"

if you persist with an access breakpoint you can catch when the rwx page is being added to the ProcessHeapList

see below

ntdll!RtlCreateHeap+0x5b9: 001b:7c9253de e8a6000000 call ntdll!RtlpAddHeapToProcessList (7c925489)

kd> !heap HEAPEXT: Unable to get address of *ntdll!RtlpGlobalTagHeap. Index Address Name Debugging options enabled
1: 00160000
2: 00260000

p  step over the call

ntdll!RtlCreateHeap+0x5be: 001b:7c9253e3 8b45e4 mov eax,dword ptr [ebp-1Ch]

kd> !heap

Index Address Name Debugging options enabled
1: 00160000
2: 00260000
3: 7f6f0000

kd> `!process 0 1 csrss.exe`
PROCESS `81160020`  SessionId: 0  Cid: 01c4    Peb: 7ffde000  ParentCid: 014c
    DirBase: 06e30000  ObjectTable: e14a7f38  HandleCount:  10.
    Image: csrss.exe
    VadRoot `812275c0 Vads 13` 

dump vadtree

kd> `!vad 812275c0`
VAD     level      start      end    commit
812201d8 ( 1)          0       ff         0 Private      READWRITE         
812280e8 ( 2)        100      100         1 Private      READWRITE         
81229dd0 ( 3)        110      110         1 Private      READWRITE         
81222a88 ( 4)        120      15f         4 Private      READWRITE         
811f30b8 ( 5)        160      25f         3 Private      READWRITE         
81223b80 ( 6)        260      26f         6 Private      READWRITE         
812275c0 ( 0)      4a680    4a684         2 Mapped  Exe  EXECUTE_WRITECOPY  \WINDOWS\system32\csrss.exe
811f4fd8 ( 2)      75b40    75b4a         2 Mapped  Exe  EXECUTE_WRITECOPY  \WINDOWS\system32\csrsrv.dll
811cced0 ( 1)      7c900    7c9b1         5 Mapped  Exe  EXECUTE_WRITECOPY  \WINDOWS\system32\ntdll.dll
8121f440 ( 3)      `7f6f0    7f7ef         0 Mapped       EXECUTE_READWRITE`  Pagefile-backed section
81167108 ( 2)      7ffb0    7ffd3         0 Mapped       READONLY           Pagefile-backed section
811e1d30 ( 4)      7ffdd    7ffdd         1 Private      READWRITE         
811e21b0 ( 3)      7ffde    7ffde         1 Private      READWRITE         

Total VADs:    13  average level:    3  maximum depth: 6

dump call stack

kd> kb
ChildEBP RetAddr  Args to Child              
0015fda4 75b437b8 00007008 7f6f0000 00100000 ntdll!RtlCreateHeap+0x5be
0015fe28 75b42f9a 001626dd 00000000 00000000 CSRSRV!CsrSrvCreateSharedSection+0x23f
0015ff74 75b430f3 0000000a 001624f0 7c90dc9e CSRSRV!CsrParseServerCommandLine+0x255
0015ff88 4a68115d 0000000a 001624f0 00000005 CSRSRV!CsrServerInitialization+0x95
0015ffa8 4a6818d7 0000000a 001624f0 0016251c csrss!main+0x4f
0015fff4 00000000 7ffde000 000000c8 00000166 csrss!NtProcessStartup+0x1d2

list of breakpoints

kd> bl
 0 e 8058124c     0001 (0001) nt!NtCreateProcessEx
 1 e 805691ea     0001 (0001) nt!NtAllocateVirtualMemory "!vad @@c++(((nt!_EPROCESS *) 0x81160020)->VadRoot);kb;.echo \n;dd poi(@esp+8);"
 2 e 7f6f0000 w 1 0001 (0001)

you can follow this methodology with winlogon further below in the chain

update to answer comment

the breakpoint @NtAllocateVirtualMemory did not catch the allocation of vad 12
which was RWX allotment from vad11 my breakpoint got hit only when vad 13 was allocated
and printing vadtree i found that the vads had increased by 2 and one of them was the 7f6f0000 rwx page so maybe another way is used to add the vad to vad tree insted of NtAllocateVirtualMemory it is possible that rwx needs to be reset and isnt being reset needs investigation

i can only confirm that the page is indeed HEAP and seems to mapped in almost every process with EXECUTE_READ permissions on all the process vads except in csrss where it is RWX

lkd> .logopen c:\check7f6f0page.txt
Opened log file 'c:\check7f6f0page.txt'
lkd> !for_each_process ".process /p /r @#Process ; !grep -c \"!vad @@c++( ( ( nt!_EPROCESS *) @#Process )->VadRoot)\" -e \"7f6f0\""
lkd> .logclose
Closing open log file c:\check7f6f0page.txt

results show this page is mapped in all process

lkd> .shell grep "7f6f0    7f7ef         0 Mapped" c:\check7f6f0page.txt
<.shell waiting 1 second(s) for process>
86d39250 ( 4)      7f6f0    7f7ef         0 Mapped       EXECUTE_READWRITE  Pagefile-backed section
86d39250 ( 4)      7f6f0    7f7ef         0 Mapped       EXECUTE_READWRITE  Pagefile-backed section
86e87fd8 ( 4)      7f6f0    7f7ef         0 Mapped       EXECUTE_READ       Pagefile-backed section
86e87fd8 ( 4)      7f6f0    7f7ef         0 Mapped       EXECUTE_READ       Pagefile-backed section
86b96d10 ( 3)      7f6f0    7f7ef         0 Mapped       EXECUTE_READ       Pagefile-backed section
86b96d10 ( 3)      7f6f0    7f7ef         0 Mapped       EXECUTE_READ       Pagefile-backed section
86abfe80 ( 3)      7f6f0    7f7ef         0 Mapped       EXECUTE_READ       Pagefile-backed section
86abfe80 ( 3)      7f6f0    7f7ef         0 Mapped       EXECUTE_READ       Pagefile-backed section
86eaf3a8 ( 3)      7f6f0    7f7ef         0 Mapped       EXECUTE_READ       Pagefile-backed section
86eaf3a8 ( 3)      7f6f0    7f7ef         0 Mapped       EXECUTE_READ       Pagefile-backed section
86b3fda8 ( 4)      7f6f0    7f7ef         0 Mapped       EXECUTE_READ       Pagefile-backed section
86e77b20 ( 2)      7f6f0    7f7ef         0 Mapped       EXECUTE_READ       Pagefile-backed section

and confirms to structure _HEAP

lkd> dt -r nt!_HEAP 0x7f6f0000
   +0x000 Entry            : _HEAP_ENTRY
      +0x000 Size             : 0xc8
      +0x002 PreviousSize     : 0
      +0x000 SubSegmentCode   : 0x000000c8 Void
      +0x004 SmallTagIndex    : 0x1e ''
      +0x005 Flags            : 0x1 ''
      +0x006 UnusedBytes      : 0 ''
      +0x007 SegmentIndex     : 0 ''
   +0x008 Signature        : 0xeeffeeff
   +0x00c Flags            : 0x7008
   +0x010 ForceFlags       : 8
   +0x014 VirtualMemoryThreshold : 0xfe00
   +0x018 SegmentReserve   : 0x100000

dump of 7f6f0000

lkd> dd 7f6f0000 l1c/4
7f6f0000  000000c8 0000011e eeffeeff 00007008
7f6f0010  00000008 0000fe00 00100000

and you can confirm this pattern is indeed heap if you look at ntdll!RtlCreateHeap

lkd> !grep -c "uf ntdll!RtlCreateHeap" -e "ebp-24h"
7c925dcd c745dc88050000  mov     dword ptr [ebp-24h],588h
7c925de7 c745dcc0050000  mov     dword ptr [ebp-24h],5C0h
7c925e87 8145dc80000000  add     dword ptr [ebp-24h],80h
7c925eb1 8b75dc          mov     esi,dword ptr [ebp-24h]
7c93c079 0145dc          add     dword ptr [ebp-24h],eax

dis assemble where the address is used

lkd> u 7c925eb1
7c925eb1 8b75dc          mov     esi,dword ptr [ebp-24h]
7c925eb4 83c607          add     esi,7
7c925eb7 83e6f8          and     esi,0FFFFFFF8h
7c925eba 8bc6            mov     eax,esi
7c925ebc c1e803          shr     eax,3
7c925ebf 8b4de4          mov     ecx,dword ptr [ebp-1Ch]
7c925ec2 668901          mov     word ptr [ecx],ax

evaluate the expression

lkd> ? ((588 + 80 >> 3) + 7)  & 0x0fffffff8 
Evaluate expression: 200 = 000000c8


the RWX page in csrss is _CsrSrvSharedSectionHeap == _CsrSrvSharedSectionBase
that specifc value is queried from registry and mapped with NtMapViewOfSection
or a Section Created using NtCreateSection all of this happens under
csrss!main ->csrsrv.dll ->CsrsrvCreateSharedSection

reg query "hklm\system\currentcontrolset\control\session manager\subsystems\csrss"
HKEY_LOCAL_MACHINE\system\currentcontrolset\control\session manager\subsystems\csrss
        CsrSrvSharedSectionBase     REG_DWORD       0x7f6f0000
  • 1
    Wow, I think I've got to read this a few more times to fully understand it. What comes to my mind now: During process creation, if a process allocates and later commits executable code to an address range (RWX permission), does the process itself have to change the permission to something like PAGE_EXECUTE_READ using VirtualProtect, which would mean that they forgot to make these calls for the RWX VAD's in winlogon and csrss process, or is there some kind of magic happening? Thank you! – user3365 Jan 17 '14 at 8:18
  • Thank you blabb, I was able to confirm that it is heap. I accepted your answer! Thank you for the very clear explanation. Anyway I will have to open a new thread on this to clearify where the rwx vads in winlogon.exe process originate. best regards! – user3365 Jan 27 '14 at 15:22

PAGE_EXECUTE_READWRITE (RWX) memory is commonly used for allocating injected processes. The permissions allow for code execution. Scanning memory dumps for RWX is an approach for detecting injected processes. Here are some examples of memory permission with malware injected into them.

Ramnit Memory: Svchost.exe 1

Private (Commit), 0x20010000, 52 kB, RWX, MZ
Private (Commit), 0x2001d000, 4 kB, R,  
Private (Commit), 0x2001e000, 12 kB, RW, DS
Private (Commit), 0x20021000, 4 kB, R, 

Ramnit Memory: Svchost.exe 2

Private (Commit), 0x20010000, 4 kB, RWX, MZ 
Private (Commit), 0x20011000, 28 kB, RX
Private (Commit), 0x20018000, 4 kB, R
Private (Commit), 0x20019000, 4 kB, RW
Private (Commit), 0x2001a000, 4 kB, R
Free, 0x2001b000, 84 kB, NA


Private (Commit), 0x2460000, 160 kB, RWX, MZ 

The output above was created using my own tool (not Volatility). It is not uncommon for explorer.exe or other processes to have a block of memory marked as RWX. It usually has a size of 4k (depending on the process). The presence of RWX memory doesn't mean something bad is present but it is a good starting point for investigation. A good read on using Volatility for detecting process injection can be found on one of the developer's (Michael Hale Ligh) site.

  • Hey alexanderh, I'm aware of remote code injection. But the dumps are from clean windows installations. I need to distinguish between those RWX vads and others that are due to an injection, thats why I was asking the question in the first place. I'm working on something similar to malfind... Any clues? Thank you! – user3365 Jan 13 '14 at 10:25
  • 1
    @user3365 odds are you will need to get an answer from an individual who has reversed explorer.exe, winlogon.exe, etc or reverse it yourself. Different processes allocate memory for different reasons. There isn't a generic rule for determining when RWX memory is legitimately allocated. There are though generic rules or clues for determining when malicious memory is allocated. Malfind is a good example of detecting off of those rules. Good luck with your project. – alexanderh Jan 13 '14 at 17:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.