Source code of Windows XP (NT5)
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.

1250 lines
37 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. ldrwx86.c
  5. Abstract:
  6. This module implements the wx86 specific ldr functions.
  7. Author:
  8. 13-Jan-1995 Jonle , created
  9. Revision History:
  10. 15-Oct-1998 CBiks Modified the code that throws the architecture
  11. mismatch exception so the exception is only
  12. thrown for NT 3,0 and lower executables. This was
  13. changed to make the Wx86 loader behave like the
  14. real loader, which does not throw this exception.
  15. Also added a call to the cleanup function when
  16. LdrpWx86LoadDll() fails. There were cases where the
  17. CPU failed to initialize but the Wx86 global pointers
  18. were not cleared and pointed to a invalid memory because
  19. wx86.dll was unloaded.
  20. 13-Mar-2001 SamerA Fix sharing of varialbes inside a SHARED read/write section.
  21. 20-May-2001 SamerA Fix mapping of image sections that have their PointerToRawData
  22. RVA overlap with other sections virtual addresses.
  23. (Fixed corel's WP2002 intro.exe)
  24. 24-Oct-2001 SamerA Correct calculation of variables offsets inside the relocated
  25. shared section.
  26. --*/
  27. #include "ntos.h"
  28. #include "ldrp.h"
  29. #define PAGE_SIZE_X86 (0x1000)
  30. #if defined(BUILD_WOW6432)
  31. //
  32. // From mi\mi.h:
  33. //
  34. #define MI_ROUND_TO_SIZE(LENGTH,ALIGNMENT) \
  35. (((LENGTH) + ((ALIGNMENT) - 1)) & ~((ALIGNMENT) - 1))
  36. PIMAGE_BASE_RELOCATION LdrpWx86ProcessRelocationBlock(
  37. IN ULONG_PTR VA,
  38. IN PUCHAR ImageBase,
  39. IN ULONG SizeOfBlock,
  40. IN PUSHORT NextOffset,
  41. IN ULONG Diff,
  42. IN ULONG_PTR SectionStartVA,
  43. IN ULONG_PTR SectionEndVA);
  44. NTSTATUS
  45. FixupBlockList(
  46. IN PUCHAR ImageBase);
  47. VOID
  48. FixupSectionHeader(
  49. IN PUCHAR ImageBase);
  50. NTSTATUS
  51. LdrpWx86FixupExportedSharedSection (
  52. IN PVOID ImageBase,
  53. IN PIMAGE_NT_HEADERS NtHeaders
  54. );
  55. BOOLEAN
  56. LdrpWx86DetectSectionOverlap (
  57. IN PVOID ImageBase,
  58. IN PIMAGE_NT_HEADERS NtHeaders
  59. )
  60. {
  61. PIMAGE_SECTION_HEADER SectionHeader;
  62. ULONG SrcRawData;
  63. ULONG SrcEndRawData;
  64. ULONG OverlapData;
  65. ULONG EndOverlapData;
  66. ULONG SrcSize;
  67. ULONG Section;
  68. ULONG SectionCheck;
  69. ULONG Count;
  70. BOOLEAN Result = FALSE;
  71. //
  72. // Run through the section and see if any one need to be moved down (higher in address space),
  73. // then for each one of those, check if it overlap with any section
  74. // that has already been moved up.
  75. //
  76. SectionHeader = IMAGE_FIRST_SECTION (NtHeaders);
  77. for (Section = NtHeaders->FileHeader.NumberOfSections-1, Count=0 ;
  78. Count < NtHeaders->FileHeader.NumberOfSections ; Section--, Count++) {
  79. SrcRawData = SectionHeader[Section].PointerToRawData;
  80. SrcSize = SectionHeader[Section].SizeOfRawData;
  81. if ((SectionHeader[Section].Misc.VirtualSize > 0) &&
  82. (SrcRawData > MI_ROUND_TO_SIZE(SectionHeader[Section].Misc.VirtualSize, PAGE_SIZE_X86))) {
  83. SrcRawData = MI_ROUND_TO_SIZE(SectionHeader[Section].Misc.VirtualSize, PAGE_SIZE_X86);
  84. }
  85. if (SectionHeader[Section].VirtualAddress <= SrcRawData) {
  86. break;
  87. }
  88. SrcEndRawData = SrcRawData + SrcSize;
  89. //
  90. // This section needs to be moved down
  91. //
  92. for (SectionCheck = 0 ; SectionCheck < NtHeaders->FileHeader.NumberOfSections ; SectionCheck++) {
  93. if (Section == SectionCheck) {
  94. continue;
  95. }
  96. OverlapData = SectionHeader[SectionCheck].PointerToRawData;
  97. SrcSize = SectionHeader[SectionCheck].SizeOfRawData;
  98. if ((SectionHeader[SectionCheck].Misc.VirtualSize > 0) &&
  99. (SrcRawData > MI_ROUND_TO_SIZE(SectionHeader[SectionCheck].Misc.VirtualSize, PAGE_SIZE_X86))) {
  100. SrcRawData = MI_ROUND_TO_SIZE(SectionHeader[SectionCheck].Misc.VirtualSize, PAGE_SIZE_X86);
  101. }
  102. if (SectionHeader[SectionCheck].VirtualAddress > OverlapData) {
  103. break;
  104. }
  105. if (((SrcRawData >= SectionHeader[SectionCheck].VirtualAddress) &&
  106. (SrcRawData < (SectionHeader[SectionCheck].VirtualAddress + SrcSize))) ||
  107. ((SrcEndRawData >= SectionHeader[SectionCheck].VirtualAddress) &&
  108. (SrcEndRawData < (SectionHeader[SectionCheck].VirtualAddress + SrcSize)))) {
  109. Result = TRUE;
  110. break;
  111. }
  112. }
  113. if (Result == TRUE) {
  114. break;
  115. }
  116. }
  117. return Result;
  118. }
  119. NTSTATUS
  120. LdrpWx86CheckVirtualSectionOverlap (
  121. IN PUNICODE_STRING ImageName OPTIONAL,
  122. IN PVOID ImageBase,
  123. IN PIMAGE_NT_HEADERS NtHeaders,
  124. OUT PVOID *SrcImageMap
  125. )
  126. /*++
  127. Routine Description:
  128. This function goes through the image sections based at ImageBase and looks
  129. for any overlap between the section physical locations and their updated virtual
  130. locations.
  131. Arguments:
  132. ImageName - Unicode string pointer to the full path to the image.
  133. ImageBase - Base of image.
  134. SrcImageMap - Pointer to pointer to receive a base pointer to the image mapped
  135. as read-only pages inside this process. The mapped pages need to be released
  136. when done.
  137. Return Value:
  138. NTSTATUS.
  139. --*/
  140. {
  141. PUNICODE_STRING NtPathName;
  142. PVOID FreeBuffer;
  143. BOOLEAN Result;
  144. OBJECT_ATTRIBUTES ObjectAttributes;
  145. IO_STATUS_BLOCK IoStatusBlock;
  146. HANDLE FileHandle;
  147. HANDLE MappingHandle;
  148. PVOID ViewBase;
  149. SIZE_T ViewSize;
  150. LARGE_INTEGER SectionOffset;
  151. UCHAR Buffer[ DOS_MAX_PATH_LENGTH ];
  152. NTSTATUS NtStatus = STATUS_UNSUCCESSFUL;
  153. //
  154. // Check for any overlap inside the image.
  155. //
  156. Result = LdrpWx86DetectSectionOverlap (ImageBase, NtHeaders);
  157. if (Result == FALSE) {
  158. return NtStatus;
  159. }
  160. FreeBuffer = NULL;
  161. //
  162. // Make sure we have a path.
  163. //
  164. NtPathName = (PUNICODE_STRING)Buffer;
  165. if (ARGUMENT_PRESENT (ImageName) == 0) {
  166. NtStatus = NtQueryInformationProcess(
  167. NtCurrentProcess(),
  168. ProcessImageFileName,
  169. NtPathName,
  170. sizeof (Buffer),
  171. NULL
  172. );
  173. } else {
  174. Result = RtlDosPathNameToNtPathName_U(
  175. ImageName->Buffer,
  176. NtPathName,
  177. NULL,
  178. NULL
  179. );
  180. if (Result != FALSE) {
  181. FreeBuffer = NtPathName->Buffer;
  182. NtStatus = STATUS_SUCCESS;
  183. }
  184. }
  185. if (NT_SUCCESS (NtStatus)) {
  186. InitializeObjectAttributes(
  187. &ObjectAttributes,
  188. NtPathName,
  189. OBJ_CASE_INSENSITIVE,
  190. NULL,
  191. NULL
  192. );
  193. NtStatus = NtCreateFile(
  194. &FileHandle,
  195. (ACCESS_MASK) GENERIC_READ | SYNCHRONIZE | FILE_READ_ATTRIBUTES,
  196. &ObjectAttributes,
  197. &IoStatusBlock,
  198. NULL,
  199. 0L,
  200. FILE_SHARE_READ | FILE_SHARE_DELETE,
  201. FILE_OPEN,
  202. 0L,
  203. NULL,
  204. 0L
  205. );
  206. if (FreeBuffer != NULL) {
  207. RtlFreeHeap (RtlProcessHeap(), 0, FreeBuffer);
  208. }
  209. if (NT_SUCCESS (NtStatus)) {
  210. NtStatus = NtCreateSection(
  211. &MappingHandle,
  212. STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ,
  213. NULL,
  214. NULL,
  215. PAGE_READONLY,
  216. SEC_COMMIT,
  217. FileHandle
  218. );
  219. NtClose (FileHandle);
  220. if (NT_SUCCESS (NtStatus)) {
  221. SectionOffset.LowPart = 0;
  222. SectionOffset.HighPart = 0;
  223. ViewSize = 0;
  224. ViewBase = NULL;
  225. NtStatus = NtMapViewOfSection(
  226. MappingHandle,
  227. NtCurrentProcess(),
  228. &ViewBase,
  229. 0L,
  230. 0L,
  231. &SectionOffset,
  232. &ViewSize,
  233. ViewShare,
  234. 0L,
  235. PAGE_READONLY
  236. );
  237. NtClose (MappingHandle);
  238. if (NT_SUCCESS (NtStatus)) {
  239. *SrcImageMap = ViewBase;
  240. }
  241. }
  242. }
  243. }
  244. return NtStatus;
  245. }
  246. NTSTATUS
  247. Wx86SetRelocatedSharedProtection (
  248. IN PVOID Base,
  249. IN BOOLEAN Reset
  250. )
  251. /*++
  252. Routine Description:
  253. This function loops thru the images sections/objects, setting
  254. all relocated shared sections/objects marked r/o to r/w. It also resets the
  255. original section/object protections.
  256. Arguments:
  257. Base - Base of image.
  258. Reset - If TRUE, reset section/object protection to original
  259. protection described by the section/object headers.
  260. If FALSE, then set all sections/objects to r/w.
  261. Return Value:
  262. SUCCESS or reason NtProtectVirtualMemory failed.
  263. --*/
  264. {
  265. HANDLE CurrentProcessHandle;
  266. SIZE_T RegionSize;
  267. ULONG NewProtect, OldProtect;
  268. PVOID VirtualAddress;
  269. ULONG i;
  270. PIMAGE_NT_HEADERS NtHeaders;
  271. PIMAGE_SECTION_HEADER SectionHeader;
  272. NTSTATUS st;
  273. ULONG NumberOfSharedDataPages;
  274. SIZE_T NumberOfNativePagesForImage;
  275. CurrentProcessHandle = NtCurrentProcess();
  276. NtHeaders = RtlImageNtHeader(Base);
  277. SectionHeader = (PIMAGE_SECTION_HEADER)((ULONG_PTR)NtHeaders + sizeof(ULONG) +
  278. sizeof(IMAGE_FILE_HEADER) +
  279. NtHeaders->FileHeader.SizeOfOptionalHeader
  280. );
  281. NumberOfSharedDataPages = 0;
  282. NumberOfNativePagesForImage =
  283. NATIVE_BYTES_TO_PAGES (NtHeaders->OptionalHeader.SizeOfImage);
  284. for (i=0; i<NtHeaders->FileHeader.NumberOfSections; i++, SectionHeader++) {
  285. RegionSize = SectionHeader->SizeOfRawData;
  286. if ((SectionHeader->Characteristics & IMAGE_SCN_MEM_SHARED) &&
  287. (!(SectionHeader->Characteristics & IMAGE_SCN_MEM_EXECUTE) ||
  288. (SectionHeader->Characteristics & IMAGE_SCN_MEM_WRITE)) &&
  289. (RegionSize != 0)) {
  290. VirtualAddress = (PVOID)((ULONG_PTR)Base +
  291. ((NumberOfNativePagesForImage + NumberOfSharedDataPages) << NATIVE_PAGE_SHIFT));
  292. NumberOfNativePagesForImage += MI_ROUND_TO_SIZE (RegionSize, NATIVE_PAGE_SIZE) >> NATIVE_PAGE_SHIFT;
  293. if (!(SectionHeader->Characteristics & IMAGE_SCN_MEM_WRITE)) {
  294. //
  295. // Object isn't writeable, so change it.
  296. //
  297. if (Reset) {
  298. if (SectionHeader->Characteristics & IMAGE_SCN_MEM_EXECUTE) {
  299. NewProtect = PAGE_EXECUTE;
  300. }
  301. else {
  302. NewProtect = PAGE_READONLY;
  303. }
  304. NewProtect |= (SectionHeader->Characteristics & IMAGE_SCN_MEM_NOT_CACHED) ? PAGE_NOCACHE : 0;
  305. }
  306. else {
  307. NewProtect = PAGE_READWRITE;
  308. }
  309. st = NtProtectVirtualMemory(CurrentProcessHandle, &VirtualAddress,
  310. &RegionSize, NewProtect, &OldProtect);
  311. if (!NT_SUCCESS(st)) {
  312. return st;
  313. }
  314. }
  315. }
  316. }
  317. if (Reset) {
  318. NtFlushInstructionCache(NtCurrentProcess(),
  319. Base,
  320. NumberOfNativePagesForImage << NATIVE_PAGE_SHIFT
  321. );
  322. }
  323. return STATUS_SUCCESS;
  324. }
  325. NTSTATUS
  326. LdrpWx86FormatVirtualImage(
  327. IN PUNICODE_STRING DosImagePathName,
  328. IN PIMAGE_NT_HEADERS32 NtHeaders,
  329. IN PVOID DllBase
  330. )
  331. {
  332. PIMAGE_SECTION_HEADER SectionTable, Section, LastSection, FirstSection;
  333. ULONG VirtualImageSize;
  334. PUCHAR NextVirtualAddress, SrcVirtualAddress, DestVirtualAddress;
  335. PUCHAR ImageBase= DllBase;
  336. LONG Size;
  337. ULONG NumberOfSharedDataPages;
  338. ULONG NumberOfNativePagesForImage;
  339. ULONG NumberOfExtraPagesForImage;
  340. ULONG_PTR PreferredImageBase;
  341. BOOLEAN ImageHasRelocatedSharedSection = FALSE;
  342. ULONG SubSectionSize;
  343. PVOID AlternateBase;
  344. NTSTATUS st;
  345. AlternateBase = NULL;
  346. st = LdrpWx86CheckVirtualSectionOverlap (DosImagePathName,
  347. DllBase,
  348. NtHeaders,
  349. &AlternateBase
  350. );
  351. st = Wx86SetRelocatedSharedProtection(DllBase, FALSE);
  352. if (!NT_SUCCESS(st)) {
  353. DbgPrint("Wx86SetRelocatedSharedProtection failed with return status %x\n", st);
  354. Wx86SetRelocatedSharedProtection(DllBase, TRUE);
  355. if (AlternateBase != NULL) {
  356. NtUnmapViewOfSection (NtCurrentProcess(), AlternateBase);
  357. }
  358. return st;
  359. }
  360. //
  361. // Copy each section from its raw file address to its virtual address
  362. //
  363. SectionTable = IMAGE_FIRST_SECTION(NtHeaders);
  364. LastSection = SectionTable + NtHeaders->FileHeader.NumberOfSections;
  365. if (SectionTable->PointerToRawData == SectionTable->VirtualAddress) {
  366. // If the first section does not need to be moved then we exclude it
  367. // from consideration in passes 1 and 2
  368. FirstSection = SectionTable + 1;
  369. }
  370. else {
  371. FirstSection = SectionTable;
  372. }
  373. //
  374. // First pass starts at the top and works down moving up each section that
  375. // is to be moved up.
  376. //
  377. Section = FirstSection;
  378. while (Section < LastSection) {
  379. SrcVirtualAddress = ImageBase + Section->PointerToRawData;
  380. DestVirtualAddress = Section->VirtualAddress + ImageBase;
  381. if (DestVirtualAddress > SrcVirtualAddress) {
  382. // Section needs to be moved down
  383. break;
  384. }
  385. // Section needs to be moved up
  386. if (Section->SizeOfRawData != 0) {
  387. if (Section->PointerToRawData != 0) {
  388. RtlMoveMemory(DestVirtualAddress,
  389. SrcVirtualAddress,
  390. Section->SizeOfRawData);
  391. }
  392. }
  393. else {
  394. Section->PointerToRawData = 0;
  395. }
  396. Section++;
  397. }
  398. //
  399. // Second pass is from the end of the image and work backwards since src and
  400. // dst overlap
  401. //
  402. Section = --LastSection;
  403. NextVirtualAddress = ImageBase + NtHeaders->OptionalHeader.SizeOfImage;
  404. while (Section >= FirstSection) {
  405. SrcVirtualAddress = ImageBase + Section->PointerToRawData;
  406. DestVirtualAddress = Section->VirtualAddress + ImageBase;
  407. //
  408. // Compute the subsection size. The mm is really flexible here...
  409. // it will allow a SizeOfRawData that far exceeds the virtual size,
  410. // so we can't trust that. If that happens, just use the page-aligned
  411. // virtual size, since that is all that the mm will map in.
  412. //
  413. SubSectionSize = Section->SizeOfRawData;
  414. if (Section->Misc.VirtualSize &&
  415. SubSectionSize > MI_ROUND_TO_SIZE(Section->Misc.VirtualSize, PAGE_SIZE_X86)) {
  416. SubSectionSize = MI_ROUND_TO_SIZE(Section->Misc.VirtualSize, PAGE_SIZE_X86);
  417. }
  418. //
  419. // ensure Virtual section doesn't overlap the next section
  420. //
  421. if (DestVirtualAddress + SubSectionSize > NextVirtualAddress) {
  422. Wx86SetRelocatedSharedProtection(DllBase, TRUE);
  423. if (AlternateBase != NULL) {
  424. NtUnmapViewOfSection (NtCurrentProcess(), AlternateBase);
  425. }
  426. return STATUS_INVALID_IMAGE_FORMAT;
  427. }
  428. if (DestVirtualAddress < SrcVirtualAddress) {
  429. // Section needs to be moved up
  430. break;
  431. }
  432. // Section needs to be moved down
  433. if (Section->SizeOfRawData != 0) {
  434. if (Section->PointerToRawData != 0) {
  435. RtlMoveMemory(DestVirtualAddress,
  436. (AlternateBase != NULL) ?
  437. ((PCHAR)AlternateBase + Section->PointerToRawData) : SrcVirtualAddress,
  438. SubSectionSize);
  439. }
  440. }
  441. else {
  442. Section->PointerToRawData = 0;
  443. }
  444. NextVirtualAddress = DestVirtualAddress;
  445. Section--;
  446. }
  447. //
  448. // Third pass is for zeroing out any memory left between the end of a
  449. // section and the end of the page. We'll do this from end to top
  450. //
  451. Section = LastSection;
  452. NextVirtualAddress = ImageBase + NtHeaders->OptionalHeader.SizeOfImage;
  453. NumberOfSharedDataPages = 0;
  454. while (Section >= SectionTable) {
  455. DestVirtualAddress = Section->VirtualAddress + ImageBase;
  456. //
  457. // Shared Data sections cannot be shared, because of
  458. // page misalignment, and are treated as Exec- Copy on Write.
  459. //
  460. if ((Section->Characteristics & IMAGE_SCN_MEM_SHARED) &&
  461. (!(Section->Characteristics & IMAGE_SCN_MEM_EXECUTE) ||
  462. (Section->Characteristics & IMAGE_SCN_MEM_WRITE))) {
  463. ImageHasRelocatedSharedSection = TRUE;
  464. #if 0
  465. DbgPrint("Unsuported IMAGE_SCN_MEM_SHARED %x\n",
  466. Section->Characteristics
  467. );
  468. #endif
  469. }
  470. //
  471. // If section was empty zero it out
  472. //
  473. if (Section->SizeOfRawData != 0) {
  474. if (Section->PointerToRawData == 0) {
  475. RtlZeroMemory(DestVirtualAddress,
  476. Section->SizeOfRawData
  477. );
  478. }
  479. }
  480. SubSectionSize = Section->SizeOfRawData;
  481. if (Section->Misc.VirtualSize &&
  482. SubSectionSize > MI_ROUND_TO_SIZE(Section->Misc.VirtualSize, PAGE_SIZE_X86)) {
  483. SubSectionSize = MI_ROUND_TO_SIZE(Section->Misc.VirtualSize, PAGE_SIZE_X86);
  484. }
  485. //
  486. // Zero out remaining bytes up to the next section
  487. //
  488. RtlZeroMemory(DestVirtualAddress + Section->SizeOfRawData,
  489. (ULONG)(NextVirtualAddress - DestVirtualAddress - SubSectionSize)
  490. );
  491. NextVirtualAddress = DestVirtualAddress;
  492. Section--;
  493. }
  494. //
  495. // Unmap the alternate base if it is there
  496. //
  497. if (AlternateBase != NULL) {
  498. NtUnmapViewOfSection (NtCurrentProcess(), AlternateBase);
  499. }
  500. // Pass 4: if the dll has any shared sections, change the shared data
  501. // references to point to additional shared pages at the end of the image.
  502. //
  503. // Note that our fixups are applied assuming that the dll is loaded at
  504. // its preferred base; if it is loaded at some other address, it will
  505. // be relocated again along will al other addresses.
  506. if (!ImageHasRelocatedSharedSection) {
  507. goto LdrwWx86FormatVirtualImageDone;
  508. }
  509. st = FixupBlockList(DllBase);
  510. if (!NT_SUCCESS(st)) {
  511. Wx86SetRelocatedSharedProtection(DllBase, TRUE);
  512. return st;
  513. }
  514. NumberOfNativePagesForImage =
  515. NATIVE_BYTES_TO_PAGES (NtHeaders->OptionalHeader.SizeOfImage);
  516. NumberOfExtraPagesForImage = 0;
  517. // Account for raw data that extends beyond SizeOfImage
  518. for (Section = SectionTable; Section <= LastSection; Section++)
  519. {
  520. ULONG EndOfSection;
  521. ULONG ExtraPages;
  522. ULONG ImagePages = NATIVE_BYTES_TO_PAGES (NtHeaders->OptionalHeader.SizeOfImage);
  523. EndOfSection = Section->PointerToRawData + Section->SizeOfRawData;
  524. if (NATIVE_BYTES_TO_PAGES (EndOfSection) > ImagePages) {
  525. ExtraPages = NATIVE_BYTES_TO_PAGES (EndOfSection) - ImagePages;
  526. if (ExtraPages > NumberOfExtraPagesForImage) {
  527. NumberOfExtraPagesForImage = ExtraPages;
  528. }
  529. }
  530. }
  531. PreferredImageBase = NtHeaders->OptionalHeader.ImageBase;
  532. NumberOfNativePagesForImage += NumberOfExtraPagesForImage;
  533. NumberOfSharedDataPages = 0;
  534. for (Section = SectionTable; Section <= LastSection; Section++)
  535. {
  536. ULONG bFirst = 1;
  537. if ((Section->Characteristics & IMAGE_SCN_MEM_SHARED) &&
  538. (!(Section->Characteristics & IMAGE_SCN_MEM_EXECUTE) ||
  539. (Section->Characteristics & IMAGE_SCN_MEM_WRITE)))
  540. {
  541. PIMAGE_BASE_RELOCATION NextBlock;
  542. PUSHORT NextOffset;
  543. ULONG TotalBytes;
  544. ULONG SizeOfBlock;
  545. ULONG_PTR VA;
  546. ULONG_PTR SectionStartVA;
  547. ULONG_PTR SectionEndVA;
  548. ULONG SectionVirtualSize;
  549. ULONG Diff;
  550. SectionVirtualSize = Section->Misc.VirtualSize;
  551. if (SectionVirtualSize == 0)
  552. {
  553. SectionVirtualSize = Section->SizeOfRawData;
  554. }
  555. SectionStartVA = PreferredImageBase + Section->VirtualAddress;
  556. SectionEndVA = SectionStartVA + SectionVirtualSize;
  557. NextBlock = RtlImageDirectoryEntryToData(DllBase, TRUE,
  558. IMAGE_DIRECTORY_ENTRY_BASERELOC,
  559. &TotalBytes);
  560. if (!NextBlock || !TotalBytes)
  561. {
  562. // Note that if this fails, it should fail in the very
  563. // first iteration and no fixups would have been performed
  564. if (!bFirst)
  565. {
  566. // Trouble
  567. if (ShowSnaps)
  568. {
  569. DbgPrint("LdrpWx86FormatVirtualImage: failure "
  570. "after relocating some sections for image at %x\n",
  571. DllBase);
  572. }
  573. Wx86SetRelocatedSharedProtection(DllBase, TRUE);
  574. return STATUS_INVALID_IMAGE_FORMAT;
  575. }
  576. if (ShowSnaps)
  577. {
  578. DbgPrint("LdrpWx86FormatVirtualImage: No fixup info "
  579. "for image at %x; private sections will be "
  580. "used for shared data sections.\n",
  581. DllBase);
  582. }
  583. break;
  584. }
  585. bFirst = 0;
  586. Diff = (NumberOfNativePagesForImage +
  587. NumberOfSharedDataPages) << NATIVE_PAGE_SHIFT;
  588. Diff -= (ULONG) (SectionStartVA - PreferredImageBase);
  589. if (ShowSnaps)
  590. {
  591. DbgPrint("LdrpWx86FormatVirtualImage: Relocating shared "
  592. "data for shared data section 0x%x of image "
  593. "at %x by 0x%lx bytes\n",
  594. Section - SectionTable + 1, DllBase, Diff);
  595. }
  596. while (TotalBytes)
  597. {
  598. SizeOfBlock = NextBlock->SizeOfBlock;
  599. if (SizeOfBlock == 0) {
  600. if (ShowSnaps) {
  601. DbgPrint("Image at %lx contains invalid block size. Stopping fixups\n",
  602. ImageBase);
  603. }
  604. break;
  605. }
  606. TotalBytes -= SizeOfBlock;
  607. SizeOfBlock -= sizeof(IMAGE_BASE_RELOCATION);
  608. SizeOfBlock /= sizeof(USHORT);
  609. NextOffset = (PUSHORT) ((PCHAR)NextBlock +
  610. sizeof(IMAGE_BASE_RELOCATION));
  611. VA = (ULONG_PTR) DllBase + NextBlock->VirtualAddress;
  612. NextBlock = LdrpWx86ProcessRelocationBlock(VA, DllBase, SizeOfBlock,
  613. NextOffset,
  614. Diff,
  615. SectionStartVA,
  616. SectionEndVA);
  617. if (NextBlock == NULL)
  618. {
  619. // Trouble
  620. if (ShowSnaps)
  621. {
  622. DbgPrint("LdrpWx86FormatVirtualImage: failure "
  623. "after relocating some sections for image at %x; "
  624. "Relocation information invalid\n",
  625. DllBase);
  626. }
  627. Wx86SetRelocatedSharedProtection(DllBase, TRUE);
  628. return STATUS_INVALID_IMAGE_FORMAT;
  629. }
  630. }
  631. NumberOfSharedDataPages += MI_ROUND_TO_SIZE (SectionVirtualSize,
  632. NATIVE_PAGE_SIZE) >>
  633. NATIVE_PAGE_SHIFT;
  634. }
  635. }
  636. //
  637. // If any of the variables inside the shared section is exported, then
  638. // we need to fix up its RVA to point to the proper location at
  639. // the end of the image.
  640. //
  641. LdrpWx86FixupExportedSharedSection (
  642. DllBase,
  643. NtHeaders
  644. );
  645. LdrwWx86FormatVirtualImageDone:
  646. //
  647. // Zero out first section's Raw Data up to its VirtualAddress
  648. //
  649. if (SectionTable->PointerToRawData != 0) {
  650. DestVirtualAddress = SectionTable->PointerToRawData + ImageBase;
  651. Size = (LONG)(NextVirtualAddress - DestVirtualAddress);
  652. if (Size > 0) {
  653. RtlZeroMemory(DestVirtualAddress,
  654. (ULONG)Size
  655. );
  656. }
  657. }
  658. Wx86SetRelocatedSharedProtection(DllBase, TRUE);
  659. return STATUS_SUCCESS;
  660. }
  661. NTSTATUS
  662. LdrpWx86FixupExportedSharedSection (
  663. IN PVOID ImageBase,
  664. IN PIMAGE_NT_HEADERS NtHeaders
  665. )
  666. /*++
  667. Routine Description:
  668. This function goes through the exported entries from this module,
  669. and relocates (fixup) any address that lie inside any shared
  670. read/write to the end of the image.
  671. Arguments:
  672. ImageBase - Virtual address for image base.
  673. NtHeaders - Address of the image's header.
  674. Return Value:
  675. NTSTATUS.
  676. --*/
  677. {
  678. PIMAGE_EXPORT_DIRECTORY ImageExportDirectory;
  679. ULONG TotalBytes;
  680. ULONG SharedRelocFixup;
  681. ULONG Export;
  682. PULONG ExportEntry;
  683. NTSTATUS NtStatus = STATUS_SUCCESS;
  684. ImageExportDirectory = RtlImageDirectoryEntryToData (
  685. ImageBase,
  686. TRUE,
  687. IMAGE_DIRECTORY_ENTRY_EXPORT,
  688. &TotalBytes);
  689. if ((ImageExportDirectory == NULL) || (TotalBytes == 0)) {
  690. return NtStatus;
  691. }
  692. ExportEntry = (PULONG)((ULONG)ImageBase + ImageExportDirectory->AddressOfFunctions);
  693. for (Export = 0 ; Export < ImageExportDirectory->NumberOfFunctions ; Export++) {
  694. SharedRelocFixup = LdrpWx86RelocatedFixupDiff (
  695. ImageBase,
  696. NtHeaders,
  697. ExportEntry[Export]
  698. );
  699. if (SharedRelocFixup != 0) {
  700. if (ShowSnaps) {
  701. DbgPrint("LdrpWx86FixupExportedSharedSection: Changing export Export[%lx] from %lx to %lx\n",
  702. Export,
  703. ExportEntry[Export],
  704. ExportEntry [Export] + SharedRelocFixup);
  705. }
  706. ExportEntry [Export] += SharedRelocFixup;
  707. }
  708. }
  709. return NtStatus;
  710. }
  711. ////////////////////////////////////////////////////
  712. ULONG
  713. LdrpWx86RelocatedFixupDiff(
  714. IN PUCHAR ImageBase,
  715. IN PIMAGE_NT_HEADERS NtHeaders,
  716. IN ULONG Offset
  717. )
  718. {
  719. PIMAGE_SECTION_HEADER SectionHeader;
  720. ULONG i;
  721. ULONG NumberOfSharedDataPages;
  722. ULONG NumberOfNativePagesForImage;
  723. ULONG Diff = 0;
  724. ULONG_PTR FixupAddr = (ULONG_PTR)(ImageBase + Offset);
  725. SectionHeader = (PIMAGE_SECTION_HEADER)((ULONG_PTR)NtHeaders + sizeof(ULONG) +
  726. sizeof(IMAGE_FILE_HEADER) +
  727. NtHeaders->FileHeader.SizeOfOptionalHeader
  728. );
  729. NumberOfNativePagesForImage =
  730. NATIVE_BYTES_TO_PAGES (NtHeaders->OptionalHeader.SizeOfImage);
  731. NumberOfSharedDataPages = 0;
  732. for (i=0; i<NtHeaders->FileHeader.NumberOfSections; i++, SectionHeader++)
  733. {
  734. ULONG_PTR SectionStartVA;
  735. ULONG_PTR SectionEndVA;
  736. ULONG SectionVirtualSize;
  737. SectionVirtualSize = SectionHeader->Misc.VirtualSize;
  738. if (SectionVirtualSize == 0) {
  739. SectionVirtualSize = SectionHeader->SizeOfRawData;
  740. }
  741. SectionStartVA = (ULONG_PTR)ImageBase + SectionHeader->VirtualAddress;
  742. SectionEndVA = SectionStartVA + SectionVirtualSize;
  743. if (((ULONG_PTR)FixupAddr >= SectionStartVA) && ((ULONG_PTR)FixupAddr <= SectionEndVA)) {
  744. if ((SectionHeader->Characteristics & IMAGE_SCN_MEM_SHARED) &&
  745. (!(SectionHeader->Characteristics & IMAGE_SCN_MEM_EXECUTE) ||
  746. (SectionHeader->Characteristics & IMAGE_SCN_MEM_WRITE))) {
  747. Diff = (NumberOfNativePagesForImage +
  748. NumberOfSharedDataPages) << NATIVE_PAGE_SHIFT;
  749. Diff -= (ULONG)SectionHeader->VirtualAddress;
  750. }
  751. break;
  752. }
  753. if ((SectionHeader->Characteristics & IMAGE_SCN_MEM_SHARED) &&
  754. (!(SectionHeader->Characteristics & IMAGE_SCN_MEM_EXECUTE) ||
  755. (SectionHeader->Characteristics & IMAGE_SCN_MEM_WRITE))) {
  756. NumberOfSharedDataPages += MI_ROUND_TO_SIZE (SectionVirtualSize,
  757. NATIVE_PAGE_SIZE) >>
  758. NATIVE_PAGE_SHIFT;
  759. }
  760. }
  761. return Diff;
  762. }
  763. NTSTATUS
  764. FixupBlockList(
  765. IN PUCHAR ImageBase)
  766. {
  767. PIMAGE_BASE_RELOCATION NextBlock;
  768. PUSHORT NextOffset;
  769. ULONG TotalBytes;
  770. ULONG SizeOfBlock;
  771. PIMAGE_NT_HEADERS NtHeaders;
  772. NTSTATUS st;
  773. NextBlock = RtlImageDirectoryEntryToData(ImageBase, TRUE,
  774. IMAGE_DIRECTORY_ENTRY_BASERELOC,
  775. &TotalBytes);
  776. if (!NextBlock || !TotalBytes) {
  777. if (ShowSnaps) {
  778. DbgPrint("LdrpWx86FixupBlockList: No fixup info "
  779. "for image at %x; private sections will be "
  780. "used for shared data sections.\n",
  781. ImageBase);
  782. }
  783. return STATUS_SUCCESS;
  784. }
  785. NtHeaders = RtlImageNtHeader (ImageBase);
  786. while (TotalBytes) {
  787. SizeOfBlock = NextBlock->SizeOfBlock;
  788. if (SizeOfBlock == 0) {
  789. if (ShowSnaps) {
  790. DbgPrint("Image at %lx contains invalid block size. Stopping fixups\n",
  791. ImageBase);
  792. }
  793. break;
  794. }
  795. TotalBytes -= SizeOfBlock;
  796. SizeOfBlock -= sizeof(IMAGE_BASE_RELOCATION);
  797. SizeOfBlock /= sizeof(USHORT);
  798. NextOffset = (PUSHORT) ((PCHAR)NextBlock +
  799. sizeof(IMAGE_BASE_RELOCATION));
  800. NextBlock->VirtualAddress += LdrpWx86RelocatedFixupDiff (
  801. ImageBase,
  802. NtHeaders,
  803. NextBlock->VirtualAddress
  804. );
  805. while (SizeOfBlock--) {
  806. switch ((*NextOffset) >> 12) {
  807. case IMAGE_REL_BASED_HIGHLOW :
  808. case IMAGE_REL_BASED_HIGH :
  809. case IMAGE_REL_BASED_LOW :
  810. break;
  811. case IMAGE_REL_BASED_HIGHADJ :
  812. ++NextOffset;
  813. --SizeOfBlock;
  814. break;
  815. case IMAGE_REL_BASED_IA64_IMM64:
  816. case IMAGE_REL_BASED_DIR64:
  817. case IMAGE_REL_BASED_MIPS_JMPADDR :
  818. case IMAGE_REL_BASED_ABSOLUTE :
  819. case IMAGE_REL_BASED_SECTION :
  820. case IMAGE_REL_BASED_REL32 :
  821. break;
  822. default :
  823. return STATUS_INVALID_IMAGE_FORMAT;
  824. }
  825. ++NextOffset;
  826. }
  827. NextBlock = (PIMAGE_BASE_RELOCATION)NextOffset;
  828. if (NextBlock == NULL) {
  829. // Trouble
  830. if (ShowSnaps) {
  831. DbgPrint("LdrpWx86FixupBlockList: failure "
  832. "after relocating some sections for image at %x; "
  833. "Relocation information invalid\n",
  834. ImageBase);
  835. }
  836. return STATUS_INVALID_IMAGE_FORMAT;
  837. }
  838. }
  839. return STATUS_SUCCESS;
  840. }
  841. BOOLEAN
  842. LdrpWx86DllHasRelocatedSharedSection(
  843. IN PUCHAR ImageBase)
  844. {
  845. PIMAGE_SECTION_HEADER SectionHeader;
  846. ULONG i;
  847. PIMAGE_NT_HEADERS32 NtHeaders = (PIMAGE_NT_HEADERS32)RtlImageNtHeader(ImageBase);
  848. SectionHeader = (PIMAGE_SECTION_HEADER)((ULONG_PTR)NtHeaders + sizeof(ULONG) +
  849. sizeof(IMAGE_FILE_HEADER) +
  850. NtHeaders->FileHeader.SizeOfOptionalHeader
  851. );
  852. for (i=0; i<NtHeaders->FileHeader.NumberOfSections; i++, SectionHeader++)
  853. {
  854. if ((SectionHeader->Characteristics & IMAGE_SCN_MEM_SHARED) &&
  855. (!(SectionHeader->Characteristics & IMAGE_SCN_MEM_EXECUTE) ||
  856. (SectionHeader->Characteristics & IMAGE_SCN_MEM_WRITE))) {
  857. return TRUE;
  858. }
  859. }
  860. return FALSE;
  861. }
  862. ////////////////////////////////////////////////
  863. // Following fn is adapted from rtl\ldrreloc.c; it should be updated when
  864. // that function changes. Eliminated 64 bit address relocations.
  865. //
  866. // Note: Instead of calling this routine, we could call
  867. // LdrpProcessRelocationBlock(VA, 1, NextOffset, Diff)
  868. //
  869. // but we should do that only if the address to be relocated is between
  870. // SectionStartVA and SectionEndVA. So we would have to replicate all the
  871. // code in the switch stmt below that computes the address of the data item -
  872. // which is pretty much the entire function. So we chose to replicate the
  873. // function as it was and change it to make the test.
  874. PIMAGE_BASE_RELOCATION LdrpWx86ProcessRelocationBlock(
  875. IN ULONG_PTR VA,
  876. IN PUCHAR ImageBase,
  877. IN ULONG SizeOfBlock,
  878. IN PUSHORT NextOffset,
  879. IN ULONG Diff,
  880. IN ULONG_PTR SectionStartVA,
  881. IN ULONG_PTR SectionEndVA)
  882. {
  883. PUCHAR FixupVA;
  884. USHORT Offset;
  885. LONG Temp;
  886. ULONG_PTR DataVA;
  887. while (SizeOfBlock--) {
  888. Offset = *NextOffset & (USHORT)0xfff;
  889. FixupVA = (PUCHAR)(VA + Offset);
  890. //
  891. // Apply the fixups.
  892. //
  893. switch ((*NextOffset) >> 12) {
  894. case IMAGE_REL_BASED_HIGHLOW :
  895. //
  896. // HighLow - (32-bits) relocate the high and low half
  897. // of an address.
  898. //
  899. Temp = *(LONG UNALIGNED *)FixupVA;
  900. DataVA = (ULONG_PTR) Temp;
  901. if (DataVA >= SectionStartVA && DataVA <= SectionEndVA)
  902. {
  903. Temp += (ULONG) Diff;
  904. *(LONG UNALIGNED *)FixupVA = Temp;
  905. }
  906. break;
  907. case IMAGE_REL_BASED_HIGH :
  908. //
  909. // High - (16-bits) relocate the high half of an address.
  910. //
  911. Temp = *(PUSHORT)FixupVA << 16;
  912. DataVA = (ULONG_PTR) Temp;
  913. if (DataVA >= SectionStartVA && DataVA <= SectionEndVA)
  914. {
  915. Temp += (ULONG) Diff;
  916. *(PUSHORT)FixupVA = (USHORT)(Temp >> 16);
  917. }
  918. break;
  919. case IMAGE_REL_BASED_HIGHADJ :
  920. //
  921. // Adjust high - (16-bits) relocate the high half of an
  922. // address and adjust for sign extension of low half.
  923. //
  924. Temp = *(PUSHORT)FixupVA << 16;
  925. ++NextOffset;
  926. --SizeOfBlock;
  927. Temp += (LONG)(*(PSHORT)NextOffset);
  928. DataVA = (ULONG_PTR) Temp;
  929. if (DataVA >= SectionStartVA && DataVA <= SectionEndVA)
  930. {
  931. Temp += (ULONG) Diff;
  932. Temp += 0x8000;
  933. *(PUSHORT)FixupVA = (USHORT)(Temp >> 16);
  934. }
  935. break;
  936. case IMAGE_REL_BASED_LOW :
  937. //
  938. // Low - (16-bit) relocate the low half of an address.
  939. //
  940. Temp = *(PSHORT)FixupVA;
  941. DataVA = (ULONG_PTR) Temp;
  942. if (DataVA >= SectionStartVA && DataVA <= SectionEndVA)
  943. {
  944. Temp += (ULONG) Diff;
  945. *(PUSHORT)FixupVA = (USHORT)Temp;
  946. }
  947. break;
  948. case IMAGE_REL_BASED_IA64_IMM64:
  949. //
  950. // Align it to bundle address before fixing up the
  951. // 64-bit immediate value of the movl instruction.
  952. //
  953. // No need to support
  954. break;
  955. case IMAGE_REL_BASED_DIR64:
  956. //
  957. // Update 32-bit address
  958. //
  959. // No need to support
  960. break;
  961. case IMAGE_REL_BASED_MIPS_JMPADDR :
  962. //
  963. // JumpAddress - (32-bits) relocate a MIPS jump address.
  964. //
  965. // No need to support
  966. break;
  967. case IMAGE_REL_BASED_ABSOLUTE :
  968. //
  969. // Absolute - no fixup required.
  970. //
  971. break;
  972. case IMAGE_REL_BASED_SECTION :
  973. //
  974. // Section Relative reloc. Ignore for now.
  975. //
  976. break;
  977. case IMAGE_REL_BASED_REL32 :
  978. //
  979. // Relative intrasection. Ignore for now.
  980. //
  981. break;
  982. default :
  983. //
  984. // Illegal - illegal relocation type.
  985. //
  986. return (PIMAGE_BASE_RELOCATION)NULL;
  987. }
  988. ++NextOffset;
  989. }
  990. return (PIMAGE_BASE_RELOCATION)NextOffset;
  991. }
  992. #endif // BUILD_WOW6432