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

5852 lines
215 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 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, SymbolNameSize );
  3308. PSYMBOL_NODE SymbolNode;
  3309. if (!UndecoratedName)
  3310. return FALSE;
  3311. MyUndecorateSymbol(
  3312. SymbolName,
  3313. UndecoratedName,
  3314. SymbolNameSize
  3315. );
  3316. SymbolNode = SymRBInsert(
  3317. SymbolTree,
  3318. UndecoratedName,
  3319. Rva
  3320. );
  3321. HeapFree(GetProcessHeap(), 0, UndecoratedName);
  3322. return ( SymbolNode != NULL );
  3323. }
  3324. BOOL
  3325. CALLBACK
  3326. NewFileEnumSymbolsCallback(
  3327. LPSTR SymbolName,
  3328. ULONG_PTR SymbolAddr,
  3329. ULONG SymbolSize,
  3330. PVOID Context
  3331. )
  3332. {
  3333. PSYMBOL_CONTEXT SymbolContext = Context;
  3334. PSYMBOL_NODE SymbolNode;
  3335. ULONG NewRva;
  3336. UNREFERENCED_PARAMETER( SymbolSize );
  3337. #ifdef TESTCODE
  3338. if ( SymbolContext->OutFile != INVALID_HANDLE_VALUE ) {
  3339. CHAR TextBuffer[ 16 + MAX_SYMBOL_NAME_LENGTH ];
  3340. CHAR Discarded;
  3341. DWORD Actual;
  3342. Discarded = 'X';
  3343. NewRva = SymbolAddr;
  3344. if ( NewRva > SymbolContext->NewImageBase ) {
  3345. NewRva -= SymbolContext->NewImageBase;
  3346. Discarded = ' ';
  3347. }
  3348. sprintf( TextBuffer, "%08X %c %s\r\n", NewRva, Discarded, SymbolName );
  3349. WriteFile( SymbolContext->OutFile, TextBuffer, strlen( TextBuffer ), &Actual, NULL );
  3350. }
  3351. #endif // TESTCODE
  3352. if ( SymbolAddr > SymbolContext->NewImageBase ) {
  3353. NewRva = (ULONG)( SymbolAddr - SymbolContext->NewImageBase );
  3354. SymbolNode = SymRBInsert(
  3355. &SymbolContext->NewDecoratedSymbolTree,
  3356. SymbolName,
  3357. NewRva
  3358. );
  3359. return ( SymbolNode != NULL );
  3360. }
  3361. return TRUE;
  3362. }
  3363. BOOL
  3364. CALLBACK
  3365. OldFileEnumSymbolsCallback(
  3366. LPSTR SymbolName,
  3367. ULONG_PTR SymbolAddr,
  3368. ULONG SymbolSize,
  3369. PVOID Context
  3370. )
  3371. {
  3372. PSYMBOL_CONTEXT SymbolContext = Context;
  3373. PSYMBOL_NODE SymbolNode;
  3374. ULONG OldRva;
  3375. UNREFERENCED_PARAMETER( SymbolSize );
  3376. #ifdef TESTCODE
  3377. if ( SymbolContext->OutFile != INVALID_HANDLE_VALUE ) {
  3378. CHAR TextBuffer[ 16 + MAX_SYMBOL_NAME_LENGTH ];
  3379. CHAR Discarded;
  3380. DWORD Actual;
  3381. Discarded = 'X';
  3382. OldRva = SymbolAddr;
  3383. if ( OldRva > SymbolContext->OldImageBase ) {
  3384. OldRva -= SymbolContext->OldImageBase;
  3385. Discarded = ' ';
  3386. }
  3387. sprintf( TextBuffer, "%08X %c %s\r\n", OldRva, Discarded, SymbolName );
  3388. WriteFile( SymbolContext->OutFile, TextBuffer, strlen( TextBuffer ), &Actual, NULL );
  3389. }
  3390. #endif // TESTCODE
  3391. if ( SymbolAddr > SymbolContext->OldImageBase ) {
  3392. OldRva = (ULONG)( SymbolAddr - SymbolContext->OldImageBase );
  3393. SymbolNode = SymRBFind(
  3394. &SymbolContext->NewDecoratedSymbolTree,
  3395. SymbolName
  3396. );
  3397. if ( SymbolNode ) {
  3398. AddRiftEntryToTable( SymbolContext->RiftTable, OldRva, SymbolNode->Rva );
  3399. SymbolNode->Hit = 1;
  3400. #ifdef TESTCODE
  3401. CountDecoratedMatches++;
  3402. #endif // TESTCODE
  3403. }
  3404. else {
  3405. //
  3406. // Didn't find matching new symbol. Build a tree of unmatched
  3407. // old symbols with UNdecorated names. Later we'll match up
  3408. // remaining unmatched new symbols to these unmatched old symbols
  3409. // by their undecorated names.
  3410. //
  3411. if ( SymbolContext->SymbolOptionFlags & PATCH_SYMBOL_UNDECORATED_TOO ) {
  3412. return UndecorateSymbolAndAddToTree(
  3413. SymbolName,
  3414. OldRva,
  3415. &SymbolContext->OldUndecoratedSymbolTree
  3416. );
  3417. }
  3418. }
  3419. }
  3420. return TRUE;
  3421. }
  3422. BOOL
  3423. MatchRemainingSymbolsThisNode(
  3424. IN PSYMBOL_NODE NewDecoratedSymbolNode,
  3425. IN PSYMBOL_TREE NewUndecoratedSymbolTree,
  3426. IN PSYMBOL_TREE OldUndecoratedSymbolTree,
  3427. IN PRIFT_TABLE RiftTable
  3428. )
  3429. {
  3430. if ( ! NewDecoratedSymbolNode->Hit ) {
  3431. ULONG SymbolNameSize = (ULONG) strlen( NewDecoratedSymbolNode->SymbolName ) + 1;
  3432. LPSTR NewUndecoratedName = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, SymbolNameSize );
  3433. PSYMBOL_NODE NewUndecoratedSymbolNode;
  3434. PSYMBOL_NODE OldUndecoratedSymbolNode;
  3435. if (!NewUndecoratedName) {
  3436. return FALSE;
  3437. }
  3438. MyUndecorateSymbol(
  3439. NewDecoratedSymbolNode->SymbolName,
  3440. NewUndecoratedName,
  3441. SymbolNameSize
  3442. );
  3443. OldUndecoratedSymbolNode = SymRBFind(
  3444. OldUndecoratedSymbolTree,
  3445. NewUndecoratedName
  3446. );
  3447. if ( OldUndecoratedSymbolNode ) {
  3448. AddRiftEntryToTable(
  3449. RiftTable,
  3450. OldUndecoratedSymbolNode->Rva,
  3451. NewDecoratedSymbolNode->Rva
  3452. );
  3453. OldUndecoratedSymbolNode->Hit = 1;
  3454. #ifdef TESTCODE
  3455. CountUndecoratedMatches++;
  3456. #endif // TESTCODE
  3457. }
  3458. else {
  3459. //
  3460. // This new symbol has no match in the old symbol tree. Build a
  3461. // tree of unmatched new undecorated symbols.
  3462. //
  3463. NewUndecoratedSymbolNode = SymRBInsert(
  3464. NewUndecoratedSymbolTree,
  3465. NewUndecoratedName,
  3466. NewDecoratedSymbolNode->Rva
  3467. );
  3468. HeapFree(GetProcessHeap(), 0, NewUndecoratedName);
  3469. return ( NewUndecoratedSymbolNode != NULL );
  3470. }
  3471. HeapFree(GetProcessHeap(), 0, NewUndecoratedName);
  3472. }
  3473. return TRUE;
  3474. }
  3475. BOOL
  3476. MatchRemainingSymbolsRecursive(
  3477. IN PSYMBOL_NODE NewDecoratedSymbolNode,
  3478. IN PSYMBOL_TREE NewUndecoratedSymbolTree,
  3479. IN PSYMBOL_TREE OldUndecoratedSymbolTree,
  3480. IN PRIFT_TABLE RiftTable
  3481. )
  3482. {
  3483. if ( NewDecoratedSymbolNode == RBNIL ) {
  3484. return TRUE;
  3485. }
  3486. return ( MatchRemainingSymbolsRecursive( NewDecoratedSymbolNode->Left, NewUndecoratedSymbolTree, OldUndecoratedSymbolTree, RiftTable ) &&
  3487. MatchRemainingSymbolsRecursive( NewDecoratedSymbolNode->Right, NewUndecoratedSymbolTree, OldUndecoratedSymbolTree, RiftTable ) &&
  3488. MatchRemainingSymbolsThisNode( NewDecoratedSymbolNode, NewUndecoratedSymbolTree, OldUndecoratedSymbolTree, RiftTable ));
  3489. }
  3490. #ifdef TESTCODE
  3491. VOID
  3492. DumpUnHitSymbolNode(
  3493. IN PSYMBOL_NODE SymbolNode,
  3494. IN HANDLE hFile
  3495. )
  3496. {
  3497. CHAR TextBuffer[ 16 + MAX_SYMBOL_NAME_LENGTH ];
  3498. DWORD Actual;
  3499. if ( ! SymbolNode->Hit ) {
  3500. sprintf( TextBuffer, "%08X %s\r\n", SymbolNode->Rva, SymbolNode->SymbolName );
  3501. WriteFile( hFile, TextBuffer, strlen( TextBuffer ), &Actual, NULL );
  3502. }
  3503. }
  3504. VOID
  3505. DumpUnHitSymbolNodesRecursive(
  3506. IN PSYMBOL_NODE SymbolNode,
  3507. IN HANDLE hFile
  3508. )
  3509. {
  3510. if ( SymbolNode == RBNIL ) {
  3511. return;
  3512. }
  3513. //
  3514. // The tree is in hash order, not Rva order, so the output will appear
  3515. // to be in random order (easily solved with sort.exe utility).
  3516. //
  3517. DumpUnHitSymbolNode( SymbolNode, hFile );
  3518. DumpUnHitSymbolNodesRecursive( SymbolNode->Left, hFile );
  3519. DumpUnHitSymbolNodesRecursive( SymbolNode->Right, hFile );
  3520. }
  3521. VOID
  3522. DumpUnHitSymbolNodes(
  3523. IN PSYMBOL_TREE SymbolTree,
  3524. IN LPCSTR DumpFileName
  3525. )
  3526. {
  3527. HANDLE hFile;
  3528. hFile = CreateFile(
  3529. DumpFileName,
  3530. GENERIC_WRITE,
  3531. FILE_SHARE_READ,
  3532. NULL,
  3533. CREATE_ALWAYS,
  3534. FILE_ATTRIBUTE_NORMAL,
  3535. NULL
  3536. );
  3537. if ( hFile != INVALID_HANDLE_VALUE ) {
  3538. DumpUnHitSymbolNodesRecursive( SymbolTree->Root, hFile );
  3539. CloseHandle( hFile );
  3540. }
  3541. }
  3542. #endif // TESTCODE
  3543. BOOL
  3544. MatchRemainingSymbols(
  3545. IN PSYMBOL_TREE NewDecoratedSymbolTree,
  3546. IN PSYMBOL_TREE NewUndecoratedSymbolTree,
  3547. IN PSYMBOL_TREE OldUndecoratedSymbolTree,
  3548. IN PRIFT_TABLE RiftTable
  3549. )
  3550. {
  3551. BOOL Success;
  3552. //
  3553. // Walk old tree, for each unmatched symbol, undecorate it and try to
  3554. // find match in the undecorated new symbol tree. If it fails to match,
  3555. // add it to the old undecorated tree.
  3556. //
  3557. Success = MatchRemainingSymbolsRecursive(
  3558. NewDecoratedSymbolTree->Root,
  3559. NewUndecoratedSymbolTree,
  3560. OldUndecoratedSymbolTree,
  3561. RiftTable
  3562. );
  3563. if ( Success ) {
  3564. //
  3565. // Now we have remaining unmatched undecorated symbols in the
  3566. // OldUndecoratedSymbolTree and NewUndecoratedSymbolTree.
  3567. //
  3568. // Here is an opportunity to do soft name matching, like for
  3569. // BBT omap generated symbol names (have trailing '_nnn').
  3570. // Unfortunately, current versions of imagehlp append an '_nnn'
  3571. // value that is useless becaue it is not the offset from the
  3572. // start of the function.
  3573. //
  3574. #ifdef TESTCODE
  3575. DumpUnHitSymbolNodes( OldUndecoratedSymbolTree, "UnmatchedOldSymbols.out" );
  3576. DumpUnHitSymbolNodes( NewUndecoratedSymbolTree, "UnmatchedNewSymbols.out" );
  3577. #endif // TESTCODE
  3578. }
  3579. return Success;
  3580. }
  3581. BOOL
  3582. GetImageSymbolRiftInfo(
  3583. IN HANDLE OldFileHandle,
  3584. IN PUCHAR OldFileMapped,
  3585. IN ULONG OldFileSize,
  3586. IN UP_IMAGE_NT_HEADERS32 OldFileNtHeader,
  3587. IN LPCSTR OldFileSymPath,
  3588. IN ULONG OldFileOriginalChecksum,
  3589. IN ULONG OldFileOriginalTimeDate,
  3590. IN ULONG OldFileIndex,
  3591. IN HANDLE NewFileHandle,
  3592. IN PUCHAR NewFileMapped,
  3593. IN ULONG NewFileSize,
  3594. IN UP_IMAGE_NT_HEADERS32 NewFileNtHeader,
  3595. IN LPCSTR NewFileSymPath,
  3596. IN ULONG SymbolOptionFlags,
  3597. IN HANDLE SubAllocator,
  3598. IN PRIFT_TABLE RiftTable,
  3599. IN PPATCH_SYMLOAD_CALLBACK SymLoadCallback,
  3600. IN PVOID SymLoadContext
  3601. )
  3602. {
  3603. SYMBOL_CONTEXT SymbolContext;
  3604. DWORD SymOptions;
  3605. ULONG_PTR OldBase;
  3606. ULONG_PTR NewBase;
  3607. BOOL Success;
  3608. #ifdef TESTCODE
  3609. ULONG InitialRiftEntries = RiftTable->RiftEntryCount;
  3610. #endif
  3611. UNREFERENCED_PARAMETER( OldFileNtHeader );
  3612. UNREFERENCED_PARAMETER( OldFileMapped );
  3613. UNREFERENCED_PARAMETER( OldFileSize );
  3614. UNREFERENCED_PARAMETER( NewFileMapped );
  3615. UNREFERENCED_PARAMETER( NewFileSize );
  3616. InitImagehlpCritSect();
  3617. EnterCriticalSection( &ImagehlpCritSect );
  3618. Success = LoadImagehlp();
  3619. if ( Success ) {
  3620. __try {
  3621. SymOptions = Imagehlp.SymGetOptions();
  3622. SymOptions &= ~SYMOPT_CASE_INSENSITIVE;
  3623. SymOptions &= ~SYMOPT_UNDNAME;
  3624. SymOptions &= ~SYMOPT_DEFERRED_LOADS;
  3625. Imagehlp.SymSetOptions( SymOptions );
  3626. Success = Imagehlp.SymInitialize( hProc, NewFileSymPath, FALSE );
  3627. if ( Success ) {
  3628. __try {
  3629. SymRBInitTree(
  3630. &SymbolContext.NewDecoratedSymbolTree,
  3631. SubAllocator
  3632. );
  3633. SymRBInitTree(
  3634. &SymbolContext.NewUndecoratedSymbolTree,
  3635. SubAllocator
  3636. );
  3637. SymRBInitTree(
  3638. &SymbolContext.OldUndecoratedSymbolTree,
  3639. SubAllocator
  3640. );
  3641. NewBase = Imagehlp.SymLoadModule( hProc, NewFileHandle, NULL, "New", (ULONG_PTR)NewFileMapped, NewFileSize );
  3642. Success = ( NewBase != 0 );
  3643. if ( Success ) {
  3644. __try {
  3645. if ( SymLoadCallback ) {
  3646. ZeroMemory( &ImagehlpModuleInfo, sizeof( ImagehlpModuleInfo ));
  3647. ImagehlpModuleInfo.SizeOfStruct = sizeof( ImagehlpModuleInfo );
  3648. Success = Imagehlp.SymGetModuleInfo(
  3649. hProc,
  3650. NewBase,
  3651. &ImagehlpModuleInfo
  3652. );
  3653. if ( Success ) {
  3654. Success = SymLoadCallback(
  3655. 0,
  3656. ImagehlpModuleInfo.LoadedImageName,
  3657. ImagehlpModuleInfo.SymType,
  3658. ImagehlpModuleInfo.CheckSum,
  3659. ImagehlpModuleInfo.TimeDateStamp,
  3660. NewFileNtHeader->OptionalHeader.CheckSum,
  3661. NewFileNtHeader->FileHeader.TimeDateStamp,
  3662. SymLoadContext
  3663. );
  3664. }
  3665. }
  3666. if ( Success ) {
  3667. SymbolContext.NewImageBase = NewBase;
  3668. SymbolContext.SymbolOptionFlags = SymbolOptionFlags;
  3669. SymbolContext.RiftTable = RiftTable;
  3670. #ifdef TESTCODE
  3671. CountDecoratedMatches = 0;
  3672. CountUndecoratedMatches = 0;
  3673. SymbolContext.OutFile = CreateFile(
  3674. "NewSymbols.out",
  3675. GENERIC_WRITE,
  3676. FILE_SHARE_READ,
  3677. NULL,
  3678. CREATE_ALWAYS,
  3679. FILE_ATTRIBUTE_NORMAL,
  3680. NULL
  3681. );
  3682. #endif // TESTCODE
  3683. Success = Imagehlp.SymEnumerateSymbols( hProc, NewBase, NewFileEnumSymbolsCallback, &SymbolContext );
  3684. #ifdef TESTCODE
  3685. if ( SymbolContext.OutFile != INVALID_HANDLE_VALUE ) {
  3686. CloseHandle( SymbolContext.OutFile );
  3687. }
  3688. #endif // TESTCODE
  3689. }
  3690. }
  3691. __except( EXCEPTION_EXECUTE_HANDLER ) {
  3692. Success = FALSE;
  3693. }
  3694. Imagehlp.SymUnloadModule( hProc, NewBase );
  3695. }
  3696. }
  3697. __except( EXCEPTION_EXECUTE_HANDLER ) {
  3698. Success = FALSE;
  3699. }
  3700. //
  3701. // Must do cleanup and reinitialize Imagehlp for this
  3702. // process identifier. Otherwise it thinks the old
  3703. // module is still hanging around.
  3704. //
  3705. Imagehlp.SymCleanup( hProc );
  3706. if ( Success ) {
  3707. Success = Imagehlp.SymInitialize( hProc, OldFileSymPath, FALSE );
  3708. if ( Success ) {
  3709. __try {
  3710. OldBase = Imagehlp.SymLoadModule( hProc, OldFileHandle, NULL, "Old", (ULONG_PTR)OldFileMapped, OldFileSize );
  3711. Success = ( OldBase != 0 );
  3712. if ( Success ) {
  3713. __try {
  3714. if ( SymLoadCallback ) {
  3715. ZeroMemory( &ImagehlpModuleInfo, sizeof( ImagehlpModuleInfo ));
  3716. ImagehlpModuleInfo.SizeOfStruct = sizeof( ImagehlpModuleInfo );
  3717. Success = Imagehlp.SymGetModuleInfo(
  3718. hProc,
  3719. OldBase,
  3720. &ImagehlpModuleInfo
  3721. );
  3722. if ( Success ) {
  3723. Success = SymLoadCallback(
  3724. OldFileIndex + 1,
  3725. ImagehlpModuleInfo.LoadedImageName,
  3726. ImagehlpModuleInfo.SymType,
  3727. ImagehlpModuleInfo.CheckSum,
  3728. ImagehlpModuleInfo.TimeDateStamp,
  3729. OldFileOriginalChecksum,
  3730. OldFileOriginalTimeDate,
  3731. SymLoadContext
  3732. );
  3733. }
  3734. }
  3735. if ( Success ) {
  3736. SymbolContext.OldImageBase = OldBase;
  3737. #ifdef TESTCODE
  3738. SymbolContext.OutFile = CreateFile(
  3739. "OldSymbols.out",
  3740. GENERIC_WRITE,
  3741. FILE_SHARE_READ,
  3742. NULL,
  3743. CREATE_ALWAYS,
  3744. FILE_ATTRIBUTE_NORMAL,
  3745. NULL
  3746. );
  3747. #endif // TESTCODE
  3748. Success = Imagehlp.SymEnumerateSymbols( hProc, OldBase, OldFileEnumSymbolsCallback, &SymbolContext );
  3749. #ifdef TESTCODE
  3750. if ( SymbolContext.OutFile != INVALID_HANDLE_VALUE ) {
  3751. CloseHandle( SymbolContext.OutFile );
  3752. }
  3753. #endif // TESTCODE
  3754. }
  3755. if ( Success ) {
  3756. //
  3757. // Need to match remaining decorated new symbols in tree
  3758. // with unmatched now-undecorated old symbols in other tree.
  3759. //
  3760. if ( SymbolOptionFlags & PATCH_SYMBOL_UNDECORATED_TOO ) {
  3761. Success = MatchRemainingSymbols(
  3762. &SymbolContext.NewDecoratedSymbolTree,
  3763. &SymbolContext.NewUndecoratedSymbolTree,
  3764. &SymbolContext.OldUndecoratedSymbolTree,
  3765. RiftTable
  3766. );
  3767. }
  3768. }
  3769. }
  3770. __except( EXCEPTION_EXECUTE_HANDLER ) {
  3771. Success = FALSE;
  3772. }
  3773. Imagehlp.SymUnloadModule( hProc, OldBase );
  3774. }
  3775. }
  3776. __except( EXCEPTION_EXECUTE_HANDLER ) {
  3777. Success = FALSE;
  3778. }
  3779. Imagehlp.SymCleanup( hProc );
  3780. }
  3781. }
  3782. }
  3783. }
  3784. __except( EXCEPTION_EXECUTE_HANDLER ) {
  3785. Success = FALSE;
  3786. }
  3787. }
  3788. LeaveCriticalSection( &ImagehlpCritSect );
  3789. if ( ! Success ) {
  3790. SetLastError( ERROR_PATCH_IMAGEHLP_FAILURE );
  3791. }
  3792. #ifdef TESTCODE
  3793. printf( "\r%9d decorated symbol matches\n", CountDecoratedMatches );
  3794. printf( "\r%9d undecorated symbol matches\n", CountUndecoratedMatches );
  3795. printf( "\r%9d rift entries from symbols\n", RiftTable->RiftEntryCount - InitialRiftEntries );
  3796. #endif
  3797. return Success;
  3798. }
  3799. BOOL
  3800. OptimizeImageRiftInfo(
  3801. IN PUCHAR OldFileMapped,
  3802. IN ULONG OldFileSize,
  3803. IN UP_IMAGE_NT_HEADERS32 OldFileNtHeader,
  3804. IN PUCHAR NewFileMapped,
  3805. IN ULONG NewFileSize,
  3806. IN UP_IMAGE_NT_HEADERS32 NewFileNtHeader,
  3807. IN HANDLE SubAllocator,
  3808. IN PRIFT_TABLE RiftTable
  3809. )
  3810. {
  3811. UNREFERENCED_PARAMETER( OldFileMapped );
  3812. UNREFERENCED_PARAMETER( OldFileSize );
  3813. UNREFERENCED_PARAMETER( OldFileNtHeader );
  3814. UNREFERENCED_PARAMETER( NewFileMapped );
  3815. UNREFERENCED_PARAMETER( NewFileSize );
  3816. UNREFERENCED_PARAMETER( NewFileNtHeader );
  3817. UNREFERENCED_PARAMETER( SubAllocator );
  3818. UNREFERENCED_PARAMETER( RiftTable );
  3819. return TRUE;
  3820. }
  3821. #if 0 // This is test code
  3822. BOOL
  3823. OptimizeImageRiftInfo(
  3824. IN PUCHAR OldFileMapped,
  3825. IN ULONG OldFileSize,
  3826. IN UP_IMAGE_NT_HEADERS32 OldFileNtHeader,
  3827. IN PUCHAR NewFileMapped,
  3828. IN ULONG NewFileSize,
  3829. IN UP_IMAGE_NT_HEADERS32 NewFileNtHeader,
  3830. IN HANDLE SubAllocator,
  3831. IN PRIFT_TABLE RiftTable
  3832. )
  3833. {
  3834. UP_IMAGE_SECTION_HEADER SectionHeader;
  3835. ULONG SectionCount;
  3836. PUCHAR SectionStart;
  3837. PUCHAR SearchExtent;
  3838. ULONG SectionLength;
  3839. ULONG SectionOffset;
  3840. ULONG SectionBaseRva;
  3841. ULONG OldFileLastRva;
  3842. ULONG NewFileLastRva;
  3843. LONG OldDisplacement;
  3844. LONG NewDisplacement;
  3845. ULONG OffsetInSection;
  3846. ULONG OldOriginRva;
  3847. ULONG OldTargetRva;
  3848. ULONG TargetOffset;
  3849. PUCHAR OldFileHintMap;
  3850. PUCHAR NewFileHintMap;
  3851. PUCHAR OldFileCopy;
  3852. PUCHAR NewFileCopy;
  3853. PVOID OldFileCopyNtHeader;
  3854. PVOID NewFileCopyNtHeader;
  3855. BOOL Success;
  3856. BOOL Skip;
  3857. ULONG i;
  3858. ULONG j;
  3859. PUCHAR p;
  3860. #ifdef TESTCODE
  3861. ULONG CountVerifiedE8Rifts = 0;
  3862. ULONG CountDiscoveredE8Rifts = 0;
  3863. #endif // TESTCODE
  3864. //
  3865. // Stage1:
  3866. //
  3867. // Trusting existing rift info, search for E8/E9/Jcc instructions in
  3868. // the Old file, get the corresponding rift, inspect the corresponding
  3869. // instruction in the New file. If they match, great. If they don't
  3870. // match, search for a correponding instruction in the new file by
  3871. // looking forward up to the next rift. If find a suitable match,
  3872. // create a new rift entry to support it.
  3873. //
  3874. // We don't have the benefit of non-exe marked bytes here.
  3875. //
  3876. if ( OldFileNtHeader->FileHeader.Machine != NewFileNtHeader->FileHeader.Machine ) {
  3877. return TRUE; // not much we can do here!
  3878. }
  3879. //
  3880. // We need the HintMap to determine which bytes in the files are not
  3881. // executable. The Transform function currently provides this, but
  3882. // we don't want to modify our mapped file views here. So, allocate
  3883. // a range of VM and make a copy of the file to Transform, perform
  3884. // the transformations on that copy just to produce a hint map, then
  3885. // free the transformed copy (do this for both old and new files).
  3886. //
  3887. Success = FALSE;
  3888. OldFileHintMap = MyVirtualAlloc( OldFileSize );
  3889. NewFileHintMap = MyVirtualAlloc( NewFileSize );
  3890. if ( OldFileHintMap && NewFileHintMap ) {
  3891. OldFileCopy = MyVirtualAlloc( OldFileSize );
  3892. if ( OldFileCopy ) {
  3893. CopyMemory( OldFileCopy, OldFileMapped, OldFileSize );
  3894. OldFileCopyNtHeader = GetNtHeader( OldFileCopy, OldFileSize );
  3895. Success = TransformCoffImage(
  3896. ( PATCH_TRANSFORM_NO_RELJMPS | PATCH_TRANSFORM_NO_RELCALLS | PATCH_TRANSFORM_NO_RESOURCE ),
  3897. OldFileCopyNtHeader,
  3898. OldFileCopy,
  3899. OldFileSize,
  3900. 0,
  3901. RiftTable,
  3902. OldFileHintMap
  3903. );
  3904. MyVirtualFree( OldFileCopy );
  3905. }
  3906. if ( Success ) {
  3907. Success = FALSE;
  3908. NewFileCopy = MyVirtualAlloc( NewFileSize );
  3909. if ( NewFileCopy ) {
  3910. CopyMemory( NewFileCopy, NewFileMapped, NewFileSize );
  3911. NewFileCopyNtHeader = GetNtHeader( NewFileCopy, NewFileSize );
  3912. Success = TransformCoffImage(
  3913. ( PATCH_TRANSFORM_NO_RELJMPS | PATCH_TRANSFORM_NO_RELCALLS | PATCH_TRANSFORM_NO_RESOURCE ),
  3914. NewFileCopyNtHeader,
  3915. NewFileCopy,
  3916. NewFileSize,
  3917. 0,
  3918. RiftTable,
  3919. NewFileHintMap
  3920. );
  3921. MyVirtualFree( NewFileCopy );
  3922. }
  3923. }
  3924. }
  3925. if ( Success ) {
  3926. //
  3927. // We now have valid OldFileHintMap and NewFileHintMap.
  3928. //
  3929. OldFileLastRva = OldFileNtHeader->OptionalHeader.SizeOfImage;
  3930. NewFileLastRva = NewFileNtHeader->OptionalHeader.SizeOfImage;
  3931. InsertRiftEntryInSortedTable( RiftTable, RiftTable->RiftEntryCount, OldFileLastRva, NewFileLastRva );
  3932. SectionHeader = IMAGE_FIRST_SECTION( OldFileNtHeader );
  3933. SectionCount = OldFileNtHeader->FileHeader.NumberOfSections;
  3934. for ( i = 0; i < SectionCount; i++ ) {
  3935. if ( SectionHeader[ i ].Characteristics & IMAGE_SCN_MEM_EXECUTE ) {
  3936. SectionBaseRva = SectionHeader[ i ].VirtualAddress;
  3937. SectionLength = MIN( SectionHeader[ i ].Misc.VirtualSize, SectionHeader[ i ].SizeOfRawData );
  3938. SectionOffset = SectionHeader[ i ].PointerToRawData;
  3939. SectionStart = OldFileMapped + SectionOffset;
  3940. if ( OldFileNtHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_I386 ) {
  3941. SearchExtent = SectionStart + SectionLength - 5;
  3942. for ( p = SectionStart; p < SearchExtent; p++ ) {
  3943. if ( *p == 0xE8 ) { // call relative32
  3944. //
  3945. // Validate that instruction is not something that
  3946. // the HintMap indicates is not an executable
  3947. // instruction. We're looking for a relative
  3948. // call instruction here, so it would not be a
  3949. // reloc target.
  3950. //
  3951. Skip = FALSE;
  3952. for ( j = 0; j < 5; j++ ) {
  3953. if ( OldFileHintMap[ SectionOffset + ( p - SectionStart ) + j ] & 0x01 ) {
  3954. Skip = TRUE;
  3955. break;
  3956. }
  3957. }
  3958. if ( Skip ) {
  3959. continue;
  3960. }
  3961. //
  3962. // Relative displacement is stored as 32-bit
  3963. // signed value following these opcodes. The
  3964. // displacement is relative to the NEXT
  3965. // instruction, which is at (p + 5).
  3966. //
  3967. OldDisplacement = *(UNALIGNED LONG*)( p + 1 );
  3968. OffsetInSection = ( p + 5 ) - SectionStart;
  3969. OldOriginRva = SectionBaseRva + OffsetInSection;
  3970. OldTargetRva = OldOriginRva + OldDisplacement;
  3971. //
  3972. // We expect a lot of false positives here because
  3973. // occurences of <E8> will
  3974. // likely occur in other parts of the instruction
  3975. // stream so now we validate that the TargetRva
  3976. // falls within the image and within an executable
  3977. // section.
  3978. //
  3979. if ( OldTargetRva < OldFileLastRva ) {
  3980. TargetOffset = ImageRvaToFileOffset( OldFileNtHeader, OldTargetRva );
  3981. if ( ! ( OldFileHintMap[ TargetOffset ] & 0x01 )) {
  3982. //
  3983. // Looks like a valid TargetRva, so lookup the
  3984. // corresponding "new" RVAs in the rift table.
  3985. //
  3986. ULONG RiftIndexOrigin = FindRiftTableEntryForOldRva( RiftTable, OldOriginRva );
  3987. ULONG RiftIndexTarget = FindRiftTableEntryForOldRva( RiftTable, OldTargetRva );
  3988. ULONG NewOriginRva = OldOriginRva + (LONG)( RiftTable->RiftEntryArray[ RiftIndexOrigin ].NewFileRva - RiftTable->RiftEntryArray[ RiftIndexOrigin ].OldFileRva );
  3989. ULONG NewTargetRva = OldTargetRva + (LONG)( RiftTable->RiftEntryArray[ RiftIndexTarget ].NewFileRva - RiftTable->RiftEntryArray[ RiftIndexTarget ].OldFileRva );
  3990. PUCHAR NewOriginMa = ImageRvaToMappedAddress( NewFileNtHeader, NewOriginRva, NewFileMapped, NewFileSize );
  3991. PUCHAR NewTargetMa = ImageRvaToMappedAddress( NewFileNtHeader, NewTargetRva, NewFileMapped, NewFileSize );
  3992. PUCHAR OldTargetMa = ImageRvaToMappedAddress( OldFileNtHeader, OldTargetRva, OldFileMapped, OldFileSize );
  3993. PUCHAR OldOriginMa = p + 5;
  3994. if (( NewOriginMa ) && ( NewTargetMa ) && ( OldTargetMa )) {
  3995. PUCHAR OldInstruct = p;
  3996. PUCHAR NewInstruct = NewOriginMa - 5;
  3997. //
  3998. // A verified call instruction should match the
  3999. // instruction byte, the byte following the
  4000. // instruction, and the target byte, because
  4001. // they should all be executable code that is
  4002. // not modified by relocs.
  4003. //
  4004. // Also verify the NewFileHintMap.
  4005. //
  4006. if (( *OldInstruct == *NewInstruct ) &&
  4007. ( *OldOriginMa == *NewOriginMa ) &&
  4008. ( *OldTargetMa == *NewTargetMa )) {
  4009. ULONG NewInstructOffset = NewInstruct - NewFileMapped;
  4010. ULONG NewTargetOffset = NewTargetMa - NewFileMapped;
  4011. BOOL Skip = FALSE;
  4012. for ( j = 0; j < 5; j++ ) {
  4013. if ( NewFileHintMap[ NewInstructOffset + j ] & 0x01 ) {
  4014. Skip = TRUE;
  4015. break;
  4016. }
  4017. }
  4018. if ( NewFileHintMap[ NewTargetOffset + j ] & 0x01 ) {
  4019. Skip = TRUE;
  4020. }
  4021. if ( ! Skip ) {
  4022. //
  4023. // This is a bonafide good match. Add a rift entry
  4024. // for both the instruction and the target. We do
  4025. // this so that subsequent rift insertions don't get
  4026. // between the rift that coasted to these and these.
  4027. //
  4028. InsertRiftEntryInSortedTable( RiftTable, RiftIndexOrigin, OldOriginRva - 5, NewOriginRva - 5 );
  4029. InsertRiftEntryInSortedTable( RiftTable, RiftIndexTarget, OldTargetRva, NewTargetRva );
  4030. #ifdef TESTCODE
  4031. CountVerifiedE8Rifts++;
  4032. #endif // TESTCODE
  4033. }
  4034. }
  4035. }
  4036. }
  4037. }
  4038. }
  4039. }
  4040. }
  4041. else if ( OldFileNtHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_ALPHA ) {
  4042. //
  4043. // Implement Alpha platform stuff here.
  4044. //
  4045. }
  4046. }
  4047. }
  4048. for ( i = 0; i < SectionCount; i++ ) {
  4049. if ( SectionHeader[ i ].Characteristics & IMAGE_SCN_MEM_EXECUTE ) {
  4050. SectionBaseRva = SectionHeader[ i ].VirtualAddress;
  4051. SectionLength = MIN( SectionHeader[ i ].Misc.VirtualSize, SectionHeader[ i ].SizeOfRawData );
  4052. SectionOffset = SectionHeader[ i ].PointerToRawData;
  4053. SectionStart = OldFileMapped + SectionOffset;
  4054. if ( OldFileNtHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_I386 ) {
  4055. SearchExtent = SectionStart + SectionLength - 5;
  4056. for ( p = SectionStart; p < SearchExtent; p++ ) {
  4057. if ( *p == 0xE8 ) { // call relative32
  4058. //
  4059. // Validate that instruction is not something that
  4060. // the HintMap indicates is not an executable
  4061. // instruction. We're looking for a relative
  4062. // call instruction here, so it would not be a
  4063. // reloc target.
  4064. //
  4065. Skip = FALSE;
  4066. for ( j = 0; j < 5; j++ ) {
  4067. if ( OldFileHintMap[ SectionOffset + ( p - SectionStart ) + j ] & 0x01 ) {
  4068. Skip = TRUE;
  4069. break;
  4070. }
  4071. }
  4072. if ( Skip ) {
  4073. continue;
  4074. }
  4075. //
  4076. // Relative displacement is stored as 32-bit
  4077. // signed value following these opcodes. The
  4078. // displacement is relative to the NEXT
  4079. // instruction, which is at (p + 5).
  4080. //
  4081. OldDisplacement = *(UNALIGNED LONG*)( p + 1 );
  4082. OffsetInSection = ( p + 5 ) - SectionStart;
  4083. OldOriginRva = SectionBaseRva + OffsetInSection;
  4084. OldTargetRva = OldOriginRva + OldDisplacement;
  4085. //
  4086. // We expect a lot of false positives here because
  4087. // occurences of <E8> will
  4088. // likely occur in other parts of the instruction
  4089. // stream so now we validate that the TargetRva
  4090. // falls within the image and within an executable
  4091. // section.
  4092. //
  4093. if ( OldTargetRva < OldFileLastRva ) {
  4094. TargetOffset = ImageRvaToFileOffset( OldFileNtHeader, OldTargetRva );
  4095. if ( ! ( OldFileHintMap[ TargetOffset ] & 0x01 )) {
  4096. //
  4097. // Looks like a valid TargetRva, so lookup the
  4098. // corresponding "new" RVAs in the rift table.
  4099. //
  4100. ULONG RiftIndexOrigin = FindRiftTableEntryForOldRva( RiftTable, OldOriginRva );
  4101. ULONG RiftIndexTarget = FindRiftTableEntryForOldRva( RiftTable, OldTargetRva );
  4102. ULONG NewOriginRva = OldOriginRva + (LONG)( RiftTable->RiftEntryArray[ RiftIndexOrigin ].NewFileRva - RiftTable->RiftEntryArray[ RiftIndexOrigin ].OldFileRva );
  4103. ULONG NewTargetRva = OldTargetRva + (LONG)( RiftTable->RiftEntryArray[ RiftIndexTarget ].NewFileRva - RiftTable->RiftEntryArray[ RiftIndexTarget ].OldFileRva );
  4104. PUCHAR NewOriginMa = ImageRvaToMappedAddress( NewFileNtHeader, NewOriginRva, NewFileMapped, NewFileSize );
  4105. PUCHAR NewTargetMa = ImageRvaToMappedAddress( NewFileNtHeader, NewTargetRva, NewFileMapped, NewFileSize );
  4106. PUCHAR OldTargetMa = ImageRvaToMappedAddress( OldFileNtHeader, OldTargetRva, OldFileMapped, OldFileSize );
  4107. PUCHAR OldOriginMa = p + 5;
  4108. if (( NewOriginMa ) && ( NewTargetMa ) && ( OldTargetMa )) {
  4109. PUCHAR OldInstruct = p;
  4110. PUCHAR NewInstruct = NewOriginMa - 5;
  4111. //
  4112. // A verified call instruction should match the
  4113. // instruction byte, the byte following the
  4114. // instruction, and the target byte, because
  4115. // they should all be executable code that is
  4116. // not modified by relocs.
  4117. //
  4118. // Check NewHintMap too.
  4119. //
  4120. if (( *OldInstruct == *NewInstruct ) &&
  4121. ( *OldOriginMa == *NewOriginMa ) &&
  4122. ( *OldTargetMa == *NewTargetMa )) {
  4123. ULONG NewInstructOffset = NewInstruct - NewFileMapped;
  4124. ULONG NewTargetOffset = NewTargetMa - NewFileMapped;
  4125. BOOL Skip = FALSE;
  4126. for ( j = 0; j < 5; j++ ) {
  4127. if ( NewFileHintMap[ NewInstructOffset + j ] & 0x01 ) {
  4128. Skip = TRUE;
  4129. break;
  4130. }
  4131. }
  4132. if ( NewFileHintMap[ NewTargetOffset + j ] & 0x01 ) {
  4133. Skip = TRUE;
  4134. }
  4135. if ( ! Skip ) {
  4136. //
  4137. // This is a bonafide good match.
  4138. //
  4139. continue;
  4140. }
  4141. }
  4142. {
  4143. //
  4144. // Instructions don't match. Scan to find
  4145. // matching instruction in new file. Scan
  4146. // the extent of this rift entry.
  4147. //
  4148. PUCHAR ScanInstruct;
  4149. PUCHAR LowestMaToScan;
  4150. PUCHAR HighestMaToScan;
  4151. ULONG LowestRvaToScan = RiftTable->RiftEntryArray[ RiftIndexOrigin ].NewFileRva;
  4152. ULONG HighestRvaToScan = RiftTable->RiftEntryArray[ RiftIndexOrigin + 1 ].NewFileRva;
  4153. ULONG ExpectedTargetRva = NewTargetRva;
  4154. BOOL Found = FALSE;
  4155. LowestMaToScan = ImageRvaToMappedAddress( NewFileNtHeader, LowestRvaToScan, NewFileMapped, NewFileSize );
  4156. HighestMaToScan = ImageRvaToMappedAddress( NewFileNtHeader, HighestRvaToScan, NewFileMapped, NewFileSize );
  4157. HighestMaToScan -= 5; // size of instruction
  4158. for ( ScanInstruct = NewInstruct + 1; ScanInstruct <= HighestMaToScan; ScanInstruct++ ) {
  4159. if ( *ScanInstruct == 0xE8 ) {
  4160. //
  4161. // check NewHintMap
  4162. //
  4163. NewOriginMa = ScanInstruct + 5;
  4164. NewOriginRva = MappedAddressToImageRva( NewFileNtHeader, NewOriginMa, NewFileMapped );
  4165. NewDisplacement = *(UNALIGNED LONG*)( ScanInstruct + 1 );
  4166. NewTargetRva = NewOriginRva + NewDisplacement;
  4167. NewTargetMa = ImageRvaToMappedAddress( NewFileNtHeader, NewTargetRva, NewFileMapped, NewFileSize );
  4168. if (( NewOriginRva ) && ( NewTargetMa )) {
  4169. //
  4170. // We already know *OldInstruct == *ScanInstruct
  4171. //
  4172. if (( *OldOriginMa == *NewOriginMa ) &&
  4173. ( *OldTargetMa == *NewTargetMa ) &&
  4174. ( NewTargetRva == ExpectedTargetRva )) {
  4175. ULONG NewInstructOffset = ScanInstruct - NewFileMapped;
  4176. ULONG NewTargetOffset = NewTargetMa - NewFileMapped;
  4177. BOOL Skip = FALSE;
  4178. for ( j = 0; j < 5; j++ ) {
  4179. if ( NewFileHintMap[ NewInstructOffset + j ] & 0x01 ) {
  4180. Skip = TRUE;
  4181. break;
  4182. }
  4183. }
  4184. if ( NewFileHintMap[ NewTargetOffset + j ] & 0x01 ) {
  4185. Skip = TRUE;
  4186. }
  4187. if ( ! Skip ) {
  4188. InsertRiftEntryInSortedTable( RiftTable, RiftIndexOrigin, OldOriginRva - 5, NewOriginRva - 5 );
  4189. InsertRiftEntryInSortedTable( RiftTable, RiftIndexTarget, OldTargetRva, NewTargetRva );
  4190. Found = TRUE;
  4191. #ifdef TESTCODE
  4192. CountDiscoveredE8Rifts++;
  4193. #endif // TESTCODE
  4194. break;
  4195. }
  4196. }
  4197. }
  4198. }
  4199. }
  4200. if ( Found ) {
  4201. continue;
  4202. }
  4203. for ( ScanInstruct = NewInstruct - 1; ScanInstruct >= LowestMaToScan; ScanInstruct-- ) {
  4204. if ( *ScanInstruct == 0xE8 ) {
  4205. //
  4206. // check NewHintMap
  4207. //
  4208. NewOriginMa = ScanInstruct + 5;
  4209. NewOriginRva = MappedAddressToImageRva( NewFileNtHeader, NewOriginMa, NewFileMapped );
  4210. NewDisplacement = *(UNALIGNED LONG*)( ScanInstruct + 1 );
  4211. NewTargetRva = NewOriginRva + NewDisplacement;
  4212. NewTargetMa = ImageRvaToMappedAddress( NewFileNtHeader, NewTargetRva, NewFileMapped, NewFileSize );
  4213. if (( NewOriginRva ) && ( NewTargetMa )) {
  4214. //
  4215. // We already know *OldInstruct == *ScanInstruct
  4216. //
  4217. if (( *OldOriginMa == *NewOriginMa ) &&
  4218. ( *OldTargetMa == *NewTargetMa ) &&
  4219. ( NewTargetRva == ExpectedTargetRva )) {
  4220. ULONG NewInstructOffset = ScanInstruct - NewFileMapped;
  4221. ULONG NewTargetOffset = NewTargetMa - NewFileMapped;
  4222. BOOL Skip = FALSE;
  4223. for ( j = 0; j < 5; j++ ) {
  4224. if ( NewFileHintMap[ NewInstructOffset + j ] & 0x01 ) {
  4225. Skip = TRUE;
  4226. break;
  4227. }
  4228. }
  4229. if ( NewFileHintMap[ NewTargetOffset + j ] & 0x01 ) {
  4230. Skip = TRUE;
  4231. }
  4232. if ( ! Skip ) {
  4233. InsertRiftEntryInSortedTable( RiftTable, RiftIndexOrigin, OldOriginRva - 5, NewOriginRva - 5 );
  4234. InsertRiftEntryInSortedTable( RiftTable, RiftIndexTarget, OldTargetRva, NewTargetRva );
  4235. Found = TRUE;
  4236. #ifdef TESTCODE
  4237. CountDiscoveredE8Rifts++;
  4238. #endif // TESTCODE
  4239. break;
  4240. }
  4241. }
  4242. }
  4243. }
  4244. }
  4245. }
  4246. }
  4247. }
  4248. }
  4249. }
  4250. }
  4251. }
  4252. else if ( OldFileNtHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_ALPHA ) {
  4253. //
  4254. // Implement Alpha platform stuff here.
  4255. //
  4256. }
  4257. }
  4258. }
  4259. }
  4260. #ifdef TESTCODE
  4261. printf( "\r%9d verified E8 rifts\n", CountVerifiedE8Rifts );
  4262. printf( "\r%9d discovered E8 rifts\n", CountDiscoveredE8Rifts );
  4263. #endif // TESTCODE
  4264. if ( OldFileHintMap ) {
  4265. MyVirtualFree( OldFileHintMap );
  4266. }
  4267. if ( NewFileHintMap ) {
  4268. MyVirtualFree( NewFileHintMap );
  4269. }
  4270. return Success;
  4271. }
  4272. #endif // 0 (test code)
  4273. BOOL
  4274. GenerateRiftTable(
  4275. IN HANDLE OldFileHandle,
  4276. IN PUCHAR OldFileMapped,
  4277. IN ULONG OldFileSize,
  4278. IN ULONG OldFileOriginalChecksum,
  4279. IN ULONG OldFileOriginalTimeDate,
  4280. IN HANDLE NewFileHandle,
  4281. IN PUCHAR NewFileMapped,
  4282. IN ULONG NewFileSize,
  4283. IN ULONG OptionFlags,
  4284. IN PPATCH_OPTION_DATA OptionData,
  4285. IN ULONG OldFileIndex,
  4286. IN PRIFT_TABLE RiftTable
  4287. )
  4288. {
  4289. UP_IMAGE_NT_HEADERS32 OldFileNtHeader;
  4290. UP_IMAGE_NT_HEADERS32 NewFileNtHeader;
  4291. LPCSTR OldFileSymPath;
  4292. LPCSTR NewFileSymPath;
  4293. HANDLE SubAllocator;
  4294. ULONG SymbolOptionFlags;
  4295. BOOL Success = FALSE;
  4296. UNREFERENCED_PARAMETER( OptionFlags );
  4297. SymbolOptionFlags = 0;
  4298. SubAllocator = NULL;
  4299. __try {
  4300. //
  4301. // See if both files are PE images.
  4302. //
  4303. OldFileNtHeader = GetNtHeader( OldFileMapped, OldFileSize );
  4304. if ( OldFileNtHeader ) {
  4305. NewFileNtHeader = GetNtHeader( NewFileMapped, NewFileSize );
  4306. if ( NewFileNtHeader ) {
  4307. //
  4308. // Both files are PE images.
  4309. //
  4310. SubAllocator = CreateSubAllocator( 0x100000, 0x100000 );
  4311. if ( ! SubAllocator ) {
  4312. Success = FALSE;
  4313. __leave;
  4314. }
  4315. //
  4316. // Before we bother with debug info, we can create initial
  4317. // rift data from the section headers to compensate for any
  4318. // section base RVA differences. This will work even if we
  4319. // don't have debug symbols.
  4320. //
  4321. Success = GetImageNonSymbolRiftInfo(
  4322. OldFileMapped,
  4323. OldFileSize,
  4324. OldFileNtHeader,
  4325. NewFileMapped,
  4326. NewFileSize,
  4327. NewFileNtHeader,
  4328. SubAllocator,
  4329. RiftTable
  4330. );
  4331. //
  4332. // Now get rift info from symbols
  4333. //
  4334. if ( Success ) {
  4335. if (( OptionData ) && ( OptionData->SizeOfThisStruct >= sizeof( PATCH_OPTION_DATA ))) {
  4336. SymbolOptionFlags = OptionData->SymbolOptionFlags;
  4337. if ( ! ( SymbolOptionFlags & PATCH_SYMBOL_NO_IMAGEHLP )) {
  4338. if ( OptionData->OldFileSymbolPathArray ) {
  4339. OldFileSymPath = OptionData->OldFileSymbolPathArray[ OldFileIndex ];
  4340. NewFileSymPath = OptionData->NewFileSymbolPath;
  4341. if (( OldFileSymPath ) && ( NewFileSymPath )) {
  4342. Success = GetImageSymbolRiftInfo(
  4343. OldFileHandle,
  4344. OldFileMapped,
  4345. OldFileSize,
  4346. OldFileNtHeader,
  4347. OldFileSymPath,
  4348. OldFileOriginalChecksum,
  4349. OldFileOriginalTimeDate,
  4350. OldFileIndex,
  4351. NewFileHandle,
  4352. NewFileMapped,
  4353. NewFileSize,
  4354. NewFileNtHeader,
  4355. NewFileSymPath,
  4356. SymbolOptionFlags,
  4357. SubAllocator,
  4358. RiftTable,
  4359. OptionData->SymLoadCallback,
  4360. OptionData->SymLoadContext
  4361. );
  4362. if ( SymbolOptionFlags & PATCH_SYMBOL_NO_FAILURES ) {
  4363. #ifdef TESTCODE
  4364. if (( ! Success ) && ( GetLastError() == ERROR_PATCH_IMAGEHLP_FAILURE )) {
  4365. printf( "\rWARNING: Imagehlp.Dll failure\n" );
  4366. }
  4367. #endif
  4368. Success = TRUE;
  4369. }
  4370. }
  4371. }
  4372. }
  4373. }
  4374. }
  4375. if ( Success ) {
  4376. RiftSortAndRemoveDuplicates(
  4377. OldFileMapped,
  4378. OldFileSize,
  4379. OldFileNtHeader,
  4380. NewFileMapped,
  4381. NewFileSize,
  4382. NewFileNtHeader,
  4383. RiftTable
  4384. );
  4385. //
  4386. // Now we can optimize the rift info by peeking into
  4387. // the mapped files.
  4388. //
  4389. Success = OptimizeImageRiftInfo(
  4390. OldFileMapped,
  4391. OldFileSize,
  4392. OldFileNtHeader,
  4393. NewFileMapped,
  4394. NewFileSize,
  4395. NewFileNtHeader,
  4396. SubAllocator,
  4397. RiftTable
  4398. );
  4399. }
  4400. #ifdef TESTCODE
  4401. if ( Success ) {
  4402. HANDLE hFile = CreateFile(
  4403. "RiftInfo.out",
  4404. GENERIC_WRITE,
  4405. FILE_SHARE_READ,
  4406. NULL,
  4407. CREATE_ALWAYS,
  4408. FILE_ATTRIBUTE_NORMAL,
  4409. NULL
  4410. );
  4411. if ( hFile != INVALID_HANDLE_VALUE ) {
  4412. CHAR TextBuffer[ 24 ];
  4413. DWORD Actual;
  4414. ULONG i;
  4415. for ( i = 0; i < RiftTable->RiftEntryCount; i++ ) {
  4416. sprintf( TextBuffer, "%08X %08X\r\n", RiftTable->RiftEntryArray[ i ].OldFileRva, RiftTable->RiftEntryArray[ i ].NewFileRva );
  4417. WriteFile( hFile, TextBuffer, 19, &Actual, NULL );
  4418. }
  4419. CloseHandle( hFile );
  4420. }
  4421. }
  4422. #endif // TESTCODE
  4423. }
  4424. }
  4425. }
  4426. __except( EXCEPTION_EXECUTE_HANDLER ) {
  4427. SetLastError( GetExceptionCode() );
  4428. Success = FALSE;
  4429. }
  4430. if ( SubAllocator ) {
  4431. DestroySubAllocator( SubAllocator );
  4432. }
  4433. return Success;
  4434. }
  4435. #endif // PATCH_APPLY_CODE_ONLY