ReactOS  r76032
image.c
Go to the documentation of this file.
1 /*
2  * COPYRIGHT: See COPYING in the top level directory
3  * PROJECT: ReactOS system libraries
4  * FILE: lib/rtl/image.c
5  * PURPOSE: Image handling functions
6  * Relocate functions were previously located in
7  * ntoskrnl/ldr/loader.c and
8  * dll/ntdll/ldr/utils.c files
9  * PROGRAMMER: Eric Kohl + original authors from loader.c and utils.c file
10  * Aleksey Bragin
11  */
12 
13 /* INCLUDES *****************************************************************/
14 
15 #include <rtl.h>
16 
17 #define NDEBUG
18 #include <debug.h>
19 
20 #define RVA(m, b) ((PVOID)((ULONG_PTR)(b) + (ULONG_PTR)(m)))
21 
22 /* FUNCTIONS *****************************************************************/
23 
25 USHORT
27 {
28  ULONG i;
29 
30  for (i=0; i<Len; i++)
31  {
32  /* Sum up the current word */
33  Sum += Src[i];
34 
35  /* Sum up everything above the low word as a carry */
36  Sum = (Sum & 0xFFFF) + (Sum >> 16);
37  }
38 
39  /* Apply carry one more time and clamp to the USHORT */
40  return (Sum + (Sum >> 16)) & 0xFFFF;
41 }
42 
43 BOOLEAN
44 NTAPI
47  IN SIZE_T ImageSize,
49 {
50 #if 0
52  PUSHORT Ptr;
53  ULONG Sum;
54  ULONG CalcSum;
55  ULONG HeaderSum;
56  ULONG i;
57 
58  // HACK: Ignore calls with ImageSize=0. Should be fixed by new MM.
59  if (ImageSize == 0) return TRUE;
60 
61  /* Get NT header to check if it's an image at all */
62  Header = RtlImageNtHeader(BaseAddress);
63  if (!Header) return FALSE;
64 
65  /* Get checksum to match */
66  HeaderSum = Header->OptionalHeader.CheckSum;
67 
68  /* Zero checksum seems to be accepted */
69  if (HeaderSum == 0) return TRUE;
70 
71  /* Calculate the checksum */
72  Sum = 0;
73  Ptr = (PUSHORT) BaseAddress;
74  for (i = 0; i < ImageSize / sizeof (USHORT); i++)
75  {
76  Sum += (ULONG)*Ptr;
77  if (HIWORD(Sum) != 0)
78  {
79  Sum = LOWORD(Sum) + HIWORD(Sum);
80  }
81  Ptr++;
82  }
83 
84  if (ImageSize & 1)
85  {
86  Sum += (ULONG)*((PUCHAR)Ptr);
87  if (HIWORD(Sum) != 0)
88  {
89  Sum = LOWORD(Sum) + HIWORD(Sum);
90  }
91  }
92 
93  CalcSum = (USHORT)(LOWORD(Sum) + HIWORD(Sum));
94 
95  /* Subtract image checksum from calculated checksum. */
96  /* fix low word of checksum */
97  if (LOWORD(CalcSum) >= LOWORD(HeaderSum))
98  {
99  CalcSum -= LOWORD(HeaderSum);
100  }
101  else
102  {
103  CalcSum = ((LOWORD(CalcSum) - LOWORD(HeaderSum)) & 0xFFFF) - 1;
104  }
105 
106  /* Fix high word of checksum */
107  if (LOWORD(CalcSum) >= HIWORD(HeaderSum))
108  {
109  CalcSum -= HIWORD(HeaderSum);
110  }
111  else
112  {
113  CalcSum = ((LOWORD(CalcSum) - HIWORD(HeaderSum)) & 0xFFFF) - 1;
114  }
115 
116  /* Add file length */
117  CalcSum += ImageSize;
118 
119  if (CalcSum != HeaderSum)
120  DPRINT1("Image %p checksum mismatches! 0x%x != 0x%x, ImageSize %x, FileLen %x\n", BaseAddress, CalcSum, HeaderSum, ImageSize, FileLength);
121 
122  return (BOOLEAN)(CalcSum == HeaderSum);
123 #else
124  /*
125  * FIXME: Warning, this violates the PE standard and makes ReactOS drivers
126  * and other system code when normally on Windows they would not, since
127  * we do not write the checksum in them.
128  * Our compilers should be made to write out the checksum and this function
129  * should be enabled as to reject badly checksummed code.
130  */
131  return TRUE;
132 #endif
133 }
134 
135 /*
136  * @implemented
137  */
138 NTSTATUS
139 NTAPI
141  _In_ ULONG Flags,
142  _In_ PVOID Base,
143  _In_ ULONG64 Size,
144  _Out_ PIMAGE_NT_HEADERS *OutHeaders)
145 {
146  PIMAGE_NT_HEADERS NtHeaders;
147  PIMAGE_DOS_HEADER DosHeader;
148  BOOLEAN WantsRangeCheck;
149  ULONG NtHeaderOffset;
150 
151  /* You must want NT Headers, no? */
152  if (OutHeaders == NULL)
153  {
154  DPRINT1("OutHeaders is NULL\n");
156  }
157 
158  /* Assume failure */
159  *OutHeaders = NULL;
160 
161  /* Validate Flags */
162  if (Flags & ~RTL_IMAGE_NT_HEADER_EX_FLAG_NO_RANGE_CHECK)
163  {
164  DPRINT1("Invalid flags: 0x%lx\n", Flags);
166  }
167 
168  /* Validate base */
169  if ((Base == NULL) || (Base == (PVOID)-1))
170  {
171  DPRINT1("Invalid base address: %p\n", Base);
173  }
174 
175  /* Check if the caller wants range checks */
176  WantsRangeCheck = !(Flags & RTL_IMAGE_NT_HEADER_EX_FLAG_NO_RANGE_CHECK);
177  if (WantsRangeCheck)
178  {
179  /* Make sure the image size is at least big enough for the DOS header */
180  if (Size < sizeof(IMAGE_DOS_HEADER))
181  {
182  DPRINT1("Size too small\n");
184  }
185  }
186 
187  /* Check if the DOS Signature matches */
188  DosHeader = Base;
189  if (DosHeader->e_magic != IMAGE_DOS_SIGNATURE)
190  {
191  /* Not a valid COFF */
192  DPRINT1("Invalid image DOS signature!\n");
194  }
195 
196  /* Get the offset to the NT headers (and copy from LONG to ULONG) */
197  NtHeaderOffset = DosHeader->e_lfanew;
198 
199  /* The offset must not be larger than 256MB, as a hard-coded check.
200  In Windows this check is only done in user mode, not in kernel mode,
201  but it shouldn't harm to have it anyway. Note that without this check,
202  other overflow checks would become necessary! */
203  if (NtHeaderOffset >= (256 * 1024 * 1024))
204  {
205  /* Fail */
206  DPRINT1("NT headers offset is larger than 256MB!\n");
208  }
209 
210  /* Check if the caller wants validation */
211  if (WantsRangeCheck)
212  {
213  /* Make sure the file header fits into the size */
214  if ((NtHeaderOffset +
215  RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS, FileHeader)) >= Size)
216  {
217  /* Fail */
218  DPRINT1("NT headers beyond image size!\n");
220  }
221  }
222 
223  /* Now get a pointer to the NT Headers */
224  NtHeaders = (PIMAGE_NT_HEADERS)((ULONG_PTR)Base + NtHeaderOffset);
225 
226  /* Check if the mapping is in user space */
227  if (Base <= MmHighestUserAddress)
228  {
229  /* Make sure we don't overflow into kernel space */
230  if ((PVOID)(NtHeaders + 1) > MmHighestUserAddress)
231  {
232  DPRINT1("Image overflows from user space into kernel space!\n");
234  }
235  }
236 
237  /* Verify the PE Signature */
238  if (NtHeaders->Signature != IMAGE_NT_SIGNATURE)
239  {
240  /* Fail */
241  DPRINT1("Invalid image NT signature!\n");
243  }
244 
245  /* Now return success and the NT header */
246  *OutHeaders = NtHeaders;
247  return STATUS_SUCCESS;
248 }
249 
250 /*
251  * @implemented
252  */
254 NTAPI
256 {
257  PIMAGE_NT_HEADERS NtHeader;
258 
259  /* Call the new API */
260  RtlImageNtHeaderEx(RTL_IMAGE_NT_HEADER_EX_FLAG_NO_RANGE_CHECK,
261  Base,
262  0,
263  &NtHeader);
264  return NtHeader;
265 }
266 
267 /*
268  * @implemented
269  */
270 PVOID
271 NTAPI
276  PULONG Size)
277 {
278  PIMAGE_NT_HEADERS NtHeader;
279  ULONG Va;
280 
281  /* Magic flag for non-mapped images. */
282  if ((ULONG_PTR)BaseAddress & 1)
283  {
284  BaseAddress = (PVOID)((ULONG_PTR)BaseAddress & ~1);
285  MappedAsImage = FALSE;
286  }
287 
288  NtHeader = RtlImageNtHeader(BaseAddress);
289  if (NtHeader == NULL)
290  return NULL;
291 
292  if (Directory >= SWAPD(NtHeader->OptionalHeader.NumberOfRvaAndSizes))
293  return NULL;
294 
295  Va = SWAPD(NtHeader->OptionalHeader.DataDirectory[Directory].VirtualAddress);
296  if (Va == 0)
297  return NULL;
298 
299  *Size = SWAPD(NtHeader->OptionalHeader.DataDirectory[Directory].Size);
300 
301  if (MappedAsImage || Va < SWAPD(NtHeader->OptionalHeader.SizeOfHeaders))
302  return (PVOID)((ULONG_PTR)BaseAddress + Va);
303 
304  /* Image mapped as ordinary file, we must find raw pointer */
305  return RtlImageRvaToVa(NtHeader, BaseAddress, Va, NULL);
306 }
307 
308 /*
309  * @implemented
310  */
312 NTAPI
314  PIMAGE_NT_HEADERS NtHeader,
316  ULONG Rva)
317 {
318  PIMAGE_SECTION_HEADER Section;
319  ULONG Va;
320  ULONG Count;
321 
322  Count = SWAPW(NtHeader->FileHeader.NumberOfSections);
323  Section = IMAGE_FIRST_SECTION(NtHeader);
324 
325  while (Count--)
326  {
327  Va = SWAPD(Section->VirtualAddress);
328  if ((Va <= Rva) && (Rva < Va + SWAPD(Section->SizeOfRawData)))
329  return Section;
330  Section++;
331  }
332 
333  return NULL;
334 }
335 
336 /*
337  * @implemented
338  */
339 PVOID
340 NTAPI
342  PIMAGE_NT_HEADERS NtHeader,
344  ULONG Rva,
345  PIMAGE_SECTION_HEADER *SectionHeader)
346 {
347  PIMAGE_SECTION_HEADER Section = NULL;
348 
349  if (SectionHeader)
350  Section = *SectionHeader;
351 
352  if ((Section == NULL) ||
353  (Rva < SWAPD(Section->VirtualAddress)) ||
354  (Rva >= SWAPD(Section->VirtualAddress) + SWAPD(Section->SizeOfRawData)))
355  {
356  Section = RtlImageRvaToSection(NtHeader, BaseAddress, Rva);
357  if (Section == NULL)
358  return NULL;
359 
360  if (SectionHeader)
361  *SectionHeader = Section;
362  }
363 
364  return (PVOID)((ULONG_PTR)BaseAddress + Rva +
365  (ULONG_PTR)SWAPD(Section->PointerToRawData) -
366  (ULONG_PTR)SWAPD(Section->VirtualAddress));
367 }
368 
370 NTAPI
373  IN ULONG Count,
374  IN PUSHORT TypeOffset,
375  IN LONGLONG Delta)
376 {
377  SHORT Offset;
378  USHORT Type;
379  ULONG i;
380  PUSHORT ShortPtr;
381  PULONG LongPtr;
382  PULONGLONG LongLongPtr;
383 
384  for (i = 0; i < Count; i++)
385  {
386  Offset = SWAPW(*TypeOffset) & 0xFFF;
387  Type = SWAPW(*TypeOffset) >> 12;
388  ShortPtr = (PUSHORT)(RVA(Address, Offset));
389  /*
390  * Don't relocate within the relocation section itself.
391  * GCC/LD generates sometimes relocation records for the relocation section.
392  * This is a bug in GCC/LD.
393  * Fix for it disabled, since it was only in ntoskrnl and not in ntdll
394  */
395  /*
396  if ((ULONG_PTR)ShortPtr < (ULONG_PTR)RelocationDir ||
397  (ULONG_PTR)ShortPtr >= (ULONG_PTR)RelocationEnd)
398  {*/
399  switch (Type)
400  {
401  /* case IMAGE_REL_BASED_SECTION : */
402  /* case IMAGE_REL_BASED_REL32 : */
404  break;
405 
407  *ShortPtr = HIWORD(MAKELONG(0, *ShortPtr) + (Delta & 0xFFFFFFFF));
408  break;
409 
410  case IMAGE_REL_BASED_LOW:
411  *ShortPtr = SWAPW(*ShortPtr) + LOWORD(Delta & 0xFFFF);
412  break;
413 
415  LongPtr = (PULONG)RVA(Address, Offset);
416  *LongPtr = SWAPD(*LongPtr) + (Delta & 0xFFFFFFFF);
417  break;
418 
420  LongLongPtr = (PUINT64)RVA(Address, Offset);
421  *LongLongPtr = SWAPQ(*LongLongPtr) + Delta;
422  break;
423 
426  default:
427  DPRINT1("Unknown/unsupported fixup type %hu.\n", Type);
428  DPRINT1("Address %p, Current %u, Count %u, *TypeOffset %x\n",
429  (PVOID)Address, i, Count, SWAPW(*TypeOffset));
431  }
432 
433  TypeOffset++;
434  }
435 
436  return (PIMAGE_BASE_RELOCATION)TypeOffset;
437 }
438 
439 ULONG
440 NTAPI
443  IN PCCH LoaderName,
444  IN ULONG Success,
445  IN ULONG Conflict,
446  IN ULONG Invalid)
447 {
448  return LdrRelocateImageWithBias(BaseAddress, 0, LoaderName, Success, Conflict, Invalid);
449 }
450 
451 ULONG
452 NTAPI
455  IN LONGLONG AdditionalBias,
456  IN PCCH LoaderName,
457  IN ULONG Success,
458  IN ULONG Conflict,
459  IN ULONG Invalid)
460 {
461  PIMAGE_NT_HEADERS NtHeaders;
462  PIMAGE_DATA_DIRECTORY RelocationDDir;
463  PIMAGE_BASE_RELOCATION RelocationDir, RelocationEnd;
464  ULONG Count;
466  PUSHORT TypeOffset;
467  LONGLONG Delta;
468 
469  NtHeaders = RtlImageNtHeader(BaseAddress);
470 
471  if (NtHeaders == NULL)
472  return Invalid;
473 
475  {
476  return Conflict;
477  }
478 
479  RelocationDDir = &NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
480 
481  if (SWAPD(RelocationDDir->VirtualAddress) == 0 || SWAPD(RelocationDDir->Size) == 0)
482  {
483  return Success;
484  }
485 
486  Delta = (ULONG_PTR)BaseAddress - SWAPD(NtHeaders->OptionalHeader.ImageBase) + AdditionalBias;
487  RelocationDir = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)BaseAddress + SWAPD(RelocationDDir->VirtualAddress));
488  RelocationEnd = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)RelocationDir + SWAPD(RelocationDDir->Size));
489 
490  while (RelocationDir < RelocationEnd &&
491  SWAPW(RelocationDir->SizeOfBlock) > 0)
492  {
493  Count = (SWAPW(RelocationDir->SizeOfBlock) - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(USHORT);
494  Address = (ULONG_PTR)RVA(BaseAddress, SWAPD(RelocationDir->VirtualAddress));
495  TypeOffset = (PUSHORT)(RelocationDir + 1);
496 
497  RelocationDir = LdrProcessRelocationBlockLongLong(Address,
498  Count,
499  TypeOffset,
500  Delta);
501 
502  if (RelocationDir == NULL)
503  {
504  DPRINT1("Error during call to LdrProcessRelocationBlockLongLong()!\n");
505  return Invalid;
506  }
507  }
508 
509  return Success;
510 }
511 
512 /* EOF */
FORCEINLINE USHORT ChkSum(ULONG Sum, PUSHORT Src, ULONG Len)
Definition: image.c:26
DWORD *typedef PVOID
Definition: winlogon.h:52
#define IN
Definition: typedefs.h:38
PIMAGE_BASE_RELOCATION NTAPI LdrProcessRelocationBlockLongLong(IN ULONG_PTR Address, IN ULONG Count, IN PUSHORT TypeOffset, IN LONGLONG Delta)
Definition: image.c:371
_Out_ PNDIS_HANDLE _Out_ PUINT FileLength
Definition: ndis.h:3208
#define TRUE
Definition: types.h:120
struct _IMAGE_BASE_RELOCATION * PIMAGE_BASE_RELOCATION
PVOID ULONG Address
Definition: oprghdlr.h:14
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]
Definition: ntddk_ex.h:178
#define IMAGE_REL_BASED_DIR64
Definition: winnt_old.h:891
Type
Definition: Type.h:6
#define SWAPW(x)
Definition: bytesex.h:8
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
return STATUS_SUCCESS
Definition: btrfs.c:2664
unsigned char * PUCHAR
Definition: retypes.h:3
_Must_inspect_result_ _In_ PFSRTL_PER_STREAM_CONTEXT Ptr
Definition: fsrtlfuncs.h:898
_In_opt_ ULONG Base
Definition: rtlfuncs.h:2327
#define SWAPD(x)
Definition: bytesex.h:7
_Inout_ __drv_aliasesMem PSLIST_ENTRY _Inout_ PSLIST_ENTRY _In_ ULONG Count
Definition: exfuncs.h:1015
struct _IMAGE_BASE_RELOCATION IMAGE_BASE_RELOCATION
PIMAGE_NT_HEADERS32 PIMAGE_NT_HEADERS
Definition: ntddk_ex.h:187
PVOID NTAPI RtlImageRvaToVa(PIMAGE_NT_HEADERS NtHeader, PVOID BaseAddress, ULONG Rva, PIMAGE_SECTION_HEADER *SectionHeader)
Definition: image.c:341
DWORD PointerToRawData
Definition: pedump.c:290
#define IMAGE_REL_BASED_HIGHLOW
Definition: winnt_old.h:886
IMAGE_OPTIONAL_HEADER32 OptionalHeader
Definition: ntddk_ex.h:184
uint32_t ULONG_PTR
Definition: typedefs.h:63
#define IMAGE_REL_BASED_ABSOLUTE
Definition: winnt_old.h:883
#define IMAGE_DOS_SIGNATURE
Definition: pedump.c:89
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
GLenum GLclampf GLint i
Definition: glfuncs.h:14
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
#define FALSE
Definition: types.h:117
Definition: Header.h:8
#define IMAGE_FIRST_SECTION(NtHeader)
Definition: ntimage.h:427
short SHORT
Definition: pedump.c:59
#define IMAGE_REL_BASED_MIPS_JMPADDR
Definition: winnt_old.h:888
uint64_t ULONG64
Definition: typedefs.h:65
#define IMAGE_REL_BASED_LOW
Definition: winnt_old.h:885
_In_ BOOLEAN MappedAsImage
Definition: rtlfuncs.h:3718
#define MAKELONG(a, b)
Definition: typedefs.h:248
smooth NULL
Definition: ftsmooth.c:557
#define FORCEINLINE
Definition: ntbasedef.h:213
#define _Out_
Definition: no_sal2.h:323
ULONG NTAPI LdrRelocateImageWithBias(IN PVOID BaseAddress, IN LONGLONG AdditionalBias, IN PCCH LoaderName, IN ULONG Success, IN ULONG Conflict, IN ULONG Invalid)
Definition: image.c:453
IMAGE_FILE_HEADER FileHeader
Definition: ntddk_ex.h:183
#define IMAGE_REL_BASED_HIGHADJ
Definition: winnt_old.h:887
#define SWAPQ(x)
Definition: rtlp.h:26
UINTN Size
Definition: acefiex.h:555
#define IMAGE_NT_SIGNATURE
Definition: pedump.c:93
int64_t LONGLONG
Definition: typedefs.h:66
unsigned char BOOLEAN
CONST CHAR * PCCH
Definition: ntbasedef.h:391
_In_ HANDLE _Outptr_result_bytebuffer_ ViewSize PVOID * BaseAddress
Definition: mmfuncs.h:404
#define STATUS_INVALID_IMAGE_FORMAT
Definition: ntstatus.h:345
unsigned short * PUSHORT
Definition: retypes.h:2
#define Len
Definition: deflate.h:82
#define RTL_SIZEOF_THROUGH_FIELD(type, field)
Definition: ntbasedef.h:671
PIMAGE_NT_HEADERS NTAPI RtlImageNtHeader(IN PVOID Base)
Definition: image.c:255
PIMAGE_SECTION_HEADER NTAPI RtlImageRvaToSection(PIMAGE_NT_HEADERS NtHeader, PVOID BaseAddress, ULONG Rva)
Definition: image.c:313
PVOID NTAPI RtlImageDirectoryEntryToData(PVOID BaseAddress, BOOLEAN MappedAsImage, USHORT Directory, PULONG Size)
Definition: image.c:272
#define _In_
Definition: no_sal2.h:204
#define IMAGE_REL_BASED_HIGH
Definition: winnt_old.h:884
ULONG_PTR SIZE_T
Definition: typedefs.h:78
LONG NTSTATUS
Definition: DriverTester.h:11
unsigned short USHORT
Definition: pedump.c:61
static ULONG Delta
Definition: xboxvideo.c:28
ULONG NTAPI LdrRelocateImage(IN PVOID BaseAddress, IN PCCH LoaderName, IN ULONG Success, IN ULONG Conflict, IN ULONG Invalid)
Definition: image.c:441
unsigned int * PULONG
Definition: retypes.h:1
PVOID MmHighestUserAddress
Definition: rtlcompat.c:26
#define IMAGE_DIRECTORY_ENTRY_BASERELOC
Definition: pedump.c:264
#define DPRINT1
Definition: precomp.h:8
__GNU_EXTENSION typedef unsigned __int64 * PULONGLONG
Definition: ntbasedef.h:382
#define HIWORD(l)
Definition: typedefs.h:246
unsigned int ULONG
Definition: retypes.h:1
#define IMAGE_FILE_RELOCS_STRIPPED
Definition: pedump.c:159
base for all directory entries
Definition: entries.h:138
#define ULONG_PTR
Definition: config.h:101
#define RVA(m, b)
Definition: image.c:20
BOOLEAN NTAPI LdrVerifyMappedImageMatchesChecksum(IN PVOID BaseAddress, IN SIZE_T ImageSize, IN ULONG FileLength)
Definition: image.c:45
NTSTATUS NTAPI RtlImageNtHeaderEx(_In_ ULONG Flags, _In_ PVOID Base, _In_ ULONG64 Size, _Out_ PIMAGE_NT_HEADERS *OutHeaders)
Definition: image.c:140
#define LOWORD(l)
Definition: pedump.c:82
unsigned __int64 * PUINT64
Definition: basetsd.h:188