2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ldr/loader.c
5 * PURPOSE: Loaders for PE executables
6 * PROGRAMMERS: Jean Michault
7 * Rex Jolliff (rex@lvcablemodem.com)
10 * RJJ 10/12/98 Completed image loader function and added hooks for MZ/PE
11 * RJJ 10/12/98 Built driver loader function and added hooks for PE/COFF
12 * RJJ 10/12/98 Rolled in David's code to load COFF drivers
13 * JM 14/12/98 Built initial PE user module loader
14 * RJJ 06/03/99 Moved user PE loader into NTDLL
17 /* INCLUDES *****************************************************************/
21 #include <internal/i386/segment.h>
22 #include <internal/linkage.h>
23 #include <internal/module.h>
24 #include <internal/ntoskrnl.h>
25 #include <internal/ob.h>
26 #include <internal/ps.h>
28 #include <internal/string.h>
29 #include <internal/symbol.h>
30 #include <internal/teb.h>
31 #include <ddk/ntddk.h>
34 #include <internal/debug.h>
36 /* FUNCTIONS ****************************************************************/
40 * Builds the initial environment for a process. Should be used
41 * to load the initial user process.
43 * HANDLE ProcessHandle handle of the process to load the module into
44 * PUNICODE_STRING Filename name of the module to load
49 #define STACK_TOP (0xb0000000)
51 static NTSTATUS
LdrCreatePeb(HANDLE ProcessHandle
)
61 Status
= ZwAllocateVirtualMemory(ProcessHandle
,
67 if (!NT_SUCCESS(Status
))
73 memset(&Peb
, 0, sizeof(Peb
));
74 Peb
.StartupInfo
= PEB_STARTUPINFO
;
76 ZwWriteVirtualMemory(ProcessHandle
,
82 return(STATUS_SUCCESS
);
85 NTSTATUS
LdrLoadImage(HANDLE ProcessHandle
, PUNICODE_STRING Filename
)
87 char BlockBuffer
[1024];
88 DWORD ImageBase
, LdrStartupAddr
, StackBase
;
89 ULONG ImageSize
, StackSize
;
91 OBJECT_ATTRIBUTES FileObjectAttributes
;
92 HANDLE FileHandle
, SectionHandle
, NTDllSectionHandle
, ThreadHandle
;
93 HANDLE DupNTDllSectionHandle
;
95 UNICODE_STRING DllPathname
;
96 PIMAGE_DOS_HEADER DosHeader
;
97 PIMAGE_NT_HEADERS NTHeaders
;
99 ULONG InitialViewSize
;
101 HANDLE DupSectionHandle
;
103 /* Locate and open NTDLL to determine ImageBase and LdrStartup */
104 RtlInitUnicodeString(&DllPathname
,L
"\\??\\C:\\reactos\\system\\ntdll.dll");
105 InitializeObjectAttributes(&FileObjectAttributes
,
110 DPRINT("Opening NTDLL\n");
111 Status
= ZwOpenFile(&FileHandle
,
113 &FileObjectAttributes
,
117 if (!NT_SUCCESS(Status
))
119 DPRINT("NTDLL open failed ");
120 DbgPrintErrorMessage(Status
);
124 Status
= ZwReadFile(FileHandle
, 0, 0, 0, 0, BlockBuffer
, 1024, 0, 0);
125 if (!NT_SUCCESS(Status
))
127 DPRINT("NTDLL header read failed ");
128 DbgPrintErrorMessage(Status
);
133 /* FIXME: this will fail if the NT headers are more than 1024 bytes from start */
134 DosHeader
= (PIMAGE_DOS_HEADER
) BlockBuffer
;
135 if (DosHeader
->e_magic
!= IMAGE_DOS_MAGIC
||
136 DosHeader
->e_lfanew
== 0L ||
137 *(PULONG
)((PUCHAR
)BlockBuffer
+ DosHeader
->e_lfanew
) != IMAGE_PE_MAGIC
)
139 DPRINT("NTDLL format invalid\n");
142 return STATUS_UNSUCCESSFUL
;
144 NTHeaders
= (PIMAGE_NT_HEADERS
)(BlockBuffer
+ DosHeader
->e_lfanew
);
145 ImageBase
= NTHeaders
->OptionalHeader
.ImageBase
;
146 ImageSize
= NTHeaders
->OptionalHeader
.SizeOfImage
;
147 /* FIXME: retrieve the offset of LdrStartup from NTDLL */
148 DPRINT("ImageBase %x\n",ImageBase
);
149 LdrStartupAddr
= ImageBase
+ NTHeaders
->OptionalHeader
.AddressOfEntryPoint
;
151 /* Create a section for NTDLL */
152 Status
= ZwCreateSection(&NTDllSectionHandle
,
159 if (!NT_SUCCESS(Status
))
161 DPRINT("NTDLL create section failed ");
162 DbgPrintErrorMessage(Status
);
168 /* Map the NTDLL into the process */
169 InitialViewSize
= DosHeader
->e_lfanew
+ sizeof(IMAGE_NT_HEADERS
)
170 + sizeof(IMAGE_SECTION_HEADER
) * NTHeaders
->FileHeader
.NumberOfSections
;
171 Status
= ZwMapViewOfSection(NTDllSectionHandle
,
181 if (!NT_SUCCESS(Status
))
183 DPRINT("NTDLL map view of secion failed ");
184 DbgPrintErrorMessage(Status
);
186 /* FIXME: destroy the section here */
192 for (i
=0; i
<NTHeaders
->FileHeader
.NumberOfSections
; i
++)
194 PIMAGE_SECTION_HEADER Sections
;
195 LARGE_INTEGER Offset
;
198 Sections
= (PIMAGE_SECTION_HEADER
)SECHDROFFSET(BlockBuffer
);
199 Base
= Sections
[i
].VirtualAddress
+ ImageBase
;
201 Offset
.LowPart
= Sections
[i
].PointerToRawData
;
202 Status
= ZwMapViewOfSection(NTDllSectionHandle
,
206 Sections
[i
].Misc
.VirtualSize
,
208 (PULONG
)&Sections
[i
].Misc
.VirtualSize
,
212 if (!NT_SUCCESS(Status
))
214 DPRINT("NTDLL map view of secion failed ");
215 DbgPrintErrorMessage(Status
);
217 /* FIXME: destroy the section here */
225 /* Open process image to determine ImageBase and StackBase/Size */
226 InitializeObjectAttributes(&FileObjectAttributes
,
231 DPRINT("Opening image file %w\n",FileObjectAttributes
.ObjectName
->Buffer
);
232 Status
= ZwOpenFile(&FileHandle
, FILE_ALL_ACCESS
, &FileObjectAttributes
,
234 if (!NT_SUCCESS(Status
))
236 DPRINT("Image open failed ");
237 DbgPrintErrorMessage(Status
);
241 Status
= ZwReadFile(FileHandle
, 0, 0, 0, 0, BlockBuffer
, 1024, 0, 0);
242 if (!NT_SUCCESS(Status
))
244 DPRINT("Image header read failed ");
245 DbgPrintErrorMessage(Status
);
251 /* FIXME: this will fail if the NT headers are more than 1024 bytes from start */
253 DosHeader
= (PIMAGE_DOS_HEADER
) BlockBuffer
;
254 if (DosHeader
->e_magic
!= IMAGE_DOS_MAGIC
||
255 DosHeader
->e_lfanew
== 0L ||
256 *(PULONG
)((PUCHAR
)BlockBuffer
+ DosHeader
->e_lfanew
) != IMAGE_PE_MAGIC
)
258 DPRINT("Image invalid format rc=%08lx\n", Status
);
261 return STATUS_UNSUCCESSFUL
;
263 NTHeaders
= (PIMAGE_NT_HEADERS
)(BlockBuffer
+ DosHeader
->e_lfanew
);
264 ImageBase
= NTHeaders
->OptionalHeader
.ImageBase
;
265 ImageSize
= NTHeaders
->OptionalHeader
.SizeOfImage
;
267 /* Create a section for the image */
268 Status
= ZwCreateSection(&SectionHandle
,
275 if (!NT_SUCCESS(Status
))
277 DPRINT("Image create section failed ");
278 DbgPrintErrorMessage(Status
);
284 /* Map the image into the process */
285 InitialViewSize
= DosHeader
->e_lfanew
+ sizeof(IMAGE_NT_HEADERS
)
286 + sizeof(IMAGE_SECTION_HEADER
) * NTHeaders
->FileHeader
.NumberOfSections
;
287 DPRINT("InitialViewSize %x\n",InitialViewSize
);
288 Status
= ZwMapViewOfSection(SectionHandle
,
298 if (!NT_SUCCESS(Status
))
300 DPRINT("Image map view of section failed ");
301 DbgPrintErrorMessage(Status
);
303 /* FIXME: destroy the section here */
311 /* Create page backed section for stack */
312 StackBase
= (STACK_TOP
- NTHeaders
->OptionalHeader
.SizeOfStackReserve
);
313 StackSize
= NTHeaders
->OptionalHeader
.SizeOfStackReserve
;
314 Status
= ZwAllocateVirtualMemory(ProcessHandle
,
320 if (!NT_SUCCESS(Status
))
322 DPRINT("Stack allocation failed ");
323 DbgPrintErrorMessage(Status
);
325 /* FIXME: unmap the section here */
326 /* FIXME: destroy the section here */
331 ZwDuplicateObject(NtCurrentProcess(),
337 DUPLICATE_SAME_ACCESS
);
338 ZwDuplicateObject(NtCurrentProcess(),
341 &DupNTDllSectionHandle
,
344 DUPLICATE_SAME_ACCESS
);
346 ZwWriteVirtualMemory(ProcessHandle
,
347 (PVOID
)(STACK_TOP
- 4),
348 &DupNTDllSectionHandle
,
349 sizeof(DupNTDllSectionHandle
),
351 ZwWriteVirtualMemory(ProcessHandle
,
352 (PVOID
)(STACK_TOP
- 8),
356 ZwWriteVirtualMemory(ProcessHandle
,
357 (PVOID
)(STACK_TOP
- 12),
359 sizeof(DupSectionHandle
),
364 * Create a peb (grungy)
366 Status
= LdrCreatePeb(ProcessHandle
);
367 if (!NT_SUCCESS(Status
))
369 DbgPrint("LDR: Failed to create initial peb\n");
373 /* Initialize context to point to LdrStartup */
374 memset(&Context
,0,sizeof(CONTEXT
));
375 Context
.SegSs
= USER_DS
;
376 Context
.Esp
= STACK_TOP
- 16;
377 Context
.EFlags
= 0x202;
378 Context
.SegCs
= USER_CS
;
379 Context
.Eip
= LdrStartupAddr
;
380 Context
.SegDs
= USER_DS
;
381 Context
.SegEs
= USER_DS
;
382 Context
.SegFs
= USER_DS
;
383 Context
.SegGs
= USER_DS
;
385 DPRINT("LdrStartupAddr %x\n",LdrStartupAddr
);
386 /* FIXME: Create process and let 'er rip */
387 Status
= ZwCreateThread(&ThreadHandle
,
395 if (!NT_SUCCESS(Status
))
397 DPRINT("Thread creation failed ");
398 DbgPrintErrorMessage(Status
);
400 /* FIXME: destroy the stack memory block here */
401 /* FIXME: unmap the section here */
402 /* FIXME: destroy the section here */
407 return STATUS_SUCCESS
;
410 NTSTATUS
LdrLoadInitialProcess(VOID
)
412 * FIXME: The location of the initial process should be configurable,
413 * from command line or registry
417 HANDLE ProcessHandle
;
418 UNICODE_STRING ProcessName
;
420 Status
= ZwCreateProcess(&ProcessHandle
,
428 if (!NT_SUCCESS(Status
))
430 DbgPrint("Could not create process\n");
434 RtlInitUnicodeString(&ProcessName
, L
"\\??\\C:\\reactos\\system\\shell.exe");
435 Status
= LdrLoadImage(ProcessHandle
, &ProcessName
);