Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

220 lines
6.5 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation
  3. Module Name:
  4. rtlimagentheader.c
  5. Abstract:
  6. The module contains RtlImageNtHeader and RtlImageNtHeaderEx.
  7. Author:
  8. Jay Krell (JayKrell) February 2002
  9. Environment:
  10. user mode
  11. kernel mode
  12. boot loader
  13. statically linked to imagehlp.dll (actually RtlpImageNtHeader)
  14. statically linked to unicows.lib (actually RtlpImageNtHeader)
  15. Revision History:
  16. --*/
  17. #include "ntrtlp.h"
  18. #if DBG
  19. int
  20. RtlImageNtHeaderEx_ExceptionFilter(
  21. BOOLEAN RangeCheck,
  22. ULONG ExceptionCode
  23. )
  24. {
  25. ASSERT(!RangeCheck || ExceptionCode == STATUS_IN_PAGE_ERROR);
  26. return EXCEPTION_EXECUTE_HANDLER;
  27. }
  28. #else
  29. #define RtlImageNtHeaderEx_ExceptionFilter(RangeCheck, ExceptionCode) EXCEPTION_EXECUTE_HANDLER
  30. #endif
  31. NTSTATUS
  32. NTAPI
  33. RtlImageNtHeaderEx(
  34. ULONG Flags,
  35. PVOID Base,
  36. ULONG64 Size,
  37. OUT PIMAGE_NT_HEADERS * OutHeaders
  38. )
  39. /*++
  40. Routine Description:
  41. This function returns the address of the NT Header.
  42. This function is a bit complicated.
  43. It is this way because RtlImageNtHeader that it replaces was hard to understand,
  44. and this function retains compatibility with RtlImageNtHeader.
  45. RtlImageNtHeader was #ifed such as to act different in each of the three
  46. boot loader, kernel, usermode flavors.
  47. boot loader -- no exception handling
  48. usermode -- limit msdos header to 256meg, catch any exception accessing the msdos-header
  49. or the pe header
  50. kernel -- don't cross user/kernel boundary, don't catch the exceptions,
  51. no 256meg limit
  52. Arguments:
  53. Flags - RTL_IMAGE_NT_HEADER_EX_FLAG_NO_RANGE_CHECK -- don't be so picky
  54. about the image, for compatibility with RtlImageNtHeader
  55. Base - Supplies the base of the image.
  56. Size - The size of the view, usually larger than the size of the file on disk.
  57. This is available from NtMapViewOfSection but not from MapViewOfFile.
  58. OutHeaders -
  59. Return Value:
  60. STATUS_SUCCESS -- everything ok
  61. STATUS_INVALID_IMAGE_FORMAT -- bad filesize or signature value
  62. STATUS_INVALID_PARAMETER -- bad parameters
  63. --*/
  64. {
  65. PIMAGE_NT_HEADERS NtHeaders = 0;
  66. ULONG e_lfanew = 0;
  67. BOOLEAN RangeCheck = 0;
  68. NTSTATUS Status = 0;
  69. const ULONG ValidFlags =
  70. RTL_IMAGE_NT_HEADER_EX_FLAG_NO_RANGE_CHECK;
  71. if (OutHeaders != NULL) {
  72. *OutHeaders = NULL;
  73. }
  74. if (OutHeaders == NULL) {
  75. Status = STATUS_INVALID_PARAMETER;
  76. goto Exit;
  77. }
  78. if ((Flags & ~ValidFlags) != 0) {
  79. Status = STATUS_INVALID_PARAMETER;
  80. goto Exit;
  81. }
  82. if (Base == NULL || Base == (PVOID)(LONG_PTR)-1) {
  83. Status = STATUS_INVALID_PARAMETER;
  84. goto Exit;
  85. }
  86. RangeCheck = ((Flags & RTL_IMAGE_NT_HEADER_EX_FLAG_NO_RANGE_CHECK) == 0);
  87. if (RangeCheck) {
  88. if (Size < sizeof(IMAGE_DOS_HEADER)) {
  89. Status = STATUS_INVALID_IMAGE_FORMAT;
  90. goto Exit;
  91. }
  92. }
  93. #if !defined (BLDR_KERNEL_RUNTIME) && !defined(NTOS_KERNEL_RUNTIME)
  94. //
  95. // In usermode, catch any exceptions taken while accessing e_magic, e_lfanew or Signature;
  96. // This should only be needed in the no_range_check case now.
  97. //
  98. __try {
  99. #define EXIT __leave
  100. #else
  101. //
  102. // Exception handling is not available in the boot loader, and exceptions
  103. // were not historically caught here in kernel mode. Drivers are considered
  104. // trusted, so we can't get an exception here due to a bad file, but we
  105. // could take an inpage error.
  106. //
  107. #define EXIT goto Exit
  108. #endif
  109. if (((PIMAGE_DOS_HEADER)Base)->e_magic != IMAGE_DOS_SIGNATURE) {
  110. Status = STATUS_INVALID_IMAGE_FORMAT;
  111. EXIT;
  112. }
  113. e_lfanew = ((PIMAGE_DOS_HEADER)Base)->e_lfanew;
  114. if (RangeCheck) {
  115. if (e_lfanew >= Size
  116. #define SIZEOF_PE_SIGNATURE 4
  117. || e_lfanew >= (MAXULONG - SIZEOF_PE_SIGNATURE - sizeof(IMAGE_FILE_HEADER))
  118. || (e_lfanew + SIZEOF_PE_SIGNATURE + sizeof(IMAGE_FILE_HEADER)) >= Size
  119. ) {
  120. Status = STATUS_INVALID_IMAGE_FORMAT;
  121. EXIT;
  122. }
  123. }
  124. #if !defined (BLDR_KERNEL_RUNTIME) && !defined(NTOS_KERNEL_RUNTIME)
  125. //
  126. // In usermode, limit msdos header to 256meg.
  127. //
  128. if (e_lfanew >= RTLP_IMAGE_MAX_DOS_HEADER) {
  129. Status = STATUS_INVALID_IMAGE_FORMAT;
  130. EXIT;
  131. }
  132. #endif
  133. NtHeaders = (PIMAGE_NT_HEADERS)((PCHAR)Base + e_lfanew);
  134. #if defined(NTOS_KERNEL_RUNTIME)
  135. //
  136. // In kernelmode, do not cross from usermode address to kernelmode address.
  137. //
  138. if (Base < MM_HIGHEST_USER_ADDRESS) {
  139. if ((PVOID)NtHeaders >= MM_HIGHEST_USER_ADDRESS) {
  140. Status = STATUS_INVALID_IMAGE_FORMAT;
  141. EXIT;
  142. }
  143. //
  144. // Note that this check is slightly overeager since IMAGE_NT_HEADERS has
  145. // a builtin array of data_directories that may be larger than the image
  146. // actually has. A better check would be to add FileHeader.SizeOfOptionalHeader,
  147. // after ensuring that the FileHeader does not cross the u/k boundary.
  148. //
  149. if ((PVOID)((PCHAR)NtHeaders + sizeof (IMAGE_NT_HEADERS)) >= MM_HIGHEST_USER_ADDRESS) {
  150. Status = STATUS_INVALID_IMAGE_FORMAT;
  151. EXIT;
  152. }
  153. }
  154. #endif
  155. if (NtHeaders->Signature != IMAGE_NT_SIGNATURE) {
  156. Status = STATUS_INVALID_IMAGE_FORMAT;
  157. EXIT;
  158. }
  159. Status = STATUS_SUCCESS;
  160. #if !defined (BLDR_KERNEL_RUNTIME) && !defined(NTOS_KERNEL_RUNTIME)
  161. } __except(RtlImageNtHeaderEx_ExceptionFilter(RangeCheck, GetExceptionCode())) {
  162. //
  163. // In usermode, catch any exceptions taken while accessing e_magic, e_lfanew or Signature;
  164. // This should only be needed in the no_range_check case now, the exception filter
  165. // asserts to that affect.
  166. //
  167. // Propagating STATUS_IN_PAGE_ERROR if that's what the exception
  168. // was may be better, but it may be incompatible.
  169. //
  170. // Letting STATUS_IN_PAGE_ERROR go as an exception may also be better.
  171. //
  172. Status = STATUS_INVALID_IMAGE_FORMAT;
  173. }
  174. #endif
  175. Exit:
  176. if (NT_SUCCESS(Status)) {
  177. *OutHeaders = NtHeaders;
  178. }
  179. return Status;
  180. }
  181. #undef EXIT
  182. PIMAGE_NT_HEADERS
  183. NTAPI
  184. RtlImageNtHeader(
  185. PVOID Base
  186. )
  187. {
  188. PIMAGE_NT_HEADERS NtHeaders = NULL;
  189. (VOID)RtlImageNtHeaderEx(RTL_IMAGE_NT_HEADER_EX_FLAG_NO_RANGE_CHECK, Base, 0, &NtHeaders);
  190. return NtHeaders;
  191. }