1、windows进程的用户空间
windows用户空间与系统空间的分界线是0x80000000。
应用软件在用户空间可以访问的最高地址是0x7ffeffff,从0x7fff0000就不让访问了,因为在分界线下留了64KB的隔离区。
应用软件在用户空间可以访问的最低地址是0x00010000,从0开始的64KB也不让访问。
特殊空间:
在系统空间的0xffdf0000处,存放着_KUSER_SHARED_DATA结构(4KB),这个结构是所有进程共享的。这个结构的字段都是一些系统信息,如NtSystemRoot字段,存放的是系统根目录的路径名。
用户空间中的格局安排:
用户空间的创建及其大的格局由内核函数MmInitializeProcessAddressSpace()实现。
//NtCreateProcess->NtCreateProcessEx->PspCreateProcess->MmInitializeProcessAddressSpace NTSTATUS NTAPI MmInitializeProcessAddressSpace(IN PEPROCESS Process, IN PEPROCESS ProcessClone OPTIONAL, IN PVOID Section OPTIONAL, IN OUT PULONG Flags, IN POBJECT_NAME_INFORMATION *AuditName OPTIONAL) { NTSTATUS Status; PMMSUPPORT ProcessAddressSpace = &Process->Vm; PVOID BaseAddress; PMEMORY_AREA MemoryArea; PHYSICAL_ADDRESS BoundaryAddressMultiple; SIZE_T ViewSize = 0; PVOID ImageBase = 0; PROS_SECTION_OBJECT SectionObject = Section; BoundaryAddressMultiple.QuadPart = 0; //以下为初始化用户空间,并设置禁区 /* Initialize the Addresss Space lock */ KeInitializeGuardedMutex(&Process->AddressCreationLock); Process->Vm.WorkingSetExpansionLinks.Flink = NULL; /* Initialize AVL tree */ ASSERT(Process->VadRoot.NumberGenericTableElements == 0); Process->VadRoot.BalancedRoot.u1.Parent = &Process->VadRoot.BalancedRoot; /* Acquire the Lock */ MmLockAddressSpace(ProcessAddressSpace); /* Protect the highest 64KB of the process address space */ BaseAddress = (PVOID)MmUserProbeAddress; //MmSystemRangeStart-0x10000 Status = MmCreateMemoryArea(ProcessAddressSpace, MEMORY_AREA_NO_ACCESS, &BaseAddress, 0x10000, PAGE_NOACCESS, //禁止访问 &MemoryArea, FALSE, 0, BoundaryAddressMultiple); if (!NT_SUCCESS(Status)) { goto exit; } /* Protect the 60KB above the shared user page */ BaseAddress = (char*)USER_SHARED_DATA + PAGE_SIZE; //0x7FFE0000+0x1000 Status = MmCreateMemoryArea(ProcessAddressSpace, MEMORY_AREA_NO_ACCESS, &BaseAddress, 0x10000 - PAGE_SIZE, //0x10000-0x1000 PAGE_NOACCESS, //禁止访问 &MemoryArea, FALSE, 0, BoundaryAddressMultiple); if (!NT_SUCCESS(Status)) { goto exit; } /* Create the shared data page */ BaseAddress = (PVOID)USER_SHARED_DATA; //0x7FFE0000 Status = MmCreateMemoryArea(ProcessAddressSpace, MEMORY_AREA_SHARED_DATA, &BaseAddress, PAGE_SIZE, //0x1000(4K) PAGE_EXECUTE_READ, //可读,可执行 &MemoryArea, FALSE, 0, BoundaryAddressMultiple); if (!NT_SUCCESS(Status)) { goto exit; } /* The process now has an address space */ Process->HasAddressSpace = TRUE; //以下为开始分配用户空间 /* Check if there's a Section Object */ if (SectionObject) {//已建立可执行文件的文件映射区 UNICODE_STRING FileName; PWCHAR szSrc; PCHAR szDest; USHORT lnFName = 0; /* Unlock the Address Space */ //为可执行文件分配虚存空间并建立映射 MmUnlockAddressSpace(ProcessAddressSpace); Status = MmMapViewOfSection(Section, (PEPROCESS)Process, (PVOID*)&ImageBase, 0, 0, NULL, &ViewSize, 0, MEM_COMMIT, PAGE_READWRITE); if (!NT_SUCCESS(Status)) { return Status; } /* Save the pointer */ Process->SectionBaseAddress = ImageBase; //指向可执行文件的起点 /* Determine the image file name and save it to EPROCESS */ //Getting Image name FileName = SectionObject->FileObject->FileName; szSrc = (PWCHAR)((PCHAR)FileName.Buffer + FileName.Length); if (FileName.Buffer) { /* Loop the file name*/ while (szSrc > FileName.Buffer) { /* Make sure this isn't a backslash */ if (*--szSrc == OBJ_NAME_PATH_SEPARATOR) { /* If so, stop it here */ szSrc++; break; } else { /* Otherwise, keep going */ lnFName++; } } } /* Copy the to the process and truncate it to 15 characters if necessary */ szDest = Process->ImageFileName; lnFName = min(lnFName, sizeof(Process->ImageFileName) - 1); while (lnFName--) *szDest++ = (UCHAR)*szSrc++; *szDest = ANSI_NULL; /* Check if caller wants an audit name */ if (AuditName) { /* Setup the audit name */ SeInitializeProcessAuditName(SectionObject->FileObject, FALSE, AuditName); } /* Return status to caller */ return Status; } exit: /* Unlock the Address Space */ DPRINT("Unlocking/n"); MmUnlockAddressSpace(ProcessAddressSpace); /* Return status to caller */ return Status; }
除了EXE文件,还有一些DLL也要装入或映射到用户空间,其中有ntdll.dll是特殊的。此DLL在内核初始化时候,系统为其创建了一个文件映射区对象,并使全局指针PspSystemDllSection指向该对象的数据结构。
在MmInitializeProcessAddressSpace后,使用PspMapSystemDll建立ntdll.dll的映射。
//NtCreateProcess->NtCreateProcessEx->PspCreateProcess->PspMapSystemDll NTSTATUS NTAPI PspMapSystemDll(IN PEPROCESS Process, IN PVOID *DllBase, IN BOOLEAN UseLargePages) { NTSTATUS Status; LARGE_INTEGER Offset = {{0, 0}}; SIZE_T ViewSize = 0; PVOID ImageBase = 0; /* Map the System DLL */ Status = MmMapViewOfSection(PspSystemDllSection, //ntdll.dll Process, (PVOID*)&ImageBase, 0, 0, &Offset, &ViewSize, ViewShare, 0, PAGE_READWRITE); if (Status != STATUS_SUCCESS) { /* Normalize status code */ Status = STATUS_CONFLICTING_ADDRESSES; } /* Write the image base and return status */ if (DllBase) *DllBase = ImageBase; return Status; }
之后,是进程环境块PEB的建立。这是由MmCreatePeb完成的。
//NtCreateProcess->NtCreateProcessEx->PspCreateProcess->MmCreatePeb NTSTATUS NTAPI MmCreatePeb(IN PEPROCESS Process, IN PINITIAL_PEB InitialPeb, OUT PPEB *BasePeb) { PPEB Peb = NULL; LARGE_INTEGER SectionOffset; SIZE_T ViewSize = 0; PVOID TableBase = NULL; PIMAGE_NT_HEADERS NtHeaders; PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigData; NTSTATUS Status; USHORT Characteristics; KAFFINITY ProcessAffinityMask = 0; SectionOffset.QuadPart = (ULONGLONG)0; *BasePeb = NULL; // Attach to Process // 挂靠新进程 KeAttachProcess(&Process->Pcb); // Allocate the PEB // 地址为MM_HIGHEST_USER_ADDRESS - (16 * PAGE_SIZE)+1 // 0x7ffeffff-(16 * PAGE_SIZE)+1 // 0x7ffdffff+1 // 0x7ffe0000 // 从0x7ffe0000向下取大小为0x1000的区间存放peb // 所以peb的首地址为0x7FFDF000,大小为0x1000 Peb = MiCreatePebOrTeb(Process, (PVOID)((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1)); ASSERT(Peb == (PVOID)0x7FFDF000); ... // Use SEH in case we can't load the PEB _SEH2_TRY { // Initialize the PEB RtlZeroMemory(Peb, sizeof(PEB)); // Set up data Peb->ImageBaseAddress = Process->SectionBaseAddress; Peb->InheritedAddressSpace = InitialPeb->InheritedAddressSpace; Peb->Mutant = InitialPeb->Mutant; Peb->ImageUsesLargePages = InitialPeb->ImageUsesLargePages; // NLS Peb->AnsiCodePageData = (PCHAR)TableBase + ExpAnsiCodePageDataOffset; Peb->OemCodePageData = (PCHAR)TableBase + ExpOemCodePageDataOffset; Peb->UnicodeCaseTableData = (PCHAR)TableBase + ExpUnicodeCaseTableDataOffset; // Default Version Data (could get changed below) Peb->OSMajorVersion = NtMajorVersion; Peb->OSMinorVersion = NtMinorVersion; Peb->OSBuildNumber = (USHORT)(NtBuildNumber & 0x3FFF); Peb->OSPlatformId = 2; /* VER_PLATFORM_WIN32_NT */ Peb->OSCSDVersion = (USHORT)CmNtCSDVersion; // Heap and Debug Data Peb->NumberOfProcessors = KeNumberProcessors; Peb->BeingDebugged = (BOOLEAN)(Process->DebugPort != NULL ? TRUE : FALSE); Peb->NtGlobalFlag = NtGlobalFlag; Peb->MaximumNumberOfHeaps = (PAGE_SIZE - sizeof(PEB)) / sizeof(PVOID); //除peb本身的剩余空间,存储堆指针数组,堆的数量由此算出 Peb->ProcessHeaps = (PVOID*)(Peb + 1); //指向堆指针数组起点 // Session ID if (Process->Session) Peb->SessionId = 0; // MmGetSessionId(Process); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { // Fail KeDetachProcess(); _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END; ... // Detach from the Process KeDetachProcess(); *BasePeb = Peb; return STATUS_SUCCESS; }