fixes
[reactos.git] / reactos / ntoskrnl / ldr / init.c
1 /*
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)
8 * UPDATE HISTORY:
9 * DW 22/05/98 Created
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
15 * EA 19990717 GetSystemDirectory()
16 */
17
18 /* INCLUDES *****************************************************************/
19
20 #include <windows.h>
21
22 #include <internal/i386/segment.h>
23 #include <internal/linkage.h>
24 #include <internal/module.h>
25 #include <internal/ntoskrnl.h>
26 #include <internal/ob.h>
27 #include <internal/ps.h>
28 #include <string.h>
29 #include <internal/string.h>
30 #include <internal/symbol.h>
31 #include <internal/teb.h>
32 #include <ddk/ntddk.h>
33
34 #define NDEBUG
35 #include <internal/debug.h>
36
37 #include "syspath.h"
38
39
40 /* FUNCTIONS ****************************************************************/
41
42 /**********************************************************************
43 * NAME
44 * LdrLoadImage
45 *
46 * FUNCTION:
47 * Builds the initial environment for a process. Should be used
48 * to load the initial user process.
49 *
50 * ARGUMENTS:
51 * HANDLE ProcessHandle handle of the process to load the module into
52 * PUNICODE_STRING Filename name of the module to load
53 *
54 * RETURNS:
55 * NTSTATUS
56 */
57
58 #define STACK_TOP (0xb0000000)
59
60 static
61 NTSTATUS
62 LdrCreatePeb(HANDLE ProcessHandle)
63 {
64 NTSTATUS Status;
65 PVOID PebBase;
66 ULONG PebSize;
67 NT_PEB Peb;
68 ULONG BytesWritten;
69
70
71 PebBase = (PVOID)PEB_BASE;
72 PebSize = 0x1000;
73 Status = ZwAllocateVirtualMemory(
74 ProcessHandle,
75 & PebBase,
76 0,
77 & PebSize,
78 MEM_COMMIT,
79 PAGE_READWRITE
80 );
81 if (!NT_SUCCESS(Status))
82 {
83 return(Status);
84 }
85
86
87 memset(
88 & Peb,
89 0,
90 sizeof Peb
91 );
92 Peb.StartupInfo = (PPROCESSINFOW) PEB_STARTUPINFO;
93
94 ZwWriteVirtualMemory(
95 ProcessHandle,
96 (PVOID) PEB_BASE,
97 & Peb,
98 sizeof Peb,
99 & BytesWritten
100 );
101
102 return(STATUS_SUCCESS);
103 }
104
105
106 NTSTATUS
107 LdrLoadImage (
108 HANDLE ProcessHandle,
109 PUNICODE_STRING Filename
110 )
111 {
112 CHAR BlockBuffer [1024];
113 DWORD ImageBase;
114 DWORD LdrStartupAddr;
115 DWORD StackBase;
116 ULONG ImageSize;
117 ULONG StackSize;
118 NTSTATUS Status;
119 OBJECT_ATTRIBUTES FileObjectAttributes;
120 HANDLE FileHandle;
121 HANDLE SectionHandle;
122 HANDLE NTDllSectionHandle;
123 HANDLE ThreadHandle;
124 HANDLE DupNTDllSectionHandle;
125 CONTEXT Context;
126 UNICODE_STRING DllPathname;
127 PIMAGE_DOS_HEADER DosHeader;
128 PIMAGE_NT_HEADERS NTHeaders;
129 ULONG BytesWritten;
130 ULONG InitialViewSize;
131 ULONG i;
132 HANDLE DupSectionHandle;
133
134 WCHAR TmpNameBuffer [MAX_PATH];
135
136
137 /* -- PART I -- */
138
139 /*
140 * Locate and open NTDLL to determine ImageBase
141 * and LdrStartup
142 */
143 GetSystemDirectory(
144 TmpNameBuffer,
145 sizeof TmpNameBuffer
146 );
147 wcscat(
148 TmpNameBuffer,
149 L"\\ntdll.dll"
150 );
151 RtlInitUnicodeString(
152 & DllPathname,
153 TmpNameBuffer
154 );
155 InitializeObjectAttributes(
156 & FileObjectAttributes,
157 & DllPathname,
158 0,
159 NULL,
160 NULL
161 );
162 DPRINT("Opening NTDLL\n");
163 Status = ZwOpenFile(
164 & FileHandle,
165 FILE_ALL_ACCESS,
166 & FileObjectAttributes,
167 NULL,
168 0,
169 0
170 );
171 if (!NT_SUCCESS(Status))
172 {
173 DPRINT("NTDLL open failed ");
174 DbgPrintErrorMessage(Status);
175
176 return Status;
177 }
178 Status = ZwReadFile(
179 FileHandle,
180 0,
181 0,
182 0,
183 0,
184 BlockBuffer,
185 sizeof BlockBuffer,
186 0,
187 0
188 );
189 if (!NT_SUCCESS(Status))
190 {
191 DPRINT("NTDLL header read failed ");
192 DbgPrintErrorMessage(Status);
193 ZwClose(FileHandle);
194
195 return Status;
196 }
197 /*
198 * FIXME: this will fail if the NT headers are
199 * more than 1024 bytes from start.
200 */
201 DosHeader = (PIMAGE_DOS_HEADER) BlockBuffer;
202 NTHeaders = (PIMAGE_NT_HEADERS) (BlockBuffer + DosHeader->e_lfanew);
203 if (
204 (DosHeader->e_magic != IMAGE_DOS_MAGIC)
205 || (DosHeader->e_lfanew == 0L)
206 || (*(PULONG) NTHeaders != IMAGE_PE_MAGIC)
207 )
208 {
209 DPRINT("NTDLL format invalid\n");
210 ZwClose(FileHandle);
211
212 return STATUS_UNSUCCESSFUL;
213 }
214 ImageBase = NTHeaders->OptionalHeader.ImageBase;
215 ImageSize = NTHeaders->OptionalHeader.SizeOfImage;
216 /*
217 * FIXME: retrieve the offset of LdrStartup from NTDLL
218 */
219 DPRINT("ImageBase %x\n",ImageBase);
220 LdrStartupAddr =
221 ImageBase
222 + NTHeaders->OptionalHeader.AddressOfEntryPoint;
223 /*
224 * Create a section for NTDLL
225 */
226 Status = ZwCreateSection(
227 & NTDllSectionHandle,
228 SECTION_ALL_ACCESS,
229 NULL,
230 NULL,
231 PAGE_READWRITE,
232 MEM_COMMIT,
233 FileHandle
234 );
235 if (!NT_SUCCESS(Status))
236 {
237 DPRINT("NTDLL create section failed ");
238 DbgPrintErrorMessage(Status);
239 ZwClose(FileHandle);
240
241 return Status;
242 }
243 /*
244 * Map the NTDLL into the process
245 */
246 InitialViewSize =
247 DosHeader->e_lfanew
248 + sizeof (IMAGE_NT_HEADERS)
249 + ( sizeof (IMAGE_SECTION_HEADER)
250 * NTHeaders->FileHeader.NumberOfSections
251 );
252 Status = ZwMapViewOfSection(
253 NTDllSectionHandle,
254 ProcessHandle,
255 (PVOID *) & ImageBase,
256 0,
257 InitialViewSize,
258 NULL,
259 & InitialViewSize,
260 0,
261 MEM_COMMIT,
262 PAGE_READWRITE
263 );
264 if (!NT_SUCCESS(Status))
265 {
266 DPRINT("NTDLL map view of secion failed ");
267 DbgPrintErrorMessage(Status);
268
269 /* FIXME: destroy the section here */
270
271 ZwClose(FileHandle);
272
273 return Status;
274 }
275 for ( i = 0;
276 (i < NTHeaders->FileHeader.NumberOfSections);
277 i++
278 )
279 {
280 PIMAGE_SECTION_HEADER Sections;
281 LARGE_INTEGER Offset;
282 ULONG Base;
283
284 Sections =
285 (PIMAGE_SECTION_HEADER) SECHDROFFSET(BlockBuffer);
286 Base =
287 Sections[i].VirtualAddress
288 + ImageBase;
289 Offset.u.LowPart =
290 Sections[i].PointerToRawData;
291 Offset.u.HighPart =
292 0;
293 Status = ZwMapViewOfSection(
294 NTDllSectionHandle,
295 ProcessHandle,
296 (PVOID *) & Base,
297 0,
298 Sections[i].Misc.VirtualSize,
299 & Offset,
300 (PULONG) & Sections[i].Misc.VirtualSize,
301 0,
302 MEM_COMMIT,
303 PAGE_READWRITE
304 );
305 if (!NT_SUCCESS(Status))
306 {
307 DPRINT("NTDLL map view of secion failed ");
308 DbgPrintErrorMessage(Status);
309
310 /* FIXME: destroy the section here */
311
312 ZwClose(FileHandle);
313 return Status;
314 }
315 }
316 ZwClose(FileHandle);
317
318 /* -- PART II -- */
319
320 /*
321 * Open process image to determine ImageBase
322 * and StackBase/Size.
323 */
324 InitializeObjectAttributes(
325 & FileObjectAttributes,
326 Filename,
327 0,
328 NULL,
329 NULL
330 );
331 DPRINT(
332 "Opening image file %w\n",
333 FileObjectAttributes.ObjectName->Buffer
334 );
335 Status = ZwOpenFile(
336 & FileHandle,
337 FILE_ALL_ACCESS,
338 & FileObjectAttributes,
339 NULL,
340 0,
341 0
342 );
343 if (!NT_SUCCESS(Status))
344 {
345 DPRINT("Image open failed ");
346 DbgPrintErrorMessage(Status);
347
348 return Status;
349 }
350 Status = ZwReadFile(
351 FileHandle,
352 0,
353 0,
354 0,
355 0,
356 BlockBuffer,
357 sizeof BlockBuffer,
358 0,
359 0
360 );
361 if (!NT_SUCCESS(Status))
362 {
363 DPRINT("Image header read failed ");
364 DbgPrintErrorMessage(Status);
365 ZwClose(FileHandle);
366
367 return Status;
368 }
369 /*
370 * FIXME: this will fail if the NT headers
371 * are more than 1024 bytes from start.
372 */
373 DosHeader = (PIMAGE_DOS_HEADER) BlockBuffer;
374 NTHeaders =
375 (PIMAGE_NT_HEADERS) (BlockBuffer + DosHeader->e_lfanew);
376 if (
377 (DosHeader->e_magic != IMAGE_DOS_MAGIC)
378 || (DosHeader->e_lfanew == 0L)
379 || (*(PULONG) NTHeaders != IMAGE_PE_MAGIC)
380 )
381 {
382 DPRINT("Image invalid format rc=%08lx\n", Status);
383 ZwClose(FileHandle);
384
385 return STATUS_UNSUCCESSFUL;
386 }
387 ImageBase = NTHeaders->OptionalHeader.ImageBase;
388 ImageSize = NTHeaders->OptionalHeader.SizeOfImage;
389 /*
390 * Create a section for the image
391 */
392 Status = ZwCreateSection(
393 & SectionHandle,
394 SECTION_ALL_ACCESS,
395 NULL,
396 NULL,
397 PAGE_READWRITE,
398 MEM_COMMIT,
399 FileHandle
400 );
401 if (!NT_SUCCESS(Status))
402 {
403 DPRINT("Image create section failed ");
404 DbgPrintErrorMessage(Status);
405 ZwClose(FileHandle);
406
407 return Status;
408 }
409 /*
410 * Map the image into the process
411 */
412 InitialViewSize =
413 DosHeader->e_lfanew
414 + sizeof (IMAGE_NT_HEADERS)
415 + (
416 sizeof(IMAGE_SECTION_HEADER)
417 * NTHeaders->FileHeader.NumberOfSections
418 );
419 DPRINT("InitialViewSize %x\n",InitialViewSize);
420 Status = ZwMapViewOfSection(
421 SectionHandle,
422 ProcessHandle,
423 (PVOID *) & ImageBase,
424 0,
425 InitialViewSize,
426 NULL,
427 & InitialViewSize,
428 0,
429 MEM_COMMIT,
430 PAGE_READWRITE
431 );
432 if (!NT_SUCCESS(Status))
433 {
434 DPRINT("Image map view of section failed ");
435 DbgPrintErrorMessage(Status);
436
437 /* FIXME: destroy the section here */
438
439 ZwClose(FileHandle);
440
441 return Status;
442 }
443 ZwClose(FileHandle);
444
445 /* -- PART III -- */
446
447 /*
448 * Create page backed section for stack
449 */
450 StackBase = (
451 STACK_TOP
452 - NTHeaders->OptionalHeader.SizeOfStackReserve
453 );
454 StackSize =
455 NTHeaders->OptionalHeader.SizeOfStackReserve;
456
457 Status = ZwAllocateVirtualMemory(
458 ProcessHandle,
459 (PVOID *) & StackBase,
460 0,
461 & StackSize,
462 MEM_COMMIT,
463 PAGE_READWRITE
464 );
465 if (!NT_SUCCESS(Status))
466 {
467 DPRINT("Stack allocation failed ");
468 DbgPrintErrorMessage(Status);
469
470 /* FIXME: unmap the section here */
471 /* FIXME: destroy the section here */
472
473 return Status;
474 }
475
476 ZwDuplicateObject(
477 NtCurrentProcess(),
478 & SectionHandle,
479 ProcessHandle,
480 & DupSectionHandle,
481 0,
482 FALSE,
483 DUPLICATE_SAME_ACCESS
484 );
485 ZwDuplicateObject(
486 NtCurrentProcess(),
487 & NTDllSectionHandle,
488 ProcessHandle,
489 &DupNTDllSectionHandle,
490 0,
491 FALSE,
492 DUPLICATE_SAME_ACCESS
493 );
494
495 ZwWriteVirtualMemory(
496 ProcessHandle,
497 (PVOID) (STACK_TOP - 4),
498 & DupNTDllSectionHandle,
499 sizeof (DupNTDllSectionHandle),
500 & BytesWritten
501 );
502 ZwWriteVirtualMemory(
503 ProcessHandle,
504 (PVOID) (STACK_TOP - 8),
505 & ImageBase,
506 sizeof (ImageBase),
507 & BytesWritten
508 );
509 ZwWriteVirtualMemory(
510 ProcessHandle,
511 (PVOID) (STACK_TOP - 12),
512 & DupSectionHandle,
513 sizeof (DupSectionHandle),
514 & BytesWritten
515 );
516 /*
517 * Create a peb (grungy)
518 */
519 Status = LdrCreatePeb(ProcessHandle);
520 if (!NT_SUCCESS(Status))
521 {
522 DbgPrint("LDR: Failed to create initial peb\n");
523 return (Status);
524 }
525 /*
526 * Initialize context to point to LdrStartup
527 */
528 memset(&Context,0,sizeof(CONTEXT));
529 Context.SegSs = USER_DS;
530 Context.Esp = STACK_TOP - 16;
531 Context.EFlags = 0x202;
532 Context.SegCs = USER_CS;
533 Context.Eip = LdrStartupAddr;
534 Context.SegDs = USER_DS;
535 Context.SegEs = USER_DS;
536 Context.SegFs = USER_DS;
537 Context.SegGs = USER_DS;
538
539 DPRINT("LdrStartupAddr %x\n",LdrStartupAddr);
540 /*
541 * FIXME: Create process and let 'er rip
542 */
543 Status = ZwCreateThread(
544 & ThreadHandle,
545 THREAD_ALL_ACCESS,
546 NULL,
547 ProcessHandle,
548 NULL,
549 & Context,
550 NULL,
551 FALSE
552 );
553 if (!NT_SUCCESS(Status))
554 {
555 DPRINT("Thread creation failed ");
556 DbgPrintErrorMessage(Status);
557
558 /* FIXME: destroy the stack memory block here */
559 /* FIXME: unmap the section here */
560 /* FIXME: destroy the section here */
561
562 return Status;
563 }
564
565 return STATUS_SUCCESS;
566 }
567
568
569 /*
570 * FIXME: The location of the initial process should be configurable,
571 * from command line or registry
572 */
573 NTSTATUS
574 LdrLoadInitialProcess (VOID)
575 {
576 NTSTATUS Status;
577 HANDLE ProcessHandle;
578 UNICODE_STRING ProcessName;
579 WCHAR TmpNameBuffer [MAX_PATH];
580
581
582 Status = ZwCreateProcess(
583 & ProcessHandle,
584 PROCESS_ALL_ACCESS,
585 NULL,
586 SystemProcessHandle,
587 FALSE,
588 NULL,
589 NULL,
590 NULL
591 );
592 if (!NT_SUCCESS(Status))
593 {
594 DbgPrint("Could not create process\n");
595 return Status;
596 }
597 /*
598 * Get the system directory's name (a DOS device
599 * alias name which is in \\??\\).
600 */
601 GetSystemDirectory(
602 TmpNameBuffer,
603 sizeof TmpNameBuffer
604 );
605 wcscat(
606 TmpNameBuffer,
607 L"\\shell.exe" /* FIXME: should be smss.exe */
608 );
609 RtlInitUnicodeString(
610 & ProcessName,
611 TmpNameBuffer
612 );
613 Status = LdrLoadImage(
614 ProcessHandle,
615 & ProcessName
616 );
617
618 return Status;
619 }
620
621 /* EOF */