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