首页 > WinDriver > WD-进程地址空间(WRK)
2015四月13

WD-进程地址空间(WRK)

[隐藏]

当PspCreateProcess创建一个进程时,如果指定的父进程不为NULL,则需要创建一个新的地址空间,空间的创建是由MmCreateProcessAddressSpace完成的,而且,地址空间被创建后,PspCreateProcess会调用MmInitializeProcessAddressSpace初始化地址空间

1.MmCreateProcessAddressSpace创建地址空间

1
2
3
4
5
6
BOOLEAN
MmCreateProcessAddressSpace (
    IN ULONG MinimumWorkingSetSize,// 待创建进程的最小工作集大小
    IN PEPROCESS NewProcess,// 进程对象
    OUT PULONG_PTR DirectoryTableBase// OUT 指向进程地址空间的页目录表
    )

WRK有MmCreateProcessAddressSpace三份,分别对应X86,PAE和X64,下面是X86的代码:

1.调用MiChargeCommitment确认有足够的页面文件空间. 

1
2
3
4
 #define MM_PROCESS_COMMIT_CHARGE 4
 if (MiChargeCommitment (MM_PROCESS_COMMIT_CHARGE, NULL) == FALSE) {
        return FALSE;
    }

 

2.检查系统当前可用的物理页面是否达到了MinimumWorkingSetSize,如果不够,则返回失败

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    //
    // Check to make sure the physical pages are available.
    //
 
    if (MI_NONPAGEABLE_MEMORY_AVAILABLE() <= (SPFN_NUMBER)MinimumWorkingSetSize){
 
        UNLOCK_PFN (OldIrql);
        MiReturnCommitment (MM_PROCESS_COMMIT_CHARGE);
 
        //
        // Indicate no directory base was allocated.
        //
 
        return FALSE;
    }

 

3.申请一个物理页面作为页目录页面,该页面已清零,页帧编号置于局部变量PageDirectoryIndex中

1
2
3
4
    //
    // Allocate a page directory page.
    //
  PageDirectoryIndex = MiRemoveZeroPageMayReleaseLocks (Color, OldIrql);

 

4.再申请一个物理页面作为超空间页表页面,同样的,该页面已清零,页帧编号置于局部变量HyperSpaceIndex中

1
2
3
4
5
6
7
8
9
10
11
12
   //
    // Allocate the hyper space page table page.
    //
 
    if (MmAvailablePages < MM_HIGH_LIMIT) {
        MiEnsureAvailablePageOrWait (NULL, OldIrql);
    }
 
    Color = MI_PAGE_COLOR_PTE_PROCESS (MiGetPdeAddress(HYPER_SPACE),
                                       &CurrentProcess->NextPageColor);
 
    HyperSpaceIndex = MiRemoveZeroPageMayReleaseLocks (Color, OldIrql);

     

5.再申请一个物理页面作为VAD位图,其页页帧编号置于局部变量VadBitMapPage中

1
2
3
4
5
6
7
8
9
10
11
12
 //
    // Remove page(s) for the VAD bitmap.
    //
 
    if (MmAvailablePages < MM_HIGH_LIMIT) {
        MiEnsureAvailablePageOrWait (NULL, OldIrql);
    }
 
    Color = MI_PAGE_COLOR_VA_PROCESS (MmWorkingSetList,
                                      &CurrentProcess->NextPageColor);
 
    VadBitMapPage = MiRemoveZeroPageMayReleaseLocks (Color, OldIrql);

    

6.再申请一个物理页面作为工作集链表,其页页帧编号置于局部变量PageContainingWorkingSet中

1
2
3
4
5
6
7
8
9
10
11
12
 //
    // Remove a page for the working set list.
    //
 
    if (MmAvailablePages < MM_HIGH_LIMIT) {
        MiEnsureAvailablePageOrWait (NULL, OldIrql);
    }
 
    Color = MI_PAGE_COLOR_VA_PROCESS (MmWorkingSetList,
                                      &CurrentProcess->NextPageColor);
 
    PageContainingWorkingSet = MiRemoveZeroPageMayReleaseLocks (Color, OldIrql);

    

7.接下来初始化新进程EPROCESS对象的Vm.MinimumWorkingSetSize、WorkingSetPage、DirectoryTableBase

1
2
3
4
5
6
7
    NewProcess->Vm.MinimumWorkingSetSize = MinimumWorkingSetSize;
 
    NewProcess->WorkingSetPage = PageContainingWorkingSet;
 
    INITIALIZE_DIRECTORY_TABLE_BASE (&DirectoryTableBase[0], PageDirectoryIndex);
 
    INITIALIZE_DIRECTORY_TABLE_BASE (&DirectoryTableBase[1], HyperSpaceIndex);

    

8.初始化超空间页表页面,在系统PTE区域保留一个PTE,用于映射超空间页表页面,以便访问其中的内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
    //
    // Initialize the page reserved for hyper space.
    //
 
    TempPte = ValidPdePde;
    MI_SET_GLOBAL_STATE (TempPte, 0);
 
    MappingPte = MiReserveSystemPtes (1, SystemPteSpace);
 
    if (MappingPte != NULL) {
 
        MI_MAKE_VALID_KERNEL_PTE (TempPte2,
                                  HyperSpaceIndex,
                                  MM_READWRITE,
                                  MappingPte);
 
        MI_SET_PTE_DIRTY (TempPte2);
 
        MI_WRITE_VALID_PTE (MappingPte, TempPte2);
 
        PointerPte = MiGetVirtualAddressMappedByPte (MappingPte);
    }
    else {
        PointerPte = MiMapPageInHyperSpace (CurrentProcess, HyperSpaceIndex, &OldIrql);
    }
 
    TempPte.u.Hard.PageFrameNumber = VadBitMapPage;
    PointerPte[MiGetPteOffset(VAD_BITMAP_SPACE)] = TempPte;
 
    TempPte.u.Hard.PageFrameNumber = PageContainingWorkingSet;
    PointerPte[MiGetPteOffset(MmWorkingSetList)] = TempPte;
 
    if (MappingPte != NULL) {
        MiReleaseSystemPtes (MappingPte, 1, SystemPteSpace);
    }
    else {
        MiUnmapPageInHyperSpace (CurrentProcess, PointerPte, OldIrql);
    }

 

9.在PFN数据库中,设置页目录页面的PTE地址,为0XC0300000

1
2
3
4
5
6
7
   //
    // Set the PTE address in the PFN for the page directory page.
    //
 
    Pfn1 = MI_PFN_ELEMENT (PageDirectoryIndex);
 
    Pfn1->PteAddress = (PMMPTE)PDE_BASE;
#define PDE_BASE_X86    0xc0300000

 

10.把新进程加入到系统内部维护的进程链表中MmProcessList

1
2
3
4
5
6
7
8
9
10
11
12
13
  //
    // Add the new process to our internal list prior to filling any
    // system PDEs so if a system PDE changes (large page map or unmap)
    // it can mark this process for a subsequent update.
    //
 
    ASSERT (NewProcess->Pcb.DirectoryTableBase[0] == 0);
 
    LOCK_EXPANSION (OldIrql);
 
    InsertTailList (&MmProcessList, &NewProcess->MmProcessLinks);
 
    UNLOCK_EXPANSION (OldIrql);

  

11.初始化页目录页面,首先在系统PTE区域保留一个PTE,用于映射页目录页面,以便访问其中的内容,在页目录页面中,把系统空间(0x80000000后)的PDE复制到页目录页面中(实际上恰好后半个页面),然后映射超空间(0xc0400000~0xc0c00000)中第一个PDE项,余下的清零,接着,在页目录中,指定0xc0000000的页目录项指向页目录页面自身,然后,把这4个页面的开销记录到MmProcessCommit全局变量中,完成后,释放此PTE.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
    //
    // Map the page directory page in hyperspace.
    //
 
    MappingPte = MiReserveSystemPtes (1, SystemPteSpace);
 
    if (MappingPte != NULL) {
 
        MI_MAKE_VALID_KERNEL_PTE (TempPte2,
                                  PageDirectoryIndex,
                                  MM_READWRITE,
                                  MappingPte);
 
        MI_SET_PTE_DIRTY (TempPte2);
 
        MI_WRITE_VALID_PTE (MappingPte, TempPte2);
 
        PointerPte = MiGetVirtualAddressMappedByPte (MappingPte);
    }
    else {
        PointerPte = MiMapPageInHyperSpace (CurrentProcess, PageDirectoryIndex, &OldIrql);
    }
 
    PdeOffset = MiGetPdeOffset (MmSystemRangeStart);
    PointerFillPte = &PointerPte[PdeOffset];
    CurrentAddressSpacePde = MiGetPdeAddress (MmSystemRangeStart);
 
    RtlCopyMemory (PointerFillPte,
                   CurrentAddressSpacePde,
                   PAGE_SIZE - PdeOffset * sizeof (MMPTE));
 
    //
    // Map the working set page table page.
    //
 
    PdeOffset = MiGetPdeOffset (HYPER_SPACE);
    PointerPte[PdeOffset] = TempPte;
 
    //
    // Zero the remaining page directory range used to map the working
    // set list and its hash.
    //
 
    PdeOffset += 1;
    ASSERT (MiGetPdeOffset (MmHyperSpaceEnd) >= PdeOffset);
 
    MiZeroMemoryPte (&PointerPte[PdeOffset],
                     (MiGetPdeOffset (MmHyperSpaceEnd) - PdeOffset + 1));
 
    //
    // Recursively map the page directory page so it points to itself.
    //
 
    TempPte.u.Hard.PageFrameNumber = PageDirectoryIndex;
    PointerPte[MiGetPdeOffset(PTE_BASE)] = TempPte;
 
    if (MappingPte != NULL) {
        MiReleaseSystemPtes (MappingPte, 1, SystemPteSpace);
    }
    else {
        MiUnmapPageInHyperSpace (CurrentProcess, PointerPte, OldIrql);
    }
 
    InterlockedExchangeAddSizeT (&MmProcessCommit, MM_PROCESS_COMMIT_CHARGE);

   

12.最后,把新进程加入到当前进程所在的会话空间

1
2
3
4
5
    //
    // Up the session space reference count.
    //
 
    MiSessionAddProcess (NewProcess);

 

在新进程地址空间中,用户空间部分(0-0x7fffffff)仍是一片空白,这部分初始化工作是由mInitializeProcessAddressSpace初始化.

  

2.MmInitializeProcessAddressSpace初始化地址空间

1
2
3
4
5
6
7
8
NTSTATUS
MmInitializeProcessAddressSpace (
    IN PEPROCESS ProcessToInitialize,//要初始化的目标进程
    IN PEPROCESS ProcessToClone OPTIONAL,//可选,表示新进程的地址空间可以从该进程拷贝获得
    IN PVOID SectionToMap OPTIONAL,//可选,提供一个内存区对象,表示在新进程地址空间中映射此对象
    IN OUT PULONG CreateFlags,//与进程创建相关的标志
    OUT POBJECT_NAME_INFORMATION *AuditName OPTIONAL//可选,提供一个对象名称信息指针
    )

 

3.地址空间切换

windows在进程切换时,只需直接切换页目录页面,即CR3寄存器,而无须对页目录中的PDE做任何调整或一致性维护,即可实现从一个进程的地址空间转换到另一个进程的地址空间。

 

4.进程地址空间的内存管理(0~0x7fffffff)

对于进程地址空间,用户程序必须经过"保留(reserve)"和"提交(commit)"两个阶段才能使用一段地址范围,"保留(reserve)"的意思为,把这段地址范围保留起来,但并不真正使用,由于不占用任何物理内存或其他外存,所以不形成实质的开销,但这对于有些需要连续地址空间的程序有意义,它们可以在初始时保留一段大地址范围,以后需要的时候陆续使用.

"提交(commit)"是指这段地址终究要消耗物理内存,由于windows支持物理内存与页面文件的交换,所以可提交内存数量是,可用物理内存总量去除系统使用的物理内存数量后,再加上页面文件的大小.

 

文章作者:hgy413
本文地址:http://hgy413.com/3000.html
版权所有 © 转载时必须以链接形式注明作者和原始出处!

本文目前尚无任何评论.

发表评论