ReactOS  0.4.11-dev-433-g473ca91
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  * @note This needs SEH (See https://jira.reactos.org/browse/CORE-14857)
138  */
139 NTSTATUS
140 NTAPI
142  _In_ ULONG Flags,
143  _In_ PVOID Base,
144  _In_ ULONG64 Size,
145  _Out_ PIMAGE_NT_HEADERS *OutHeaders)
146 {
147  PIMAGE_NT_HEADERS NtHeaders;
148  PIMAGE_DOS_HEADER DosHeader;
149  BOOLEAN WantsRangeCheck;
150  ULONG NtHeaderOffset;
151 
152  /* You must want NT Headers, no? */
153  if (OutHeaders == NULL)
154  {
155  DPRINT1("OutHeaders is NULL\n");
157  }
158 
159  /* Assume failure */
160  *OutHeaders = NULL;
161 
162  /* Validate Flags */
163  if (Flags & ~RTL_IMAGE_NT_HEADER_EX_FLAG_NO_RANGE_CHECK)
164  {
165  DPRINT1("Invalid flags: 0x%lx\n", Flags);
167  }
168 
169  /* Validate base */
170  if ((Base == NULL) || (Base == (PVOID)-1))
171  {
172  DPRINT1("Invalid base address: %p\n", Base);
174  }
175 
176  /* Check if the caller wants range checks */
177  WantsRangeCheck = !(Flags & RTL_IMAGE_NT_HEADER_EX_FLAG_NO_RANGE_CHECK);
178  if (WantsRangeCheck)
179  {
180  /* Make sure the image size is at least big enough for the DOS header */
181  if (Size < sizeof(IMAGE_DOS_HEADER))
182  {
183  DPRINT1("Size too small\n");
185  }
186  }
187 
188  /* Check if the DOS Signature matches */
189  DosHeader = Base;
190  if (DosHeader->e_magic != IMAGE_DOS_SIGNATURE)
191  {
192  /* Not a valid COFF */
193  DPRINT1("Invalid image DOS signature!\n");
195  }
196 
197  /* Get the offset to the NT headers (and copy from LONG to ULONG) */
198  NtHeaderOffset = DosHeader->e_lfanew;
199 
200  /* The offset must not be larger than 256MB, as a hard-coded check.
201  In Windows this check is only done in user mode, not in kernel mode,
202  but it shouldn't harm to have it anyway. Note that without this check,
203  other overflow checks would become necessary! */
204  if (NtHeaderOffset >= (256 * 1024 * 1024))
205  {
206  /* Fail */
207  DPRINT1("NT headers offset is larger than 256MB!\n");
209  }
210 
211  /* Check if the caller wants validation */
212  if (WantsRangeCheck)
213  {
214  /* Make sure the file header fits into the size */
215  if ((NtHeaderOffset +
216  RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS, FileHeader)) >= Size)
217  {
218  /* Fail */
219  DPRINT1("NT headers beyond image size!\n");
221  }
222  }
223 
224  /* Now get a pointer to the NT Headers */
225  NtHeaders = (PIMAGE_NT_HEADERS)((ULONG_PTR)Base + NtHeaderOffset);
226 
227  /* Check if the mapping is in user space */
228  if (Base <= MmHighestUserAddress)
229  {
230  /* Make sure we don't overflow into kernel space */
231  if ((PVOID)(NtHeaders + 1) > MmHighestUserAddress)
232  {
233  DPRINT1("Image overflows from user space into kernel space!\n");
235  }
236  }
237 
238  /* Verify the PE Signature */
239  if (NtHeaders->Signature != IMAGE_NT_SIGNATURE)
240  {
241  /* Fail */
242  DPRINT1("Invalid image NT signature!\n");
244  }
245 
246  /* Now return success and the NT header */
247  *OutHeaders = NtHeaders;
248  return STATUS_SUCCESS;
249 }
250 
251 /*
252  * @implemented
253  */
255 NTAPI
257 {
258  PIMAGE_NT_HEADERS NtHeader;
259 
260  /* Call the new API */
261  RtlImageNtHeaderEx(RTL_IMAGE_NT_HEADER_EX_FLAG_NO_RANGE_CHECK,
262  Base,
263  0,
264  &NtHeader);
265  return NtHeader;
266 }
267 
268 /*
269  * @implemented
270  */
271 PVOID
272 NTAPI
277  PULONG Size)
278 {
279  PIMAGE_NT_HEADERS NtHeader;
280  ULONG Va;
281 
282  /* Magic flag for non-mapped images. */
283  if ((ULONG_PTR)BaseAddress & 1)
284  {
285  BaseAddress = (PVOID)((ULONG_PTR)BaseAddress & ~1);
286  MappedAsImage = FALSE;
287  }
288 
289  NtHeader = RtlImageNtHeader(BaseAddress);
290  if (NtHeader == NULL)
291  return NULL;
292 
293  if (Directory >= SWAPD(NtHeader->OptionalHeader.NumberOfRvaAndSizes))
294  return NULL;
295 
296  Va = SWAPD(NtHeader->OptionalHeader.DataDirectory[Directory].VirtualAddress);
297  if (Va == 0)
298  return NULL;
299 
300  *Size = SWAPD(NtHeader->OptionalHeader.DataDirectory[Directory].Size);
301 
302  if (MappedAsImage || Va < SWAPD(NtHeader->OptionalHeader.SizeOfHeaders))
303  return (PVOID)((ULONG_PTR)BaseAddress + Va);
304 
305  /* Image mapped as ordinary file, we must find raw pointer */
306  return RtlImageRvaToVa(NtHeader, BaseAddress, Va, NULL);
307 }
308 
309 /*
310  * @implemented
311  */
313 NTAPI
315  PIMAGE_NT_HEADERS NtHeader,
317  ULONG Rva)
318 {
319  PIMAGE_SECTION_HEADER Section;
320  ULONG Va;
321  ULONG Count;
322 
323  Count = SWAPW(NtHeader->FileHeader.NumberOfSections);
324  Section = IMAGE_FIRST_SECTION(NtHeader);
325 
326  while (Count--)
327  {
328  Va = SWAPD(Section->VirtualAddress);
329  if ((Va <= Rva) && (Rva < Va + SWAPD(Section->SizeOfRawData)))
330  return Section;
331  Section++;
332  }
333 
334  return NULL;
335 }
336 
337 /*
338  * @implemented
339  */
340 PVOID
341 NTAPI
343  PIMAGE_NT_HEADERS NtHeader,
345  ULONG Rva,
346  PIMAGE_SECTION_HEADER *SectionHeader)
347 {
348  PIMAGE_SECTION_HEADER Section = NULL;
349 
350  if (SectionHeader)
351  Section = *SectionHeader;
352 
353  if ((Section == NULL) ||
354  (Rva < SWAPD(Section->VirtualAddress)) ||
355  (Rva >= SWAPD(Section->VirtualAddress) + SWAPD(Section->SizeOfRawData)))
356  {
357  Section = RtlImageRvaToSection(NtHeader, BaseAddress, Rva);
358  if (Section == NULL)
359  return NULL;
360 
361  if (SectionHeader)
362  *SectionHeader = Section;
363  }
364 
365  return (PVOID)((ULONG_PTR)BaseAddress + Rva +
366  (ULONG_PTR)SWAPD(Section->PointerToRawData) -
367  (ULONG_PTR)SWAPD(Section->VirtualAddress));
368 }
369 
371 NTAPI
374  IN ULONG Count,
375  IN PUSHORT TypeOffset,
376  IN LONGLONG Delta)
377 {
378  SHORT Offset;
379  USHORT Type;
380  ULONG i;
381  PUSHORT ShortPtr;
382  PULONG LongPtr;
383  PULONGLONG LongLongPtr;
384 
385  for (i = 0; i < Count; i++)
386  {
387  Offset = SWAPW(*TypeOffset) & 0xFFF;
388  Type = SWAPW(*TypeOffset) >> 12;
389  ShortPtr = (PUSHORT)(RVA(Address, Offset));
390  /*
391  * Don't relocate within the relocation section itself.
392  * GCC/LD generates sometimes relocation records for the relocation section.
393  * This is a bug in GCC/LD.
394  * Fix for it disabled, since it was only in ntoskrnl and not in ntdll
395  */
396  /*
397  if ((ULONG_PTR)ShortPtr < (ULONG_PTR)RelocationDir ||
398  (ULONG_PTR)ShortPtr >= (ULONG_PTR)RelocationEnd)
399  {*/
400  switch (Type)
401  {
402  /* case IMAGE_REL_BASED_SECTION : */
403  /* case IMAGE_REL_BASED_REL32 : */
405  break;
406 
408  *ShortPtr = HIWORD(MAKELONG(0, *ShortPtr) + (Delta & 0xFFFFFFFF));
409  break;
410 
411  case IMAGE_REL_BASED_LOW:
412  *ShortPtr = SWAPW(*ShortPtr) + LOWORD(Delta & 0xFFFF);
413  break;
414 
416  LongPtr = (PULONG)RVA(Address, Offset);
417  *LongPtr = SWAPD(*LongPtr) + (Delta & 0xFFFFFFFF);
418  break;
419 
421  LongLongPtr = (PUINT64)RVA(Address, Offset);
422  *LongLongPtr = SWAPQ(*LongLongPtr) + Delta;
423  break;
424 
427  default:
428  DPRINT1("Unknown/unsupported fixup type %hu.\n", Type);
429  DPRINT1("Address %p, Current %u, Count %u, *TypeOffset %x\n",
430  (PVOID)Address, i, Count, SWAPW(*TypeOffset));
432  }
433 
434  TypeOffset++;
435  }
436 
437  return (PIMAGE_BASE_RELOCATION)TypeOffset;
438 }
439 
440 ULONG
441 NTAPI
444  IN PCCH LoaderName,
445  IN ULONG Success,
446  IN ULONG Conflict,
447  IN ULONG Invalid)
448 {
449  return LdrRelocateImageWithBias(BaseAddress, 0, LoaderName, Success, Conflict, Invalid);
450 }
451 
452 ULONG
453 NTAPI
456  IN LONGLONG AdditionalBias,
457  IN PCCH LoaderName,
458  IN ULONG Success,
459  IN ULONG Conflict,
460  IN ULONG Invalid)
461 {
462  PIMAGE_NT_HEADERS NtHeaders;
463  PIMAGE_DATA_DIRECTORY RelocationDDir;
464  PIMAGE_BASE_RELOCATION RelocationDir, RelocationEnd;
465  ULONG Count;
467  PUSHORT TypeOffset;
468  LONGLONG Delta;
469 
470  NtHeaders = RtlImageNtHeader(BaseAddress);
471 
472  if (NtHeaders == NULL)
473  return Invalid;
474 
476  {
477  return Conflict;
478  }
479 
480  RelocationDDir = &NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
481 
482  if (SWAPD(RelocationDDir->VirtualAddress) == 0 || SWAPD(RelocationDDir->Size) == 0)
483  {
484  return Success;
485  }
486 
487  Delta = (ULONG_PTR)BaseAddress - SWAPD(NtHeaders->OptionalHeader.ImageBase) + AdditionalBias;
488  RelocationDir = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)BaseAddress + SWAPD(RelocationDDir->VirtualAddress));
489  RelocationEnd = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)RelocationDir + SWAPD(RelocationDDir->Size));
490 
491  while (RelocationDir < RelocationEnd &&
492  SWAPW(RelocationDir->SizeOfBlock) > 0)
493  {
494  Count = (SWAPW(RelocationDir->SizeOfBlock) - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(USHORT);
495  Address = (ULONG_PTR)RVA(BaseAddress, SWAPD(RelocationDir->VirtualAddress));
496  TypeOffset = (PUSHORT)(RelocationDir + 1);
497 
498  RelocationDir = LdrProcessRelocationBlockLongLong(Address,
499  Count,
500  TypeOffset,
501  Delta);
502 
503  if (RelocationDir == NULL)
504  {
505  DPRINT1("Error during call to LdrProcessRelocationBlockLongLong()!\n");
506  return Invalid;
507  }
508  }
509 
510  return Success;
511 }
512 
513 /* EOF */
FORCEINLINE USHORT ChkSum(ULONG Sum, PUSHORT Src, ULONG Len)
Definition: image.c:26
DWORD *typedef PVOID
Definition: winlogon.h:61
#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:372
_Out_ PNDIS_HANDLE _Out_ PUINT FileLength
Definition: ndis.h:3209
#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:890
Type
Definition: Type.h:6
#define SWAPW(x)
Definition: bytesex.h:8
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
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:342
DWORD PointerToRawData
Definition: pedump.c:290
#define IMAGE_REL_BASED_HIGHLOW
Definition: winnt_old.h:885
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:882
#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:887
#define IMAGE_REL_BASED_LOW
Definition: winnt_old.h:884
_In_ BOOLEAN MappedAsImage
Definition: rtlfuncs.h:3718
#define MAKELONG(a, b)
Definition: typedefs.h:248
smooth NULL
Definition: ftsmooth.c:416
#define FORCEINLINE
Definition: ntbasedef.h:221
#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:454
IMAGE_FILE_HEADER FileHeader
Definition: ntddk_ex.h:183
#define IMAGE_REL_BASED_HIGHADJ
Definition: winnt_old.h:886
#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:399
_In_ HANDLE _Outptr_result_bytebuffer_ ViewSize PVOID * BaseAddress
Definition: mmfuncs.h:404
LONG NTSTATUS
Definition: precomp.h:26
#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:679
PIMAGE_NT_HEADERS NTAPI RtlImageNtHeader(IN PVOID Base)
Definition: image.c:256
unsigned __int64 ULONG64
Definition: imports.h:198
PIMAGE_SECTION_HEADER NTAPI RtlImageRvaToSection(PIMAGE_NT_HEADERS NtHeader, PVOID BaseAddress, ULONG Rva)
Definition: image.c:314
PVOID NTAPI RtlImageDirectoryEntryToData(PVOID BaseAddress, BOOLEAN MappedAsImage, USHORT Directory, PULONG Size)
Definition: image.c:273
#define _In_
Definition: no_sal2.h:204
#define IMAGE_REL_BASED_HIGH
Definition: winnt_old.h:883
ULONG_PTR SIZE_T
Definition: typedefs.h:78
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:442
unsigned int * PULONG
Definition: retypes.h:1
PVOID MmHighestUserAddress
Definition: rtlcompat.c:29
#define IMAGE_DIRECTORY_ENTRY_BASERELOC
Definition: pedump.c:264
#define DPRINT1
Definition: precomp.h:8
__GNU_EXTENSION typedef unsigned __int64 * PULONGLONG
Definition: ntbasedef.h:390
#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
return STATUS_SUCCESS
Definition: btrfs.c:2710
#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:141
#define LOWORD(l)
Definition: pedump.c:82
unsigned __int64 * PUINT64
Definition: basetsd.h:189