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