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.

5843 lines
209 KiB

  1. #include <precomp.h>
  2. //
  3. // pestuff.c
  4. //
  5. // Author: Tom McGuire (tommcg) 2/97 - 3/98
  6. //
  7. // Copyright (C) Microsoft, 1997-1999.
  8. //
  9. // MICROSOFT CONFIDENTIAL
  10. //
  11. #define MAX_SYMBOL_NAME_LENGTH 2048
  12. typedef struct _SYMBOL_CONTEXT SYMBOL_CONTEXT, *PSYMBOL_CONTEXT;
  13. struct _SYMBOL_CONTEXT {
  14. SYMBOL_TREE NewDecoratedSymbolTree;
  15. SYMBOL_TREE NewUndecoratedSymbolTree;
  16. SYMBOL_TREE OldUndecoratedSymbolTree;
  17. ULONG_PTR NewImageBase;
  18. ULONG_PTR OldImageBase;
  19. ULONG SymbolOptionFlags;
  20. PRIFT_TABLE RiftTable;
  21. #ifdef TESTCODE
  22. HANDLE OutFile;
  23. #endif
  24. };
  25. typedef struct _RELOC_ARRAY_ENTRY RELOC_ARRAY_ENTRY, *PRELOC_ARRAY_ENTRY;
  26. struct _RELOC_ARRAY_ENTRY {
  27. ULONG RelocRva;
  28. UCHAR RelocType;
  29. USHORT HighAdjValue;
  30. };
  31. #ifndef PATCH_APPLY_CODE_ONLY
  32. #ifdef TESTCODE
  33. ULONG CountDecoratedMatches;
  34. ULONG CountUndecoratedMatches;
  35. #endif
  36. LPCSTR ImagehlpImportNames[] = {
  37. "SymInitialize",
  38. "SymGetOptions",
  39. "SymSetOptions",
  40. "SymLoadModule",
  41. "SymGetModuleInfo",
  42. "SymEnumerateSymbols",
  43. "UnDecorateSymbolName",
  44. "SymUnloadModule",
  45. "SymCleanup"
  46. };
  47. #define COUNT_IMAGEHLP_IMPORTS ( sizeof( ImagehlpImportNames ) / sizeof( ImagehlpImportNames[ 0 ] ))
  48. //
  49. // NOTE: Above names must be in SAME ORDER as the prototypes below.
  50. //
  51. union {
  52. VOID ( __stdcall * Imports[ COUNT_IMAGEHLP_IMPORTS ] )();
  53. struct {
  54. BOOL ( __stdcall * SymInitialize )( HANDLE, LPCSTR, BOOL );
  55. DWORD ( __stdcall * SymGetOptions )( VOID );
  56. DWORD ( __stdcall * SymSetOptions )( DWORD );
  57. DWORD ( __stdcall * SymLoadModule )( HANDLE, HANDLE, LPCSTR, LPCSTR, DWORD_PTR, DWORD );
  58. BOOL ( __stdcall * SymGetModuleInfo )( HANLDE, DWORD, PIMAGEHLP_MODULE );
  59. BOOL ( __stdcall * SymEnumerateSymbols )( HANDLE, DWORD_PTR, PSYM_ENUMSYMBOLS_CALLBACK, PVOID );
  60. BOOL ( __stdcall * UnDecorateSymbolName )( LPCSTR, LPSTR, DWORD, DWORD );
  61. BOOL ( __stdcall * SymUnloadModule )( HANDLE, DWORD_PTR );
  62. BOOL ( __stdcall * SymCleanup )( HANDLE );
  63. };
  64. } Imagehlp;
  65. BOOL ImagehlpCritSectInitialized;
  66. CRITICAL_SECTION ImagehlpCritSect;
  67. HANDLE hLibImagehlp;
  68. HANDLE hProc;
  69. IMAGEHLP_MODULE ImagehlpModuleInfo;
  70. VOID
  71. InitImagehlpCritSect(
  72. VOID
  73. )
  74. {
  75. if ( ! ImagehlpCritSectInitialized ) {
  76. InitializeCriticalSection( &ImagehlpCritSect );
  77. ImagehlpCritSectInitialized = TRUE;
  78. hProc = GetCurrentProcess();
  79. }
  80. }
  81. BOOL
  82. LoadImagehlp(
  83. VOID
  84. )
  85. {
  86. HANDLE hLib;
  87. ULONG i;
  88. if ( Imagehlp.Imports[ COUNT_IMAGEHLP_IMPORTS - 1 ] == NULL ) {
  89. hLib = LoadLibrary( "imagehlp.dll" );
  90. if ( hLib == NULL ) {
  91. return FALSE;
  92. }
  93. for ( i = 0; i < COUNT_IMAGEHLP_IMPORTS; i++ ) {
  94. Imagehlp.Imports[ i ] = GetProcAddress( hLib, ImagehlpImportNames[ i ] );
  95. if ( Imagehlp.Imports[ i ] == NULL ) {
  96. FreeLibrary( hLib );
  97. return FALSE;
  98. }
  99. }
  100. hLibImagehlp = hLib;
  101. }
  102. return TRUE;
  103. }
  104. #ifdef BUILDING_PATCHAPI_DLL
  105. VOID
  106. UnloadImagehlp(
  107. VOID
  108. )
  109. {
  110. if ( hLibImagehlp ) {
  111. FreeLibrary( hLibImagehlp );
  112. hLibImagehlp = NULL;
  113. Imagehlp.Imports[ COUNT_IMAGEHLP_IMPORTS - 1 ] = NULL;
  114. DeleteCriticalSection( &ImagehlpCritSect );
  115. ImagehlpCritSectInitialized = FALSE;
  116. }
  117. }
  118. #endif // BUILDING_PATCHAPI_DLL
  119. #endif // ! PATCH_APPLY_CODE_ONLY
  120. UP_IMAGE_NT_HEADERS32
  121. __fastcall
  122. GetNtHeader(
  123. IN PVOID MappedFile,
  124. IN ULONG MappedFileSize
  125. )
  126. {
  127. UP_IMAGE_DOS_HEADER DosHeader;
  128. UP_IMAGE_NT_HEADERS32 RetHeader;
  129. UP_IMAGE_NT_HEADERS32 NtHeader;
  130. RetHeader = NULL;
  131. __try {
  132. if ( MappedFileSize >= 0x200 ) {
  133. DosHeader = (UP_IMAGE_DOS_HEADER) MappedFile;
  134. if ( DosHeader->e_magic == IMAGE_DOS_SIGNATURE ) {
  135. NtHeader = (UP_IMAGE_NT_HEADERS32)((PUCHAR) MappedFile + DosHeader->e_lfanew );
  136. if (((PUCHAR) NtHeader + sizeof( IMAGE_NT_HEADERS32 )) <= ((PUCHAR) MappedFile + MappedFileSize )) {
  137. if ( NtHeader->Signature == IMAGE_NT_SIGNATURE ) {
  138. if (NtHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
  139. RetHeader = NtHeader;
  140. }
  141. }
  142. }
  143. }
  144. }
  145. }
  146. __except( EXCEPTION_EXECUTE_HANDLER ) {
  147. }
  148. return RetHeader;
  149. }
  150. BOOL
  151. __fastcall
  152. IsImageRvaInExecutableSection(
  153. IN UP_IMAGE_NT_HEADERS32 NtHeader,
  154. IN ULONG Rva
  155. )
  156. {
  157. UP_IMAGE_SECTION_HEADER SectionHeader;
  158. ULONG SectionCount;
  159. ULONG i;
  160. SectionHeader = IMAGE_FIRST_SECTION( NtHeader );
  161. SectionCount = NtHeader->FileHeader.NumberOfSections;
  162. for ( i = 0; i < SectionCount; i++ ) {
  163. if (( Rva >= SectionHeader[ i ].VirtualAddress ) &&
  164. ( Rva < SectionHeader[ i ].VirtualAddress + SectionHeader[ i ].Misc.VirtualSize )) {
  165. return (( SectionHeader[ i ].Characteristics & IMAGE_SCN_MEM_EXECUTE ) ? TRUE : FALSE );
  166. }
  167. }
  168. return FALSE;
  169. }
  170. ULONG
  171. __fastcall
  172. ImageRvaToFileOffset(
  173. IN UP_IMAGE_NT_HEADERS32 NtHeader,
  174. IN ULONG Rva
  175. )
  176. {
  177. UP_IMAGE_SECTION_HEADER SectionHeader;
  178. ULONG SectionCount;
  179. ULONG i;
  180. if ( Rva < NtHeader->OptionalHeader.SizeOfHeaders ) {
  181. return Rva;
  182. }
  183. SectionHeader = IMAGE_FIRST_SECTION( NtHeader );
  184. SectionCount = NtHeader->FileHeader.NumberOfSections;
  185. for ( i = 0; i < SectionCount; i++ ) {
  186. if (( Rva >= SectionHeader[ i ].VirtualAddress ) &&
  187. ( Rva < SectionHeader[ i ].VirtualAddress + SectionHeader[ i ].SizeOfRawData )) {
  188. return ( SectionHeader[ i ].PointerToRawData + ( Rva - SectionHeader[ i ].VirtualAddress ));
  189. }
  190. }
  191. return 0;
  192. }
  193. PVOID
  194. __fastcall
  195. ImageRvaToMappedAddress(
  196. IN UP_IMAGE_NT_HEADERS32 NtHeader,
  197. IN ULONG Rva,
  198. IN PVOID MappedBase,
  199. IN ULONG MappedSize
  200. )
  201. {
  202. ULONG MappedOffset = ImageRvaToFileOffset( NtHeader, Rva );
  203. if (( MappedOffset ) && ( MappedOffset < MappedSize )) {
  204. return ((PUCHAR)MappedBase + MappedOffset );
  205. }
  206. return NULL;
  207. }
  208. ULONG
  209. __fastcall
  210. ImageVaToFileOffset(
  211. IN UP_IMAGE_NT_HEADERS32 NtHeader,
  212. IN ULONG Va
  213. )
  214. {
  215. return ImageRvaToFileOffset( NtHeader, Va - NtHeader->OptionalHeader.ImageBase );
  216. }
  217. PVOID
  218. __fastcall
  219. ImageVaToMappedAddress(
  220. IN UP_IMAGE_NT_HEADERS32 NtHeader,
  221. IN ULONG Va,
  222. IN PVOID MappedBase,
  223. IN ULONG MappedSize
  224. )
  225. {
  226. return ImageRvaToMappedAddress( NtHeader, Va - NtHeader->OptionalHeader.ImageBase, MappedBase, MappedSize );
  227. }
  228. ULONG
  229. __fastcall
  230. ImageDirectoryRvaAndSize(
  231. IN UP_IMAGE_NT_HEADERS32 NtHeader,
  232. IN ULONG DirectoryIndex,
  233. OUT PULONG DirectorySize
  234. )
  235. {
  236. if ( DirectoryIndex < NtHeader->OptionalHeader.NumberOfRvaAndSizes ) {
  237. if ( DirectorySize ) {
  238. *DirectorySize = NtHeader->OptionalHeader.DataDirectory[ DirectoryIndex ].Size;
  239. }
  240. return NtHeader->OptionalHeader.DataDirectory[ DirectoryIndex ].VirtualAddress;
  241. }
  242. return 0;
  243. }
  244. ULONG
  245. __fastcall
  246. ImageDirectoryOffsetAndSize(
  247. IN UP_IMAGE_NT_HEADERS32 NtHeader,
  248. IN ULONG DirectoryIndex,
  249. OUT PULONG DirectorySize
  250. )
  251. {
  252. ULONG Rva = ImageDirectoryRvaAndSize( NtHeader, DirectoryIndex, DirectorySize );
  253. if ( Rva ) {
  254. return ImageRvaToFileOffset( NtHeader, Rva );
  255. }
  256. return 0;
  257. }
  258. PVOID
  259. __fastcall
  260. ImageDirectoryMappedAddress(
  261. IN UP_IMAGE_NT_HEADERS32 NtHeader,
  262. IN ULONG DirectoryIndex,
  263. OUT PULONG DirectorySize,
  264. IN PUCHAR MappedBase,
  265. IN ULONG MappedSize
  266. )
  267. {
  268. PUCHAR Directory;
  269. ULONG LocalSize;
  270. ULONG Rva;
  271. Rva = ImageDirectoryRvaAndSize( NtHeader, DirectoryIndex, &LocalSize );
  272. Directory = ImageRvaToMappedAddress( NtHeader, Rva, MappedBase, MappedSize );
  273. if (( Directory ) && (( Directory + LocalSize ) <= ( MappedBase + MappedSize ))) {
  274. if ( DirectorySize ) {
  275. *DirectorySize = LocalSize;
  276. }
  277. return Directory;
  278. }
  279. return NULL;
  280. }
  281. ULONG
  282. __fastcall
  283. FileOffsetToImageRva(
  284. IN UP_IMAGE_NT_HEADERS32 NtHeader,
  285. IN ULONG FileOffset
  286. )
  287. {
  288. UP_IMAGE_SECTION_HEADER SectionHeader;
  289. ULONG SectionCount;
  290. ULONG i;
  291. SectionHeader = IMAGE_FIRST_SECTION( NtHeader );
  292. SectionCount = NtHeader->FileHeader.NumberOfSections;
  293. for ( i = 0; i < SectionCount; i++ ) {
  294. if (( FileOffset >= SectionHeader[ i ].PointerToRawData ) &&
  295. ( FileOffset < SectionHeader[ i ].PointerToRawData + SectionHeader[ i ].SizeOfRawData )) {
  296. return ( SectionHeader[ i ].VirtualAddress + ( FileOffset - SectionHeader[ i ].PointerToRawData ));
  297. }
  298. }
  299. return 0;
  300. }
  301. ULONG
  302. MappedAddressToImageRva(
  303. IN UP_IMAGE_NT_HEADERS32 NtHeader,
  304. IN PVOID MappedAddress,
  305. IN PVOID MappedFile
  306. )
  307. {
  308. LONG FileOffset = (LONG)((PUCHAR)MappedAddress - (PUCHAR)MappedFile);
  309. if ( FileOffset > 0 ) {
  310. return FileOffsetToImageRva( NtHeader, FileOffset );
  311. }
  312. return 0;
  313. }
  314. BOOL
  315. RebaseMappedImage(
  316. IN PUCHAR MappedFile,
  317. IN ULONG FileSize,
  318. IN UP_IMAGE_NT_HEADERS32 NtHeader,
  319. IN ULONG NewBase
  320. )
  321. {
  322. UP_IMAGE_BASE_RELOCATION RelocBlock;
  323. LONG RelocAmount;
  324. LONG RelocDirRemaining;
  325. ULONG RelocDirSize;
  326. PUCHAR RelocBlockMa;
  327. PUCHAR RelocFixupMa;
  328. ULONG RelocCount;
  329. USHORT UNALIGNED* RelocEntry;
  330. PUCHAR MappedFileEnd;
  331. BOOL Modified;
  332. //
  333. // Carefully rebase the image, ignoring invalid info as much as possible
  334. // without taking an access violation. We don't want to use try/except
  335. // here because this code needs to be workable without any imports from
  336. // kernel32.dll. This code is not intended to catch errors in invalid
  337. // rebase info -- it is intended to silently do the best it can at
  338. // rebasing the image in memory. If the rebase info is valid, it will
  339. // correctly rebase the image. If the rebase info is not valid, it will
  340. // attempt to avoid causing an access violation.
  341. //
  342. ASSERT( NtHeader->OptionalHeader.ImageBase != NewBase );
  343. ASSERT(( NewBase & 0x0000FFFF ) == 0 );
  344. ASSERT(( NewBase & 0xFFFF0000 ) != 0 );
  345. Modified = FALSE;
  346. MappedFileEnd = MappedFile + FileSize;
  347. RelocAmount = NewBase - NtHeader->OptionalHeader.ImageBase;
  348. RelocBlock = ImageDirectoryMappedAddress( NtHeader, IMAGE_DIRECTORY_ENTRY_BASERELOC, &RelocDirSize, MappedFile, FileSize );
  349. if ( RelocBlock ) {
  350. NtHeader->OptionalHeader.ImageBase = NewBase;
  351. Modified = TRUE;
  352. RelocDirRemaining = (LONG)RelocDirSize;
  353. while ( RelocDirRemaining > 0 ) {
  354. if (( RelocBlock->SizeOfBlock <= (ULONG)RelocDirRemaining ) &&
  355. ( RelocBlock->SizeOfBlock > sizeof( IMAGE_BASE_RELOCATION ))) {
  356. //
  357. // ImageRvaToMappedAddress returns NULL if the Rva is zero,
  358. // but that is a valid base address of a reloc block. Use
  359. // ImageRvaToFileOffset instead.
  360. //
  361. RelocBlockMa = MappedFile + ImageRvaToFileOffset( NtHeader, RelocBlock->VirtualAddress );
  362. if ( RelocBlockMa ) {
  363. RelocEntry = (PUSHORT)((PUCHAR)RelocBlock + sizeof( IMAGE_BASE_RELOCATION ));
  364. RelocCount = ( RelocBlock->SizeOfBlock - sizeof( IMAGE_BASE_RELOCATION )) / sizeof( USHORT );
  365. while ( RelocCount-- ) {
  366. RelocFixupMa = RelocBlockMa + ( *RelocEntry & 0x0FFF );
  367. if ( RelocFixupMa < MappedFileEnd ) {
  368. switch ( *RelocEntry >> 12 ) {
  369. case IMAGE_REL_BASED_HIGHLOW:
  370. *(UNALIGNED LONG *)RelocFixupMa += RelocAmount;
  371. break;
  372. case IMAGE_REL_BASED_LOW:
  373. *(UNALIGNED USHORT *)RelocFixupMa = (USHORT)( *(UNALIGNED SHORT *)RelocFixupMa + RelocAmount );
  374. break;
  375. case IMAGE_REL_BASED_HIGH:
  376. *(UNALIGNED USHORT *)RelocFixupMa = (USHORT)((( *(UNALIGNED USHORT *)RelocFixupMa << 16 ) + RelocAmount ) >> 16 );
  377. break;
  378. case IMAGE_REL_BASED_HIGHADJ:
  379. ++RelocEntry;
  380. --RelocCount;
  381. *(UNALIGNED USHORT *)RelocFixupMa = (USHORT)((( *(UNALIGNED USHORT *)RelocFixupMa << 16 ) + *(UNALIGNED SHORT *)RelocEntry + RelocAmount + 0x8000 ) >> 16 );
  382. break;
  383. //
  384. // Just skip and continue if we don't
  385. // recognize the reloc type.
  386. //
  387. }
  388. }
  389. ++RelocEntry;
  390. }
  391. }
  392. }
  393. RelocDirRemaining -= RelocBlock->SizeOfBlock;
  394. RelocBlock = (UP_IMAGE_BASE_RELOCATION)((PUCHAR)RelocBlock + RelocBlock->SizeOfBlock );
  395. }
  396. }
  397. return Modified;
  398. }
  399. BOOL
  400. UnBindMappedImage(
  401. IN PUCHAR MappedFile,
  402. IN ULONG FileSize,
  403. IN UP_IMAGE_NT_HEADERS32 NtHeader
  404. )
  405. {
  406. UP_IMAGE_SECTION_HEADER SectionHeader;
  407. UP_IMAGE_IMPORT_DESCRIPTOR ImportDesc;
  408. ULONG SectionCount;
  409. DWORDLONG SectionName;
  410. PVOID BoundImportDir;
  411. ULONG BoundImportSize;
  412. ULONG UNALIGNED* OriginalIat;
  413. ULONG UNALIGNED* BoundIat;
  414. PUCHAR MappedFileEnd;
  415. BOOL Modified;
  416. ULONG i;
  417. Modified = FALSE;
  418. MappedFileEnd = MappedFile + FileSize;
  419. BoundImportDir = ImageDirectoryMappedAddress( NtHeader, IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT, &BoundImportSize, MappedFile, FileSize );
  420. if ( BoundImportDir ) {
  421. //
  422. // Zero the bound import directory and pointers to bound
  423. // import directory.
  424. //
  425. ZeroMemory( BoundImportDir, BoundImportSize );
  426. NtHeader->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT ].VirtualAddress = 0;
  427. NtHeader->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT ].Size = 0;
  428. Modified = TRUE;
  429. }
  430. //
  431. // Now walk imports and zero the TimeDate and
  432. // ForwarderChain fields.
  433. //
  434. ImportDesc = ImageDirectoryMappedAddress( NtHeader, IMAGE_DIRECTORY_ENTRY_IMPORT, NULL, MappedFile, FileSize );
  435. if ( ImportDesc ) {
  436. while (((ULONG_PTR)ImportDesc < ((ULONG_PTR)MappedFileEnd - sizeof( IMAGE_IMPORT_DESCRIPTOR ))) &&
  437. ( ImportDesc->Characteristics )) {
  438. if ( ImportDesc->TimeDateStamp ) {
  439. //
  440. // This is a bound import. Copy the unbound
  441. // IAT over the bound IAT to restore.
  442. //
  443. ImportDesc->TimeDateStamp = 0;
  444. Modified = TRUE;
  445. OriginalIat = ImageRvaToMappedAddress( NtHeader, (ULONG)ImportDesc->OriginalFirstThunk, MappedFile, FileSize );
  446. BoundIat = ImageRvaToMappedAddress( NtHeader, (ULONG)ImportDesc->FirstThunk, MappedFile, FileSize );
  447. if (( OriginalIat ) && ( BoundIat )) {
  448. while (((PUCHAR)OriginalIat < MappedFileEnd ) &&
  449. ((PUCHAR)BoundIat < MappedFileEnd ) &&
  450. ( *OriginalIat )) {
  451. *BoundIat++ = *OriginalIat++;
  452. }
  453. }
  454. }
  455. if ( ImportDesc->ForwarderChain ) {
  456. ImportDesc->ForwarderChain = 0;
  457. Modified = TRUE;
  458. }
  459. ++ImportDesc;
  460. }
  461. }
  462. //
  463. // The bind utility marks the .idata section as read-only so we want to
  464. // change it back to read-write.
  465. //
  466. SectionHeader = IMAGE_FIRST_SECTION( NtHeader );
  467. SectionCount = NtHeader->FileHeader.NumberOfSections;
  468. for ( i = 0; i < SectionCount; i++ ) {
  469. SectionName = *(UNALIGNED DWORDLONG*)( &SectionHeader[ i ].Name );
  470. SectionName |= 0x2020202020202020; // fast lower case
  471. if ( SectionName == 0x202061746164692E ) { // ".idata "
  472. if ( ! ( SectionHeader[ i ].Characteristics & IMAGE_SCN_MEM_WRITE )) {
  473. SectionHeader[ i ].Characteristics |= ( IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE );
  474. Modified = TRUE;
  475. }
  476. break;
  477. }
  478. }
  479. return Modified;
  480. }
  481. BOOL
  482. SmashLockPrefixesInMappedImage(
  483. IN PUCHAR MappedFile,
  484. IN ULONG FileSize,
  485. IN UP_IMAGE_NT_HEADERS32 NtHeader,
  486. IN UCHAR NewOpCode // X86_OPCODE_NOP or X86_OPCODE_LOCK
  487. )
  488. {
  489. UP_IMAGE_LOAD_CONFIG_DIRECTORY32 LoadConfig;
  490. ULONG UNALIGNED* LockPrefixEntry;
  491. PUCHAR LockPrefixInstruction;
  492. BOOL Modified;
  493. Modified = FALSE;
  494. LoadConfig = ImageDirectoryMappedAddress( NtHeader, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, NULL, MappedFile, FileSize );
  495. if ( LoadConfig ) {
  496. if ( LoadConfig->LockPrefixTable ) {
  497. //
  498. // The LoadConfig->LockPrefixTable field and
  499. // the lock prefix addresses are stored in the
  500. // image as image VA, not RVA values.
  501. //
  502. LockPrefixEntry = ImageVaToMappedAddress( NtHeader, LoadConfig->LockPrefixTable, MappedFile, FileSize );
  503. if ( LockPrefixEntry ) {
  504. while ( *LockPrefixEntry ) {
  505. LockPrefixInstruction = ImageVaToMappedAddress( NtHeader, *LockPrefixEntry, MappedFile, FileSize );
  506. if ( LockPrefixInstruction ) {
  507. if ( *LockPrefixInstruction != NewOpCode ) {
  508. //
  509. // Lock prefix instruction is not what we want,
  510. // so modify it.
  511. //
  512. *LockPrefixInstruction = NewOpCode;
  513. Modified = TRUE;
  514. }
  515. }
  516. ++LockPrefixEntry;
  517. }
  518. }
  519. }
  520. }
  521. return Modified;
  522. }
  523. USHORT
  524. ChkSum(
  525. IN USHORT Initial,
  526. IN PUSHORT Buffer,
  527. IN ULONG Bytes
  528. )
  529. {
  530. USHORT UNALIGNED* p = Buffer;
  531. ULONG WordsRemaining = Bytes / 2;
  532. ULONG WordsInChunk;
  533. ULONG SumChunk;
  534. ULONG SumTotal;
  535. SumTotal = Initial;
  536. while ( WordsRemaining ) {
  537. WordsInChunk = WordsRemaining;
  538. if ( WordsInChunk > 0x10000 ) {
  539. WordsInChunk = 0x10000;
  540. }
  541. WordsRemaining -= WordsInChunk;
  542. SumChunk = 0;
  543. do {
  544. SumChunk += *p++;
  545. }
  546. while ( --WordsInChunk != 0 );
  547. SumTotal += ( SumChunk >> 16 ) + ( SumChunk & 0xFFFF );
  548. }
  549. if ( Bytes % 2 ) {
  550. SumTotal += *((PBYTE) p);
  551. }
  552. return (USHORT)(( SumTotal >> 16 ) + ( SumTotal & 0xFFFF ));
  553. }
  554. BOOL
  555. NormalizeCoffImage(
  556. IN OUT UP_IMAGE_NT_HEADERS32 NtHeader,
  557. IN OUT PUCHAR MappedFile,
  558. IN ULONG FileSize,
  559. IN ULONG OptionFlags,
  560. IN PVOID OptionData,
  561. IN ULONG NewFileCoffBase,
  562. IN ULONG NewFileCoffTime
  563. )
  564. {
  565. BOOL Modified = FALSE;
  566. UNREFERENCED_PARAMETER( OptionData );
  567. if ( ! ( OptionFlags & PATCH_OPTION_NO_REBASE )) {
  568. if (( NewFileCoffTime != 0 ) && ( NtHeader->FileHeader.TimeDateStamp != NewFileCoffTime )) {
  569. NtHeader->FileHeader.TimeDateStamp = NewFileCoffTime;
  570. Modified = TRUE;
  571. }
  572. if (( NewFileCoffBase != 0 ) && ( NtHeader->OptionalHeader.ImageBase != NewFileCoffBase )) {
  573. Modified |= RebaseMappedImage( MappedFile, FileSize, NtHeader, NewFileCoffBase );
  574. }
  575. }
  576. if ( ! ( OptionFlags & PATCH_OPTION_NO_BINDFIX )) {
  577. Modified |= UnBindMappedImage( MappedFile, FileSize, NtHeader );
  578. }
  579. if ( ! ( OptionFlags & PATCH_OPTION_NO_LOCKFIX )) {
  580. Modified |= SmashLockPrefixesInMappedImage( MappedFile, FileSize, NtHeader, X86_OPCODE_LOCK );
  581. }
  582. //
  583. // If the target file has zero checksum (PATCH_OPTION_NO_CHECKSUM),
  584. // set the checksum in this image to zero.
  585. //
  586. // Otherwise, if we either modified the image or if the image has
  587. // a zero checksum, recompute the correct checksum.
  588. //
  589. if ( OptionFlags & PATCH_OPTION_NO_CHECKSUM ) {
  590. if ( NtHeader->OptionalHeader.CheckSum != 0 ) {
  591. NtHeader->OptionalHeader.CheckSum = 0;
  592. Modified = TRUE;
  593. }
  594. }
  595. else {
  596. if ( Modified ) {
  597. (ULONG)( NtHeader->OptionalHeader.CheckSum ) = 0;
  598. NtHeader->OptionalHeader.CheckSum = ChkSum( 0, (PVOID)MappedFile, FileSize ) + FileSize;
  599. }
  600. }
  601. return Modified;
  602. }
  603. //
  604. // For some odd reason, the VC4 compiler says there is unreachable code
  605. // in the GetNewRvaFromRiftTable and FindRiftTableEntryForOldRva functions,
  606. // but I can't find it by inspection, and the VC5 and VC6 compilers don't
  607. // complain about it, so it's probably just a VC4 issue. So, if the compiler
  608. // version is previous to VC5, disable this particular warning.
  609. //
  610. #if ( _MSC_VER < 1100 )
  611. #pragma warning( disable: 4702 ) // unreachable code
  612. #endif
  613. ULONG
  614. __fastcall
  615. GetNewRvaFromRiftTable(
  616. IN PRIFT_TABLE RiftTable,
  617. IN ULONG OldRva
  618. )
  619. {
  620. PRIFT_ENTRY RiftEntryArray;
  621. ULONG NewRva;
  622. ULONG Index;
  623. ULONG MinIndexInclusive;
  624. ULONG MaxIndexExclusive;
  625. LONG Displacement;
  626. BOOL Found;
  627. //
  628. // Rift table is in sorted order by OldRva, so do a binary search for
  629. // matching or nearest preceding OldRva value.
  630. //
  631. RiftEntryArray = RiftTable->RiftEntryArray;
  632. MaxIndexExclusive = RiftTable->RiftEntryCount;
  633. MinIndexInclusive = 0;
  634. Index = 0;
  635. Found = FALSE;
  636. while (( ! Found ) && ( MinIndexInclusive < MaxIndexExclusive )) {
  637. Index = ( MinIndexInclusive + MaxIndexExclusive ) / 2; // won't overflow
  638. if ( RiftEntryArray[ Index ].OldFileRva < OldRva ) {
  639. MinIndexInclusive = Index + 1;
  640. }
  641. else if ( RiftEntryArray[ Index ].OldFileRva > OldRva ) {
  642. MaxIndexExclusive = Index;
  643. }
  644. else {
  645. Found = TRUE;
  646. break;
  647. }
  648. }
  649. if ( ! Found ) {
  650. //
  651. // MinIndex is pointing to next highest entry, which could also be
  652. // the zeroth entry if the search value was lower than anything in
  653. // the table.
  654. //
  655. if ( MinIndexInclusive == 0 ) {
  656. return OldRva; // zero displacement
  657. }
  658. Index = MinIndexInclusive - 1;
  659. }
  660. Displacement = (LONG)( RiftEntryArray[ Index ].NewFileRva - RiftEntryArray[ Index ].OldFileRva );
  661. #ifndef PATCH_APPLY_CODE_ONLY
  662. //
  663. // If we're updating the RiftUsageArray during compression, we want to
  664. // mark the contributing entry as being used.
  665. //
  666. if ( RiftTable->RiftUsageArray != NULL ) {
  667. RiftTable->RiftUsageArray[ Index ] = 1;
  668. }
  669. #endif
  670. NewRva = OldRva + Displacement;
  671. return NewRva;
  672. }
  673. ULONG
  674. __fastcall
  675. FindRiftTableEntryForOldRva(
  676. IN PRIFT_TABLE RiftTable,
  677. IN ULONG OldRva
  678. )
  679. {
  680. PRIFT_ENTRY RiftEntryArray;
  681. ULONG MinIndexInclusive;
  682. ULONG MaxIndexExclusive;
  683. ULONG Index;
  684. BOOL Found;
  685. //
  686. // Rift table is in sorted order by OldRva, so do a binary search for
  687. // matching or nearest preceding OldRva value.
  688. //
  689. RiftEntryArray = RiftTable->RiftEntryArray;
  690. MaxIndexExclusive = RiftTable->RiftEntryCount;
  691. MinIndexInclusive = 0;
  692. Index = 0;
  693. Found = FALSE;
  694. while (( ! Found ) && ( MinIndexInclusive < MaxIndexExclusive )) {
  695. Index = ( MinIndexInclusive + MaxIndexExclusive ) / 2; // won't overflow
  696. if ( RiftEntryArray[ Index ].OldFileRva < OldRva ) {
  697. MinIndexInclusive = Index + 1;
  698. }
  699. else if ( RiftEntryArray[ Index ].OldFileRva > OldRva ) {
  700. MaxIndexExclusive = Index;
  701. }
  702. else {
  703. Found = TRUE;
  704. break;
  705. }
  706. }
  707. if ( ! Found ) {
  708. //
  709. // MinIndex is pointing to next highest entry, which could also be
  710. // the zeroth entry if the search value was lower than anything in
  711. // the table.
  712. //
  713. if ( MinIndexInclusive == 0 ) {
  714. return 0;
  715. }
  716. Index = MinIndexInclusive - 1;
  717. }
  718. return Index;
  719. }
  720. #if ( _MSC_VER < 1100 )
  721. #pragma warning( default: 4702 ) // unreachable code
  722. #endif
  723. VOID
  724. __inline
  725. ChangeOldRvaToNewRva(
  726. IN PRIFT_TABLE RiftTable,
  727. IN OUT PVOID AddressOfRvaToChange
  728. )
  729. {
  730. //
  731. // Assuming all addresses of RVAs in a PE image are aligned.
  732. //
  733. ULONG UNALIGNED* RvaToChange = AddressOfRvaToChange;
  734. *RvaToChange = GetNewRvaFromRiftTable(
  735. RiftTable,
  736. *RvaToChange
  737. );
  738. }
  739. VOID
  740. __inline
  741. SwapRelocs(
  742. PRELOC_ARRAY_ENTRY One,
  743. PRELOC_ARRAY_ENTRY Two
  744. )
  745. {
  746. RELOC_ARRAY_ENTRY Tmp;
  747. Tmp = *One;
  748. *One = *Two;
  749. *Two = Tmp;
  750. }
  751. VOID
  752. __fastcall
  753. RelocQsort(
  754. PRELOC_ARRAY_ENTRY LowerBound,
  755. PRELOC_ARRAY_ENTRY UpperBound
  756. )
  757. {
  758. PRELOC_ARRAY_ENTRY Lower = LowerBound;
  759. PRELOC_ARRAY_ENTRY Upper = UpperBound;
  760. PRELOC_ARRAY_ENTRY Pivot = Lower + (( Upper - Lower ) / 2 );
  761. ULONG PivotRva = Pivot->RelocRva;
  762. do {
  763. while (( Lower <= Upper ) && ( Lower->RelocRva <= PivotRva )) {
  764. ++Lower;
  765. }
  766. while (( Upper >= Lower ) && ( Upper->RelocRva >= PivotRva )) {
  767. --Upper;
  768. }
  769. if ( Lower < Upper ) {
  770. SwapRelocs( Lower++, Upper-- );
  771. }
  772. }
  773. while ( Lower <= Upper );
  774. if ( Lower < Pivot ) {
  775. SwapRelocs( Lower, Pivot );
  776. Pivot = Lower;
  777. }
  778. else if ( Upper > Pivot ) {
  779. SwapRelocs( Upper, Pivot );
  780. Pivot = Upper;
  781. }
  782. if ( LowerBound < ( Pivot - 1 )) {
  783. RelocQsort( LowerBound, Pivot - 1 );
  784. }
  785. if (( Pivot + 1 ) < UpperBound ) {
  786. RelocQsort( Pivot + 1, UpperBound );
  787. }
  788. }
  789. VOID
  790. TransformOldFile_PE_Relocations(
  791. IN UP_IMAGE_NT_HEADERS32 NtHeader,
  792. IN PVOID FileMappedImage,
  793. IN ULONG FileSize,
  794. IN PRIFT_TABLE RiftTable,
  795. IN PUCHAR HintMap
  796. )
  797. {
  798. PUCHAR MappedFile;
  799. PUCHAR MappedFileEnd;
  800. ULONG ImageBaseVa;
  801. ULONG ImageLastVa;
  802. PUCHAR ImageFirstSectionMa; // Mapped address
  803. ULONG ImageFirstSectionVa; // Virtual address
  804. ULONG RelocDirOff;
  805. ULONG RelocDirSize;
  806. LONG RelocDirRemaining;
  807. UP_IMAGE_BASE_RELOCATION RelocBlock;
  808. UP_IMAGE_BASE_RELOCATION RelocBlockBaseMa; // Mapped address
  809. ULONG RelocBlockBaseVa; // Virtual address
  810. ULONG RelocCount;
  811. USHORT UNALIGNED* RelocEntry;
  812. USHORT UNALIGNED* RelocFirst;
  813. UCHAR RelocType;
  814. PUCHAR RelocFixupMa; // Mapped address
  815. ULONG RelocFixupVa; // Virtual address
  816. ULONG RelocFixupRva;
  817. ULONG RelocTargetVa; // Virtual address
  818. ULONG RelocTargetRva;
  819. ULONG NewRva;
  820. ULONG NewVa;
  821. PRELOC_ARRAY_ENTRY RelocArray;
  822. ULONG RelocArrayCount;
  823. ULONG RelocArrayIndex;
  824. UP_IMAGE_SECTION_HEADER SectionHeader;
  825. ULONG SectionCount;
  826. DWORDLONG SectionName;
  827. PUCHAR p;
  828. ULONG i;
  829. #ifdef TESTCODE
  830. ULONG CountRelocChanges = 0;
  831. #endif // TESTCODE
  832. MappedFile = FileMappedImage;
  833. MappedFileEnd = MappedFile + FileSize;
  834. ImageBaseVa = NtHeader->OptionalHeader.ImageBase;
  835. RelocDirOff = ImageDirectoryOffsetAndSize( NtHeader, IMAGE_DIRECTORY_ENTRY_BASERELOC, &RelocDirSize );
  836. if (( RelocDirOff ) && (( RelocDirOff + RelocDirSize ) <= FileSize )) {
  837. memset( HintMap + RelocDirOff, 0x01, RelocDirSize ); // may need to be OR'd if other bits are used
  838. // allocate an array for the new reloc entries, approximating the needed size
  839. RelocArray = MyVirtualAlloc( sizeof( *RelocArray ) * ( RelocDirSize / sizeof(USHORT)));
  840. if ( RelocArray != NULL ) {
  841. RelocArrayCount = 0;
  842. RelocBlock = (UP_IMAGE_BASE_RELOCATION)( MappedFile + RelocDirOff );
  843. RelocDirRemaining = (LONG)RelocDirSize;
  844. while ( RelocDirRemaining > 0 ) {
  845. if (( RelocBlock->SizeOfBlock <= (ULONG)RelocDirRemaining ) &&
  846. ( RelocBlock->SizeOfBlock > sizeof( IMAGE_BASE_RELOCATION ))) {
  847. //
  848. // ImageRvaToMappedAddress returns NULL if the Rva is zero,
  849. // but that is a valid base address of a reloc block. Use
  850. // ImageRvaToFileOffset instead.
  851. //
  852. RelocBlockBaseMa = (UP_IMAGE_BASE_RELOCATION)( MappedFile + ImageRvaToFileOffset( NtHeader, RelocBlock->VirtualAddress ));
  853. if ( RelocBlockBaseMa ) {
  854. RelocBlockBaseVa = RelocBlock->VirtualAddress + ImageBaseVa;
  855. RelocEntry = (PUSHORT)((PUCHAR)RelocBlock + sizeof( IMAGE_BASE_RELOCATION ));
  856. RelocCount = ( RelocBlock->SizeOfBlock - sizeof( IMAGE_BASE_RELOCATION )) / sizeof( USHORT );
  857. while ( RelocCount-- ) {
  858. RelocType = (UCHAR)( *RelocEntry >> 12 );
  859. if ( RelocType != IMAGE_REL_BASED_ABSOLUTE ) {
  860. RelocFixupMa = (PUCHAR)RelocBlockBaseMa + ( *RelocEntry & 0x0FFF );
  861. RelocFixupVa = RelocBlockBaseVa + ( *RelocEntry & 0x0FFF );
  862. RelocFixupRva = RelocFixupVa - ImageBaseVa;
  863. RelocArray[ RelocArrayCount ].RelocRva = GetNewRvaFromRiftTable(
  864. RiftTable,
  865. RelocFixupRva
  866. );
  867. RelocArray[ RelocArrayCount ].RelocType = RelocType;
  868. switch ( RelocType ) {
  869. case IMAGE_REL_BASED_HIGHLOW:
  870. if ( RelocFixupMa < MappedFileEnd ) {
  871. *(UNALIGNED ULONG *)( HintMap + ( RelocFixupMa - MappedFile )) |= 0x01010101;
  872. //
  873. // Target is a 32-bit VA that we want to
  874. // change to the corresponding VA in the
  875. // new file.
  876. //
  877. RelocTargetVa = *(UNALIGNED ULONG *) RelocFixupMa;
  878. RelocTargetRva = RelocTargetVa - ImageBaseVa;
  879. NewRva = GetNewRvaFromRiftTable(
  880. RiftTable,
  881. RelocTargetRva
  882. );
  883. if ( NewRva != RelocTargetRva ) {
  884. NewVa = NewRva + ImageBaseVa;
  885. *(UNALIGNED ULONG *) RelocFixupMa = NewVa;
  886. #ifdef TESTCODE
  887. ++CountRelocChanges;
  888. #endif // TESTCODE
  889. }
  890. }
  891. break;
  892. case IMAGE_REL_BASED_LOW:
  893. case IMAGE_REL_BASED_HIGH:
  894. if ( RelocFixupMa < MappedFileEnd ) {
  895. *(UNALIGNED USHORT *)( HintMap + ( RelocFixupMa - MappedFile )) |= 0x0101;
  896. }
  897. break;
  898. case IMAGE_REL_BASED_HIGHADJ:
  899. if ( RelocFixupMa < MappedFileEnd ) {
  900. *(UNALIGNED USHORT *)( HintMap + ( RelocFixupMa - MappedFile )) |= 0x0101;
  901. }
  902. ++RelocEntry;
  903. --RelocCount;
  904. RelocArray[ RelocArrayCount ].HighAdjValue = *RelocEntry;
  905. break;
  906. }
  907. ++RelocArrayCount;
  908. }
  909. ++RelocEntry;
  910. }
  911. }
  912. }
  913. RelocDirRemaining -= RelocBlock->SizeOfBlock;
  914. RelocBlock = (UP_IMAGE_BASE_RELOCATION)((PUCHAR)RelocBlock + RelocBlock->SizeOfBlock );
  915. }
  916. #ifdef TESTCODE
  917. printf( "\r%9d modified reloc targets\n", CountRelocChanges );
  918. #endif TESTCODE
  919. //
  920. // Now we want to reconstruct the .reloc table based on the new values
  921. // hoping that it will more closely match the .reloc table in the new
  922. // file.
  923. //
  924. // First we want to sort our RelocArray by Rva.
  925. //
  926. if ( RelocArrayCount > 1 ) {
  927. RelocQsort( &RelocArray[ 0 ], &RelocArray[ RelocArrayCount - 1 ] );
  928. #ifdef TESTCODE
  929. for ( i = 0; i < RelocArrayCount - 1; i++ ) {
  930. if ( RelocArray[ i ].RelocRva > RelocArray[ i + 1 ].RelocRva ) {
  931. printf( "\nReloc sort failed at index %d of %d\n", i, RelocArrayCount );
  932. for ( i = 0; i < RelocArrayCount; i++ ) {
  933. printf( "%08X\n", RelocArray[ i ].RelocRva );
  934. }
  935. exit( 1 );
  936. break;
  937. }
  938. }
  939. #endif // TESTCODE
  940. }
  941. RelocDirRemaining = (LONG)RelocDirSize;
  942. //
  943. // Look for .reloc section to determine max size we can use for new
  944. // .reloc data (may be bigger than old RelocDirSize).
  945. //
  946. SectionHeader = IMAGE_FIRST_SECTION( NtHeader );
  947. SectionCount = NtHeader->FileHeader.NumberOfSections;
  948. for ( i = 0; i < SectionCount; i++ ) {
  949. SectionName = *(UNALIGNED DWORDLONG*)( &SectionHeader[ i ].Name );
  950. SectionName |= 0x2020202020202020; // fast lower case
  951. if ( SectionName == 0x2020636F6C65722E ) { // ".reloc "
  952. if (( RelocDirOff >= SectionHeader[ i ].PointerToRawData ) &&
  953. ( RelocDirOff < SectionHeader[ i ].PointerToRawData + SectionHeader[ i ].SizeOfRawData )) {
  954. RelocDirRemaining = ( SectionHeader[ i ].PointerToRawData + SectionHeader[ i ].SizeOfRawData ) - RelocDirOff;
  955. }
  956. }
  957. }
  958. RelocDirRemaining &= ~1; // force to even value
  959. RelocBlock = (UP_IMAGE_BASE_RELOCATION)( MappedFile + RelocDirOff );
  960. RelocArrayIndex = 0;
  961. while (( RelocDirRemaining > sizeof( IMAGE_BASE_RELOCATION )) &&
  962. ( RelocArrayIndex < RelocArrayCount )) {
  963. RelocBlock->VirtualAddress = ( RelocArray[ RelocArrayIndex ].RelocRva & 0xFFFFF000 );
  964. RelocFirst = RelocEntry = (PUSHORT)((PUCHAR)RelocBlock + sizeof( IMAGE_BASE_RELOCATION ));
  965. RelocDirRemaining -= sizeof( IMAGE_BASE_RELOCATION );
  966. while (( RelocDirRemaining > 0 ) &&
  967. ( RelocArrayIndex < RelocArrayCount ) &&
  968. (( RelocArray[ RelocArrayIndex ].RelocRva & 0xFFFFF000 ) == RelocBlock->VirtualAddress )) {
  969. *RelocEntry++ = (USHORT)(( RelocArray[ RelocArrayIndex ].RelocType << 12 ) | ( RelocArray[ RelocArrayIndex ].RelocRva & 0x00000FFF ));
  970. RelocDirRemaining -= sizeof( USHORT );
  971. if ((( RelocArray[ RelocArrayIndex ].RelocType << 12 ) == IMAGE_REL_BASED_HIGHADJ ) &&
  972. ( RelocDirRemaining > 0 )) {
  973. *RelocEntry++ = RelocArray[ RelocArrayIndex ].HighAdjValue;
  974. RelocDirRemaining -= sizeof( USHORT );
  975. }
  976. ++RelocArrayIndex;
  977. }
  978. if (( RelocDirRemaining > 0 ) && ((ULONG_PTR)RelocEntry & 2 )) {
  979. *RelocEntry++ = 0;
  980. RelocDirRemaining -= sizeof( USHORT );
  981. }
  982. RelocBlock->SizeOfBlock = (ULONG)((PUCHAR)RelocEntry - (PUCHAR)RelocFirst ) + sizeof( IMAGE_BASE_RELOCATION );
  983. RelocBlock = (UP_IMAGE_BASE_RELOCATION)((PUCHAR)RelocBlock + RelocBlock->SizeOfBlock );
  984. }
  985. MyVirtualFree( RelocArray );
  986. }
  987. }
  988. else {
  989. //
  990. // No relocation table exists for this binary. We can still perform
  991. // this transformation for x86 images by inferring some of the
  992. // relocation targets in the mapped image by scanning the image for
  993. // 4-byte values that are virtual addresses that fall within the
  994. // mapped image range. We start with the address of the first
  995. // section, assuming no relocs occur in the image header.
  996. //
  997. if ( NtHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_I386 ) {
  998. SectionHeader = IMAGE_FIRST_SECTION( NtHeader );
  999. ImageFirstSectionMa = MappedFile + SectionHeader->PointerToRawData;
  1000. ImageFirstSectionVa = ImageBaseVa + SectionHeader->VirtualAddress;
  1001. ImageLastVa = ImageBaseVa + NtHeader->OptionalHeader.SizeOfImage;
  1002. for ( p = ImageFirstSectionMa; p < ( MappedFileEnd - 4 ); p++ ) {
  1003. RelocTargetVa = *(UNALIGNED ULONG *) p;
  1004. if (( RelocTargetVa >= ImageFirstSectionVa ) && ( RelocTargetVa < ImageLastVa )) {
  1005. //
  1006. // This looks like a 32-bit VA that points within the image,
  1007. // so we'll transform it to the corresponding new address.
  1008. //
  1009. *(UNALIGNED ULONG *)( HintMap + ( p - MappedFile )) |= 0x01010101;
  1010. RelocTargetRva = RelocTargetVa - ImageBaseVa;
  1011. NewRva = GetNewRvaFromRiftTable( RiftTable, RelocTargetRva );
  1012. if ( NewRva != RelocTargetRva ) {
  1013. NewVa = NewRva + ImageBaseVa;
  1014. *(UNALIGNED ULONG *) p = NewVa;
  1015. #ifdef TESTCODE
  1016. ++CountRelocChanges;
  1017. #endif // TESTCODE
  1018. }
  1019. p += 3;
  1020. }
  1021. }
  1022. #ifdef TESTCODE
  1023. printf( "\r%9d modified inferred reloc targets\n", CountRelocChanges );
  1024. #endif // TESTCODE
  1025. }
  1026. }
  1027. }
  1028. VOID
  1029. TransformOldFile_PE_Exports(
  1030. IN UP_IMAGE_NT_HEADERS32 NtHeader,
  1031. IN PVOID FileMappedImage,
  1032. IN ULONG FileSize,
  1033. IN PRIFT_TABLE RiftTable,
  1034. IN PUCHAR HintMap
  1035. )
  1036. {
  1037. UP_IMAGE_EXPORT_DIRECTORY ExportBlock;
  1038. ULONG UNALIGNED* Entry;
  1039. PUCHAR MappedFile;
  1040. PUCHAR MappedFileEnd;
  1041. ULONG FileOffset;
  1042. ULONG ExportDirOff;
  1043. ULONG ExportDirSize;
  1044. ULONG EntryCount;
  1045. MappedFile = FileMappedImage;
  1046. MappedFileEnd = MappedFile + FileSize;
  1047. ExportDirOff = ImageDirectoryOffsetAndSize( NtHeader, IMAGE_DIRECTORY_ENTRY_EXPORT, &ExportDirSize );
  1048. if (( ExportDirOff ) && (( ExportDirOff + ExportDirSize ) <= FileSize )) {
  1049. memset( HintMap + ExportDirOff, 0x01, ExportDirSize ); // may need to be OR'd if other bits are used
  1050. ExportBlock = (UP_IMAGE_EXPORT_DIRECTORY)( MappedFile + ExportDirOff );
  1051. EntryCount = ExportBlock->NumberOfFunctions;
  1052. FileOffset = ImageRvaToFileOffset( NtHeader, (ULONG) ExportBlock->AddressOfFunctions );
  1053. memset( HintMap + FileOffset, 0x01, EntryCount * sizeof( ULONG )); // may need to be OR'd if other bits are used
  1054. Entry = (PULONG)( MappedFile + FileOffset );
  1055. while ( EntryCount-- ) {
  1056. ChangeOldRvaToNewRva( RiftTable, Entry++ );
  1057. }
  1058. EntryCount = ExportBlock->NumberOfNames;
  1059. FileOffset = ImageRvaToFileOffset( NtHeader, (ULONG) ExportBlock->AddressOfNames );
  1060. memset( HintMap + FileOffset, 0x01, EntryCount * sizeof( ULONG )); // may need to be OR'd if other bits are used
  1061. Entry = (PULONG)( MappedFile + FileOffset );
  1062. while ( EntryCount-- ) {
  1063. ChangeOldRvaToNewRva( RiftTable, Entry++ );
  1064. }
  1065. EntryCount = ExportBlock->NumberOfNames;
  1066. FileOffset = ImageRvaToFileOffset( NtHeader, (ULONG) ExportBlock->AddressOfNameOrdinals );
  1067. memset( HintMap + FileOffset, 0x01, EntryCount * sizeof( USHORT )); // may need to be OR'd if other bits are used
  1068. ChangeOldRvaToNewRva( RiftTable, &ExportBlock->Name );
  1069. ChangeOldRvaToNewRva( RiftTable, &ExportBlock->AddressOfFunctions );
  1070. ChangeOldRvaToNewRva( RiftTable, &ExportBlock->AddressOfNames );
  1071. ChangeOldRvaToNewRva( RiftTable, &ExportBlock->AddressOfNameOrdinals );
  1072. }
  1073. return;
  1074. }
  1075. VOID
  1076. TransformOldFile_PE_Imports(
  1077. IN UP_IMAGE_NT_HEADERS32 NtHeader,
  1078. IN PVOID FileMappedImage,
  1079. IN ULONG FileSize,
  1080. IN PRIFT_TABLE RiftTable,
  1081. IN PUCHAR HintMap
  1082. )
  1083. {
  1084. UP_IMAGE_IMPORT_BY_NAME ImportByNameData;
  1085. UP_IMAGE_IMPORT_DESCRIPTOR ImportBlock;
  1086. UP_IMAGE_THUNK_DATA32 ThunkDataStart;
  1087. UP_IMAGE_THUNK_DATA32 ThunkData;
  1088. PUCHAR MappedFile;
  1089. PUCHAR MappedFileEnd;
  1090. ULONG FileOffset;
  1091. ULONG ImportDirOff;
  1092. ULONG ImportDirSize;
  1093. ULONG ImportByNameDataOffset;
  1094. MappedFile = FileMappedImage;
  1095. MappedFileEnd = MappedFile + FileSize;
  1096. ImportDirOff = ImageDirectoryOffsetAndSize( NtHeader, IMAGE_DIRECTORY_ENTRY_IMPORT, &ImportDirSize );
  1097. if (( ImportDirOff ) && (( ImportDirOff + ImportDirSize ) <= FileSize )) {
  1098. memset( HintMap + ImportDirOff, 0x01, ImportDirSize ); // may need to be OR'd if other bits are used
  1099. ImportBlock = (UP_IMAGE_IMPORT_DESCRIPTOR)( MappedFile + ImportDirOff );
  1100. while ( ImportBlock->OriginalFirstThunk ) {
  1101. if ( ! ImportBlock->TimeDateStamp ) {
  1102. FileOffset = ImageRvaToFileOffset( NtHeader, (ULONG) ImportBlock->OriginalFirstThunk );
  1103. ThunkData = ThunkDataStart = (UP_IMAGE_THUNK_DATA32)( MappedFile + FileOffset );
  1104. while ( ThunkData->u1.Ordinal != 0 ) {
  1105. if ( ! IMAGE_SNAP_BY_ORDINAL32( ThunkData->u1.Ordinal )) {
  1106. ImportByNameDataOffset = ImageRvaToFileOffset( NtHeader, (ULONG) ThunkData->u1.AddressOfData );
  1107. ImportByNameData = (UP_IMAGE_IMPORT_BY_NAME)( MappedFile + ImportByNameDataOffset );
  1108. memset( HintMap + ImportByNameDataOffset, 0x01, strlen( (LPSTR)ImportByNameData->Name ) + 3 ); // may need to be OR'd if other bits are used
  1109. ChangeOldRvaToNewRva( RiftTable, &ThunkData->u1.AddressOfData );
  1110. }
  1111. ThunkData++;
  1112. }
  1113. memset( HintMap + FileOffset, 0x01, ((PUCHAR)ThunkData - (PUCHAR)ThunkDataStart )); // may need to be OR'd if other bits are used
  1114. FileOffset = ImageRvaToFileOffset( NtHeader, (ULONG) ImportBlock->FirstThunk );
  1115. ThunkData = ThunkDataStart = (UP_IMAGE_THUNK_DATA32)( MappedFile + FileOffset );
  1116. while ( ThunkData->u1.Ordinal != 0 ) {
  1117. if ( ! IMAGE_SNAP_BY_ORDINAL32( ThunkData->u1.Ordinal )) {
  1118. ImportByNameDataOffset = ImageRvaToFileOffset( NtHeader, (ULONG) ThunkData->u1.AddressOfData );
  1119. ImportByNameData = (UP_IMAGE_IMPORT_BY_NAME)( MappedFile + ImportByNameDataOffset );
  1120. memset( HintMap + ImportByNameDataOffset, 0x01, strlen( (LPSTR)ImportByNameData->Name ) + 3 ); // may need to be OR'd if other bits are used
  1121. ChangeOldRvaToNewRva( RiftTable, &ThunkData->u1.AddressOfData );
  1122. }
  1123. ThunkData++;
  1124. }
  1125. memset( HintMap + FileOffset, 0x01, ((PUCHAR)ThunkData - (PUCHAR)ThunkDataStart )); // may need to be OR'd if other bits are used
  1126. }
  1127. ChangeOldRvaToNewRva( RiftTable, &ImportBlock->Name );
  1128. ChangeOldRvaToNewRva( RiftTable, &ImportBlock->OriginalFirstThunk );
  1129. ChangeOldRvaToNewRva( RiftTable, &ImportBlock->FirstThunk );
  1130. ImportBlock++;
  1131. }
  1132. }
  1133. //
  1134. // Another other big thing that will prevent long matches through
  1135. // the IMAGE_IMPORT_BY_NAME entries is the Hint values which
  1136. // may change (from implib for dll being imported). The Hint
  1137. // values are stored between each of the names. Maybe a separate
  1138. // "hint rift table" to fix those, or zero out all the hints in
  1139. // both the old and new files, then after the new file is built,
  1140. // go fill-in the hint values.
  1141. //
  1142. // Currently we have no infrastructure for pre-modification of
  1143. // the new file before compression and post-modification after
  1144. // decompression.
  1145. //
  1146. return;
  1147. }
  1148. #ifdef DONTCOMPILE // jmps2 and jmps3 are experimental
  1149. VOID
  1150. TransformOldFile_PE_RelativeJmps2(
  1151. IN UP_IMAGE_NT_HEADERS32 NtHeader,
  1152. IN PUCHAR OldFileMapped,
  1153. IN ULONG OldFileSize,
  1154. IN PUCHAR NewFileMapped, // OPTIONAL
  1155. IN ULONG NewFileSize, // OPTIONAL
  1156. IN PRIFT_TABLE RiftTable,
  1157. IN PUCHAR HintMap
  1158. )
  1159. {
  1160. UP_IMAGE_NT_HEADERS32 NewNtHeader;
  1161. UP_IMAGE_SECTION_HEADER SectionHeader;
  1162. ULONG SectionCount;
  1163. PUCHAR SectionStart;
  1164. PUCHAR SectionExtent;
  1165. PUCHAR SearchExtent;
  1166. ULONG SectionLength;
  1167. ULONG SectionOffset;
  1168. ULONG SectionBaseRva;
  1169. ULONG SectionLastRva;
  1170. ULONG ImageLastRva;
  1171. LONG Displacement;
  1172. LONG NewDisplacement;
  1173. ULONG OffsetInSection;
  1174. ULONG OriginRva;
  1175. ULONG TargetRva;
  1176. ULONG NewOriginRva;
  1177. ULONG NewTargetRva;
  1178. ULONG i;
  1179. PUCHAR p;
  1180. //
  1181. // For each executable section, scan for opcodes that indicate
  1182. // relative call or branch instructions (different opcodes for
  1183. // different machine types).
  1184. //
  1185. #ifdef TESTCODE
  1186. ULONG CountRelativeBranchChanges = 0;
  1187. ULONG CountRiftModifications = 0;
  1188. ULONG CountRiftDeletions = 0;
  1189. ULONG CountUnmatchedBranches = 0;
  1190. ULONG CountUnmatchedE8 = 0;
  1191. ULONG CountUnmatchedE9 = 0;
  1192. ULONG CountUnmatched0F = 0;
  1193. ULONG CountUnmatchedE8Targets = 0;
  1194. ULONG CountUnmatchedE9Targets = 0;
  1195. ULONG CountUnmatched0FTargets = 0;
  1196. ULONG CountUnmatchedE8Followers = 0;
  1197. ULONG CountUnmatchedE9Followers = 0;
  1198. ULONG CountUnmatched0FFollowers = 0;
  1199. ULONG CountUnmatchedE8Instructions = 0;
  1200. ULONG CountUnmatchedE9Instructions = 0;
  1201. ULONG CountUnmatched0FInstructions = 0;
  1202. ULONG CountBranchInversions = 0;
  1203. #endif // TESTCODE
  1204. NewNtHeader = NewFileMapped ? GetNtHeader( NewFileMapped, NewFileSize ) : NULL;
  1205. ImageLastRva = NtHeader->OptionalHeader.SizeOfImage;
  1206. SectionHeader = IMAGE_FIRST_SECTION( NtHeader );
  1207. SectionCount = NtHeader->FileHeader.NumberOfSections;
  1208. for ( i = 0; i < SectionCount; i++ ) {
  1209. if ( SectionHeader[ i ].Characteristics & IMAGE_SCN_MEM_EXECUTE ) {
  1210. SectionBaseRva = SectionHeader[ i ].VirtualAddress;
  1211. SectionLength = MIN( SectionHeader[ i ].Misc.VirtualSize, SectionHeader[ i ].SizeOfRawData );
  1212. SectionOffset = SectionHeader[ i ].PointerToRawData;
  1213. SectionStart = OldFileMapped + SectionOffset;
  1214. SectionLastRva = SectionBaseRva + SectionLength;
  1215. if (( SectionOffset < OldFileSize ) &&
  1216. (( SectionOffset + SectionLength ) <= OldFileSize )) {
  1217. if ( NtHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_I386 ) {
  1218. SearchExtent = SectionStart + SectionLength - 5;
  1219. for ( p = SectionStart; p < SearchExtent; p++ ) {
  1220. if (( *p == 0xE8 ) || // call relative
  1221. ( *p == 0xE9 ) || // jmp relative
  1222. (( *p == 0x0F ) && // jcc relative (0F 8x)
  1223. (( *( p + 1 ) & 0xF0 ) == 0x80 ) &&
  1224. ( ++p < SearchExtent ))) {
  1225. //
  1226. // Relative displacement is stored as
  1227. // 32-bit signed value following these
  1228. // opcodes. The displacement is relative
  1229. // to the NEXT instruction, which is at
  1230. // (p + 5).
  1231. //
  1232. Displacement = *(UNALIGNED LONG*)( p + 1 );
  1233. //
  1234. // We expect a lot of false positives here because
  1235. // occurences of <E8>, <E9>, and <0F><8x> will
  1236. // likely occur in other parts of the instruction
  1237. // stream so now we validate that the TargetRva
  1238. // falls within the image and within an executable
  1239. // section.
  1240. //
  1241. // Also, for jmp and jcc instructions, verify that
  1242. // the displacement is larger than +/- 127 because
  1243. // if it wasn't, the instruction should have been
  1244. // encoded as an 8-bit near branch, not a 32-bit
  1245. // branch. This prevents us from falsely matching
  1246. // data that looks like:
  1247. //
  1248. // xxE9xxxx 00000000
  1249. //
  1250. if (( *p == 0xE8 ) ||
  1251. ( Displacement > 127 ) ||
  1252. ( Displacement < -128 )) {
  1253. OffsetInSection = ( p + 5 ) - SectionStart;
  1254. OriginRva = SectionBaseRva + OffsetInSection;
  1255. TargetRva = OriginRva + Displacement;
  1256. if ((( TargetRva >= SectionBaseRva ) &&
  1257. ( TargetRva < SectionLastRva )) ||
  1258. (( TargetRva < ImageLastRva ) &&
  1259. ( IsImageRvaInExecutableSection( NtHeader, TargetRva )))) {
  1260. //
  1261. // Looks like a valid TargetRva.
  1262. //
  1263. #ifndef PATCH_APPLY_CODE_ONLY
  1264. //
  1265. // If we're creating the patch, then we need
  1266. // to validate the corresponding branch in the
  1267. // new file (might want to modify a rift entry).
  1268. //
  1269. if ( NewFileMapped != NULL ) { // we're compressing
  1270. BOOL OriginNext = FALSE;
  1271. BOOL OriginFound = FALSE;
  1272. BOOL TargetNext = FALSE;
  1273. BOOL TargetFound = FALSE;
  1274. ULONG RiftIndexOrigin = FindRiftTableEntryForOldRva( RiftTable, OriginRva );
  1275. ULONG NewOriginRva = OriginRva + (LONG)( RiftTable->RiftEntryArray[ RiftIndexOrigin ].NewFileRva - RiftTable->RiftEntryArray[ RiftIndexOrigin ].OldFileRva );
  1276. PUCHAR NewOriginMa = NewFileMapped + ImageRvaToFileOffset( NewNtHeader, NewOriginRva );
  1277. #ifdef TESTCODE
  1278. ULONG NewOriginRva1 = NewOriginRva;
  1279. ULONG NewOriginMo1 = NewOriginMa - NewFileMapped;
  1280. ULONG NewOriginVa1 = NewOriginRva + NewNtHeader->OptionalHeader.ImageBase;
  1281. ULONG NewOriginRva2 = 0;
  1282. ULONG NewOriginMo2 = 0;
  1283. ULONG NewOriginVa2 = 0;
  1284. UCHAR OldInstruction = *p;
  1285. UCHAR NewInstruction = *( NewOriginMa - 5 );
  1286. BOOL InstructionsMatch = ( *p == *( NewOriginMa - 5 ));
  1287. BOOL FollowersMatch = ( *( p + 5 ) == *NewOriginMa );
  1288. #endif // TESTCODE
  1289. if (( *p == *( NewOriginMa - 5 )) && // instructions match, and
  1290. (( *p == 0xE9 ) || // jmp instruction, or
  1291. ( *( p + 5 ) == *NewOriginMa ))) { // followers match
  1292. OriginFound = TRUE;
  1293. }
  1294. else {
  1295. if (( RiftIndexOrigin + 1 ) < RiftTable->RiftEntryCount ) {
  1296. NewOriginRva = OriginRva + (LONG)( RiftTable->RiftEntryArray[ RiftIndexOrigin + 1 ].NewFileRva - RiftTable->RiftEntryArray[ RiftIndexOrigin + 1 ].OldFileRva );
  1297. NewOriginMa = NewFileMapped + ImageRvaToFileOffset( NewNtHeader, NewOriginRva );
  1298. #ifdef TESTCODE
  1299. NewOriginRva2 = NewOriginRva;
  1300. NewOriginMo2 = NewOriginMa - NewFileMapped;
  1301. NewOriginVa2 = NewOriginRva + NewNtHeader->OptionalHeader.ImageBase;
  1302. #endif // TESTCODE
  1303. if (( *p == *( NewOriginMa - 5 )) && // instructions match, and
  1304. (( *p == 0xE9 ) || // jmp instruction, or
  1305. ( *( p + 5 ) == *NewOriginMa ))) { // followers match
  1306. OriginFound = TRUE;
  1307. OriginNext = TRUE;
  1308. }
  1309. }
  1310. }
  1311. if ( OriginFound ) {
  1312. ULONG RiftIndexTarget = FindRiftTableEntryForOldRva( RiftTable, TargetRva );
  1313. ULONG NewTargetRva = TargetRva + (LONG)( RiftTable->RiftEntryArray[ RiftIndexTarget ].NewFileRva - RiftTable->RiftEntryArray[ RiftIndexTarget ].OldFileRva );
  1314. PUCHAR NewTargetMa = NewFileMapped + ImageRvaToFileOffset( NewNtHeader, NewTargetRva );
  1315. PUCHAR TargetMa = OldFileMapped + ImageRvaToFileOffset( NtHeader, TargetRva );
  1316. if ( *NewTargetMa == *TargetMa ) { // target instructions match
  1317. TargetFound = TRUE;
  1318. }
  1319. else {
  1320. if (( RiftIndexTarget + 1 ) < RiftTable->RiftEntryCount ) {
  1321. NewTargetRva = TargetRva + (LONG)( RiftTable->RiftEntryArray[ RiftIndexTarget + 1 ].NewFileRva - RiftTable->RiftEntryArray[ RiftIndexTarget + 1 ].OldFileRva );
  1322. NewTargetMa = NewFileMapped + ImageRvaToFileOffset( NewNtHeader, NewTargetRva );
  1323. if ( *NewTargetMa == *TargetMa ) { // target instructions match
  1324. TargetFound = TRUE;
  1325. TargetNext = TRUE;
  1326. }
  1327. }
  1328. }
  1329. if ( TargetFound ) { // target and origin found
  1330. if ( OriginNext ) {
  1331. //
  1332. // Coast the rift entry at [RiftIndexOrigin+1]
  1333. // backwards to the Rva of the instruction.
  1334. //
  1335. LONG Delta = (LONG)( RiftTable->RiftEntryArray[ RiftIndexOrigin + 1 ].OldFileRva - OriginRva );
  1336. RiftTable->RiftEntryArray[ RiftIndexOrigin + 1 ].OldFileRva -= Delta;
  1337. RiftTable->RiftEntryArray[ RiftIndexOrigin + 1 ].NewFileRva -= Delta;
  1338. #ifdef TESTCODE
  1339. ++CountRiftModifications;
  1340. #endif // TESTCODE
  1341. ASSERT( RiftTable->RiftEntryArray[ RiftIndexOrigin ].OldFileRva <= RiftTable->RiftEntryArray[ RiftIndexOrigin + 1 ].OldFileRva );
  1342. if ( RiftTable->RiftEntryArray[ RiftIndexOrigin ].OldFileRva == RiftTable->RiftEntryArray[ RiftIndexOrigin + 1 ].OldFileRva ) {
  1343. RiftTable->RiftEntryArray[ RiftIndexOrigin ].NewFileRva = RiftTable->RiftEntryArray[ RiftIndexOrigin + 1 ].NewFileRva;
  1344. #ifdef TESTCODE
  1345. ++CountRiftDeletions;
  1346. #endif // TESTCODE
  1347. }
  1348. }
  1349. if ( TargetNext ) {
  1350. //
  1351. // Coast the rift entry at [RiftIndexTarget+1]
  1352. // backwards to the Rva of the target.
  1353. //
  1354. LONG Delta = (LONG)( RiftTable->RiftEntryArray[ RiftIndexTarget + 1 ].OldFileRva - TargetRva );
  1355. RiftTable->RiftEntryArray[ RiftIndexTarget + 1 ].OldFileRva -= Delta;
  1356. RiftTable->RiftEntryArray[ RiftIndexTarget + 1 ].NewFileRva -= Delta;
  1357. #ifdef TESTCODE
  1358. ++CountRiftModifications;
  1359. #endif // TESTCODE
  1360. ASSERT( RiftTable->RiftEntryArray[ RiftIndexTarget ].OldFileRva <= RiftTable->RiftEntryArray[ RiftIndexTarget + 1 ].OldFileRva );
  1361. if ( RiftTable->RiftEntryArray[ RiftIndexTarget ].OldFileRva == RiftTable->RiftEntryArray[ RiftIndexTarget + 1 ].OldFileRva ) {
  1362. RiftTable->RiftEntryArray[ RiftIndexTarget ].NewFileRva = RiftTable->RiftEntryArray[ RiftIndexTarget + 1 ].NewFileRva;
  1363. #ifdef TESTCODE
  1364. ++CountRiftDeletions;
  1365. #endif // TESTCODE
  1366. }
  1367. }
  1368. }
  1369. }
  1370. #ifdef TESTCODE
  1371. if ( ! (( OriginFound ) && ( TargetFound ))) {
  1372. ++CountUnmatchedBranches;
  1373. switch ( *p ) {
  1374. case 0xE8:
  1375. ++CountUnmatchedE8;
  1376. if ( OriginFound ) {
  1377. ++CountUnmatchedE8Targets;
  1378. }
  1379. else if ( InstructionsMatch ) {
  1380. ASSERT( ! FollowersMatch );
  1381. ++CountUnmatchedE8Followers;
  1382. }
  1383. else {
  1384. ++CountUnmatchedE8Instructions;
  1385. printf( "\rUnmatched E8 at old RVA %08X (VA %08X, FO %08X)\n"
  1386. " with either new RVA %08X (VA %08X, FO %08X)\n"
  1387. " or backcoasted RVA %08X (VA %08X, FO %08X)\n\n",
  1388. OriginRva - 5,
  1389. ( OriginRva - 5 ) + NtHeader->OptionalHeader.ImageBase,
  1390. p - OldFileMapped,
  1391. NewOriginRva1,
  1392. NewOriginVa1,
  1393. NewOriginMo1,
  1394. NewOriginRva2,
  1395. NewOriginVa2,
  1396. NewOriginMo2
  1397. );
  1398. }
  1399. break;
  1400. case 0xE9:
  1401. ++CountUnmatchedE9;
  1402. if ( OriginFound ) {
  1403. ++CountUnmatchedE9Targets;
  1404. }
  1405. else {
  1406. ++CountUnmatchedE9Instructions;
  1407. }
  1408. break;
  1409. default:
  1410. ++CountUnmatched0F;
  1411. if ( OriginFound ) {
  1412. ++CountUnmatched0FTargets;
  1413. }
  1414. else if ( InstructionsMatch ) {
  1415. ASSERT( ! FollowersMatch );
  1416. ++CountUnmatched0FFollowers;
  1417. }
  1418. else {
  1419. ++CountUnmatched0FInstructions;
  1420. }
  1421. if ( ! InstructionsMatch ) {
  1422. if (( OldInstruction & ~1 ) == ( NewInstruction & ~1 )) {
  1423. ++CountBranchInversions;
  1424. }
  1425. }
  1426. break;
  1427. }
  1428. }
  1429. #endif // TESTCODE
  1430. }
  1431. #endif // PATCH_APPLY_CODE_ONLY
  1432. NewTargetRva = GetNewRvaFromRiftTable( RiftTable, TargetRva );
  1433. NewOriginRva = GetNewRvaFromRiftTable( RiftTable, OriginRva );
  1434. NewDisplacement = NewTargetRva - NewOriginRva;
  1435. if ( NewDisplacement != Displacement ) {
  1436. *(UNALIGNED LONG*)( p + 1 ) = NewDisplacement;
  1437. #ifdef TESTCODE
  1438. ++CountRelativeBranchChanges;
  1439. #endif // TESTCODE
  1440. }
  1441. p += 4;
  1442. }
  1443. }
  1444. }
  1445. }
  1446. }
  1447. else if ( NtHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_ALPHA ) {
  1448. //
  1449. // Need to implement the scan for Alpha platform
  1450. // relative call/jmp/jcc opcodes.
  1451. //
  1452. }
  1453. }
  1454. }
  1455. }
  1456. #ifdef TESTCODE
  1457. printf( "\r%d modified relative branches\n", CountRelativeBranchChanges );
  1458. printf( "%d rift back-coasting modifications due to branch inspection\n", CountRiftModifications );
  1459. printf( "%d rift deletions due to branch inspection back-coasting\n", CountRiftDeletions );
  1460. printf( "%d total unmatched relative branches, composed of:\n", CountUnmatchedBranches );
  1461. printf( "\t%d unmatched E8 (call)\n", CountUnmatchedE8 );
  1462. printf( "\t\t%d unmatched E8 (call) instructions\n", CountUnmatchedE8Instructions );
  1463. printf( "\t\t%d unmatched E8 (call) followers\n", CountUnmatchedE8Followers );
  1464. printf( "\t\t%d unmatched E8 (call) targets\n", CountUnmatchedE8Targets );
  1465. printf( "\t%d unmatched E9 (jmp)\n", CountUnmatchedE9 );
  1466. printf( "\t\t%d unmatched E9 (jmp) instructions\n", CountUnmatchedE9Instructions );
  1467. printf( "\t\t%d unmatched E9 (jmp) targets\n", CountUnmatchedE9Targets );
  1468. printf( "\t%d unmatched 0F 8x (jcc)\n", CountUnmatched0F );
  1469. printf( "\t\t%d unmatched 0F 8x (jcc) instructions\n", CountUnmatched0FInstructions );
  1470. printf( "\t\t\t%d unmatched 0F 8x (jcc) instruction inversions\n", CountBranchInversions );
  1471. printf( "\t\t%d unmatched 0F 8x (jcc) followers\n", CountUnmatched0FFollowers );
  1472. printf( "\t\t%d unmatched 0F 8x (jcc) targets\n", CountUnmatched0FTargets );
  1473. #endif // TESTCODE
  1474. }
  1475. #ifdef _M_IX86
  1476. __inline char * mymemchr( char *buf, int c, unsigned count ) {
  1477. __asm {
  1478. mov edi, buf
  1479. mov ecx, count
  1480. mov eax, c
  1481. repne scasb
  1482. lea eax, [edi-1]
  1483. jz RETURNIT
  1484. xor eax, eax
  1485. RETURNIT:
  1486. }
  1487. }
  1488. #else // ! _M_IX86
  1489. #define mymemchr memchr
  1490. #endif // ! _M_IX86
  1491. VOID
  1492. TransformOldFile_PE_RelativeJmps3(
  1493. IN UP_IMAGE_NT_HEADERS32 NtHeader,
  1494. IN PUCHAR OldFileMapped,
  1495. IN ULONG OldFileSize,
  1496. IN PUCHAR NewFileMapped, // OPTIONAL
  1497. IN ULONG NewFileSize, // OPTIONAL
  1498. IN PRIFT_TABLE RiftTable,
  1499. IN PUCHAR HintMap
  1500. )
  1501. {
  1502. UP_IMAGE_NT_HEADERS32 NewNtHeader;
  1503. UP_IMAGE_SECTION_HEADER SectionHeader;
  1504. ULONG SectionCount;
  1505. PUCHAR SectionStart;
  1506. PUCHAR SectionExtent;
  1507. ULONG SearchExtent;
  1508. ULONG SectionLength;
  1509. ULONG SectionOffset;
  1510. ULONG SectionBaseRva;
  1511. ULONG SectionLastRva;
  1512. ULONG ImageLastRva;
  1513. LONG DisplacementValue;
  1514. LONG NewDisplacement;
  1515. LONG OffsetToRvaAdjust;
  1516. ULONG FileOffset;
  1517. ULONG TargetOffset;
  1518. UCHAR Instruction;
  1519. ULONG InstructionLength;
  1520. ULONG DisplacementOrigin;
  1521. ULONG DisplacementOffset;
  1522. BOOL Skip;
  1523. ULONG OffsetInSection;
  1524. ULONG OriginRva;
  1525. ULONG TargetRva;
  1526. ULONG NewOriginRva;
  1527. ULONG NewTargetRva;
  1528. ULONG i;
  1529. ULONG j;
  1530. PUCHAR p;
  1531. //
  1532. // For each executable section, scan for opcodes that indicate
  1533. // relative call or branch instructions (different opcodes for
  1534. // different machine types).
  1535. //
  1536. #ifdef TESTCODE
  1537. ULONG CountRelativeBranchChanges = 0;
  1538. ULONG CountRiftModifications = 0;
  1539. ULONG CountRiftDeletions = 0;
  1540. ULONG CountUnmatchedBranches = 0;
  1541. ULONG CountUnmatchedE8 = 0;
  1542. ULONG CountUnmatchedE9 = 0;
  1543. ULONG CountUnmatched0F = 0;
  1544. ULONG CountUnmatchedE8Targets = 0;
  1545. ULONG CountUnmatchedE9Targets = 0;
  1546. ULONG CountUnmatched0FTargets = 0;
  1547. ULONG CountUnmatchedE8Followers = 0;
  1548. ULONG CountUnmatchedE9Followers = 0;
  1549. ULONG CountUnmatched0FFollowers = 0;
  1550. ULONG CountUnmatchedE8Instructions = 0;
  1551. ULONG CountUnmatchedE9Instructions = 0;
  1552. ULONG CountUnmatched0FInstructions = 0;
  1553. ULONG CountBranchInversions = 0;
  1554. #endif // TESTCODE
  1555. NewNtHeader = NewFileMapped ? GetNtHeader( NewFileMapped, NewFileSize ) : NULL;
  1556. ImageLastRva = NtHeader->OptionalHeader.SizeOfImage - 1;
  1557. SectionHeader = IMAGE_FIRST_SECTION( NtHeader );
  1558. SectionCount = NtHeader->FileHeader.NumberOfSections;
  1559. for ( i = 0; i < SectionCount; i++ ) {
  1560. if ( SectionHeader[ i ].Characteristics & IMAGE_SCN_MEM_EXECUTE ) {
  1561. SectionBaseRva = SectionHeader[ i ].VirtualAddress;
  1562. SectionLength = MIN( SectionHeader[ i ].Misc.VirtualSize, SectionHeader[ i ].SizeOfRawData );
  1563. SectionOffset = SectionHeader[ i ].PointerToRawData;
  1564. SectionStart = OldFileMapped + SectionOffset;
  1565. SectionLastRva = SectionBaseRva + SectionLength;
  1566. OffsetToRvaAdjust = SectionHeader[ i ].VirtualAddress - SectionHeader[ i ].PointerToRawData;
  1567. if (( SectionOffset < OldFileSize ) &&
  1568. (( SectionOffset + SectionLength ) <= OldFileSize )) {
  1569. if ( NtHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_I386 ) {
  1570. SearchExtent = SectionOffset + SectionLength - 6;
  1571. for ( FileOffset = SectionOffset; FileOffset < SearchExtent; FileOffset++ ) {
  1572. Instruction = OldFileMapped[ FileOffset ];
  1573. switch ( Instruction ) {
  1574. case 0xE8:
  1575. InstructionLength = 6; // E8 xx xx xx xx yy
  1576. DisplacementOrigin = FileOffset + 5;
  1577. DisplacementOffset = 1;
  1578. break;
  1579. case 0xE9:
  1580. continue;
  1581. InstructionLength = 5; // E9 xx xx xx xx
  1582. DisplacementOrigin = FileOffset + 5;
  1583. DisplacementOffset = 1;
  1584. break;
  1585. case 0x0F:
  1586. continue;
  1587. if (( OldFileMapped[ FileOffset + 1 ] & 0xF0 ) != 0x80 ) {
  1588. continue;
  1589. }
  1590. InstructionLength = 7; // 0F 8x yy yy yy yy zz
  1591. DisplacementOrigin = FileOffset + 6;
  1592. DisplacementOffset = 2;
  1593. break;
  1594. default:
  1595. continue;
  1596. }
  1597. Skip = FALSE;
  1598. for ( j = 0; j < InstructionLength; j++ ) {
  1599. if ( HintMap[ FileOffset + j ] & 0x01 ) {
  1600. Skip = TRUE;
  1601. break;
  1602. }
  1603. }
  1604. if ( Skip ) {
  1605. continue;
  1606. }
  1607. DisplacementValue = *(UNALIGNED LONG*)( OldFileMapped + FileOffset + DisplacementOffset );
  1608. if (( Instruction != 0xE8 ) &&
  1609. (( DisplacementValue > 127 ) || ( DisplacementValue < -128 ))) {
  1610. continue;
  1611. }
  1612. OriginRva = DisplacementOrigin + OffsetToRvaAdjust;
  1613. TargetRva = OriginRva + DisplacementValue;
  1614. if ( TargetRva > ImageLastRva ) {
  1615. continue;
  1616. }
  1617. TargetOffset = ImageRvaToFileOffset( NtHeader, TargetRva );
  1618. if ( HintMap[ TargetOffset ] & 0x01 ) {
  1619. continue;
  1620. }
  1621. #ifndef PATCH_APPLY_CODE_ONLY
  1622. //
  1623. // If we're creating the patch, then we want
  1624. // to validate the corresponding branch in the
  1625. // new file (might want to modify a rift entry).
  1626. //
  1627. if ( NewFileMapped != NULL ) { // we're compressing
  1628. BOOL OriginNext = FALSE;
  1629. BOOL OriginFound = FALSE;
  1630. BOOL TargetNext = FALSE;
  1631. BOOL TargetFound = FALSE;
  1632. ULONG RiftIndexOrigin = FindRiftTableEntryForOldRva( RiftTable, OriginRva );
  1633. ULONG NewOriginRva = OriginRva + (LONG)( RiftTable->RiftEntryArray[ RiftIndexOrigin ].NewFileRva - RiftTable->RiftEntryArray[ RiftIndexOrigin ].OldFileRva );
  1634. PUCHAR NewOriginMa = NewFileMapped + ImageRvaToFileOffset( NewNtHeader, NewOriginRva );
  1635. #ifdef TESTCODE
  1636. ULONG NewOriginRva1 = NewOriginRva;
  1637. ULONG NewOriginMo1 = NewOriginMa - NewFileMapped;
  1638. ULONG NewOriginVa1 = NewOriginRva + NewNtHeader->OptionalHeader.ImageBase;
  1639. ULONG NewOriginRva2 = 0;
  1640. ULONG NewOriginMo2 = 0;
  1641. ULONG NewOriginVa2 = 0;
  1642. BOOL InstructionsMatch;
  1643. BOOL FollowersMatch;
  1644. BOOL BranchInversion;
  1645. BranchInversion = FALSE;
  1646. if ( Instruction == 0x0F ) {
  1647. InstructionsMatch = ( *( NewOriginMa - 6 ) == Instruction ) && ( *( NewOriginMa - 5 ) == OldFileMapped[ FileOffset + 1 ] );
  1648. if ( ! InstructionsMatch ) {
  1649. BranchInversion = ( *( NewOriginMa - 6 ) == Instruction ) && (( *( NewOriginMa - 5 ) & ~1 ) == ( OldFileMapped[ FileOffset + 1 ] & ~1 ));
  1650. }
  1651. }
  1652. else {
  1653. InstructionsMatch = ( *( NewOriginMa - 5 ) == Instruction );
  1654. }
  1655. FollowersMatch = ( *NewOriginMa == OldFileMapped[ DisplacementOrigin ] );
  1656. #endif // TESTCODE
  1657. if (( InstructionsMatch ) &&
  1658. (( FollowersMatch ) || ( Instruction == 0xE9 ))) {
  1659. OriginFound = TRUE;
  1660. }
  1661. else {
  1662. if (( RiftIndexOrigin + 1 ) < RiftTable->RiftEntryCount ) {
  1663. NewOriginRva = OriginRva + (LONG)( RiftTable->RiftEntryArray[ RiftIndexOrigin + 1 ].NewFileRva - RiftTable->RiftEntryArray[ RiftIndexOrigin + 1 ].OldFileRva );
  1664. NewOriginMa = NewFileMapped + ImageRvaToFileOffset( NewNtHeader, NewOriginRva );
  1665. #ifdef TESTCODE
  1666. NewOriginRva2 = NewOriginRva;
  1667. NewOriginMo2 = NewOriginMa - NewFileMapped;
  1668. NewOriginVa2 = NewOriginRva + NewNtHeader->OptionalHeader.ImageBase;
  1669. #endif // TESTCODE
  1670. if ( Instruction == 0x0F ) {
  1671. InstructionsMatch = ( *( NewOriginMa - 6 ) == Instruction ) && ( *( NewOriginMa - 5 ) == OldFileMapped[ FileOffset + 1 ] );
  1672. }
  1673. else {
  1674. InstructionsMatch = ( *( NewOriginMa - 5 ) == Instruction );
  1675. }
  1676. FollowersMatch = ( *NewOriginMa == OldFileMapped[ DisplacementOrigin ] );
  1677. if (( InstructionsMatch ) &&
  1678. (( FollowersMatch ) || ( Instruction == 0xE9 ))) {
  1679. OriginFound = TRUE;
  1680. OriginNext = TRUE;
  1681. }
  1682. }
  1683. }
  1684. if ( OriginFound ) {
  1685. ULONG RiftIndexTarget = FindRiftTableEntryForOldRva( RiftTable, TargetRva );
  1686. ULONG NewTargetRva = TargetRva + (LONG)( RiftTable->RiftEntryArray[ RiftIndexTarget ].NewFileRva - RiftTable->RiftEntryArray[ RiftIndexTarget ].OldFileRva );
  1687. PUCHAR NewTargetMa = NewFileMapped + ImageRvaToFileOffset( NewNtHeader, NewTargetRva );
  1688. PUCHAR TargetMa = OldFileMapped + ImageRvaToFileOffset( NtHeader, TargetRva );
  1689. if ( *NewTargetMa == *TargetMa ) { // target instructions match
  1690. TargetFound = TRUE;
  1691. }
  1692. else {
  1693. if (( RiftIndexTarget + 1 ) < RiftTable->RiftEntryCount ) {
  1694. NewTargetRva = TargetRva + (LONG)( RiftTable->RiftEntryArray[ RiftIndexTarget + 1 ].NewFileRva - RiftTable->RiftEntryArray[ RiftIndexTarget + 1 ].OldFileRva );
  1695. NewTargetMa = NewFileMapped + ImageRvaToFileOffset( NewNtHeader, NewTargetRva );
  1696. if ( *NewTargetMa == *TargetMa ) { // target instructions match
  1697. TargetFound = TRUE;
  1698. TargetNext = TRUE;
  1699. }
  1700. }
  1701. }
  1702. if ( TargetFound ) { // target and origin found
  1703. if ( OriginNext ) {
  1704. //
  1705. // Coast the rift entry at [RiftIndexOrigin+1]
  1706. // backwards to the Rva of the instruction.
  1707. //
  1708. LONG Delta = (LONG)( RiftTable->RiftEntryArray[ RiftIndexOrigin + 1 ].OldFileRva - OriginRva );
  1709. RiftTable->RiftEntryArray[ RiftIndexOrigin + 1 ].OldFileRva -= Delta;
  1710. RiftTable->RiftEntryArray[ RiftIndexOrigin + 1 ].NewFileRva -= Delta;
  1711. #ifdef TESTCODE
  1712. ++CountRiftModifications;
  1713. #endif // TESTCODE
  1714. ASSERT( RiftTable->RiftEntryArray[ RiftIndexOrigin ].OldFileRva <= RiftTable->RiftEntryArray[ RiftIndexOrigin + 1 ].OldFileRva );
  1715. if ( RiftTable->RiftEntryArray[ RiftIndexOrigin ].OldFileRva == RiftTable->RiftEntryArray[ RiftIndexOrigin + 1 ].OldFileRva ) {
  1716. RiftTable->RiftEntryArray[ RiftIndexOrigin ].NewFileRva = RiftTable->RiftEntryArray[ RiftIndexOrigin + 1 ].NewFileRva;
  1717. #ifdef TESTCODE
  1718. ++CountRiftDeletions;
  1719. #endif // TESTCODE
  1720. }
  1721. }
  1722. if ( TargetNext ) {
  1723. //
  1724. // Coast the rift entry at [RiftIndexTarget+1]
  1725. // backwards to the Rva of the target.
  1726. //
  1727. LONG Delta = (LONG)( RiftTable->RiftEntryArray[ RiftIndexTarget + 1 ].OldFileRva - TargetRva );
  1728. RiftTable->RiftEntryArray[ RiftIndexTarget + 1 ].OldFileRva -= Delta;
  1729. RiftTable->RiftEntryArray[ RiftIndexTarget + 1 ].NewFileRva -= Delta;
  1730. #ifdef TESTCODE
  1731. ++CountRiftModifications;
  1732. #endif // TESTCODE
  1733. ASSERT( RiftTable->RiftEntryArray[ RiftIndexTarget ].OldFileRva <= RiftTable->RiftEntryArray[ RiftIndexTarget + 1 ].OldFileRva );
  1734. if ( RiftTable->RiftEntryArray[ RiftIndexTarget ].OldFileRva == RiftTable->RiftEntryArray[ RiftIndexTarget + 1 ].OldFileRva ) {
  1735. RiftTable->RiftEntryArray[ RiftIndexTarget ].NewFileRva = RiftTable->RiftEntryArray[ RiftIndexTarget + 1 ].NewFileRva;
  1736. #ifdef TESTCODE
  1737. ++CountRiftDeletions;
  1738. #endif // TESTCODE
  1739. }
  1740. }
  1741. }
  1742. }
  1743. #ifdef TESTCODE
  1744. if ( ! (( OriginFound ) && ( TargetFound ))) {
  1745. ++CountUnmatchedBranches;
  1746. switch ( Instruction ) {
  1747. case 0xE8:
  1748. ++CountUnmatchedE8;
  1749. if ( OriginFound ) {
  1750. ++CountUnmatchedE8Targets;
  1751. }
  1752. else if ( InstructionsMatch ) {
  1753. ASSERT( ! FollowersMatch );
  1754. ++CountUnmatchedE8Followers;
  1755. }
  1756. else {
  1757. ++CountUnmatchedE8Instructions;
  1758. printf( "\rUnmatched E8 at old RVA %08X (VA %08X, FO %08X)\n"
  1759. " with either new RVA %08X (VA %08X, FO %08X)\n"
  1760. " or backcoasted RVA %08X (VA %08X, FO %08X)\n\n",
  1761. OriginRva - 5,
  1762. ( OriginRva - 5 ) + NtHeader->OptionalHeader.ImageBase,
  1763. FileOffset,
  1764. NewOriginRva1,
  1765. NewOriginVa1,
  1766. NewOriginMo1,
  1767. NewOriginRva2,
  1768. NewOriginVa2,
  1769. NewOriginMo2
  1770. );
  1771. }
  1772. break;
  1773. case 0xE9:
  1774. ++CountUnmatchedE9;
  1775. if ( OriginFound ) {
  1776. ++CountUnmatchedE9Targets;
  1777. }
  1778. else {
  1779. ++CountUnmatchedE9Instructions;
  1780. }
  1781. break;
  1782. default:
  1783. ++CountUnmatched0F;
  1784. if ( OriginFound ) {
  1785. ++CountUnmatched0FTargets;
  1786. }
  1787. else if ( InstructionsMatch ) {
  1788. ASSERT( ! FollowersMatch );
  1789. ++CountUnmatched0FFollowers;
  1790. }
  1791. else {
  1792. ++CountUnmatched0FInstructions;
  1793. }
  1794. if ( BranchInversion ) {
  1795. ++CountBranchInversions;
  1796. }
  1797. break;
  1798. }
  1799. }
  1800. #endif // TESTCODE
  1801. }
  1802. #endif // PATCH_APPLY_CODE_ONLY
  1803. NewTargetRva = GetNewRvaFromRiftTable( RiftTable, TargetRva );
  1804. NewOriginRva = GetNewRvaFromRiftTable( RiftTable, OriginRva );
  1805. NewDisplacement = NewTargetRva - NewOriginRva;
  1806. if ( NewDisplacement != DisplacementValue ) {
  1807. *(UNALIGNED LONG*)( OldFileMapped + FileOffset + DisplacementOffset ) = NewDisplacement;
  1808. #ifdef TESTCODE
  1809. ++CountRelativeBranchChanges;
  1810. #endif // TESTCODE
  1811. }
  1812. FileOffset = DisplacementOrigin - 1;
  1813. }
  1814. }
  1815. else if ( NtHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_ALPHA ) {
  1816. //
  1817. // Need to implement the scan for Alpha platform
  1818. // relative call/jmp/jcc opcodes.
  1819. //
  1820. }
  1821. }
  1822. }
  1823. }
  1824. #ifdef TESTCODE
  1825. printf( "\r%d modified relative branches\n", CountRelativeBranchChanges );
  1826. printf( "%d rift back-coasting modifications due to branch inspection\n", CountRiftModifications );
  1827. printf( "%d rift deletions due to branch inspection back-coasting\n", CountRiftDeletions );
  1828. printf( "%d total unmatched relative branches, composed of:\n", CountUnmatchedBranches );
  1829. printf( "\t%d unmatched E8 (call)\n", CountUnmatchedE8 );
  1830. printf( "\t\t%d unmatched E8 (call) instructions\n", CountUnmatchedE8Instructions );
  1831. printf( "\t\t%d unmatched E8 (call) followers\n", CountUnmatchedE8Followers );
  1832. printf( "\t\t%d unmatched E8 (call) targets\n", CountUnmatchedE8Targets );
  1833. printf( "\t%d unmatched E9 (jmp)\n", CountUnmatchedE9 );
  1834. printf( "\t\t%d unmatched E9 (jmp) instructions\n", CountUnmatchedE9Instructions );
  1835. printf( "\t\t%d unmatched E9 (jmp) targets\n", CountUnmatchedE9Targets );
  1836. printf( "\t%d unmatched 0F 8x (jcc)\n", CountUnmatched0F );
  1837. printf( "\t\t%d unmatched 0F 8x (jcc) instructions\n", CountUnmatched0FInstructions );
  1838. printf( "\t\t\t%d unmatched 0F 8x (jcc) instruction inversions\n", CountBranchInversions );
  1839. printf( "\t\t%d unmatched 0F 8x (jcc) followers\n", CountUnmatched0FFollowers );
  1840. printf( "\t\t%d unmatched 0F 8x (jcc) targets\n", CountUnmatched0FTargets );
  1841. #endif // TESTCODE
  1842. }
  1843. #endif // DONTCOMPILE
  1844. VOID
  1845. TransformOldFile_PE_RelativeJmps(
  1846. IN UP_IMAGE_NT_HEADERS32 NtHeader,
  1847. IN PVOID FileMappedImage,
  1848. IN ULONG FileSize,
  1849. IN PRIFT_TABLE RiftTable,
  1850. IN PUCHAR HintMap
  1851. )
  1852. {
  1853. UP_IMAGE_SECTION_HEADER SectionHeader;
  1854. ULONG SectionCount;
  1855. PUCHAR SectionStart;
  1856. PUCHAR SearchExtent;
  1857. ULONG SectionLength;
  1858. ULONG SectionOffset;
  1859. ULONG SectionBaseRva;
  1860. ULONG ImageLastRva;
  1861. LONG Displacement;
  1862. LONG NewDisplacement;
  1863. ULONG OffsetInSection;
  1864. ULONG OriginRva;
  1865. ULONG TargetRva;
  1866. ULONG NewOriginRva;
  1867. ULONG NewTargetRva;
  1868. ULONG TargetOffset;
  1869. BOOL Skip;
  1870. ULONG i;
  1871. ULONG j;
  1872. PUCHAR p;
  1873. //
  1874. // For each executable section, scan for opcodes that indicate
  1875. // relative branch instructions (different opcodes for different
  1876. // machine types).
  1877. //
  1878. #ifdef TESTCODE
  1879. ULONG CountRelativeBranchChanges = 0;
  1880. #endif // TESTCODE
  1881. ImageLastRva = NtHeader->OptionalHeader.SizeOfImage;
  1882. SectionHeader = IMAGE_FIRST_SECTION( NtHeader );
  1883. SectionCount = NtHeader->FileHeader.NumberOfSections;
  1884. for ( i = 0; i < SectionCount; i++ ) {
  1885. if ( SectionHeader[ i ].Characteristics & IMAGE_SCN_MEM_EXECUTE ) {
  1886. SectionBaseRva = SectionHeader[ i ].VirtualAddress;
  1887. SectionLength = MIN( SectionHeader[ i ].Misc.VirtualSize, SectionHeader[ i ].SizeOfRawData );
  1888. SectionOffset = SectionHeader[ i ].PointerToRawData;
  1889. SectionStart = (PUCHAR)FileMappedImage + SectionOffset;
  1890. if (( SectionOffset < FileSize ) &&
  1891. (( SectionOffset + SectionLength ) <= FileSize )) {
  1892. if ( NtHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_I386 ) {
  1893. SearchExtent = SectionStart + SectionLength - 5;
  1894. for ( p = SectionStart; p < SearchExtent; p++ ) {
  1895. if (( *p == 0xE9 ) || // jmp relative32 (E9)
  1896. (( *p == 0x0F ) && // jcc relative32 (0F 8x)
  1897. (( *( p + 1 ) & 0xF0 ) == 0x80 ) &&
  1898. ( ++p < SearchExtent ))) {
  1899. //
  1900. // Validate that instruction and target are NOT
  1901. // something we've already identified as something
  1902. // else (reloc target, etc).
  1903. //
  1904. Skip = FALSE;
  1905. if (( *p & 0xF0 ) == 0x80 ) {
  1906. if ( HintMap[ SectionOffset + ( p - SectionStart ) - 1 ] & 0x01 ) {
  1907. Skip = TRUE;
  1908. }
  1909. }
  1910. if ( ! Skip ) {
  1911. for ( j = 0; j < 5; j++ ) {
  1912. if ( HintMap[ SectionOffset + ( p - SectionStart ) + j ] & 0x01 ) {
  1913. Skip = TRUE;
  1914. break;
  1915. }
  1916. }
  1917. }
  1918. if ( ! Skip ) {
  1919. //
  1920. // Relative displacement is stored as 32-bit
  1921. // signed value following these opcodes. The
  1922. // displacement is relative to the NEXT
  1923. // instruction, which is at (p + 5).
  1924. //
  1925. // Also, for jmp and jcc instructions, verify that
  1926. // the displacement is larger than +/- 127 because
  1927. // if it wasn't, the instruction should have been
  1928. // encoded as an 8-bit near branch, not a 32-bit
  1929. // branch. This prevents us from falsely matching
  1930. // data that looks like:
  1931. //
  1932. // xxE9xxxx 00000000
  1933. //
  1934. Displacement = *(UNALIGNED LONG*)( p + 1 );
  1935. if (( Displacement > 127 ) ||
  1936. ( Displacement < -128 )) {
  1937. OffsetInSection = (ULONG)(( p + 5 ) - SectionStart );
  1938. OriginRva = SectionBaseRva + OffsetInSection;
  1939. TargetRva = OriginRva + Displacement;
  1940. //
  1941. // We expect a lot of false positives here because
  1942. // occurences of <E9>, and <0F><8x> will
  1943. // likely occur in other parts of the instruction
  1944. // stream so now we validate that the TargetRva
  1945. // falls within the image and within an executable
  1946. // section.
  1947. //
  1948. if ( TargetRva < ImageLastRva ) {
  1949. TargetOffset = ImageRvaToFileOffset( NtHeader, TargetRva );
  1950. if ( ! ( HintMap[ TargetOffset ] & 0x01 )) {
  1951. //
  1952. // Looks like a valid TargetRva, so lookup its
  1953. // corresponding "new" RVA in the rift table.
  1954. //
  1955. NewTargetRva = GetNewRvaFromRiftTable( RiftTable, TargetRva );
  1956. NewOriginRva = GetNewRvaFromRiftTable( RiftTable, OriginRva );
  1957. NewDisplacement = NewTargetRva - NewOriginRva;
  1958. if (( NewDisplacement > 127 ) ||
  1959. ( NewDisplacement < -128 )) {
  1960. if ( NewDisplacement != Displacement ) {
  1961. *(UNALIGNED LONG*)( p + 1 ) = NewDisplacement;
  1962. #ifdef TESTCODE
  1963. ++CountRelativeBranchChanges;
  1964. #endif // TESTCODE
  1965. }
  1966. }
  1967. else {
  1968. //
  1969. // If new displacement is 8 bits, it would be
  1970. // encoded as an 8-bit relative instruction.
  1971. // For E9, instructions, that is EB. For
  1972. // 0F 8x instructions, that is 7x. In both
  1973. // cases, we're shrinking the instruction stream.
  1974. // We'll leave the extra bytes alone.
  1975. //
  1976. if ( *p == 0xE9 ) {
  1977. *p = 0xEB;
  1978. *( p + 1 ) = (CHAR) NewDisplacement;
  1979. }
  1980. else {
  1981. *( p - 1 ) = (UCHAR)(( *p & 0x0F ) | ( 0x70 ));
  1982. *p = (CHAR) NewDisplacement;
  1983. }
  1984. #ifdef TESTCODE
  1985. ++CountRelativeBranchChanges;
  1986. #endif // TESTCODE
  1987. }
  1988. p += 4;
  1989. }
  1990. }
  1991. }
  1992. }
  1993. }
  1994. }
  1995. }
  1996. else if ( NtHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_ALPHA ) {
  1997. //
  1998. // Need to implement the scan for Alpha platform
  1999. // relative jmp/jcc opcodes.
  2000. //
  2001. }
  2002. }
  2003. }
  2004. }
  2005. #ifdef TESTCODE
  2006. printf( "\r%9d modified relative branches\n", CountRelativeBranchChanges );
  2007. #endif // TESTCODE
  2008. }
  2009. VOID
  2010. TransformOldFile_PE_RelativeCalls(
  2011. IN UP_IMAGE_NT_HEADERS32 NtHeader,
  2012. IN PVOID FileMappedImage,
  2013. IN ULONG FileSize,
  2014. IN PRIFT_TABLE RiftTable,
  2015. IN PUCHAR HintMap
  2016. )
  2017. {
  2018. UP_IMAGE_SECTION_HEADER SectionHeader;
  2019. ULONG SectionCount;
  2020. PUCHAR SectionStart;
  2021. PUCHAR SearchExtent;
  2022. ULONG SectionLength;
  2023. ULONG SectionOffset;
  2024. ULONG SectionBaseRva;
  2025. ULONG ImageLastRva;
  2026. LONG Displacement;
  2027. LONG NewDisplacement;
  2028. ULONG OffsetInSection;
  2029. ULONG OriginRva;
  2030. ULONG TargetRva;
  2031. ULONG NewOriginRva;
  2032. ULONG NewTargetRva;
  2033. ULONG TargetOffset;
  2034. BOOL Skip;
  2035. ULONG i;
  2036. ULONG j;
  2037. PUCHAR p;
  2038. //
  2039. // For each executable section, scan for opcodes that indicate
  2040. // relative call or branch instructions (different opcodes for
  2041. // different machine types).
  2042. //
  2043. #ifdef TESTCODE
  2044. ULONG CountRelativeCallChanges = 0;
  2045. #endif // TESTCODE
  2046. ImageLastRva = NtHeader->OptionalHeader.SizeOfImage;
  2047. SectionHeader = IMAGE_FIRST_SECTION( NtHeader );
  2048. SectionCount = NtHeader->FileHeader.NumberOfSections;
  2049. for ( i = 0; i < SectionCount; i++ ) {
  2050. if ( SectionHeader[ i ].Characteristics & IMAGE_SCN_MEM_EXECUTE ) {
  2051. SectionBaseRva = SectionHeader[ i ].VirtualAddress;
  2052. SectionLength = MIN( SectionHeader[ i ].Misc.VirtualSize, SectionHeader[ i ].SizeOfRawData );
  2053. SectionOffset = SectionHeader[ i ].PointerToRawData;
  2054. SectionStart = (PUCHAR)FileMappedImage + SectionOffset;
  2055. if (( SectionOffset < FileSize ) &&
  2056. (( SectionOffset + SectionLength ) <= FileSize )) {
  2057. if ( NtHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_I386 ) {
  2058. SearchExtent = SectionStart + SectionLength - 5;
  2059. for ( p = SectionStart; p < SearchExtent; p++ ) {
  2060. if ( *p == 0xE8 ) { // call relative32
  2061. //
  2062. // Validate that instruction and target are NOT
  2063. // something we've already identified as something
  2064. // else (reloc target, etc).
  2065. //
  2066. Skip = FALSE;
  2067. for ( j = 0; j < 5; j++ ) {
  2068. if ( HintMap[ SectionOffset + ( p - SectionStart ) + j ] & 0x01 ) {
  2069. Skip = TRUE;
  2070. break;
  2071. }
  2072. }
  2073. if ( ! Skip ) {
  2074. //
  2075. // Relative displacement is stored as 32-bit
  2076. // signed value following these opcodes. The
  2077. // displacement is relative to the NEXT
  2078. // instruction, which is at (p + 5).
  2079. //
  2080. Displacement = *(UNALIGNED LONG*)( p + 1 );
  2081. OffsetInSection = (ULONG)(( p + 5 ) - SectionStart );
  2082. OriginRva = SectionBaseRva + OffsetInSection;
  2083. TargetRva = OriginRva + Displacement;
  2084. //
  2085. // We expect a lot of false positives here because
  2086. // occurences of <E8> will
  2087. // likely occur in other parts of the instruction
  2088. // stream so now we validate that the TargetRva
  2089. // falls within the image and within an executable
  2090. // section.
  2091. //
  2092. if ( TargetRva < ImageLastRva ) {
  2093. TargetOffset = ImageRvaToFileOffset( NtHeader, TargetRva );
  2094. if ( ! ( HintMap[ TargetOffset ] & 0x01 )) {
  2095. //
  2096. // Looks like a valid TargetRva, so lookup its
  2097. // corresponding "new" RVA in the rift table.
  2098. //
  2099. NewTargetRva = GetNewRvaFromRiftTable( RiftTable, TargetRva );
  2100. NewOriginRva = GetNewRvaFromRiftTable( RiftTable, OriginRva );
  2101. NewDisplacement = NewTargetRva - NewOriginRva;
  2102. if ( NewDisplacement != Displacement ) {
  2103. *(UNALIGNED LONG*)( p + 1 ) = NewDisplacement;
  2104. #ifdef TESTCODE
  2105. ++CountRelativeCallChanges;
  2106. #endif // TESTCODE
  2107. }
  2108. p += 4;
  2109. }
  2110. }
  2111. }
  2112. }
  2113. }
  2114. }
  2115. else if ( NtHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_ALPHA ) {
  2116. //
  2117. // Need to implement the scan for Alpha platform
  2118. // relative call/jmp/jcc opcodes.
  2119. //
  2120. }
  2121. }
  2122. }
  2123. }
  2124. #ifdef TESTCODE
  2125. printf( "\r%9d modified relative calls\n", CountRelativeCallChanges );
  2126. #endif // TESTCODE
  2127. }
  2128. VOID
  2129. TransformOldFile_PE_MarkNonExe(
  2130. IN UP_IMAGE_NT_HEADERS32 NtHeader,
  2131. IN PUCHAR OldFileMapped,
  2132. IN ULONG OldFileSize,
  2133. IN PUCHAR HintMap
  2134. )
  2135. {
  2136. UP_IMAGE_SECTION_HEADER SectionHeader;
  2137. ULONG SectionCount;
  2138. ULONG Offset;
  2139. ULONG Size;
  2140. ULONG Rva;
  2141. ULONG i;
  2142. UNREFERENCED_PARAMETER( OldFileMapped );
  2143. UNREFERENCED_PARAMETER( OldFileSize );
  2144. //
  2145. // Need to mark all non-exectuble bytes in hint map:
  2146. //
  2147. // Image header
  2148. // All PE image directories (import, export, etc)
  2149. // All non-executable sections
  2150. // All relocation targets
  2151. // (a reloc target can be in the middle of an instruction, but
  2152. // never the first byte of an instruction)
  2153. //
  2154. // If we use other bits in hint map, may need to change these
  2155. // memsets to bitwise OR.
  2156. //
  2157. memset( HintMap + 0, 0x01, NtHeader->OptionalHeader.SizeOfHeaders );
  2158. for ( i = 0; i < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; i++ ) {
  2159. Rva = NtHeader->OptionalHeader.DataDirectory[ i ].VirtualAddress;
  2160. Size = NtHeader->OptionalHeader.DataDirectory[ i ].Size;
  2161. if (( Rva != 0 ) && ( Size != 0 )) {
  2162. Offset = ImageRvaToFileOffset( NtHeader, Rva );
  2163. memset( HintMap + Offset, 0x01, Size );
  2164. }
  2165. }
  2166. SectionHeader = IMAGE_FIRST_SECTION( NtHeader );
  2167. SectionCount = NtHeader->FileHeader.NumberOfSections;
  2168. for ( i = 0; i < SectionCount; i++ ) {
  2169. if ( ! ( SectionHeader[ i ].Characteristics & IMAGE_SCN_MEM_EXECUTE )) {
  2170. memset( HintMap + SectionHeader[ i ].PointerToRawData, 0x01, SectionHeader[ i ].SizeOfRawData );
  2171. }
  2172. }
  2173. }
  2174. typedef struct _RES_RECURSION_CONTEXT {
  2175. PRIFT_TABLE RiftTable;
  2176. PUCHAR ResBase;
  2177. PUCHAR ResEnd;
  2178. ULONG ResSize;
  2179. ULONG ResDone;
  2180. ULONG ResTime;
  2181. ULONG OldResRva;
  2182. ULONG NewResRva;
  2183. } RES_RECURSION_CONTEXT, *PRES_RECURSION_CONTEXT;
  2184. VOID
  2185. TransformResourceRecursive(
  2186. IN PRES_RECURSION_CONTEXT ResContext,
  2187. IN UP_IMAGE_RESOURCE_DIRECTORY ResDir
  2188. )
  2189. {
  2190. UP_IMAGE_RESOURCE_DIRECTORY_ENTRY ResEntry;
  2191. UP_IMAGE_RESOURCE_DATA_ENTRY ResData;
  2192. ULONG ResEntryCount;
  2193. ULONG NewOffset;
  2194. ULONG NewRva;
  2195. if (((PUCHAR)ResDir + sizeof( IMAGE_RESOURCE_DIRECTORY )) < ResContext->ResEnd ) {
  2196. ResContext->ResDone += sizeof( *ResDir );
  2197. if ( ResContext->ResDone > ResContext->ResSize ) {
  2198. return;
  2199. }
  2200. if ( ResDir->TimeDateStamp != ResContext->ResTime ) {
  2201. ResDir->TimeDateStamp = ResContext->ResTime;
  2202. }
  2203. ResEntryCount = ResDir->NumberOfNamedEntries + ResDir->NumberOfIdEntries;
  2204. ResEntry = (UP_IMAGE_RESOURCE_DIRECTORY_ENTRY)( ResDir + 1 );
  2205. while (( ResEntryCount > 0 ) && ((PUCHAR)ResEntry < ( ResContext->ResEnd - sizeof( *ResEntry )))) {
  2206. if ( ResEntry->DataIsDirectory ) {
  2207. TransformResourceRecursive(
  2208. ResContext,
  2209. (UP_IMAGE_RESOURCE_DIRECTORY)( ResContext->ResBase + ResEntry->OffsetToDirectory )
  2210. );
  2211. }
  2212. else {
  2213. ResData = (UP_IMAGE_RESOURCE_DATA_ENTRY)( ResContext->ResBase + ResEntry->OffsetToData );
  2214. if (((PUCHAR)ResData > ( ResContext->ResBase )) &&
  2215. ((PUCHAR)ResData < ( ResContext->ResEnd - sizeof( *ResData )))) {
  2216. ResContext->ResDone += ResData->Size;
  2217. if ( ResContext->ResDone > ResContext->ResSize ) {
  2218. return;
  2219. }
  2220. NewRva = GetNewRvaFromRiftTable( ResContext->RiftTable, ResData->OffsetToData );
  2221. if ( ResData->OffsetToData != NewRva ) {
  2222. ResData->OffsetToData = NewRva;
  2223. }
  2224. }
  2225. }
  2226. NewOffset = GetNewRvaFromRiftTable( ResContext->RiftTable, ResContext->OldResRva + ResEntry->OffsetToDirectory ) - ResContext->NewResRva;
  2227. if ( ResEntry->OffsetToDirectory != NewOffset ) {
  2228. ResEntry->OffsetToDirectory = NewOffset;
  2229. }
  2230. if ( ResEntry->NameIsString ) {
  2231. NewOffset = GetNewRvaFromRiftTable( ResContext->RiftTable, ResContext->OldResRva + ResEntry->NameOffset ) - ResContext->NewResRva;
  2232. if ( ResEntry->NameOffset != NewOffset ) {
  2233. ResEntry->NameOffset = NewOffset;
  2234. }
  2235. }
  2236. ResContext->ResDone += sizeof( *ResEntry );
  2237. if ( ResContext->ResDone > ResContext->ResSize ) {
  2238. return;
  2239. }
  2240. ++ResEntry;
  2241. --ResEntryCount;
  2242. }
  2243. }
  2244. }
  2245. VOID
  2246. TransformOldFile_PE_Resources(
  2247. IN UP_IMAGE_NT_HEADERS32 NtHeader,
  2248. IN PUCHAR OldFileMapped,
  2249. IN ULONG OldFileSize,
  2250. IN ULONG NewFileResTime,
  2251. IN PRIFT_TABLE RiftTable
  2252. )
  2253. {
  2254. RES_RECURSION_CONTEXT ResContext;
  2255. ResContext.ResBase = ImageDirectoryMappedAddress(
  2256. NtHeader,
  2257. IMAGE_DIRECTORY_ENTRY_RESOURCE,
  2258. &ResContext.ResSize,
  2259. OldFileMapped,
  2260. OldFileSize
  2261. );
  2262. if ( ResContext.ResBase ) {
  2263. ResContext.ResEnd = ResContext.ResBase + ResContext.ResSize;
  2264. ResContext.ResDone = 0;
  2265. ResContext.OldResRva = ImageDirectoryRvaAndSize( NtHeader, IMAGE_DIRECTORY_ENTRY_RESOURCE, NULL );
  2266. ResContext.NewResRva = GetNewRvaFromRiftTable( RiftTable, ResContext.OldResRva );
  2267. ResContext.ResTime = NewFileResTime;
  2268. ResContext.RiftTable = RiftTable;
  2269. TransformResourceRecursive(
  2270. &ResContext,
  2271. (UP_IMAGE_RESOURCE_DIRECTORY) ResContext.ResBase
  2272. );
  2273. }
  2274. }
  2275. BOOL
  2276. TransformCoffImage(
  2277. IN ULONG TransformOptions,
  2278. IN OUT UP_IMAGE_NT_HEADERS32 NtHeader,
  2279. IN OUT PUCHAR OldFileMapped,
  2280. IN ULONG OldFileSize,
  2281. IN ULONG NewFileResTime,
  2282. IN OUT PRIFT_TABLE RiftTable,
  2283. IN OUT PUCHAR HintMap,
  2284. ...
  2285. )
  2286. {
  2287. PUCHAR InternalHintMap = NULL;
  2288. //
  2289. // First, zero out the rift usage array
  2290. //
  2291. if ( RiftTable->RiftUsageArray != NULL ) {
  2292. ZeroMemory( RiftTable->RiftUsageArray, RiftTable->RiftEntryAlloc * sizeof( RiftTable->RiftUsageArray[ 0 ] ));
  2293. }
  2294. //
  2295. // Allocated parallel "hint" mapping the same size as the old
  2296. // file. Each one of the 8 bits corresponding to each byte in
  2297. // the old file can be used to track information about that
  2298. // byte during the transformations.
  2299. //
  2300. if ( HintMap == NULL ) {
  2301. InternalHintMap = MyVirtualAlloc( OldFileSize );
  2302. HintMap = InternalHintMap;
  2303. }
  2304. if ( HintMap != NULL ) {
  2305. //
  2306. // Apply PE image transforms (each inside try/except)
  2307. //
  2308. __try {
  2309. TransformOldFile_PE_MarkNonExe( NtHeader, OldFileMapped, OldFileSize, HintMap );
  2310. }
  2311. __except( EXCEPTION_EXECUTE_HANDLER ) {
  2312. }
  2313. if ( ! ( TransformOptions & PATCH_TRANSFORM_NO_RELOCS )) {
  2314. __try {
  2315. TransformOldFile_PE_Relocations( NtHeader, OldFileMapped, OldFileSize, RiftTable, HintMap );
  2316. }
  2317. __except( EXCEPTION_EXECUTE_HANDLER ) {
  2318. }
  2319. }
  2320. if ( ! ( TransformOptions & PATCH_TRANSFORM_NO_IMPORTS )) {
  2321. __try {
  2322. TransformOldFile_PE_Imports( NtHeader, OldFileMapped, OldFileSize, RiftTable, HintMap );
  2323. }
  2324. __except( EXCEPTION_EXECUTE_HANDLER ) {
  2325. }
  2326. }
  2327. if ( ! ( TransformOptions & PATCH_TRANSFORM_NO_EXPORTS )) {
  2328. __try {
  2329. TransformOldFile_PE_Exports( NtHeader, OldFileMapped, OldFileSize, RiftTable, HintMap );
  2330. }
  2331. __except( EXCEPTION_EXECUTE_HANDLER ) {
  2332. }
  2333. }
  2334. if ( ! ( TransformOptions & PATCH_TRANSFORM_NO_RELJMPS )) {
  2335. __try {
  2336. TransformOldFile_PE_RelativeJmps( NtHeader, OldFileMapped, OldFileSize, RiftTable, HintMap );
  2337. }
  2338. __except( EXCEPTION_EXECUTE_HANDLER ) {
  2339. }
  2340. }
  2341. if ( ! ( TransformOptions & PATCH_TRANSFORM_NO_RELCALLS )) {
  2342. __try {
  2343. TransformOldFile_PE_RelativeCalls( NtHeader, OldFileMapped, OldFileSize, RiftTable, HintMap );
  2344. }
  2345. __except( EXCEPTION_EXECUTE_HANDLER ) {
  2346. }
  2347. }
  2348. if ( ! ( TransformOptions & PATCH_TRANSFORM_NO_RESOURCE )) {
  2349. __try {
  2350. TransformOldFile_PE_Resources( NtHeader, OldFileMapped, OldFileSize, NewFileResTime, RiftTable );
  2351. }
  2352. __except( EXCEPTION_EXECUTE_HANDLER ) {
  2353. }
  2354. }
  2355. if ( InternalHintMap != NULL ) {
  2356. MyVirtualFree( InternalHintMap );
  2357. }
  2358. }
  2359. return TRUE;
  2360. }
  2361. #ifndef PATCH_APPLY_CODE_ONLY
  2362. BOOL
  2363. AddRiftEntryToTable(
  2364. IN PRIFT_TABLE RiftTable,
  2365. IN ULONG OldRva,
  2366. IN ULONG NewRva
  2367. )
  2368. {
  2369. ULONG RiftIndex;
  2370. if (( OldRva != 0 ) && ( NewRva != 0 )) {
  2371. RiftIndex = RiftTable->RiftEntryCount;
  2372. if (( RiftIndex + 1 ) < RiftTable->RiftEntryAlloc ) {
  2373. RiftTable->RiftEntryCount = RiftIndex + 1;
  2374. RiftTable->RiftEntryArray[ RiftIndex ].OldFileRva = OldRva;
  2375. RiftTable->RiftEntryArray[ RiftIndex ].NewFileRva = NewRva;
  2376. return TRUE;
  2377. }
  2378. }
  2379. return FALSE;
  2380. }
  2381. BOOL
  2382. InsertRiftEntryInSortedTable(
  2383. IN PRIFT_TABLE RiftTable,
  2384. IN ULONG RiftIndex,
  2385. IN ULONG OldRva,
  2386. IN ULONG NewRva
  2387. )
  2388. {
  2389. if (( OldRva != 0 ) && ( NewRva != 0 )) {
  2390. //
  2391. // First scoot to the correct index in case RiftIndex is off by a few.
  2392. //
  2393. while (( RiftIndex > 0 ) && ( RiftTable->RiftEntryArray[ RiftIndex ].OldFileRva > OldRva )) {
  2394. --RiftIndex;
  2395. }
  2396. while (( RiftIndex < RiftTable->RiftEntryCount ) && ( RiftTable->RiftEntryArray[ RiftIndex ].OldFileRva < OldRva )) {
  2397. ++RiftIndex;
  2398. }
  2399. if ( RiftIndex < RiftTable->RiftEntryCount ) {
  2400. if ( RiftTable->RiftEntryArray[ RiftIndex ].OldFileRva == OldRva ) {
  2401. //
  2402. // Don't insert duplicates. If it matches an existing OldRva,
  2403. // just warn if the NewRva doesn't match the rift.
  2404. //
  2405. #ifdef TESTCODE
  2406. if ( RiftTable->RiftEntryArray[ RiftIndex ].NewFileRva != NewRva ) {
  2407. printf( "\rAttempt to insert different rift at same OldRva\n"
  2408. " OldRva:%08X NewRva:%08X (discarded)\n"
  2409. " OldRva:%08X NewRva:%08X (kept)\n\n",
  2410. OldRva,
  2411. NewRva,
  2412. RiftTable->RiftEntryArray[ RiftIndex ].OldFileRva,
  2413. RiftTable->RiftEntryArray[ RiftIndex ].NewFileRva
  2414. );
  2415. return FALSE;
  2416. }
  2417. #endif /* TESTCODE */
  2418. return TRUE;
  2419. }
  2420. }
  2421. //
  2422. // Verify we have enough allocation to insert a new entry.
  2423. //
  2424. if (( RiftTable->RiftEntryCount + 1 ) < RiftTable->RiftEntryAlloc ) {
  2425. //
  2426. // Slide everything from RiftIndex to make room for new
  2427. // entry at RiftIndex.
  2428. //
  2429. LONG CountToMove = RiftTable->RiftEntryCount - RiftIndex;
  2430. if ( CountToMove > 0 ) {
  2431. MoveMemory(
  2432. &RiftTable->RiftEntryArray[ RiftIndex + 1 ],
  2433. &RiftTable->RiftEntryArray[ RiftIndex ],
  2434. CountToMove * sizeof( RiftTable->RiftEntryArray[ 0 ] )
  2435. );
  2436. #ifdef DONTCOMPILE // we don't use the RiftUsageArray when we're inserting
  2437. if ( RiftTable->RiftUsageArray ) {
  2438. MoveMemory(
  2439. &RiftTable->RiftUsageArray[ RiftIndex + 1 ],
  2440. &RiftTable->RiftUsageArray[ RiftIndex ],
  2441. CountToMove * sizeof( RiftTable->RiftUsageArray[ 0 ] )
  2442. );
  2443. }
  2444. #endif // DONTCOMPILE
  2445. }
  2446. #ifdef DONTCOMPILE // we don't use the RiftUsageArray when we're inserting
  2447. RiftTable->RiftUsageArray[ RiftIndex ] = 0;
  2448. #endif // DONTCOMPILE
  2449. RiftTable->RiftEntryArray[ RiftIndex ].OldFileRva = OldRva;
  2450. RiftTable->RiftEntryArray[ RiftIndex ].NewFileRva = NewRva;
  2451. RiftTable->RiftEntryCount++;
  2452. return TRUE;
  2453. }
  2454. }
  2455. return FALSE;
  2456. }
  2457. VOID
  2458. __inline
  2459. SwapRifts(
  2460. PRIFT_ENTRY One,
  2461. PRIFT_ENTRY Two
  2462. )
  2463. {
  2464. RIFT_ENTRY Tmp;
  2465. Tmp = *One;
  2466. *One = *Two;
  2467. *Two = Tmp;
  2468. }
  2469. VOID
  2470. __fastcall
  2471. RiftQsort(
  2472. PRIFT_ENTRY LowerBound,
  2473. PRIFT_ENTRY UpperBound
  2474. )
  2475. {
  2476. PRIFT_ENTRY Lower = LowerBound;
  2477. PRIFT_ENTRY Upper = UpperBound;
  2478. PRIFT_ENTRY Pivot = Lower + (( Upper - Lower ) / 2 );
  2479. ULONG PivotRva = Pivot->OldFileRva;
  2480. do {
  2481. while (( Lower <= Upper ) && ( Lower->OldFileRva <= PivotRva )) {
  2482. ++Lower;
  2483. }
  2484. while (( Upper >= Lower ) && ( Upper->OldFileRva >= PivotRva )) {
  2485. --Upper;
  2486. }
  2487. if ( Lower < Upper ) {
  2488. SwapRifts( Lower++, Upper-- );
  2489. }
  2490. }
  2491. while ( Lower <= Upper );
  2492. if ( Lower < Pivot ) {
  2493. SwapRifts( Lower, Pivot );
  2494. Pivot = Lower;
  2495. }
  2496. else if ( Upper > Pivot ) {
  2497. SwapRifts( Upper, Pivot );
  2498. Pivot = Upper;
  2499. }
  2500. if ( LowerBound < ( Pivot - 1 )) {
  2501. RiftQsort( LowerBound, Pivot - 1 );
  2502. }
  2503. if (( Pivot + 1 ) < UpperBound ) {
  2504. RiftQsort( Pivot + 1, UpperBound );
  2505. }
  2506. }
  2507. VOID
  2508. RiftSortAndRemoveDuplicates(
  2509. IN PUCHAR OldFileMapped,
  2510. IN ULONG OldFileSize,
  2511. IN UP_IMAGE_NT_HEADERS32 OldFileNtHeader,
  2512. IN PUCHAR NewFileMapped,
  2513. IN ULONG NewFileSize,
  2514. IN UP_IMAGE_NT_HEADERS32 NewFileNtHeader,
  2515. IN OUT PRIFT_TABLE RiftTable
  2516. )
  2517. {
  2518. ULONG i, n;
  2519. if ( RiftTable->RiftEntryCount > 1 ) {
  2520. n = RiftTable->RiftEntryCount - 1;
  2521. RiftQsort( &RiftTable->RiftEntryArray[ 0 ], &RiftTable->RiftEntryArray[ n ] );
  2522. for ( i = 0; i < n; i++ ) {
  2523. while (( i < n ) &&
  2524. ( RiftTable->RiftEntryArray[ i ].OldFileRva ==
  2525. RiftTable->RiftEntryArray[ i + 1 ].OldFileRva )) {
  2526. if ( RiftTable->RiftEntryArray[ i ].NewFileRva !=
  2527. RiftTable->RiftEntryArray[ i + 1 ].NewFileRva ) {
  2528. //
  2529. // This is an ambiguous entry since the OldRva values
  2530. // match but the NewRva values do not. Inspect the
  2531. // bytes in the old and new files and choose the one
  2532. // that is correct. If both are correct, or neither is
  2533. // correct, choose the lower of the two NewRva values.
  2534. //
  2535. ULONG ChosenNewRva;
  2536. PUCHAR OldFileRiftMa;
  2537. PUCHAR NewFileRiftMa1;
  2538. PUCHAR NewFileRiftMa2;
  2539. #ifdef TESTCODE
  2540. LPSTR Method = "lower";
  2541. #endif
  2542. ChosenNewRva = MIN( RiftTable->RiftEntryArray[ i ].NewFileRva,
  2543. RiftTable->RiftEntryArray[ i + 1 ].NewFileRva );
  2544. OldFileRiftMa = ImageRvaToMappedAddress(
  2545. OldFileNtHeader,
  2546. RiftTable->RiftEntryArray[ i ].OldFileRva,
  2547. OldFileMapped,
  2548. OldFileSize
  2549. );
  2550. NewFileRiftMa1 = ImageRvaToMappedAddress(
  2551. NewFileNtHeader,
  2552. RiftTable->RiftEntryArray[ i ].NewFileRva,
  2553. NewFileMapped,
  2554. NewFileSize
  2555. );
  2556. NewFileRiftMa2 = ImageRvaToMappedAddress(
  2557. NewFileNtHeader,
  2558. RiftTable->RiftEntryArray[ i + 1 ].NewFileRva,
  2559. NewFileMapped,
  2560. NewFileSize
  2561. );
  2562. //
  2563. // Use try/except to touch the mapped files.
  2564. //
  2565. __try {
  2566. if ( OldFileRiftMa != NULL ) {
  2567. if (( NewFileRiftMa1 != NULL ) &&
  2568. ( *NewFileRiftMa1 == *OldFileRiftMa ) &&
  2569. (( NewFileRiftMa2 == NULL ) ||
  2570. ( *NewFileRiftMa2 != *OldFileRiftMa ))) {
  2571. ChosenNewRva = RiftTable->RiftEntryArray[ i ].NewFileRva;
  2572. #ifdef TESTCODE
  2573. Method = "match inspection";
  2574. #endif
  2575. }
  2576. else if (( NewFileRiftMa2 != NULL ) &&
  2577. ( *NewFileRiftMa2 == *OldFileRiftMa ) &&
  2578. (( NewFileRiftMa1 == NULL ) ||
  2579. ( *NewFileRiftMa1 != *OldFileRiftMa ))) {
  2580. ChosenNewRva = RiftTable->RiftEntryArray[ i + 1 ].NewFileRva;
  2581. #ifdef TESTCODE
  2582. Method = "match inspection";
  2583. #endif
  2584. }
  2585. }
  2586. }
  2587. __except( EXCEPTION_EXECUTE_HANDLER ) {
  2588. }
  2589. #ifdef TESTCODE
  2590. printf(
  2591. "RiftInfo contains ambiguous entries:\n"
  2592. " OldRva:%08X NewRva:%08X (discarded)\n"
  2593. " OldRva:%08X NewRva:%08X (kept %s)\n\n",
  2594. RiftTable->RiftEntryArray[ i ].OldFileRva,
  2595. ( RiftTable->RiftEntryArray[ i ].NewFileRva == ChosenNewRva ) ?
  2596. RiftTable->RiftEntryArray[ i + 1 ].NewFileRva :
  2597. RiftTable->RiftEntryArray[ i ].NewFileRva,
  2598. RiftTable->RiftEntryArray[ i ].OldFileRva,
  2599. ChosenNewRva,
  2600. Method
  2601. );
  2602. #endif
  2603. RiftTable->RiftEntryArray[ i + 1 ].NewFileRva = ChosenNewRva;
  2604. }
  2605. MoveMemory(
  2606. &RiftTable->RiftEntryArray[ i ],
  2607. &RiftTable->RiftEntryArray[ i + 1 ],
  2608. ( n - i ) * sizeof( RIFT_ENTRY )
  2609. );
  2610. --n;
  2611. }
  2612. }
  2613. RiftTable->RiftEntryCount = n + 1;
  2614. }
  2615. }
  2616. #ifdef _M_IX86
  2617. //
  2618. // The x86 compiler might not optimize (a=x/y;b=x%y) into a single
  2619. // divide instruction that provides both the quotient and the remainder.
  2620. //
  2621. #pragma warning( disable: 4035 ) // no return value
  2622. __inline
  2623. DWORDLONG
  2624. QuotientAndRemainder(
  2625. IN ULONG Dividend,
  2626. IN ULONG Divisor
  2627. )
  2628. {
  2629. __asm {
  2630. mov eax, Dividend
  2631. xor edx, edx
  2632. div Divisor ; eax <- quotient, edx <- remainder
  2633. }
  2634. }
  2635. #pragma warning( default: 4035 ) // no return value
  2636. #else // ! _M_IX86
  2637. __inline
  2638. DWORDLONG
  2639. QuotientAndRemainder(
  2640. IN ULONG Dividend,
  2641. IN ULONG Divisor
  2642. )
  2643. {
  2644. ULONG Quotient = ( Dividend / Divisor );
  2645. ULONG Remainder = ( Dividend % Divisor );
  2646. return (((DWORDLONG)Remainder << 32 ) | Quotient );
  2647. }
  2648. #endif // ! _M_IX86
  2649. BOOL
  2650. IsMatchingResourceString(
  2651. IN UP_IMAGE_RESOURCE_DIR_STRING_U OldString,
  2652. IN UP_IMAGE_RESOURCE_DIR_STRING_U NewString
  2653. )
  2654. {
  2655. USHORT Length;
  2656. if ( OldString->Length != NewString->Length ) {
  2657. return FALSE;
  2658. }
  2659. Length = OldString->Length;
  2660. while ( Length-- ) {
  2661. if ( OldString->NameString[ Length ] != NewString->NameString[ Length ] ) {
  2662. return FALSE;
  2663. }
  2664. }
  2665. return TRUE;
  2666. }
  2667. VOID
  2668. GetResourceRiftInfoRecursive(
  2669. IN UP_IMAGE_RESOURCE_DIRECTORY OldResDir,
  2670. IN PUCHAR OldResBase,
  2671. IN PUCHAR OldResEnd,
  2672. IN ULONG OldResRva,
  2673. IN UP_IMAGE_RESOURCE_DIRECTORY NewResDir,
  2674. IN PUCHAR NewResBase,
  2675. IN PUCHAR NewResEnd,
  2676. IN ULONG NewResRva,
  2677. IN PRIFT_TABLE RiftTable
  2678. )
  2679. {
  2680. UP_IMAGE_RESOURCE_DIRECTORY_ENTRY OldResEntry;
  2681. UP_IMAGE_RESOURCE_DIRECTORY_ENTRY NewResEntry;
  2682. UP_IMAGE_RESOURCE_DATA_ENTRY OldResData;
  2683. UP_IMAGE_RESOURCE_DATA_ENTRY NewResData;
  2684. ULONG OldResEntryCount;
  2685. ULONG NewResEntryCount;
  2686. if ((( (PUCHAR) OldResDir + sizeof( IMAGE_RESOURCE_DIRECTORY )) < OldResEnd ) &&
  2687. (( (PUCHAR) NewResDir + sizeof( IMAGE_RESOURCE_DIRECTORY )) < NewResEnd )) {
  2688. OldResEntryCount = OldResDir->NumberOfNamedEntries + OldResDir->NumberOfIdEntries;
  2689. OldResEntry = (UP_IMAGE_RESOURCE_DIRECTORY_ENTRY) ( OldResDir + 1 );
  2690. while (( OldResEntryCount > 0 ) && ((PUCHAR)OldResEntry < OldResEnd )) {
  2691. NewResEntryCount = NewResDir->NumberOfNamedEntries + NewResDir->NumberOfIdEntries;
  2692. NewResEntry = (UP_IMAGE_RESOURCE_DIRECTORY_ENTRY)( NewResDir + 1 );
  2693. while ( NewResEntryCount > 0 ) {
  2694. if ( (PUCHAR) NewResEntry > NewResEnd ) {
  2695. NewResEntryCount = 0;
  2696. break;
  2697. }
  2698. if ( !OldResEntry->NameIsString && !NewResEntry->NameIsString &&
  2699. ( OldResEntry->Id == NewResEntry->Id )) {
  2700. break;
  2701. }
  2702. else if (( OldResEntry->NameIsString && NewResEntry->NameIsString ) &&
  2703. IsMatchingResourceString(
  2704. (UP_IMAGE_RESOURCE_DIR_STRING_U)( OldResBase + OldResEntry->NameOffset ),
  2705. (UP_IMAGE_RESOURCE_DIR_STRING_U)( NewResBase + NewResEntry->NameOffset ))) {
  2706. break;
  2707. }
  2708. ++NewResEntry;
  2709. --NewResEntryCount;
  2710. }
  2711. if ( NewResEntryCount > 0 ) {
  2712. if ( OldResEntry->NameIsString ) {
  2713. AddRiftEntryToTable(
  2714. RiftTable,
  2715. OldResRva + OldResEntry->NameOffset,
  2716. NewResRva + NewResEntry->NameOffset
  2717. );
  2718. }
  2719. AddRiftEntryToTable(
  2720. RiftTable,
  2721. OldResRva + OldResEntry->OffsetToDirectory,
  2722. NewResRva + NewResEntry->OffsetToDirectory
  2723. );
  2724. if ( OldResEntry->DataIsDirectory ) {
  2725. GetResourceRiftInfoRecursive(
  2726. (UP_IMAGE_RESOURCE_DIRECTORY)( OldResBase + OldResEntry->OffsetToDirectory ),
  2727. OldResBase,
  2728. OldResEnd,
  2729. OldResRva,
  2730. (UP_IMAGE_RESOURCE_DIRECTORY)( NewResBase + NewResEntry->OffsetToDirectory ),
  2731. NewResBase,
  2732. NewResEnd,
  2733. NewResRva,
  2734. RiftTable
  2735. );
  2736. }
  2737. else {
  2738. OldResData = (UP_IMAGE_RESOURCE_DATA_ENTRY)( OldResBase + OldResEntry->OffsetToData );
  2739. NewResData = (UP_IMAGE_RESOURCE_DATA_ENTRY)( NewResBase + NewResEntry->OffsetToData );
  2740. AddRiftEntryToTable(
  2741. RiftTable,
  2742. OldResData->OffsetToData,
  2743. NewResData->OffsetToData
  2744. );
  2745. }
  2746. }
  2747. ++OldResEntry;
  2748. --OldResEntryCount;
  2749. }
  2750. }
  2751. }
  2752. BOOL
  2753. GetImageNonSymbolRiftInfo(
  2754. IN PUCHAR OldFileMapped,
  2755. IN ULONG OldFileSize,
  2756. IN UP_IMAGE_NT_HEADERS32 OldFileNtHeader,
  2757. IN PUCHAR NewFileMapped,
  2758. IN ULONG NewFileSize,
  2759. IN UP_IMAGE_NT_HEADERS32 NewFileNtHeader,
  2760. IN HANDLE SubAllocator,
  2761. IN PRIFT_TABLE RiftTable
  2762. )
  2763. {
  2764. //
  2765. // Create rifts for sections by section names.
  2766. //
  2767. {
  2768. UP_IMAGE_SECTION_HEADER OldSectionHeader;
  2769. UP_IMAGE_SECTION_HEADER NewSectionHeader;
  2770. ULONG OldSectionCount;
  2771. ULONG NewSectionCount;
  2772. ULONG i, j;
  2773. OldSectionHeader = IMAGE_FIRST_SECTION( OldFileNtHeader );
  2774. OldSectionCount = OldFileNtHeader->FileHeader.NumberOfSections;
  2775. NewSectionHeader = IMAGE_FIRST_SECTION( NewFileNtHeader );
  2776. NewSectionCount = NewFileNtHeader->FileHeader.NumberOfSections;
  2777. ASSERT( sizeof( OldSectionHeader->Name ) == sizeof( DWORDLONG ));
  2778. for ( i = 0; i < OldSectionCount; i++ ) {
  2779. for ( j = 0; j < NewSectionCount; j++ ) {
  2780. if ( *(UNALIGNED DWORDLONG *)OldSectionHeader[ i ].Name ==
  2781. *(UNALIGNED DWORDLONG *)NewSectionHeader[ j ].Name ) {
  2782. //
  2783. // Add a rift entry for this section name match.
  2784. //
  2785. // Note that we create rift values here that are minus
  2786. // one from the actual section boundary because if a
  2787. // symbol exists at the start of the section, its rift
  2788. // entry would conflict with this section entry.
  2789. //
  2790. AddRiftEntryToTable(
  2791. RiftTable,
  2792. OldSectionHeader[ i ].VirtualAddress - 1,
  2793. NewSectionHeader[ i ].VirtualAddress - 1
  2794. );
  2795. break;
  2796. }
  2797. }
  2798. }
  2799. }
  2800. //
  2801. // Create rifts for image directories.
  2802. //
  2803. {
  2804. ULONG i, n;
  2805. n = MIN( OldFileNtHeader->OptionalHeader.NumberOfRvaAndSizes,
  2806. NewFileNtHeader->OptionalHeader.NumberOfRvaAndSizes );
  2807. for ( i = 0; i < n; i++ ) {
  2808. if (( OldFileNtHeader->OptionalHeader.DataDirectory[ i ].VirtualAddress ) &&
  2809. ( OldFileNtHeader->OptionalHeader.DataDirectory[ i ].Size ) &&
  2810. ( NewFileNtHeader->OptionalHeader.DataDirectory[ i ].VirtualAddress ) &&
  2811. ( NewFileNtHeader->OptionalHeader.DataDirectory[ i ].Size )) {
  2812. AddRiftEntryToTable(
  2813. RiftTable,
  2814. OldFileNtHeader->OptionalHeader.DataDirectory[ i ].VirtualAddress,
  2815. NewFileNtHeader->OptionalHeader.DataDirectory[ i ].VirtualAddress
  2816. );
  2817. }
  2818. }
  2819. }
  2820. //
  2821. // Create rifts for image export directory
  2822. //
  2823. {
  2824. UP_IMAGE_EXPORT_DIRECTORY OldExportDir;
  2825. UP_IMAGE_EXPORT_DIRECTORY NewExportDir;
  2826. ULONG OldExportIndex;
  2827. ULONG NewExportIndex;
  2828. ULONG OldExportNameCount;
  2829. ULONG NewExportNameCount;
  2830. ULONG OldExportFunctionCount;
  2831. ULONG NewExportFunctionCount;
  2832. ULONG UNALIGNED* OldExportFunctionArray;
  2833. ULONG UNALIGNED* NewExportFunctionArray;
  2834. USHORT UNALIGNED* OldExportNameToOrdinal;
  2835. USHORT UNALIGNED* NewExportNameToOrdinal;
  2836. ULONG UNALIGNED* OldExportNameArray;
  2837. ULONG UNALIGNED* NewExportNameArray;
  2838. LPSTR OldExportName;
  2839. LPSTR NewExportName;
  2840. ULONG OldOrdinal;
  2841. ULONG NewOrdinal;
  2842. LONG OrdinalBaseNewToOld;
  2843. PBYTE NewExportOrdinalNameExists;
  2844. PSYMBOL_NODE NewExportSymbolNode;
  2845. SYMBOL_TREE NewExportNameTree;
  2846. OldExportDir = ImageDirectoryMappedAddress(
  2847. OldFileNtHeader,
  2848. IMAGE_DIRECTORY_ENTRY_EXPORT,
  2849. NULL,
  2850. OldFileMapped,
  2851. OldFileSize
  2852. );
  2853. NewExportDir = ImageDirectoryMappedAddress(
  2854. NewFileNtHeader,
  2855. IMAGE_DIRECTORY_ENTRY_EXPORT,
  2856. NULL,
  2857. NewFileMapped,
  2858. NewFileSize
  2859. );
  2860. if (( OldExportDir ) && ( NewExportDir )) {
  2861. AddRiftEntryToTable( RiftTable, (ULONG)( OldExportDir->Name ), (ULONG)( NewExportDir->Name ));
  2862. AddRiftEntryToTable( RiftTable, (ULONG)( OldExportDir->AddressOfFunctions ), (ULONG)( NewExportDir->AddressOfFunctions ));
  2863. AddRiftEntryToTable( RiftTable, (ULONG)( OldExportDir->AddressOfNames ), (ULONG)( NewExportDir->AddressOfNames ));
  2864. AddRiftEntryToTable( RiftTable, (ULONG)( OldExportDir->AddressOfNameOrdinals ), (ULONG)( NewExportDir->AddressOfNameOrdinals ));
  2865. //
  2866. // Now build a tree of new export names, then walk old export names
  2867. // looking for matches in tree of new export names.
  2868. //
  2869. SymRBInitTree(
  2870. &NewExportNameTree,
  2871. SubAllocator
  2872. );
  2873. //
  2874. // First insert new export names.
  2875. //
  2876. NewExportNameCount = NewExportDir->NumberOfNames;
  2877. NewExportFunctionCount = NewExportDir->NumberOfFunctions;
  2878. NewExportFunctionArray = ImageRvaToMappedAddress( NewFileNtHeader, (ULONG) NewExportDir->AddressOfFunctions, NewFileMapped, NewFileSize );
  2879. NewExportNameToOrdinal = ImageRvaToMappedAddress( NewFileNtHeader, (ULONG) NewExportDir->AddressOfNameOrdinals, NewFileMapped, NewFileSize );
  2880. NewExportNameArray = ImageRvaToMappedAddress( NewFileNtHeader, (ULONG) NewExportDir->AddressOfNames, NewFileMapped, NewFileSize );
  2881. if ( NewExportNameArray ) {
  2882. for ( NewExportIndex = 0; NewExportIndex < NewExportNameCount; NewExportIndex++ ) {
  2883. if ( NewExportNameArray[ NewExportIndex ] ) {
  2884. NewExportName = ImageRvaToMappedAddress( NewFileNtHeader, NewExportNameArray[ NewExportIndex ], NewFileMapped, NewFileSize );
  2885. if ( NewExportName ) {
  2886. SymRBInsert( &NewExportNameTree, NewExportName, NewExportIndex );
  2887. }
  2888. }
  2889. }
  2890. }
  2891. //
  2892. // Walk old export names and match them up.
  2893. //
  2894. OldExportNameCount = OldExportDir->NumberOfNames;
  2895. OldExportFunctionCount = OldExportDir->NumberOfFunctions;
  2896. OldExportFunctionArray = ImageRvaToMappedAddress( OldFileNtHeader, (ULONG) OldExportDir->AddressOfFunctions, OldFileMapped, OldFileSize );
  2897. OldExportNameToOrdinal = ImageRvaToMappedAddress( OldFileNtHeader, (ULONG) OldExportDir->AddressOfNameOrdinals, OldFileMapped, OldFileSize );
  2898. OldExportNameArray = ImageRvaToMappedAddress( OldFileNtHeader, (ULONG) OldExportDir->AddressOfNames, OldFileMapped, OldFileSize );
  2899. if ( OldExportNameArray ) {
  2900. for ( OldExportIndex = 0; OldExportIndex < OldExportNameCount; OldExportIndex++ ) {
  2901. if ( OldExportNameArray[ OldExportIndex ] ) {
  2902. OldExportName = ImageRvaToMappedAddress( OldFileNtHeader, OldExportNameArray[ OldExportIndex ], OldFileMapped, OldFileSize );
  2903. if ( OldExportName ) {
  2904. NewExportSymbolNode = SymRBFind( &NewExportNameTree, OldExportName );
  2905. if ( NewExportSymbolNode ) {
  2906. //
  2907. // Found a name match. The Rva field in the
  2908. // symbol node contains the index into the
  2909. // NewExportNameArray.
  2910. //
  2911. // This match gives us two rift entries: one
  2912. // for the locations of the names themselves,
  2913. // and another for the locations of the
  2914. // functions corresponding to those names.
  2915. //
  2916. NewExportIndex = NewExportSymbolNode->Rva;
  2917. AddRiftEntryToTable(
  2918. RiftTable,
  2919. OldExportNameArray[ OldExportIndex ],
  2920. NewExportNameArray[ NewExportIndex ]
  2921. );
  2922. if ( OldExportNameToOrdinal && NewExportNameToOrdinal ) {
  2923. OldOrdinal = OldExportNameToOrdinal[ OldExportIndex ];
  2924. NewOrdinal = NewExportNameToOrdinal[ NewExportIndex ];
  2925. if (( OldOrdinal < OldExportFunctionCount ) &&
  2926. ( NewOrdinal < NewExportFunctionCount )) {
  2927. AddRiftEntryToTable(
  2928. RiftTable,
  2929. OldExportFunctionArray[ OldOrdinal ],
  2930. NewExportFunctionArray[ NewOrdinal ]
  2931. );
  2932. }
  2933. }
  2934. }
  2935. }
  2936. }
  2937. }
  2938. }
  2939. //
  2940. // Now use ordinals to match any exports that don't have names.
  2941. // We use the NameToOrdinal table to determine if a name exists.
  2942. // For all ordinals that don't have a NameToOrdinal entry, we
  2943. // create a match.
  2944. //
  2945. if (( NewExportFunctionArray ) && ( NewExportNameToOrdinal )) {
  2946. NewExportOrdinalNameExists = SubAllocate( SubAllocator, NewExportFunctionCount );
  2947. if ( NewExportOrdinalNameExists != NULL ) {
  2948. for ( NewExportIndex = 0; NewExportIndex < NewExportNameCount; NewExportIndex++ ) {
  2949. NewOrdinal = NewExportNameToOrdinal[ NewExportIndex ];
  2950. if ( NewOrdinal < NewExportFunctionCount ) {
  2951. NewExportOrdinalNameExists[ NewOrdinal ] = TRUE;
  2952. }
  2953. }
  2954. OrdinalBaseNewToOld = (LONG)NewExportDir->Base - (LONG)OldExportDir->Base;
  2955. for ( NewOrdinal = 0; NewOrdinal < NewExportFunctionCount; NewOrdinal++ ) {
  2956. if ( ! NewExportOrdinalNameExists[ NewOrdinal ] ) {
  2957. OldOrdinal = NewOrdinal + OrdinalBaseNewToOld;
  2958. if ( OldOrdinal < OldExportFunctionCount ) {
  2959. AddRiftEntryToTable(
  2960. RiftTable,
  2961. OldExportFunctionArray[ OldOrdinal ],
  2962. NewExportFunctionArray[ NewOrdinal ]
  2963. );
  2964. }
  2965. }
  2966. }
  2967. }
  2968. }
  2969. }
  2970. }
  2971. //
  2972. // Create rifts for image import directory
  2973. //
  2974. {
  2975. UP_IMAGE_IMPORT_DESCRIPTOR OldImportDir;
  2976. UP_IMAGE_IMPORT_DESCRIPTOR NewImportDir;
  2977. ULONG OldImportDirRva;
  2978. ULONG NewImportDirRva;
  2979. ULONG OldImportDirIndex;
  2980. ULONG NewImportDirIndex;
  2981. LPSTR OldImportDllName;
  2982. LPSTR NewImportDllName;
  2983. LPSTR OldImportDllNameLowercase;
  2984. LPSTR NewImportDllNameLowercase;
  2985. UP_IMAGE_THUNK_DATA32 OldImportThunk;
  2986. UP_IMAGE_THUNK_DATA32 NewImportThunk;
  2987. UP_IMAGE_THUNK_DATA32 OldImportOriginalThunk;
  2988. UP_IMAGE_THUNK_DATA32 NewImportOriginalThunk;
  2989. ULONG OldImportThunkIndex;
  2990. ULONG NewImportThunkIndex;
  2991. UP_IMAGE_IMPORT_BY_NAME OldImportByName;
  2992. UP_IMAGE_IMPORT_BY_NAME NewImportByName;
  2993. LPSTR OldImportName;
  2994. LPSTR NewImportName;
  2995. SYMBOL_TREE NewImportDllNameTree;
  2996. SYMBOL_TREE NewImportFunctionNameTree;
  2997. PSYMBOL_NODE NewImportDllSymbolNode;
  2998. PSYMBOL_NODE NewImportFunctionSymbolNode;
  2999. OldImportDirRva = ImageDirectoryRvaAndSize(
  3000. OldFileNtHeader,
  3001. IMAGE_DIRECTORY_ENTRY_IMPORT,
  3002. NULL
  3003. );
  3004. NewImportDirRva = ImageDirectoryRvaAndSize(
  3005. NewFileNtHeader,
  3006. IMAGE_DIRECTORY_ENTRY_IMPORT,
  3007. NULL
  3008. );
  3009. OldImportDir = ImageDirectoryMappedAddress(
  3010. OldFileNtHeader,
  3011. IMAGE_DIRECTORY_ENTRY_IMPORT,
  3012. NULL,
  3013. OldFileMapped,
  3014. OldFileSize
  3015. );
  3016. NewImportDir = ImageDirectoryMappedAddress(
  3017. NewFileNtHeader,
  3018. IMAGE_DIRECTORY_ENTRY_IMPORT,
  3019. NULL,
  3020. NewFileMapped,
  3021. NewFileSize
  3022. );
  3023. if (( OldImportDir ) && ( NewImportDir )) {
  3024. //
  3025. // Now build a tree of new import names, then walk old export names
  3026. // looking for matches in tree of new import names.
  3027. //
  3028. SymRBInitTree(
  3029. &NewImportDllNameTree,
  3030. SubAllocator
  3031. );
  3032. SymRBInitTree(
  3033. &NewImportFunctionNameTree,
  3034. SubAllocator
  3035. );
  3036. for ( NewImportDirIndex = 0; NewImportDir[ NewImportDirIndex ].Characteristics; NewImportDirIndex++ ) {
  3037. if ( NewImportDir[ NewImportDirIndex ].Name ) {
  3038. NewImportDllName = ImageRvaToMappedAddress( NewFileNtHeader, NewImportDir[ NewImportDirIndex ].Name, NewFileMapped, NewFileSize );
  3039. if ( NewImportDllName ) {
  3040. NewImportDllNameLowercase = MySubAllocStrDup( SubAllocator, NewImportDllName );
  3041. if ( NewImportDllNameLowercase ) {
  3042. MyLowercase( NewImportDllNameLowercase );
  3043. SymRBInsert( &NewImportDllNameTree, NewImportDllNameLowercase, NewImportDirIndex );
  3044. NewImportThunk = ImageRvaToMappedAddress( NewFileNtHeader, (ULONG)NewImportDir[ NewImportDirIndex ].FirstThunk, NewFileMapped, NewFileSize );
  3045. if ( NewImportThunk ) {
  3046. for ( NewImportThunkIndex = 0; NewImportThunk[ NewImportThunkIndex ].u1.Ordinal; NewImportThunkIndex++ ) {
  3047. if ( ! IMAGE_SNAP_BY_ORDINAL32( NewImportThunk[ NewImportThunkIndex ].u1.Ordinal )) {
  3048. NewImportByName = ImageRvaToMappedAddress( NewFileNtHeader, (ULONG)NewImportThunk[ NewImportThunkIndex ].u1.AddressOfData, NewFileMapped, NewFileSize );
  3049. if ( NewImportByName ) {
  3050. NewImportName = MySubAllocStrDupAndCat(
  3051. SubAllocator,
  3052. NewImportDllNameLowercase,
  3053. (LPSTR)NewImportByName->Name,
  3054. '!'
  3055. );
  3056. if ( NewImportName ) {
  3057. SymRBInsert( &NewImportFunctionNameTree, NewImportName, NewImportThunkIndex );
  3058. }
  3059. }
  3060. }
  3061. }
  3062. }
  3063. }
  3064. }
  3065. }
  3066. }
  3067. for ( OldImportDirIndex = 0; OldImportDir[ OldImportDirIndex ].Characteristics; OldImportDirIndex++ ) {
  3068. if ( OldImportDir[ OldImportDirIndex ].Name ) {
  3069. OldImportDllName = ImageRvaToMappedAddress( OldFileNtHeader, OldImportDir[ OldImportDirIndex ].Name, OldFileMapped, OldFileSize );
  3070. if ( OldImportDllName ) {
  3071. OldImportDllNameLowercase = MySubAllocStrDup( SubAllocator, OldImportDllName );
  3072. if ( OldImportDllNameLowercase ) {
  3073. MyLowercase( OldImportDllNameLowercase );
  3074. NewImportDllSymbolNode = SymRBFind( &NewImportDllNameTree, OldImportDllNameLowercase );
  3075. if ( NewImportDllSymbolNode ) {
  3076. //
  3077. // Found a matching dll import descriptor.
  3078. // This will give us four rifts: one for the
  3079. // descriptor itself, another for the
  3080. // dll name referenced by the descriptor, and
  3081. // the FirstThunk and OriginalFirstThunk
  3082. // arrays.
  3083. //
  3084. // The index of the new import descriptor is
  3085. // stored in the Rva field of the node.
  3086. //
  3087. NewImportDirIndex = NewImportDllSymbolNode->Rva;
  3088. AddRiftEntryToTable(
  3089. RiftTable,
  3090. OldImportDirRva + ( OldImportDirIndex * sizeof( IMAGE_IMPORT_DESCRIPTOR )),
  3091. NewImportDirRva + ( NewImportDirIndex * sizeof( IMAGE_IMPORT_DESCRIPTOR ))
  3092. );
  3093. AddRiftEntryToTable(
  3094. RiftTable,
  3095. (ULONG)OldImportDir[ OldImportDirIndex ].Name,
  3096. (ULONG)NewImportDir[ NewImportDirIndex ].Name
  3097. );
  3098. AddRiftEntryToTable(
  3099. RiftTable,
  3100. (ULONG)OldImportDir[ OldImportDirIndex ].OriginalFirstThunk,
  3101. (ULONG)NewImportDir[ NewImportDirIndex ].OriginalFirstThunk
  3102. );
  3103. AddRiftEntryToTable(
  3104. RiftTable,
  3105. (ULONG)OldImportDir[ OldImportDirIndex ].FirstThunk,
  3106. (ULONG)NewImportDir[ NewImportDirIndex ].FirstThunk
  3107. );
  3108. OldImportThunk = ImageRvaToMappedAddress( OldFileNtHeader, (ULONG)OldImportDir[ OldImportDirIndex ].FirstThunk, OldFileMapped, OldFileSize );
  3109. if ( OldImportThunk ) {
  3110. for ( OldImportThunkIndex = 0; OldImportThunk[ OldImportThunkIndex ].u1.Ordinal; OldImportThunkIndex++ ) {
  3111. if ( ! IMAGE_SNAP_BY_ORDINAL32( OldImportThunk[ OldImportThunkIndex ].u1.Ordinal )) {
  3112. OldImportByName = ImageRvaToMappedAddress( OldFileNtHeader, (ULONG)OldImportThunk[ OldImportThunkIndex ].u1.AddressOfData, OldFileMapped, OldFileSize );
  3113. if ( OldImportByName ) {
  3114. OldImportName = MySubAllocStrDupAndCat(
  3115. SubAllocator,
  3116. OldImportDllNameLowercase,
  3117. (LPSTR)OldImportByName->Name,
  3118. '!'
  3119. );
  3120. if ( OldImportName ) {
  3121. NewImportFunctionSymbolNode = SymRBFind( &NewImportFunctionNameTree, OldImportName );
  3122. if ( NewImportFunctionSymbolNode ) {
  3123. //
  3124. // Found a matching import function name.
  3125. // This will give us two rifts: one for the
  3126. // FirstThunk arrays and another for the
  3127. // OriginalFirstThunk arrays.
  3128. //
  3129. // The index of the new import thunk is
  3130. // stored in the Rva field of the node.
  3131. //
  3132. NewImportThunkIndex = NewImportFunctionSymbolNode->Rva;
  3133. NewImportThunk = ImageRvaToMappedAddress( NewFileNtHeader, (ULONG)NewImportDir[ NewImportDirIndex ].FirstThunk, NewFileMapped, NewFileSize );
  3134. if ( NewImportThunk ) {
  3135. AddRiftEntryToTable(
  3136. RiftTable,
  3137. (ULONG)OldImportThunk[ OldImportThunkIndex ].u1.AddressOfData,
  3138. (ULONG)NewImportThunk[ NewImportThunkIndex ].u1.AddressOfData
  3139. );
  3140. }
  3141. OldImportOriginalThunk = ImageRvaToMappedAddress( OldFileNtHeader, (ULONG)OldImportDir[ OldImportDirIndex ].OriginalFirstThunk, OldFileMapped, OldFileSize );
  3142. NewImportOriginalThunk = ImageRvaToMappedAddress( NewFileNtHeader, (ULONG)NewImportDir[ NewImportDirIndex ].OriginalFirstThunk, NewFileMapped, NewFileSize );
  3143. if ( OldImportOriginalThunk && NewImportOriginalThunk ) {
  3144. AddRiftEntryToTable(
  3145. RiftTable,
  3146. (ULONG)OldImportOriginalThunk[ OldImportThunkIndex ].u1.AddressOfData,
  3147. (ULONG)NewImportOriginalThunk[ NewImportThunkIndex ].u1.AddressOfData
  3148. );
  3149. }
  3150. }
  3151. }
  3152. }
  3153. }
  3154. }
  3155. }
  3156. }
  3157. }
  3158. }
  3159. }
  3160. }
  3161. }
  3162. }
  3163. //
  3164. // Create rift entries for resources
  3165. //
  3166. {
  3167. PUCHAR OldResBase, NewResBase;
  3168. ULONG OldResSize, NewResSize;
  3169. ULONG OldResRva, NewResRva;
  3170. OldResBase = ImageDirectoryMappedAddress(
  3171. OldFileNtHeader,
  3172. IMAGE_DIRECTORY_ENTRY_RESOURCE,
  3173. &OldResSize,
  3174. OldFileMapped,
  3175. OldFileSize
  3176. );
  3177. NewResBase = ImageDirectoryMappedAddress(
  3178. NewFileNtHeader,
  3179. IMAGE_DIRECTORY_ENTRY_RESOURCE,
  3180. &NewResSize,
  3181. NewFileMapped,
  3182. NewFileSize
  3183. );
  3184. if ( OldResBase && NewResBase ) {
  3185. OldResRva = ImageDirectoryRvaAndSize( OldFileNtHeader, IMAGE_DIRECTORY_ENTRY_RESOURCE, NULL );
  3186. NewResRva = ImageDirectoryRvaAndSize( NewFileNtHeader, IMAGE_DIRECTORY_ENTRY_RESOURCE, NULL );
  3187. GetResourceRiftInfoRecursive(
  3188. (UP_IMAGE_RESOURCE_DIRECTORY) OldResBase,
  3189. OldResBase,
  3190. OldResBase + OldResSize,
  3191. OldResRva,
  3192. (UP_IMAGE_RESOURCE_DIRECTORY) NewResBase,
  3193. NewResBase,
  3194. NewResBase + NewResSize,
  3195. NewResRva,
  3196. RiftTable
  3197. );
  3198. }
  3199. }
  3200. //
  3201. // Gen rift info for other non-symbol stuff here.
  3202. //
  3203. #ifdef TESTCODE
  3204. printf( "\r%9d non-symbol rift entries\n", RiftTable->RiftEntryCount );
  3205. #endif
  3206. return TRUE;
  3207. }
  3208. VOID
  3209. MyUndecorateSymbol(
  3210. IN LPCSTR DecoratedSymbol,
  3211. OUT LPSTR UndecoratedSymbol,
  3212. IN DWORD BufferSize
  3213. )
  3214. {
  3215. LPCSTR d;
  3216. LPCSTR e;
  3217. ULONG Len;
  3218. ULONG Ext;
  3219. d = DecoratedSymbol;
  3220. if (( d[ 0 ] == '.' ) &&
  3221. ( d[ 1 ] == '.' ) &&
  3222. ( d[ 2 ] == '?' )) {
  3223. d += 2;
  3224. }
  3225. if ( *d == '?' ) {
  3226. *UndecoratedSymbol = 0; // in case UnDecorateSymbolName fails
  3227. Imagehlp.UnDecorateSymbolName( d, UndecoratedSymbol, BufferSize, UNDNAME_NAME_ONLY );
  3228. //
  3229. // UnDecorateSymbolName will strip any trailing '_nnn' (from BBT omap
  3230. // info), but we want to preserved it. Check for that pattern in the
  3231. // original, and if found, append it to the new string.
  3232. //
  3233. d += strlen( d + 1 ); // point d to last character in string
  3234. if (( *d >= '0' ) && ( *d <= '9' )) {
  3235. do {
  3236. --d;
  3237. }
  3238. while (( *d >= '0' ) && ( *d <= '9' ));
  3239. if ( *d == '_' ) {
  3240. //
  3241. // Matches the '_nnn' pattern, append to new string.
  3242. //
  3243. if (( strlen( UndecoratedSymbol ) + strlen( d )) < ( BufferSize - 1 )) {
  3244. strcat( UndecoratedSymbol, d );
  3245. }
  3246. }
  3247. }
  3248. }
  3249. else {
  3250. //
  3251. // Strip any preceding '_' or '@'.
  3252. //
  3253. if (( *d == '_' ) || ( *d == '@' )) {
  3254. ++d;
  3255. }
  3256. //
  3257. // Find end of name as either terminator or '@nn'.
  3258. //
  3259. for ( e = d; ( *e ) && ( *e != '@' ); ) {
  3260. ++e;
  3261. }
  3262. //
  3263. // Copy as much of name as will fit in the buffer.
  3264. //
  3265. Len = (ULONG)( e - d );
  3266. if ( Len > ( BufferSize - 1 )) {
  3267. Len = ( BufferSize - 1 );
  3268. }
  3269. memcpy( UndecoratedSymbol, d, Len );
  3270. if ( *e == '@' ) {
  3271. //
  3272. // Skip '@nn' to append remainder of symbol
  3273. //
  3274. do {
  3275. ++e;
  3276. }
  3277. while (( *e >= '0' ) && ( *e <= '9' ));
  3278. d = e;
  3279. while ( *e ) {
  3280. ++e;
  3281. }
  3282. //
  3283. // Now 'd' points to first character after '@nn' and 'e' points
  3284. // to end of the string. If the extension will fit in the buffer,
  3285. // append it.
  3286. //
  3287. Ext = (ULONG)( e - d );
  3288. if (( Len + Ext ) < ( BufferSize - 1 )) {
  3289. memcpy( UndecoratedSymbol + Len, d, Ext );
  3290. }
  3291. Len += Ext;
  3292. }
  3293. //
  3294. // Terminate the string.
  3295. //
  3296. UndecoratedSymbol[ Len ] = 0;
  3297. }
  3298. }
  3299. BOOL
  3300. UndecorateSymbolAndAddToTree(
  3301. IN LPCSTR SymbolName,
  3302. IN ULONG Rva,
  3303. IN PSYMBOL_TREE SymbolTree
  3304. )
  3305. {
  3306. ULONG SymbolNameSize = (ULONG) strlen( SymbolName ) + 1;
  3307. LPSTR UndecoratedName = _alloca( SymbolNameSize );
  3308. PSYMBOL_NODE SymbolNode;
  3309. MyUndecorateSymbol(
  3310. SymbolName,
  3311. UndecoratedName,
  3312. SymbolNameSize
  3313. );
  3314. SymbolNode = SymRBInsert(
  3315. SymbolTree,
  3316. UndecoratedName,
  3317. Rva
  3318. );
  3319. return ( SymbolNode != NULL );
  3320. }
  3321. BOOL
  3322. CALLBACK
  3323. NewFileEnumSymbolsCallback(
  3324. LPSTR SymbolName,
  3325. ULONG_PTR SymbolAddr,
  3326. ULONG SymbolSize,
  3327. PVOID Context
  3328. )
  3329. {
  3330. PSYMBOL_CONTEXT SymbolContext = Context;
  3331. PSYMBOL_NODE SymbolNode;
  3332. ULONG NewRva;
  3333. UNREFERENCED_PARAMETER( SymbolSize );
  3334. #ifdef TESTCODE
  3335. if ( SymbolContext->OutFile != INVALID_HANDLE_VALUE ) {
  3336. CHAR TextBuffer[ 16 + MAX_SYMBOL_NAME_LENGTH ];
  3337. CHAR Discarded;
  3338. DWORD Actual;
  3339. Discarded = 'X';
  3340. NewRva = SymbolAddr;
  3341. if ( NewRva > SymbolContext->NewImageBase ) {
  3342. NewRva -= SymbolContext->NewImageBase;
  3343. Discarded = ' ';
  3344. }
  3345. sprintf( TextBuffer, "%08X %c %s\r\n", NewRva, Discarded, SymbolName );
  3346. WriteFile( SymbolContext->OutFile, TextBuffer, strlen( TextBuffer ), &Actual, NULL );
  3347. }
  3348. #endif // TESTCODE
  3349. if ( SymbolAddr > SymbolContext->NewImageBase ) {
  3350. NewRva = (ULONG)( SymbolAddr - SymbolContext->NewImageBase );
  3351. SymbolNode = SymRBInsert(
  3352. &SymbolContext->NewDecoratedSymbolTree,
  3353. SymbolName,
  3354. NewRva
  3355. );
  3356. return ( SymbolNode != NULL );
  3357. }
  3358. return TRUE;
  3359. }
  3360. BOOL
  3361. CALLBACK
  3362. OldFileEnumSymbolsCallback(
  3363. LPSTR SymbolName,
  3364. ULONG_PTR SymbolAddr,
  3365. ULONG SymbolSize,
  3366. PVOID Context
  3367. )
  3368. {
  3369. PSYMBOL_CONTEXT SymbolContext = Context;
  3370. PSYMBOL_NODE SymbolNode;
  3371. ULONG OldRva;
  3372. UNREFERENCED_PARAMETER( SymbolSize );
  3373. #ifdef TESTCODE
  3374. if ( SymbolContext->OutFile != INVALID_HANDLE_VALUE ) {
  3375. CHAR TextBuffer[ 16 + MAX_SYMBOL_NAME_LENGTH ];
  3376. CHAR Discarded;
  3377. DWORD Actual;
  3378. Discarded = 'X';
  3379. OldRva = SymbolAddr;
  3380. if ( OldRva > SymbolContext->OldImageBase ) {
  3381. OldRva -= SymbolContext->OldImageBase;
  3382. Discarded = ' ';
  3383. }
  3384. sprintf( TextBuffer, "%08X %c %s\r\n", OldRva, Discarded, SymbolName );
  3385. WriteFile( SymbolContext->OutFile, TextBuffer, strlen( TextBuffer ), &Actual, NULL );
  3386. }
  3387. #endif // TESTCODE
  3388. if ( SymbolAddr > SymbolContext->OldImageBase ) {
  3389. OldRva = (ULONG)( SymbolAddr - SymbolContext->OldImageBase );
  3390. SymbolNode = SymRBFind(
  3391. &SymbolContext->NewDecoratedSymbolTree,
  3392. SymbolName
  3393. );
  3394. if ( SymbolNode ) {
  3395. AddRiftEntryToTable( SymbolContext->RiftTable, OldRva, SymbolNode->Rva );
  3396. SymbolNode->Hit = 1;
  3397. #ifdef TESTCODE
  3398. CountDecoratedMatches++;
  3399. #endif // TESTCODE
  3400. }
  3401. else {
  3402. //
  3403. // Didn't find matching new symbol. Build a tree of unmatched
  3404. // old symbols with UNdecorated names. Later we'll match up
  3405. // remaining unmatched new symbols to these unmatched old symbols
  3406. // by their undecorated names.
  3407. //
  3408. if ( SymbolContext->SymbolOptionFlags & PATCH_SYMBOL_UNDECORATED_TOO ) {
  3409. return UndecorateSymbolAndAddToTree(
  3410. SymbolName,
  3411. OldRva,
  3412. &SymbolContext->OldUndecoratedSymbolTree
  3413. );
  3414. }
  3415. }
  3416. }
  3417. return TRUE;
  3418. }
  3419. BOOL
  3420. MatchRemainingSymbolsThisNode(
  3421. IN PSYMBOL_NODE NewDecoratedSymbolNode,
  3422. IN PSYMBOL_TREE NewUndecoratedSymbolTree,
  3423. IN PSYMBOL_TREE OldUndecoratedSymbolTree,
  3424. IN PRIFT_TABLE RiftTable
  3425. )
  3426. {
  3427. if ( ! NewDecoratedSymbolNode->Hit ) {
  3428. ULONG SymbolNameSize = (ULONG) strlen( NewDecoratedSymbolNode->SymbolName ) + 1;
  3429. LPSTR NewUndecoratedName = _alloca( SymbolNameSize );
  3430. PSYMBOL_NODE NewUndecoratedSymbolNode;
  3431. PSYMBOL_NODE OldUndecoratedSymbolNode;
  3432. MyUndecorateSymbol(
  3433. NewDecoratedSymbolNode->SymbolName,
  3434. NewUndecoratedName,
  3435. SymbolNameSize
  3436. );
  3437. OldUndecoratedSymbolNode = SymRBFind(
  3438. OldUndecoratedSymbolTree,
  3439. NewUndecoratedName
  3440. );
  3441. if ( OldUndecoratedSymbolNode ) {
  3442. AddRiftEntryToTable(
  3443. RiftTable,
  3444. OldUndecoratedSymbolNode->Rva,
  3445. NewDecoratedSymbolNode->Rva
  3446. );
  3447. OldUndecoratedSymbolNode->Hit = 1;
  3448. #ifdef TESTCODE
  3449. CountUndecoratedMatches++;
  3450. #endif // TESTCODE
  3451. }
  3452. else {
  3453. //
  3454. // This new symbol has no match in the old symbol tree. Build a
  3455. // tree of unmatched new undecorated symbols.
  3456. //
  3457. NewUndecoratedSymbolNode = SymRBInsert(
  3458. NewUndecoratedSymbolTree,
  3459. NewUndecoratedName,
  3460. NewDecoratedSymbolNode->Rva
  3461. );
  3462. return ( NewUndecoratedSymbolNode != NULL );
  3463. }
  3464. }
  3465. return TRUE;
  3466. }
  3467. BOOL
  3468. MatchRemainingSymbolsRecursive(
  3469. IN PSYMBOL_NODE NewDecoratedSymbolNode,
  3470. IN PSYMBOL_TREE NewUndecoratedSymbolTree,
  3471. IN PSYMBOL_TREE OldUndecoratedSymbolTree,
  3472. IN PRIFT_TABLE RiftTable
  3473. )
  3474. {
  3475. if ( NewDecoratedSymbolNode == RBNIL ) {
  3476. return TRUE;
  3477. }
  3478. return ( MatchRemainingSymbolsRecursive( NewDecoratedSymbolNode->Left, NewUndecoratedSymbolTree, OldUndecoratedSymbolTree, RiftTable ) &&
  3479. MatchRemainingSymbolsRecursive( NewDecoratedSymbolNode->Right, NewUndecoratedSymbolTree, OldUndecoratedSymbolTree, RiftTable ) &&
  3480. MatchRemainingSymbolsThisNode( NewDecoratedSymbolNode, NewUndecoratedSymbolTree, OldUndecoratedSymbolTree, RiftTable ));
  3481. }
  3482. #ifdef TESTCODE
  3483. VOID
  3484. DumpUnHitSymbolNode(
  3485. IN PSYMBOL_NODE SymbolNode,
  3486. IN HANDLE hFile
  3487. )
  3488. {
  3489. CHAR TextBuffer[ 16 + MAX_SYMBOL_NAME_LENGTH ];
  3490. DWORD Actual;
  3491. if ( ! SymbolNode->Hit ) {
  3492. sprintf( TextBuffer, "%08X %s\r\n", SymbolNode->Rva, SymbolNode->SymbolName );
  3493. WriteFile( hFile, TextBuffer, strlen( TextBuffer ), &Actual, NULL );
  3494. }
  3495. }
  3496. VOID
  3497. DumpUnHitSymbolNodesRecursive(
  3498. IN PSYMBOL_NODE SymbolNode,
  3499. IN HANDLE hFile
  3500. )
  3501. {
  3502. if ( SymbolNode == RBNIL ) {
  3503. return;
  3504. }
  3505. //
  3506. // The tree is in hash order, not Rva order, so the output will appear
  3507. // to be in random order (easily solved with sort.exe utility).
  3508. //
  3509. DumpUnHitSymbolNode( SymbolNode, hFile );
  3510. DumpUnHitSymbolNodesRecursive( SymbolNode->Left, hFile );
  3511. DumpUnHitSymbolNodesRecursive( SymbolNode->Right, hFile );
  3512. }
  3513. VOID
  3514. DumpUnHitSymbolNodes(
  3515. IN PSYMBOL_TREE SymbolTree,
  3516. IN LPCSTR DumpFileName
  3517. )
  3518. {
  3519. HANDLE hFile;
  3520. hFile = CreateFile(
  3521. DumpFileName,
  3522. GENERIC_WRITE,
  3523. FILE_SHARE_READ,
  3524. NULL,
  3525. CREATE_ALWAYS,
  3526. FILE_ATTRIBUTE_NORMAL,
  3527. NULL
  3528. );
  3529. if ( hFile != INVALID_HANDLE_VALUE ) {
  3530. DumpUnHitSymbolNodesRecursive( SymbolTree->Root, hFile );
  3531. CloseHandle( hFile );
  3532. }
  3533. }
  3534. #endif // TESTCODE
  3535. BOOL
  3536. MatchRemainingSymbols(
  3537. IN PSYMBOL_TREE NewDecoratedSymbolTree,
  3538. IN PSYMBOL_TREE NewUndecoratedSymbolTree,
  3539. IN PSYMBOL_TREE OldUndecoratedSymbolTree,
  3540. IN PRIFT_TABLE RiftTable
  3541. )
  3542. {
  3543. BOOL Success;
  3544. //
  3545. // Walk old tree, for each unmatched symbol, undecorate it and try to
  3546. // find match in the undecorated new symbol tree. If it fails to match,
  3547. // add it to the old undecorated tree.
  3548. //
  3549. Success = MatchRemainingSymbolsRecursive(
  3550. NewDecoratedSymbolTree->Root,
  3551. NewUndecoratedSymbolTree,
  3552. OldUndecoratedSymbolTree,
  3553. RiftTable
  3554. );
  3555. if ( Success ) {
  3556. //
  3557. // Now we have remaining unmatched undecorated symbols in the
  3558. // OldUndecoratedSymbolTree and NewUndecoratedSymbolTree.
  3559. //
  3560. // Here is an opportunity to do soft name matching, like for
  3561. // BBT omap generated symbol names (have trailing '_nnn').
  3562. // Unfortunately, current versions of imagehlp append an '_nnn'
  3563. // value that is useless becaue it is not the offset from the
  3564. // start of the function.
  3565. //
  3566. #ifdef TESTCODE
  3567. DumpUnHitSymbolNodes( OldUndecoratedSymbolTree, "UnmatchedOldSymbols.out" );
  3568. DumpUnHitSymbolNodes( NewUndecoratedSymbolTree, "UnmatchedNewSymbols.out" );
  3569. #endif // TESTCODE
  3570. }
  3571. return Success;
  3572. }
  3573. BOOL
  3574. GetImageSymbolRiftInfo(
  3575. IN HANDLE OldFileHandle,
  3576. IN PUCHAR OldFileMapped,
  3577. IN ULONG OldFileSize,
  3578. IN UP_IMAGE_NT_HEADERS32 OldFileNtHeader,
  3579. IN LPCSTR OldFileSymPath,
  3580. IN ULONG OldFileOriginalChecksum,
  3581. IN ULONG OldFileOriginalTimeDate,
  3582. IN ULONG OldFileIndex,
  3583. IN HANDLE NewFileHandle,
  3584. IN PUCHAR NewFileMapped,
  3585. IN ULONG NewFileSize,
  3586. IN UP_IMAGE_NT_HEADERS32 NewFileNtHeader,
  3587. IN LPCSTR NewFileSymPath,
  3588. IN ULONG SymbolOptionFlags,
  3589. IN HANDLE SubAllocator,
  3590. IN PRIFT_TABLE RiftTable,
  3591. IN PPATCH_SYMLOAD_CALLBACK SymLoadCallback,
  3592. IN PVOID SymLoadContext
  3593. )
  3594. {
  3595. SYMBOL_CONTEXT SymbolContext;
  3596. DWORD SymOptions;
  3597. ULONG_PTR OldBase;
  3598. ULONG_PTR NewBase;
  3599. BOOL Success;
  3600. #ifdef TESTCODE
  3601. ULONG InitialRiftEntries = RiftTable->RiftEntryCount;
  3602. #endif
  3603. UNREFERENCED_PARAMETER( OldFileNtHeader );
  3604. UNREFERENCED_PARAMETER( OldFileMapped );
  3605. UNREFERENCED_PARAMETER( OldFileSize );
  3606. UNREFERENCED_PARAMETER( NewFileMapped );
  3607. UNREFERENCED_PARAMETER( NewFileSize );
  3608. InitImagehlpCritSect();
  3609. EnterCriticalSection( &ImagehlpCritSect );
  3610. Success = LoadImagehlp();
  3611. if ( Success ) {
  3612. __try {
  3613. SymOptions = Imagehlp.SymGetOptions();
  3614. SymOptions &= ~SYMOPT_CASE_INSENSITIVE;
  3615. SymOptions &= ~SYMOPT_UNDNAME;
  3616. SymOptions &= ~SYMOPT_DEFERRED_LOADS;
  3617. Imagehlp.SymSetOptions( SymOptions );
  3618. Success = Imagehlp.SymInitialize( hProc, NewFileSymPath, FALSE );
  3619. if ( Success ) {
  3620. __try {
  3621. SymRBInitTree(
  3622. &SymbolContext.NewDecoratedSymbolTree,
  3623. SubAllocator
  3624. );
  3625. SymRBInitTree(
  3626. &SymbolContext.NewUndecoratedSymbolTree,
  3627. SubAllocator
  3628. );
  3629. SymRBInitTree(
  3630. &SymbolContext.OldUndecoratedSymbolTree,
  3631. SubAllocator
  3632. );
  3633. NewBase = Imagehlp.SymLoadModule( hProc, NewFileHandle, NULL, "New", (ULONG_PTR)NewFileMapped, NewFileSize );
  3634. Success = ( NewBase != 0 );
  3635. if ( Success ) {
  3636. __try {
  3637. if ( SymLoadCallback ) {
  3638. ZeroMemory( &ImagehlpModuleInfo, sizeof( ImagehlpModuleInfo ));
  3639. ImagehlpModuleInfo.SizeOfStruct = sizeof( ImagehlpModuleInfo );
  3640. Success = Imagehlp.SymGetModuleInfo(
  3641. hProc,
  3642. NewBase,
  3643. &ImagehlpModuleInfo
  3644. );
  3645. if ( Success ) {
  3646. Success = SymLoadCallback(
  3647. 0,
  3648. ImagehlpModuleInfo.LoadedImageName,
  3649. ImagehlpModuleInfo.SymType,
  3650. ImagehlpModuleInfo.CheckSum,
  3651. ImagehlpModuleInfo.TimeDateStamp,
  3652. NewFileNtHeader->OptionalHeader.CheckSum,
  3653. NewFileNtHeader->FileHeader.TimeDateStamp,
  3654. SymLoadContext
  3655. );
  3656. }
  3657. }
  3658. if ( Success ) {
  3659. SymbolContext.NewImageBase = NewBase;
  3660. SymbolContext.SymbolOptionFlags = SymbolOptionFlags;
  3661. SymbolContext.RiftTable = RiftTable;
  3662. #ifdef TESTCODE
  3663. CountDecoratedMatches = 0;
  3664. CountUndecoratedMatches = 0;
  3665. SymbolContext.OutFile = CreateFile(
  3666. "NewSymbols.out",
  3667. GENERIC_WRITE,
  3668. FILE_SHARE_READ,
  3669. NULL,
  3670. CREATE_ALWAYS,
  3671. FILE_ATTRIBUTE_NORMAL,
  3672. NULL
  3673. );
  3674. #endif // TESTCODE
  3675. Success = Imagehlp.SymEnumerateSymbols( hProc, NewBase, NewFileEnumSymbolsCallback, &SymbolContext );
  3676. #ifdef TESTCODE
  3677. if ( SymbolContext.OutFile != INVALID_HANDLE_VALUE ) {
  3678. CloseHandle( SymbolContext.OutFile );
  3679. }
  3680. #endif // TESTCODE
  3681. }
  3682. }
  3683. __except( EXCEPTION_EXECUTE_HANDLER ) {
  3684. Success = FALSE;
  3685. }
  3686. Imagehlp.SymUnloadModule( hProc, NewBase );
  3687. }
  3688. }
  3689. __except( EXCEPTION_EXECUTE_HANDLER ) {
  3690. Success = FALSE;
  3691. }
  3692. //
  3693. // Must do cleanup and reinitialize Imagehlp for this
  3694. // process identifier. Otherwise it thinks the old
  3695. // module is still hanging around.
  3696. //
  3697. Imagehlp.SymCleanup( hProc );
  3698. if ( Success ) {
  3699. Success = Imagehlp.SymInitialize( hProc, OldFileSymPath, FALSE );
  3700. if ( Success ) {
  3701. __try {
  3702. OldBase = Imagehlp.SymLoadModule( hProc, OldFileHandle, NULL, "Old", (ULONG_PTR)OldFileMapped, OldFileSize );
  3703. Success = ( OldBase != 0 );
  3704. if ( Success ) {
  3705. __try {
  3706. if ( SymLoadCallback ) {
  3707. ZeroMemory( &ImagehlpModuleInfo, sizeof( ImagehlpModuleInfo ));
  3708. ImagehlpModuleInfo.SizeOfStruct = sizeof( ImagehlpModuleInfo );
  3709. Success = Imagehlp.SymGetModuleInfo(
  3710. hProc,
  3711. OldBase,
  3712. &ImagehlpModuleInfo
  3713. );
  3714. if ( Success ) {
  3715. Success = SymLoadCallback(
  3716. OldFileIndex + 1,
  3717. ImagehlpModuleInfo.LoadedImageName,
  3718. ImagehlpModuleInfo.SymType,
  3719. ImagehlpModuleInfo.CheckSum,
  3720. ImagehlpModuleInfo.TimeDateStamp,
  3721. OldFileOriginalChecksum,
  3722. OldFileOriginalTimeDate,
  3723. SymLoadContext
  3724. );
  3725. }
  3726. }
  3727. if ( Success ) {
  3728. SymbolContext.OldImageBase = OldBase;
  3729. #ifdef TESTCODE
  3730. SymbolContext.OutFile = CreateFile(
  3731. "OldSymbols.out",
  3732. GENERIC_WRITE,
  3733. FILE_SHARE_READ,
  3734. NULL,
  3735. CREATE_ALWAYS,
  3736. FILE_ATTRIBUTE_NORMAL,
  3737. NULL
  3738. );
  3739. #endif // TESTCODE
  3740. Success = Imagehlp.SymEnumerateSymbols( hProc, OldBase, OldFileEnumSymbolsCallback, &SymbolContext );
  3741. #ifdef TESTCODE
  3742. if ( SymbolContext.OutFile != INVALID_HANDLE_VALUE ) {
  3743. CloseHandle( SymbolContext.OutFile );
  3744. }
  3745. #endif // TESTCODE
  3746. }
  3747. if ( Success ) {
  3748. //
  3749. // Need to match remaining decorated new symbols in tree
  3750. // with unmatched now-undecorated old symbols in other tree.
  3751. //
  3752. if ( SymbolOptionFlags & PATCH_SYMBOL_UNDECORATED_TOO ) {
  3753. Success = MatchRemainingSymbols(
  3754. &SymbolContext.NewDecoratedSymbolTree,
  3755. &SymbolContext.NewUndecoratedSymbolTree,
  3756. &SymbolContext.OldUndecoratedSymbolTree,
  3757. RiftTable
  3758. );
  3759. }
  3760. }
  3761. }
  3762. __except( EXCEPTION_EXECUTE_HANDLER ) {
  3763. Success = FALSE;
  3764. }
  3765. Imagehlp.SymUnloadModule( hProc, OldBase );
  3766. }
  3767. }
  3768. __except( EXCEPTION_EXECUTE_HANDLER ) {
  3769. Success = FALSE;
  3770. }
  3771. Imagehlp.SymCleanup( hProc );
  3772. }
  3773. }
  3774. }
  3775. }
  3776. __except( EXCEPTION_EXECUTE_HANDLER ) {
  3777. Success = FALSE;
  3778. }
  3779. }
  3780. LeaveCriticalSection( &ImagehlpCritSect );
  3781. if ( ! Success ) {
  3782. SetLastError( ERROR_PATCH_IMAGEHLP_FAILURE );
  3783. }
  3784. #ifdef TESTCODE
  3785. printf( "\r%9d decorated symbol matches\n", CountDecoratedMatches );
  3786. printf( "\r%9d undecorated symbol matches\n", CountUndecoratedMatches );
  3787. printf( "\r%9d rift entries from symbols\n", RiftTable->RiftEntryCount - InitialRiftEntries );
  3788. #endif
  3789. return Success;
  3790. }
  3791. BOOL
  3792. OptimizeImageRiftInfo(
  3793. IN PUCHAR OldFileMapped,
  3794. IN ULONG OldFileSize,
  3795. IN UP_IMAGE_NT_HEADERS32 OldFileNtHeader,
  3796. IN PUCHAR NewFileMapped,
  3797. IN ULONG NewFileSize,
  3798. IN UP_IMAGE_NT_HEADERS32 NewFileNtHeader,
  3799. IN HANDLE SubAllocator,
  3800. IN PRIFT_TABLE RiftTable
  3801. )
  3802. {
  3803. UNREFERENCED_PARAMETER( OldFileMapped );
  3804. UNREFERENCED_PARAMETER( OldFileSize );
  3805. UNREFERENCED_PARAMETER( OldFileNtHeader );
  3806. UNREFERENCED_PARAMETER( NewFileMapped );
  3807. UNREFERENCED_PARAMETER( NewFileSize );
  3808. UNREFERENCED_PARAMETER( NewFileNtHeader );
  3809. UNREFERENCED_PARAMETER( SubAllocator );
  3810. UNREFERENCED_PARAMETER( RiftTable );
  3811. return TRUE;
  3812. }
  3813. #if 0 // This is test code
  3814. BOOL
  3815. OptimizeImageRiftInfo(
  3816. IN PUCHAR OldFileMapped,
  3817. IN ULONG OldFileSize,
  3818. IN UP_IMAGE_NT_HEADERS32 OldFileNtHeader,
  3819. IN PUCHAR NewFileMapped,
  3820. IN ULONG NewFileSize,
  3821. IN UP_IMAGE_NT_HEADERS32 NewFileNtHeader,
  3822. IN HANDLE SubAllocator,
  3823. IN PRIFT_TABLE RiftTable
  3824. )
  3825. {
  3826. UP_IMAGE_SECTION_HEADER SectionHeader;
  3827. ULONG SectionCount;
  3828. PUCHAR SectionStart;
  3829. PUCHAR SearchExtent;
  3830. ULONG SectionLength;
  3831. ULONG SectionOffset;
  3832. ULONG SectionBaseRva;
  3833. ULONG OldFileLastRva;
  3834. ULONG NewFileLastRva;
  3835. LONG OldDisplacement;
  3836. LONG NewDisplacement;
  3837. ULONG OffsetInSection;
  3838. ULONG OldOriginRva;
  3839. ULONG OldTargetRva;
  3840. ULONG TargetOffset;
  3841. PUCHAR OldFileHintMap;
  3842. PUCHAR NewFileHintMap;
  3843. PUCHAR OldFileCopy;
  3844. PUCHAR NewFileCopy;
  3845. PVOID OldFileCopyNtHeader;
  3846. PVOID NewFileCopyNtHeader;
  3847. BOOL Success;
  3848. BOOL Skip;
  3849. ULONG i;
  3850. ULONG j;
  3851. PUCHAR p;
  3852. #ifdef TESTCODE
  3853. ULONG CountVerifiedE8Rifts = 0;
  3854. ULONG CountDiscoveredE8Rifts = 0;
  3855. #endif // TESTCODE
  3856. //
  3857. // Stage1:
  3858. //
  3859. // Trusting existing rift info, search for E8/E9/Jcc instructions in
  3860. // the Old file, get the corresponding rift, inspect the corresponding
  3861. // instruction in the New file. If they match, great. If they don't
  3862. // match, search for a correponding instruction in the new file by
  3863. // looking forward up to the next rift. If find a suitable match,
  3864. // create a new rift entry to support it.
  3865. //
  3866. // We don't have the benefit of non-exe marked bytes here.
  3867. //
  3868. if ( OldFileNtHeader->FileHeader.Machine != NewFileNtHeader->FileHeader.Machine ) {
  3869. return TRUE; // not much we can do here!
  3870. }
  3871. //
  3872. // We need the HintMap to determine which bytes in the files are not
  3873. // executable. The Transform function currently provides this, but
  3874. // we don't want to modify our mapped file views here. So, allocate
  3875. // a range of VM and make a copy of the file to Transform, perform
  3876. // the transformations on that copy just to produce a hint map, then
  3877. // free the transformed copy (do this for both old and new files).
  3878. //
  3879. Success = FALSE;
  3880. OldFileHintMap = MyVirtualAlloc( OldFileSize );
  3881. NewFileHintMap = MyVirtualAlloc( NewFileSize );
  3882. if ( OldFileHintMap && NewFileHintMap ) {
  3883. OldFileCopy = MyVirtualAlloc( OldFileSize );
  3884. if ( OldFileCopy ) {
  3885. CopyMemory( OldFileCopy, OldFileMapped, OldFileSize );
  3886. OldFileCopyNtHeader = GetNtHeader( OldFileCopy, OldFileSize );
  3887. Success = TransformCoffImage(
  3888. ( PATCH_TRANSFORM_NO_RELJMPS | PATCH_TRANSFORM_NO_RELCALLS | PATCH_TRANSFORM_NO_RESOURCE ),
  3889. OldFileCopyNtHeader,
  3890. OldFileCopy,
  3891. OldFileSize,
  3892. 0,
  3893. RiftTable,
  3894. OldFileHintMap
  3895. );
  3896. MyVirtualFree( OldFileCopy );
  3897. }
  3898. if ( Success ) {
  3899. Success = FALSE;
  3900. NewFileCopy = MyVirtualAlloc( NewFileSize );
  3901. if ( NewFileCopy ) {
  3902. CopyMemory( NewFileCopy, NewFileMapped, NewFileSize );
  3903. NewFileCopyNtHeader = GetNtHeader( NewFileCopy, NewFileSize );
  3904. Success = TransformCoffImage(
  3905. ( PATCH_TRANSFORM_NO_RELJMPS | PATCH_TRANSFORM_NO_RELCALLS | PATCH_TRANSFORM_NO_RESOURCE ),
  3906. NewFileCopyNtHeader,
  3907. NewFileCopy,
  3908. NewFileSize,
  3909. 0,
  3910. RiftTable,
  3911. NewFileHintMap
  3912. );
  3913. MyVirtualFree( NewFileCopy );
  3914. }
  3915. }
  3916. }
  3917. if ( Success ) {
  3918. //
  3919. // We now have valid OldFileHintMap and NewFileHintMap.
  3920. //
  3921. OldFileLastRva = OldFileNtHeader->OptionalHeader.SizeOfImage;
  3922. NewFileLastRva = NewFileNtHeader->OptionalHeader.SizeOfImage;
  3923. InsertRiftEntryInSortedTable( RiftTable, RiftTable->RiftEntryCount, OldFileLastRva, NewFileLastRva );
  3924. SectionHeader = IMAGE_FIRST_SECTION( OldFileNtHeader );
  3925. SectionCount = OldFileNtHeader->FileHeader.NumberOfSections;
  3926. for ( i = 0; i < SectionCount; i++ ) {
  3927. if ( SectionHeader[ i ].Characteristics & IMAGE_SCN_MEM_EXECUTE ) {
  3928. SectionBaseRva = SectionHeader[ i ].VirtualAddress;
  3929. SectionLength = MIN( SectionHeader[ i ].Misc.VirtualSize, SectionHeader[ i ].SizeOfRawData );
  3930. SectionOffset = SectionHeader[ i ].PointerToRawData;
  3931. SectionStart = OldFileMapped + SectionOffset;
  3932. if ( OldFileNtHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_I386 ) {
  3933. SearchExtent = SectionStart + SectionLength - 5;
  3934. for ( p = SectionStart; p < SearchExtent; p++ ) {
  3935. if ( *p == 0xE8 ) { // call relative32
  3936. //
  3937. // Validate that instruction is not something that
  3938. // the HintMap indicates is not an executable
  3939. // instruction. We're looking for a relative
  3940. // call instruction here, so it would not be a
  3941. // reloc target.
  3942. //
  3943. Skip = FALSE;
  3944. for ( j = 0; j < 5; j++ ) {
  3945. if ( OldFileHintMap[ SectionOffset + ( p - SectionStart ) + j ] & 0x01 ) {
  3946. Skip = TRUE;
  3947. break;
  3948. }
  3949. }
  3950. if ( Skip ) {
  3951. continue;
  3952. }
  3953. //
  3954. // Relative displacement is stored as 32-bit
  3955. // signed value following these opcodes. The
  3956. // displacement is relative to the NEXT
  3957. // instruction, which is at (p + 5).
  3958. //
  3959. OldDisplacement = *(UNALIGNED LONG*)( p + 1 );
  3960. OffsetInSection = ( p + 5 ) - SectionStart;
  3961. OldOriginRva = SectionBaseRva + OffsetInSection;
  3962. OldTargetRva = OldOriginRva + OldDisplacement;
  3963. //
  3964. // We expect a lot of false positives here because
  3965. // occurences of <E8> will
  3966. // likely occur in other parts of the instruction
  3967. // stream so now we validate that the TargetRva
  3968. // falls within the image and within an executable
  3969. // section.
  3970. //
  3971. if ( OldTargetRva < OldFileLastRva ) {
  3972. TargetOffset = ImageRvaToFileOffset( OldFileNtHeader, OldTargetRva );
  3973. if ( ! ( OldFileHintMap[ TargetOffset ] & 0x01 )) {
  3974. //
  3975. // Looks like a valid TargetRva, so lookup the
  3976. // corresponding "new" RVAs in the rift table.
  3977. //
  3978. ULONG RiftIndexOrigin = FindRiftTableEntryForOldRva( RiftTable, OldOriginRva );
  3979. ULONG RiftIndexTarget = FindRiftTableEntryForOldRva( RiftTable, OldTargetRva );
  3980. ULONG NewOriginRva = OldOriginRva + (LONG)( RiftTable->RiftEntryArray[ RiftIndexOrigin ].NewFileRva - RiftTable->RiftEntryArray[ RiftIndexOrigin ].OldFileRva );
  3981. ULONG NewTargetRva = OldTargetRva + (LONG)( RiftTable->RiftEntryArray[ RiftIndexTarget ].NewFileRva - RiftTable->RiftEntryArray[ RiftIndexTarget ].OldFileRva );
  3982. PUCHAR NewOriginMa = ImageRvaToMappedAddress( NewFileNtHeader, NewOriginRva, NewFileMapped, NewFileSize );
  3983. PUCHAR NewTargetMa = ImageRvaToMappedAddress( NewFileNtHeader, NewTargetRva, NewFileMapped, NewFileSize );
  3984. PUCHAR OldTargetMa = ImageRvaToMappedAddress( OldFileNtHeader, OldTargetRva, OldFileMapped, OldFileSize );
  3985. PUCHAR OldOriginMa = p + 5;
  3986. if (( NewOriginMa ) && ( NewTargetMa ) && ( OldTargetMa )) {
  3987. PUCHAR OldInstruct = p;
  3988. PUCHAR NewInstruct = NewOriginMa - 5;
  3989. //
  3990. // A verified call instruction should match the
  3991. // instruction byte, the byte following the
  3992. // instruction, and the target byte, because
  3993. // they should all be executable code that is
  3994. // not modified by relocs.
  3995. //
  3996. // Also verify the NewFileHintMap.
  3997. //
  3998. if (( *OldInstruct == *NewInstruct ) &&
  3999. ( *OldOriginMa == *NewOriginMa ) &&
  4000. ( *OldTargetMa == *NewTargetMa )) {
  4001. ULONG NewInstructOffset = NewInstruct - NewFileMapped;
  4002. ULONG NewTargetOffset = NewTargetMa - NewFileMapped;
  4003. BOOL Skip = FALSE;
  4004. for ( j = 0; j < 5; j++ ) {
  4005. if ( NewFileHintMap[ NewInstructOffset + j ] & 0x01 ) {
  4006. Skip = TRUE;
  4007. break;
  4008. }
  4009. }
  4010. if ( NewFileHintMap[ NewTargetOffset + j ] & 0x01 ) {
  4011. Skip = TRUE;
  4012. }
  4013. if ( ! Skip ) {
  4014. //
  4015. // This is a bonafide good match. Add a rift entry
  4016. // for both the instruction and the target. We do
  4017. // this so that subsequent rift insertions don't get
  4018. // between the rift that coasted to these and these.
  4019. //
  4020. InsertRiftEntryInSortedTable( RiftTable, RiftIndexOrigin, OldOriginRva - 5, NewOriginRva - 5 );
  4021. InsertRiftEntryInSortedTable( RiftTable, RiftIndexTarget, OldTargetRva, NewTargetRva );
  4022. #ifdef TESTCODE
  4023. CountVerifiedE8Rifts++;
  4024. #endif // TESTCODE
  4025. }
  4026. }
  4027. }
  4028. }
  4029. }
  4030. }
  4031. }
  4032. }
  4033. else if ( OldFileNtHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_ALPHA ) {
  4034. //
  4035. // Implement Alpha platform stuff here.
  4036. //
  4037. }
  4038. }
  4039. }
  4040. for ( i = 0; i < SectionCount; i++ ) {
  4041. if ( SectionHeader[ i ].Characteristics & IMAGE_SCN_MEM_EXECUTE ) {
  4042. SectionBaseRva = SectionHeader[ i ].VirtualAddress;
  4043. SectionLength = MIN( SectionHeader[ i ].Misc.VirtualSize, SectionHeader[ i ].SizeOfRawData );
  4044. SectionOffset = SectionHeader[ i ].PointerToRawData;
  4045. SectionStart = OldFileMapped + SectionOffset;
  4046. if ( OldFileNtHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_I386 ) {
  4047. SearchExtent = SectionStart + SectionLength - 5;
  4048. for ( p = SectionStart; p < SearchExtent; p++ ) {
  4049. if ( *p == 0xE8 ) { // call relative32
  4050. //
  4051. // Validate that instruction is not something that
  4052. // the HintMap indicates is not an executable
  4053. // instruction. We're looking for a relative
  4054. // call instruction here, so it would not be a
  4055. // reloc target.
  4056. //
  4057. Skip = FALSE;
  4058. for ( j = 0; j < 5; j++ ) {
  4059. if ( OldFileHintMap[ SectionOffset + ( p - SectionStart ) + j ] & 0x01 ) {
  4060. Skip = TRUE;
  4061. break;
  4062. }
  4063. }
  4064. if ( Skip ) {
  4065. continue;
  4066. }
  4067. //
  4068. // Relative displacement is stored as 32-bit
  4069. // signed value following these opcodes. The
  4070. // displacement is relative to the NEXT
  4071. // instruction, which is at (p + 5).
  4072. //
  4073. OldDisplacement = *(UNALIGNED LONG*)( p + 1 );
  4074. OffsetInSection = ( p + 5 ) - SectionStart;
  4075. OldOriginRva = SectionBaseRva + OffsetInSection;
  4076. OldTargetRva = OldOriginRva + OldDisplacement;
  4077. //
  4078. // We expect a lot of false positives here because
  4079. // occurences of <E8> will
  4080. // likely occur in other parts of the instruction
  4081. // stream so now we validate that the TargetRva
  4082. // falls within the image and within an executable
  4083. // section.
  4084. //
  4085. if ( OldTargetRva < OldFileLastRva ) {
  4086. TargetOffset = ImageRvaToFileOffset( OldFileNtHeader, OldTargetRva );
  4087. if ( ! ( OldFileHintMap[ TargetOffset ] & 0x01 )) {
  4088. //
  4089. // Looks like a valid TargetRva, so lookup the
  4090. // corresponding "new" RVAs in the rift table.
  4091. //
  4092. ULONG RiftIndexOrigin = FindRiftTableEntryForOldRva( RiftTable, OldOriginRva );
  4093. ULONG RiftIndexTarget = FindRiftTableEntryForOldRva( RiftTable, OldTargetRva );
  4094. ULONG NewOriginRva = OldOriginRva + (LONG)( RiftTable->RiftEntryArray[ RiftIndexOrigin ].NewFileRva - RiftTable->RiftEntryArray[ RiftIndexOrigin ].OldFileRva );
  4095. ULONG NewTargetRva = OldTargetRva + (LONG)( RiftTable->RiftEntryArray[ RiftIndexTarget ].NewFileRva - RiftTable->RiftEntryArray[ RiftIndexTarget ].OldFileRva );
  4096. PUCHAR NewOriginMa = ImageRvaToMappedAddress( NewFileNtHeader, NewOriginRva, NewFileMapped, NewFileSize );
  4097. PUCHAR NewTargetMa = ImageRvaToMappedAddress( NewFileNtHeader, NewTargetRva, NewFileMapped, NewFileSize );
  4098. PUCHAR OldTargetMa = ImageRvaToMappedAddress( OldFileNtHeader, OldTargetRva, OldFileMapped, OldFileSize );
  4099. PUCHAR OldOriginMa = p + 5;
  4100. if (( NewOriginMa ) && ( NewTargetMa ) && ( OldTargetMa )) {
  4101. PUCHAR OldInstruct = p;
  4102. PUCHAR NewInstruct = NewOriginMa - 5;
  4103. //
  4104. // A verified call instruction should match the
  4105. // instruction byte, the byte following the
  4106. // instruction, and the target byte, because
  4107. // they should all be executable code that is
  4108. // not modified by relocs.
  4109. //
  4110. // Check NewHintMap too.
  4111. //
  4112. if (( *OldInstruct == *NewInstruct ) &&
  4113. ( *OldOriginMa == *NewOriginMa ) &&
  4114. ( *OldTargetMa == *NewTargetMa )) {
  4115. ULONG NewInstructOffset = NewInstruct - NewFileMapped;
  4116. ULONG NewTargetOffset = NewTargetMa - NewFileMapped;
  4117. BOOL Skip = FALSE;
  4118. for ( j = 0; j < 5; j++ ) {
  4119. if ( NewFileHintMap[ NewInstructOffset + j ] & 0x01 ) {
  4120. Skip = TRUE;
  4121. break;
  4122. }
  4123. }
  4124. if ( NewFileHintMap[ NewTargetOffset + j ] & 0x01 ) {
  4125. Skip = TRUE;
  4126. }
  4127. if ( ! Skip ) {
  4128. //
  4129. // This is a bonafide good match.
  4130. //
  4131. continue;
  4132. }
  4133. }
  4134. {
  4135. //
  4136. // Instructions don't match. Scan to find
  4137. // matching instruction in new file. Scan
  4138. // the extent of this rift entry.
  4139. //
  4140. PUCHAR ScanInstruct;
  4141. PUCHAR LowestMaToScan;
  4142. PUCHAR HighestMaToScan;
  4143. ULONG LowestRvaToScan = RiftTable->RiftEntryArray[ RiftIndexOrigin ].NewFileRva;
  4144. ULONG HighestRvaToScan = RiftTable->RiftEntryArray[ RiftIndexOrigin + 1 ].NewFileRva;
  4145. ULONG ExpectedTargetRva = NewTargetRva;
  4146. BOOL Found = FALSE;
  4147. LowestMaToScan = ImageRvaToMappedAddress( NewFileNtHeader, LowestRvaToScan, NewFileMapped, NewFileSize );
  4148. HighestMaToScan = ImageRvaToMappedAddress( NewFileNtHeader, HighestRvaToScan, NewFileMapped, NewFileSize );
  4149. HighestMaToScan -= 5; // size of instruction
  4150. for ( ScanInstruct = NewInstruct + 1; ScanInstruct <= HighestMaToScan; ScanInstruct++ ) {
  4151. if ( *ScanInstruct == 0xE8 ) {
  4152. //
  4153. // check NewHintMap
  4154. //
  4155. NewOriginMa = ScanInstruct + 5;
  4156. NewOriginRva = MappedAddressToImageRva( NewFileNtHeader, NewOriginMa, NewFileMapped );
  4157. NewDisplacement = *(UNALIGNED LONG*)( ScanInstruct + 1 );
  4158. NewTargetRva = NewOriginRva + NewDisplacement;
  4159. NewTargetMa = ImageRvaToMappedAddress( NewFileNtHeader, NewTargetRva, NewFileMapped, NewFileSize );
  4160. if (( NewOriginRva ) && ( NewTargetMa )) {
  4161. //
  4162. // We already know *OldInstruct == *ScanInstruct
  4163. //
  4164. if (( *OldOriginMa == *NewOriginMa ) &&
  4165. ( *OldTargetMa == *NewTargetMa ) &&
  4166. ( NewTargetRva == ExpectedTargetRva )) {
  4167. ULONG NewInstructOffset = ScanInstruct - NewFileMapped;
  4168. ULONG NewTargetOffset = NewTargetMa - NewFileMapped;
  4169. BOOL Skip = FALSE;
  4170. for ( j = 0; j < 5; j++ ) {
  4171. if ( NewFileHintMap[ NewInstructOffset + j ] & 0x01 ) {
  4172. Skip = TRUE;
  4173. break;
  4174. }
  4175. }
  4176. if ( NewFileHintMap[ NewTargetOffset + j ] & 0x01 ) {
  4177. Skip = TRUE;
  4178. }
  4179. if ( ! Skip ) {
  4180. InsertRiftEntryInSortedTable( RiftTable, RiftIndexOrigin, OldOriginRva - 5, NewOriginRva - 5 );
  4181. InsertRiftEntryInSortedTable( RiftTable, RiftIndexTarget, OldTargetRva, NewTargetRva );
  4182. Found = TRUE;
  4183. #ifdef TESTCODE
  4184. CountDiscoveredE8Rifts++;
  4185. #endif // TESTCODE
  4186. break;
  4187. }
  4188. }
  4189. }
  4190. }
  4191. }
  4192. if ( Found ) {
  4193. continue;
  4194. }
  4195. for ( ScanInstruct = NewInstruct - 1; ScanInstruct >= LowestMaToScan; ScanInstruct-- ) {
  4196. if ( *ScanInstruct == 0xE8 ) {
  4197. //
  4198. // check NewHintMap
  4199. //
  4200. NewOriginMa = ScanInstruct + 5;
  4201. NewOriginRva = MappedAddressToImageRva( NewFileNtHeader, NewOriginMa, NewFileMapped );
  4202. NewDisplacement = *(UNALIGNED LONG*)( ScanInstruct + 1 );
  4203. NewTargetRva = NewOriginRva + NewDisplacement;
  4204. NewTargetMa = ImageRvaToMappedAddress( NewFileNtHeader, NewTargetRva, NewFileMapped, NewFileSize );
  4205. if (( NewOriginRva ) && ( NewTargetMa )) {
  4206. //
  4207. // We already know *OldInstruct == *ScanInstruct
  4208. //
  4209. if (( *OldOriginMa == *NewOriginMa ) &&
  4210. ( *OldTargetMa == *NewTargetMa ) &&
  4211. ( NewTargetRva == ExpectedTargetRva )) {
  4212. ULONG NewInstructOffset = ScanInstruct - NewFileMapped;
  4213. ULONG NewTargetOffset = NewTargetMa - NewFileMapped;
  4214. BOOL Skip = FALSE;
  4215. for ( j = 0; j < 5; j++ ) {
  4216. if ( NewFileHintMap[ NewInstructOffset + j ] & 0x01 ) {
  4217. Skip = TRUE;
  4218. break;
  4219. }
  4220. }
  4221. if ( NewFileHintMap[ NewTargetOffset + j ] & 0x01 ) {
  4222. Skip = TRUE;
  4223. }
  4224. if ( ! Skip ) {
  4225. InsertRiftEntryInSortedTable( RiftTable, RiftIndexOrigin, OldOriginRva - 5, NewOriginRva - 5 );
  4226. InsertRiftEntryInSortedTable( RiftTable, RiftIndexTarget, OldTargetRva, NewTargetRva );
  4227. Found = TRUE;
  4228. #ifdef TESTCODE
  4229. CountDiscoveredE8Rifts++;
  4230. #endif // TESTCODE
  4231. break;
  4232. }
  4233. }
  4234. }
  4235. }
  4236. }
  4237. }
  4238. }
  4239. }
  4240. }
  4241. }
  4242. }
  4243. }
  4244. else if ( OldFileNtHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_ALPHA ) {
  4245. //
  4246. // Implement Alpha platform stuff here.
  4247. //
  4248. }
  4249. }
  4250. }
  4251. }
  4252. #ifdef TESTCODE
  4253. printf( "\r%9d verified E8 rifts\n", CountVerifiedE8Rifts );
  4254. printf( "\r%9d discovered E8 rifts\n", CountDiscoveredE8Rifts );
  4255. #endif // TESTCODE
  4256. if ( OldFileHintMap ) {
  4257. MyVirtualFree( OldFileHintMap );
  4258. }
  4259. if ( NewFileHintMap ) {
  4260. MyVirtualFree( NewFileHintMap );
  4261. }
  4262. return Success;
  4263. }
  4264. #endif // 0 (test code)
  4265. BOOL
  4266. GenerateRiftTable(
  4267. IN HANDLE OldFileHandle,
  4268. IN PUCHAR OldFileMapped,
  4269. IN ULONG OldFileSize,
  4270. IN ULONG OldFileOriginalChecksum,
  4271. IN ULONG OldFileOriginalTimeDate,
  4272. IN HANDLE NewFileHandle,
  4273. IN PUCHAR NewFileMapped,
  4274. IN ULONG NewFileSize,
  4275. IN ULONG OptionFlags,
  4276. IN PPATCH_OPTION_DATA OptionData,
  4277. IN ULONG OldFileIndex,
  4278. IN PRIFT_TABLE RiftTable
  4279. )
  4280. {
  4281. UP_IMAGE_NT_HEADERS32 OldFileNtHeader;
  4282. UP_IMAGE_NT_HEADERS32 NewFileNtHeader;
  4283. LPCSTR OldFileSymPath;
  4284. LPCSTR NewFileSymPath;
  4285. HANDLE SubAllocator;
  4286. ULONG SymbolOptionFlags;
  4287. BOOL Success = FALSE;
  4288. UNREFERENCED_PARAMETER( OptionFlags );
  4289. SymbolOptionFlags = 0;
  4290. SubAllocator = NULL;
  4291. __try {
  4292. //
  4293. // See if both files are PE images.
  4294. //
  4295. OldFileNtHeader = GetNtHeader( OldFileMapped, OldFileSize );
  4296. if ( OldFileNtHeader ) {
  4297. NewFileNtHeader = GetNtHeader( NewFileMapped, NewFileSize );
  4298. if ( NewFileNtHeader ) {
  4299. //
  4300. // Both files are PE images.
  4301. //
  4302. SubAllocator = CreateSubAllocator( 0x100000, 0x100000 );
  4303. if ( ! SubAllocator ) {
  4304. Success = FALSE;
  4305. __leave;
  4306. }
  4307. //
  4308. // Before we bother with debug info, we can create initial
  4309. // rift data from the section headers to compensate for any
  4310. // section base RVA differences. This will work even if we
  4311. // don't have debug symbols.
  4312. //
  4313. Success = GetImageNonSymbolRiftInfo(
  4314. OldFileMapped,
  4315. OldFileSize,
  4316. OldFileNtHeader,
  4317. NewFileMapped,
  4318. NewFileSize,
  4319. NewFileNtHeader,
  4320. SubAllocator,
  4321. RiftTable
  4322. );
  4323. //
  4324. // Now get rift info from symbols
  4325. //
  4326. if ( Success ) {
  4327. if (( OptionData ) && ( OptionData->SizeOfThisStruct >= sizeof( PATCH_OPTION_DATA ))) {
  4328. SymbolOptionFlags = OptionData->SymbolOptionFlags;
  4329. if ( ! ( SymbolOptionFlags & PATCH_SYMBOL_NO_IMAGEHLP )) {
  4330. if ( OptionData->OldFileSymbolPathArray ) {
  4331. OldFileSymPath = OptionData->OldFileSymbolPathArray[ OldFileIndex ];
  4332. NewFileSymPath = OptionData->NewFileSymbolPath;
  4333. if (( OldFileSymPath ) && ( NewFileSymPath )) {
  4334. Success = GetImageSymbolRiftInfo(
  4335. OldFileHandle,
  4336. OldFileMapped,
  4337. OldFileSize,
  4338. OldFileNtHeader,
  4339. OldFileSymPath,
  4340. OldFileOriginalChecksum,
  4341. OldFileOriginalTimeDate,
  4342. OldFileIndex,
  4343. NewFileHandle,
  4344. NewFileMapped,
  4345. NewFileSize,
  4346. NewFileNtHeader,
  4347. NewFileSymPath,
  4348. SymbolOptionFlags,
  4349. SubAllocator,
  4350. RiftTable,
  4351. OptionData->SymLoadCallback,
  4352. OptionData->SymLoadContext
  4353. );
  4354. if ( SymbolOptionFlags & PATCH_SYMBOL_NO_FAILURES ) {
  4355. #ifdef TESTCODE
  4356. if (( ! Success ) && ( GetLastError() == ERROR_PATCH_IMAGEHLP_FAILURE )) {
  4357. printf( "\rWARNING: Imagehlp.Dll failure\n" );
  4358. }
  4359. #endif
  4360. Success = TRUE;
  4361. }
  4362. }
  4363. }
  4364. }
  4365. }
  4366. }
  4367. if ( Success ) {
  4368. RiftSortAndRemoveDuplicates(
  4369. OldFileMapped,
  4370. OldFileSize,
  4371. OldFileNtHeader,
  4372. NewFileMapped,
  4373. NewFileSize,
  4374. NewFileNtHeader,
  4375. RiftTable
  4376. );
  4377. //
  4378. // Now we can optimize the rift info by peeking into
  4379. // the mapped files.
  4380. //
  4381. Success = OptimizeImageRiftInfo(
  4382. OldFileMapped,
  4383. OldFileSize,
  4384. OldFileNtHeader,
  4385. NewFileMapped,
  4386. NewFileSize,
  4387. NewFileNtHeader,
  4388. SubAllocator,
  4389. RiftTable
  4390. );
  4391. }
  4392. #ifdef TESTCODE
  4393. if ( Success ) {
  4394. HANDLE hFile = CreateFile(
  4395. "RiftInfo.out",
  4396. GENERIC_WRITE,
  4397. FILE_SHARE_READ,
  4398. NULL,
  4399. CREATE_ALWAYS,
  4400. FILE_ATTRIBUTE_NORMAL,
  4401. NULL
  4402. );
  4403. if ( hFile != INVALID_HANDLE_VALUE ) {
  4404. CHAR TextBuffer[ 24 ];
  4405. DWORD Actual;
  4406. ULONG i;
  4407. for ( i = 0; i < RiftTable->RiftEntryCount; i++ ) {
  4408. sprintf( TextBuffer, "%08X %08X\r\n", RiftTable->RiftEntryArray[ i ].OldFileRva, RiftTable->RiftEntryArray[ i ].NewFileRva );
  4409. WriteFile( hFile, TextBuffer, 19, &Actual, NULL );
  4410. }
  4411. CloseHandle( hFile );
  4412. }
  4413. }
  4414. #endif // TESTCODE
  4415. }
  4416. }
  4417. }
  4418. __except( EXCEPTION_EXECUTE_HANDLER ) {
  4419. SetLastError( GetExceptionCode() );
  4420. Success = FALSE;
  4421. }
  4422. if ( SubAllocator ) {
  4423. DestroySubAllocator( SubAllocator );
  4424. }
  4425. return Success;
  4426. }
  4427. #endif // PATCH_APPLY_CODE_ONLY