:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / ntoskrnl / ldr / sysdll.c
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS kernel
4  * FILE:            ntoskrnl/ldr/sysdll.c
5  * PURPOSE:         Loaders for PE executables
6  * PROGRAMMERS:     Jean Michault
7  *                  Rex Jolliff (rex@lvcablemodem.com)
8  * UPDATE HISTORY:
9  *   DW   26/01/00  Created
10  */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ddk/ntddk.h>
15 #include <internal/module.h>
16 #include <internal/ntoskrnl.h>
17 #include <internal/ob.h>
18 #include <internal/ps.h>
19 #include <internal/ldr.h>
20
21 #define NDEBUG
22 #include <internal/debug.h>
23
24 /* GLOBALS *******************************************************************/
25
26 static PVOID SystemDllEntryPoint = NULL;
27 static PVOID SystemDllApcDispatcher = NULL;
28 static PVOID SystemDllCallbackDispatcher = NULL;
29 static PVOID SystemDllExceptionDispatcher = NULL;
30
31 /* FUNCTIONS *****************************************************************/
32
33 PVOID LdrpGetSystemDllExceptionDispatcher(VOID)
34 {
35   return(SystemDllExceptionDispatcher);
36 }
37
38 PVOID LdrpGetSystemDllCallbackDispatcher(VOID)
39 {
40   return(SystemDllCallbackDispatcher);
41 }
42
43 PVOID LdrpGetSystemDllEntryPoint(VOID)
44 {
45    return(SystemDllEntryPoint);
46 }
47
48 PVOID LdrpGetSystemDllApcDispatcher(VOID)
49 {
50    return(SystemDllApcDispatcher);
51 }
52
53 NTSTATUS LdrpMapSystemDll(HANDLE ProcessHandle,
54                           PVOID* LdrStartupAddr)
55 /*
56  * FUNCTION: LdrpMapSystemDll maps the system dll into the specified process
57  * address space and returns its startup address.
58  * PARAMETERS:
59  *   ProcessHandle
60  *              Points to the process to map the system dll into
61  * 
62  *   LdrStartupAddress
63  *              Receives the startup address of the system dll on function
64  *              completion
65  * 
66  * RETURNS: Status
67  */
68 {
69    CHAR                 BlockBuffer [1024];
70    DWORD                        ImageBase;
71    ULONG                        ImageSize;
72    NTSTATUS             Status;
73    OBJECT_ATTRIBUTES    FileObjectAttributes;
74    HANDLE                       FileHandle;
75    HANDLE                       NTDllSectionHandle;
76    UNICODE_STRING DllPathname = UNICODE_STRING_INITIALIZER(L"\\SystemRoot\\system32\\ntdll.dll");
77    PIMAGE_DOS_HEADER    DosHeader;
78    PIMAGE_NT_HEADERS    NTHeaders;
79    PEPROCESS Process;
80    ANSI_STRING ProcedureName;
81    ULONG ViewSize;
82    IO_STATUS_BLOCK Iosb;
83
84    /*
85     * Locate and open NTDLL to determine ImageBase
86     * and LdrStartup
87     */
88    InitializeObjectAttributes(&FileObjectAttributes,
89                               &DllPathname,
90                               0,
91                               NULL,
92                               NULL);
93    DPRINT("Opening NTDLL\n");
94    Status = ZwOpenFile(&FileHandle,
95                        FILE_ALL_ACCESS,
96                        &FileObjectAttributes,
97                        NULL,
98                        FILE_SHARE_READ,
99                        FILE_SYNCHRONOUS_IO_NONALERT);
100    if (!NT_SUCCESS(Status))
101      {
102         DbgPrint("NTDLL open failed (Status %x)\n", Status);
103         return Status;
104      }
105    Status = ZwReadFile(FileHandle,
106                        0,
107                        0,
108                        0,
109                        &Iosb,
110                        BlockBuffer,
111                        sizeof(BlockBuffer),
112                        0,
113                        0);
114    if (!NT_SUCCESS(Status) || Iosb.Information != sizeof(BlockBuffer))
115      {
116         DbgPrint("NTDLL header read failed (Status %x)\n", Status);
117         ZwClose(FileHandle);
118         return Status;
119      }
120
121    /*
122     * FIXME: this will fail if the NT headers are
123     * more than 1024 bytes from start.
124     */
125    DosHeader = (PIMAGE_DOS_HEADER) BlockBuffer;
126    NTHeaders = (PIMAGE_NT_HEADERS) (BlockBuffer + DosHeader->e_lfanew);
127    if ((DosHeader->e_magic != IMAGE_DOS_MAGIC)
128        || (DosHeader->e_lfanew == 0L)
129        || (*(PULONG) NTHeaders != IMAGE_PE_MAGIC))
130      {
131         DbgPrint("NTDLL format invalid\n");
132         ZwClose(FileHandle);    
133         return(STATUS_UNSUCCESSFUL);
134      }
135    ImageBase = NTHeaders->OptionalHeader.ImageBase;
136    ImageSize = NTHeaders->OptionalHeader.SizeOfImage;
137    
138    /*
139     * Create a section for NTDLL
140     */
141    DPRINT("Creating section\n");
142    Status = ZwCreateSection(&NTDllSectionHandle,
143                             SECTION_ALL_ACCESS,
144                             NULL,
145                             NULL,
146                             PAGE_READWRITE,
147                             SEC_IMAGE | SEC_COMMIT,
148                             FileHandle);
149    if (!NT_SUCCESS(Status))
150      {
151         DbgPrint("NTDLL create section failed (Status %x)\n", Status);
152         ZwClose(FileHandle);    
153         return(Status);
154      }
155    ZwClose(FileHandle);
156    
157    /*
158     * Map the NTDLL into the process
159     */
160    ViewSize = 0;
161    ImageBase = 0;
162    Status = ZwMapViewOfSection(NTDllSectionHandle,
163                                ProcessHandle,
164                                (PVOID*)&ImageBase,
165                                0,
166                                ViewSize,
167                                NULL,
168                                &ViewSize,
169                                0,
170                                MEM_COMMIT,
171                                PAGE_READWRITE);
172    if (!NT_SUCCESS(Status))
173      {
174         DbgPrint("NTDLL map view of secion failed (Status %x)", Status);
175         ZwClose(NTDllSectionHandle);
176         return(Status);
177      }
178
179    DPRINT("Referencing process\n");
180    Status = ObReferenceObjectByHandle(ProcessHandle,
181                                       PROCESS_ALL_ACCESS,
182                                       PsProcessType,
183                                       KernelMode,
184                                       (PVOID*)&Process,
185                                       NULL);
186    if (!NT_SUCCESS(Status))
187      {
188         DbgPrint("ObReferenceObjectByProcess() failed (Status %x)\n", Status);
189         return(Status);
190      }
191
192    DPRINT("Attaching to Process\n");
193    KeAttachProcess(Process);
194
195    /*
196     * retrieve ntdll's startup address
197     */   
198    if (SystemDllEntryPoint == NULL)
199      {
200        RtlInitAnsiString (&ProcedureName,
201                           "LdrInitializeThunk");
202        Status = LdrGetProcedureAddress ((PVOID)ImageBase,
203                                         &ProcedureName,
204                                         0,
205                                         &SystemDllEntryPoint);
206        if (!NT_SUCCESS(Status))
207          {
208            DbgPrint ("LdrGetProcedureAddress failed (Status %x)\n", Status);
209            KeDetachProcess();
210            ObDereferenceObject(Process);
211            ZwClose(NTDllSectionHandle);
212            return (Status);
213          }
214        *LdrStartupAddr = SystemDllEntryPoint;
215      }
216
217    /*
218     * Retrieve the offset of the APC dispatcher from NTDLL
219     */
220    if (SystemDllApcDispatcher == NULL)
221      {
222        RtlInitAnsiString (&ProcedureName,
223                           "KiUserApcDispatcher");
224        Status = LdrGetProcedureAddress ((PVOID)ImageBase,
225                                         &ProcedureName,
226                                         0,
227                                         &SystemDllApcDispatcher);
228        if (!NT_SUCCESS(Status))
229          {
230            DbgPrint ("LdrGetProcedureAddress failed (Status %x)\n", Status);
231            KeDetachProcess();
232            ObDereferenceObject(Process);
233            ZwClose(NTDllSectionHandle);
234            return (Status);
235          }
236      }
237
238    /*
239     * Retrieve the offset of the exception dispatcher from NTDLL
240     */
241    if (SystemDllExceptionDispatcher == NULL)
242      {
243        RtlInitAnsiString (&ProcedureName,
244                           "KiUserExceptionDispatcher");
245        Status = LdrGetProcedureAddress ((PVOID)ImageBase,
246                                         &ProcedureName,
247                                         0,
248                                         &SystemDllExceptionDispatcher);
249        if (!NT_SUCCESS(Status))
250          {
251            DbgPrint ("LdrGetProcedureAddress failed (Status %x)\n", Status);
252            KeDetachProcess();
253            ObDereferenceObject(Process);
254            ZwClose(NTDllSectionHandle);
255            return (Status);
256          }
257      }
258
259    /*
260     * Retrieve the offset of the callback dispatcher from NTDLL
261     */
262    if (SystemDllCallbackDispatcher == NULL)
263      {
264        RtlInitAnsiString (&ProcedureName,
265                           "KiUserCallbackDispatcher");
266        Status = LdrGetProcedureAddress ((PVOID)ImageBase,
267                                         &ProcedureName,
268                                         0,
269                                         &SystemDllCallbackDispatcher);
270        if (!NT_SUCCESS(Status))
271          {
272            DbgPrint ("LdrGetProcedureAddress failed (Status %x)\n", Status);
273            KeDetachProcess();
274            ObDereferenceObject(Process);
275            ZwClose(NTDllSectionHandle);
276            return (Status);
277          }
278      }
279    
280    KeDetachProcess();
281    ObDereferenceObject(Process);
282
283    ZwClose(NTDllSectionHandle);
284
285    return(STATUS_SUCCESS);
286 }
287
288 /* EOF */