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.

614 lines
21 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. rebase.c
  5. Abstract:
  6. Source file for the REBASE utility that takes a group of image files and
  7. rebases them so they are packed as closely together in the virtual address
  8. space as possible.
  9. Author:
  10. Mark Lucovsky (markl) 30-Apr-1993
  11. Revision History:
  12. --*/
  13. #include <private.h>
  14. //
  15. // byte swapping macros (LE/BE) used for IA64 relocations
  16. // source != destination
  17. //
  18. #define SWAP_SHORT(_dst,_src) \
  19. ((((unsigned char *)_dst)[1] = ((unsigned char *)_src)[0]), \
  20. (((unsigned char *)_dst)[0] = ((unsigned char *)_src)[1]))
  21. #define SWAP_INT(_dst,_src) \
  22. ((((unsigned char *)_dst)[3] = ((unsigned char *)_src)[0]), \
  23. (((unsigned char *)_dst)[2] = ((unsigned char *)_src)[1]), \
  24. (((unsigned char *)_dst)[1] = ((unsigned char *)_src)[2]), \
  25. (((unsigned char *)_dst)[0] = ((unsigned char *)_src)[3]))
  26. #define SWAP_LONG_LONG(_dst,_src) \
  27. ((((unsigned char *)_dst)[7] = ((unsigned char *)_src)[0]), \
  28. (((unsigned char *)_dst)[6] = ((unsigned char *)_src)[1]), \
  29. (((unsigned char *)_dst)[5] = ((unsigned char *)_src)[2]), \
  30. (((unsigned char *)_dst)[4] = ((unsigned char *)_src)[3]), \
  31. (((unsigned char *)_dst)[3] = ((unsigned char *)_src)[4]), \
  32. (((unsigned char *)_dst)[2] = ((unsigned char *)_src)[5]), \
  33. (((unsigned char *)_dst)[1] = ((unsigned char *)_src)[6]), \
  34. (((unsigned char *)_dst)[0] = ((unsigned char *)_src)[7]))
  35. #define REBASE_ERR 99
  36. #define REBASE_OK 0
  37. static
  38. PVOID
  39. RvaToVa(
  40. ULONG Rva,
  41. PLOADED_IMAGE Image
  42. );
  43. typedef
  44. PIMAGE_BASE_RELOCATION
  45. (WINAPI *LPRELOCATE_ROUTINE)(
  46. IN ULONG_PTR VA,
  47. IN ULONG SizeOfBlock,
  48. IN PUSHORT NextOffset,
  49. IN LONG_PTR Diff
  50. );
  51. typedef
  52. PIMAGE_BASE_RELOCATION
  53. (WINAPI *LPRELOCATE_ROUTINE64)(
  54. IN ULONG_PTR VA,
  55. IN ULONG SizeOfBlock,
  56. IN PUSHORT NextOffset,
  57. IN LONGLONG Diff
  58. );
  59. static LPRELOCATE_ROUTINE RelocRoutineNative;
  60. static LPRELOCATE_ROUTINE64 RelocRoutine64;
  61. #include <ldrreloc_rebase.c> // P/u ldrreloc from ntos\rtl
  62. #define x256MEG (256*(1024*1024))
  63. #define x256MEGSHIFT 28
  64. #define ROUND_UP( Size, Amount ) (((ULONG)(Size) + ((Amount) - 1)) & ~((Amount) - 1))
  65. VOID
  66. AdjImageBaseSize(
  67. PULONG pImageBase,
  68. PULONG ImageSize,
  69. BOOL fGoingDown
  70. );
  71. BOOL
  72. RelocateImage(
  73. PLOADED_IMAGE LoadedImage,
  74. ULONG64 NewBase,
  75. ULONG64 *Diff,
  76. ULONG tstamp
  77. );
  78. BOOL
  79. ReBaseImage(
  80. IN LPSTR CurrentImageName,
  81. IN LPSTR SymbolPath, // Symbol path (if
  82. IN BOOL fReBase, // TRUE if actually rebasing, false if only summing
  83. IN BOOL fRebaseSysfileOk, // TRUE is system images s/b rebased
  84. IN BOOL fGoingDown, // TRUE if the image s/b rebased below the given base
  85. IN ULONG CheckImageSize, // Max size allowed (0 if don't care)
  86. OUT ULONG *OldImageSize, // Returned from the header
  87. OUT ULONG_PTR *OldImageBase, // Returned from the header
  88. OUT ULONG *NewImageSize, // Image size rounded to next separation boundary
  89. IN OUT ULONG_PTR *NewImageBase, // (in) Desired new address.
  90. // (out) Next new address (above/below this one)
  91. IN ULONG tstamp // new timestamp for image
  92. )
  93. {
  94. ULONG64 xOldImageBase = *OldImageBase;
  95. ULONG64 xNewImageBase = *NewImageBase;
  96. BOOL rc;
  97. rc = ReBaseImage64(
  98. CurrentImageName,
  99. SymbolPath,
  100. fReBase,
  101. fRebaseSysfileOk,
  102. fGoingDown,
  103. CheckImageSize,
  104. OldImageSize,
  105. &xOldImageBase,
  106. NewImageSize,
  107. &xNewImageBase,
  108. tstamp);
  109. *OldImageBase = (ULONG_PTR)xOldImageBase;
  110. *NewImageBase = (ULONG_PTR)xNewImageBase;
  111. return rc;
  112. }
  113. BOOL
  114. ReBaseImage64(
  115. IN LPSTR CurrentImageName,
  116. IN LPSTR SymbolPath, // Symbol path (if
  117. IN BOOL fReBase, // TRUE if actually rebasing, false if only summing
  118. IN BOOL fRebaseSysfileOk, // TRUE is system images s/b rebased
  119. IN BOOL fGoingDown, // TRUE if the image s/b rebased below the given base
  120. IN ULONG CheckImageSize, // Max size allowed (0 if don't care)
  121. OUT ULONG *OldImageSize, // Returned from the header
  122. OUT ULONG64 *OldImageBase, // Returned from the header
  123. OUT ULONG *NewImageSize, // Image size rounded to next separation boundary
  124. IN OUT ULONG64 *NewImageBase, // (in) Desired new address.
  125. // (out) Next new address (above/below this one)
  126. IN ULONG tstamp // new timestamp for image
  127. )
  128. {
  129. BOOL fSymbolsAlreadySplit = FALSE;
  130. CHAR DebugFileName[ MAX_PATH+1 ];
  131. CHAR DebugFilePath[ MAX_PATH+1 ];
  132. ULONG CurrentImageSize;
  133. ULONG64 DesiredImageBase;
  134. ULONG OldChecksum;
  135. ULONG64 Diff = 0;
  136. ULONG UpdateSymbolsError = 0;
  137. LOADED_IMAGE CurrentImage = {0};
  138. BOOL rc = TRUE;
  139. if (fReBase && (*NewImageBase & 0x0000FFFF) != 0) {
  140. rc = FALSE;
  141. UpdateSymbolsError = ERROR_INVALID_ADDRESS;
  142. goto Exit;
  143. }
  144. // Map and load the current image
  145. if ( MapAndLoad( CurrentImageName, NULL, &CurrentImage, FALSE, fReBase ? FALSE : TRUE ) ) {
  146. PVOID pData;
  147. DWORD dwDataSize;
  148. pData = ImageDirectoryEntryToData(
  149. CurrentImage.MappedAddress,
  150. FALSE,
  151. IMAGE_DIRECTORY_ENTRY_SECURITY,
  152. &dwDataSize
  153. );
  154. if (pData || dwDataSize) {
  155. // Certificates in the image, can't rebase
  156. UpdateSymbolsError = ERROR_EXE_CANNOT_MODIFY_SIGNED_BINARY;
  157. rc = FALSE;
  158. goto CleanupAndExit;
  159. }
  160. pData = ImageDirectoryEntryToData(
  161. CurrentImage.MappedAddress,
  162. FALSE,
  163. IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR,
  164. &dwDataSize
  165. );
  166. if (pData || dwDataSize) {
  167. // COR header found - see if it's strong signed
  168. if (((IMAGE_COR20_HEADER *)pData)->Flags & COMIMAGE_FLAGS_STRONGNAMESIGNED)
  169. {
  170. UpdateSymbolsError = ERROR_EXE_CANNOT_MODIFY_STRONG_SIGNED_BINARY;
  171. rc = FALSE;
  172. goto CleanupAndExit;
  173. }
  174. }
  175. if (!(!fRebaseSysfileOk && CurrentImage.fSystemImage)) {
  176. fSymbolsAlreadySplit = CurrentImage.Characteristics & IMAGE_FILE_DEBUG_STRIPPED ? TRUE : FALSE;
  177. if ( fSymbolsAlreadySplit ) {
  178. // Find DebugFileName for later use.
  179. PIMAGE_DEBUG_DIRECTORY DebugDirectories;
  180. ULONG DebugDirectoriesSize;
  181. PIMAGE_DEBUG_MISC MiscDebug;
  182. strcpy( DebugFileName, CurrentImageName );
  183. DebugDirectories = (PIMAGE_DEBUG_DIRECTORY)ImageDirectoryEntryToData(
  184. CurrentImage.MappedAddress,
  185. FALSE,
  186. IMAGE_DIRECTORY_ENTRY_DEBUG,
  187. &DebugDirectoriesSize
  188. );
  189. if (DebugDirectoryIsUseful(DebugDirectories, DebugDirectoriesSize)) {
  190. while (DebugDirectoriesSize != 0) {
  191. if (DebugDirectories->Type == IMAGE_DEBUG_TYPE_MISC) {
  192. MiscDebug = (PIMAGE_DEBUG_MISC)
  193. ((PCHAR)CurrentImage.MappedAddress +
  194. DebugDirectories->PointerToRawData
  195. );
  196. strcpy( DebugFileName, (PCHAR) MiscDebug->Data );
  197. break;
  198. }
  199. else {
  200. DebugDirectories += 1;
  201. DebugDirectoriesSize -= sizeof( *DebugDirectories );
  202. }
  203. }
  204. }
  205. }
  206. if (CurrentImage.FileHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
  207. CurrentImageSize = ((PIMAGE_NT_HEADERS32)CurrentImage.FileHeader)->OptionalHeader.SizeOfImage;
  208. *OldImageBase = ((PIMAGE_NT_HEADERS32)CurrentImage.FileHeader)->OptionalHeader.ImageBase;
  209. } else {
  210. CurrentImageSize = ((PIMAGE_NT_HEADERS64)CurrentImage.FileHeader)->OptionalHeader.SizeOfImage;
  211. *OldImageBase = ((PIMAGE_NT_HEADERS64)CurrentImage.FileHeader)->OptionalHeader.ImageBase;
  212. }
  213. // Save the current settings for the caller.
  214. *OldImageSize = CurrentImageSize;
  215. *NewImageSize = ROUND_UP( CurrentImageSize, IMAGE_SEPARATION );
  216. if (CheckImageSize) {
  217. // The user asked for a max size test.
  218. if ( *NewImageSize > ROUND_UP(CheckImageSize, IMAGE_SEPARATION) ) {
  219. *NewImageBase = 0;
  220. rc = FALSE;
  221. goto CleanupAndExit;
  222. }
  223. }
  224. DesiredImageBase = *NewImageBase;
  225. // So long as we're not basing to zero or rebasing to the same address,
  226. // go for it.
  227. if (fReBase) {
  228. BOOL fAdjust;
  229. if ((CurrentImage.FileHeader->FileHeader.Machine != IMAGE_FILE_MACHINE_I386) &&
  230. (CurrentImage.FileHeader->FileHeader.Machine != IMAGE_FILE_MACHINE_ALPHA) &&
  231. (CurrentImage.FileHeader->FileHeader.Machine != IMAGE_FILE_MACHINE_ALPHA64) &&
  232. (CurrentImage.FileHeader->FileHeader.Machine != IMAGE_FILE_MACHINE_IA64))
  233. {
  234. fAdjust = TRUE;
  235. } else {
  236. fAdjust = FALSE;
  237. }
  238. if (fGoingDown) {
  239. DesiredImageBase -= *NewImageSize;
  240. if (fAdjust) {
  241. AdjImageBaseSize( (PULONG)&DesiredImageBase, &CurrentImageSize, fGoingDown );
  242. }
  243. }
  244. if ((DesiredImageBase) &&
  245. (DesiredImageBase != *OldImageBase)
  246. ) {
  247. if (CurrentImage.FileHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
  248. OldChecksum = ((PIMAGE_NT_HEADERS32)CurrentImage.FileHeader)->OptionalHeader.CheckSum;
  249. } else {
  250. OldChecksum = ((PIMAGE_NT_HEADERS64)CurrentImage.FileHeader)->OptionalHeader.CheckSum;
  251. }
  252. if ( !RelocateImage( &CurrentImage, DesiredImageBase, &Diff, tstamp ) ) {
  253. UpdateSymbolsError = GetLastError();
  254. rc = FALSE;
  255. goto CleanupAndExit;
  256. }
  257. if ( fSymbolsAlreadySplit && Diff ) {
  258. if ( UpdateDebugInfoFileEx(CurrentImageName,
  259. SymbolPath,
  260. DebugFilePath,
  261. (PIMAGE_NT_HEADERS32)(CurrentImage.FileHeader),
  262. OldChecksum )) {
  263. UpdateSymbolsError = GetLastError();
  264. } else {
  265. UpdateSymbolsError = 0;
  266. }
  267. }
  268. } else {
  269. //
  270. // Should this be -1?? shouldn't it be 0 instead? - kentf
  271. //
  272. Diff = (ULONG) -1;
  273. }
  274. if (!fGoingDown && Diff) {
  275. DesiredImageBase += *NewImageSize;
  276. if (fAdjust) {
  277. AdjImageBaseSize( (PULONG)&DesiredImageBase, &CurrentImageSize, fGoingDown );
  278. }
  279. }
  280. }
  281. }
  282. if (fReBase) {
  283. if (Diff) {
  284. *NewImageBase = DesiredImageBase;
  285. } else {
  286. UpdateSymbolsError = ERROR_INVALID_ADDRESS;
  287. rc = FALSE;
  288. goto CleanupAndExit;
  289. }
  290. }
  291. } else {
  292. if (CurrentImage.fDOSImage == TRUE) {
  293. UpdateSymbolsError = ERROR_BAD_EXE_FORMAT;
  294. } else {
  295. UpdateSymbolsError = GetLastError();
  296. }
  297. rc = FALSE;
  298. goto Exit;
  299. }
  300. CleanupAndExit:
  301. UnmapViewOfFile( CurrentImage.MappedAddress );
  302. if ( CurrentImage.hFile != INVALID_HANDLE_VALUE ) {
  303. CloseHandle( CurrentImage.hFile );
  304. }
  305. ZeroMemory( &CurrentImage, sizeof( CurrentImage ) );
  306. Exit:
  307. SetLastError(UpdateSymbolsError);
  308. return(rc);
  309. }
  310. VOID
  311. AdjImageBaseSize (
  312. PULONG pulImageBase,
  313. PULONG pulImageSize,
  314. BOOL fGoingDown
  315. )
  316. {
  317. DWORD Meg1, Meg2, Delta;
  318. //
  319. // ImageBase is the base for the current image. Make sure that
  320. // the image does not span a 256Mb boundry. This is due to an r4000
  321. // chip bug that has problems computing the correct address for absolute
  322. // jumps that occur in the last few instructions of a 256mb region
  323. //
  324. Meg1 = *pulImageBase >> x256MEGSHIFT;
  325. Meg2 = ( *pulImageBase + ROUND_UP( *pulImageSize, IMAGE_SEPARATION ) ) >> x256MEGSHIFT;
  326. if ( Meg1 != Meg2 ) {
  327. //
  328. // If we are going down, then subtract the overlap from ThisBase
  329. //
  330. if ( fGoingDown ) {
  331. Delta = ( *pulImageBase + ROUND_UP( *pulImageSize, IMAGE_SEPARATION ) ) -
  332. ( Meg2 << x256MEGSHIFT );
  333. Delta += IMAGE_SEPARATION;
  334. *pulImageBase = *pulImageBase - Delta;
  335. *pulImageSize += Delta;
  336. }
  337. else {
  338. Delta = ( Meg2 << x256MEGSHIFT ) - *pulImageBase;
  339. *pulImageBase += Delta;
  340. *pulImageSize += Delta;
  341. }
  342. }
  343. }
  344. BOOL
  345. RelocateImage(
  346. PLOADED_IMAGE LoadedImage,
  347. ULONG64 NewBase,
  348. ULONG64 *Diff,
  349. ULONG tstamp
  350. )
  351. {
  352. ULONG_PTR VA;
  353. ULONG64 OldBase;
  354. ULONG SizeOfBlock;
  355. PUSHORT NextOffset;
  356. PIMAGE_NT_HEADERS NtHeaders;
  357. PIMAGE_BASE_RELOCATION NextBlock;
  358. ULONG CheckSum;
  359. ULONG HeaderSum;
  360. PIMAGE_FILE_HEADER FileHeader;
  361. BOOL rc = TRUE;
  362. ULONG TotalCountBytes = 0;
  363. static BOOL fInit = FALSE;
  364. if (!fInit) {
  365. RelocRoutineNative = (LPRELOCATE_ROUTINE)GetProcAddress(GetModuleHandle("ntdll"), "LdrProcessRelocationBlock");
  366. #ifdef _WIN64
  367. RelocRoutine64 = RelocRoutineNative;
  368. #else
  369. RelocRoutine64 = xxLdrProcessRelocationBlock64;
  370. #endif
  371. }
  372. __try {
  373. if (LoadedImage->FileHeader->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) {
  374. // Relocations stripped. Nothing to do.
  375. __leave;
  376. }
  377. NtHeaders = LoadedImage->FileHeader;
  378. FileHeader = &NtHeaders->FileHeader;
  379. if (NtHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
  380. OldBase = ((PIMAGE_NT_HEADERS32)NtHeaders)->OptionalHeader.ImageBase;
  381. } else {
  382. OldBase = ((PIMAGE_NT_HEADERS64)NtHeaders)->OptionalHeader.ImageBase;
  383. }
  384. //
  385. // Locate the relocation section.
  386. //
  387. NextBlock = (PIMAGE_BASE_RELOCATION)ImageDirectoryEntryToData(
  388. LoadedImage->MappedAddress,
  389. FALSE,
  390. IMAGE_DIRECTORY_ENTRY_BASERELOC,
  391. &TotalCountBytes
  392. );
  393. *Diff = NewBase - OldBase;
  394. //
  395. // If the image has a relocation table, then apply the specified fixup
  396. // information to the image.
  397. //
  398. while (TotalCountBytes) {
  399. SizeOfBlock = NextBlock->SizeOfBlock;
  400. TotalCountBytes -= SizeOfBlock;
  401. SizeOfBlock -= sizeof(IMAGE_BASE_RELOCATION);
  402. SizeOfBlock /= sizeof(USHORT);
  403. NextOffset = (PUSHORT)(NextBlock + 1);
  404. //
  405. // Compute the address and value for the fixup.
  406. //
  407. if ( SizeOfBlock ) {
  408. VA = (ULONG_PTR)RvaToVa(NextBlock->VirtualAddress,LoadedImage);
  409. if ( !VA ) {
  410. NtHeaders->Signature = (ULONG)-1;
  411. rc = FALSE;
  412. __leave;
  413. }
  414. if (NtHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
  415. if ( !(NextBlock = (RelocRoutine64)(VA,SizeOfBlock,NextOffset,*Diff)) ) {
  416. NtHeaders->Signature = (ULONG)-1;
  417. rc = FALSE;
  418. __leave;
  419. }
  420. } else {
  421. if ( !(NextBlock = (RelocRoutineNative)(VA,SizeOfBlock,NextOffset,(LONG_PTR)*Diff)) ) {
  422. NtHeaders->Signature = (ULONG)-1;
  423. rc = FALSE;
  424. __leave;
  425. }
  426. }
  427. }
  428. else {
  429. NextBlock++;
  430. }
  431. }
  432. if (tstamp) {
  433. FileHeader->TimeDateStamp = tstamp;
  434. } else {
  435. FileHeader->TimeDateStamp++;
  436. }
  437. if (NtHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
  438. ((PIMAGE_NT_HEADERS32)NtHeaders)->OptionalHeader.ImageBase = (ULONG)NewBase;
  439. if ( LoadedImage->hFile != INVALID_HANDLE_VALUE ) {
  440. ((PIMAGE_NT_HEADERS32)NtHeaders)->OptionalHeader.CheckSum = 0;
  441. CheckSumMappedFile(
  442. (PVOID)LoadedImage->MappedAddress,
  443. GetFileSize(LoadedImage->hFile, NULL),
  444. &HeaderSum,
  445. &CheckSum
  446. );
  447. ((PIMAGE_NT_HEADERS32)NtHeaders)->OptionalHeader.CheckSum = CheckSum;
  448. }
  449. } else {
  450. ((PIMAGE_NT_HEADERS64)NtHeaders)->OptionalHeader.ImageBase = NewBase;
  451. if ( LoadedImage->hFile != INVALID_HANDLE_VALUE ) {
  452. ((PIMAGE_NT_HEADERS64)NtHeaders)->OptionalHeader.CheckSum = 0;
  453. CheckSumMappedFile(
  454. (PVOID)LoadedImage->MappedAddress,
  455. GetFileSize(LoadedImage->hFile, NULL),
  456. &HeaderSum,
  457. &CheckSum
  458. );
  459. ((PIMAGE_NT_HEADERS64)NtHeaders)->OptionalHeader.CheckSum = CheckSum;
  460. }
  461. }
  462. FlushViewOfFile(LoadedImage->MappedAddress,0);
  463. TouchFileTimes(LoadedImage->hFile,NULL);
  464. } __except (EXCEPTION_EXECUTE_HANDLER) {
  465. rc = FALSE;
  466. }
  467. return rc;
  468. }
  469. PVOID
  470. RvaToVa(
  471. ULONG Rva,
  472. PLOADED_IMAGE Image
  473. )
  474. {
  475. PIMAGE_SECTION_HEADER Section;
  476. ULONG i;
  477. PVOID Va;
  478. Va = NULL;
  479. Section = Image->LastRvaSection;
  480. if (Rva == 0) {
  481. // a NULL Rva will be sent if there are relocs before the first page
  482. // (ie: we're relocating a system image)
  483. Va = Image->MappedAddress;
  484. } else {
  485. if ( Rva >= Section->VirtualAddress &&
  486. Rva < (Section->VirtualAddress + Section->SizeOfRawData) ) {
  487. Va = (PVOID)(Rva - Section->VirtualAddress + Section->PointerToRawData + Image->MappedAddress);
  488. } else {
  489. for(Section = Image->Sections,i=0; i<Image->NumberOfSections; i++,Section++) {
  490. if ( Rva >= Section->VirtualAddress &&
  491. Rva < (Section->VirtualAddress + Section->SizeOfRawData) ) {
  492. Va = (PVOID)(Rva - Section->VirtualAddress + Section->PointerToRawData + Image->MappedAddress);
  493. Image->LastRvaSection = Section;
  494. break;
  495. }
  496. }
  497. }
  498. }
  499. return Va;
  500. }
  501. #ifndef STANDALONE_REBASE
  502. // Dummy stub so the rebase.exe that shipped with VC5/VC6 will load.
  503. VOID
  504. RemoveRelocations(
  505. PCHAR ImageName
  506. )
  507. {
  508. return;
  509. }
  510. #endif