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.

2182 lines
61 KiB

  1. /*
  2. Copyright (c) 2001 Microsoft Corporation
  3. File name:
  4. hotpatch.c
  5. Author:
  6. Adrian Marinescu (adrmarin) Dec 12 2001
  7. Description:
  8. The file implements common utility functions for user and kernel mode
  9. hotpatching.
  10. */
  11. #include <ntos.h>
  12. #include <nt.h>
  13. #include <ntrtl.h>
  14. #include <nturtl.h>
  15. #include "hotpatch.h"
  16. #pragma intrinsic( _rotl64 )
  17. #define HASH_INFO_SIZE 0xc
  18. #define COLDPATCH_SIGNATURE 0XD202
  19. #define FLGP_COLDPATCH_TARGET 0x00010000
  20. PVOID
  21. RtlpAllocateHotpatchMemory (
  22. IN SIZE_T BlockSize,
  23. IN BOOLEAN AccessedAtDPC
  24. );
  25. VOID
  26. RtlpFreeHotpatchMemory (
  27. IN PVOID Block
  28. );
  29. PIMAGE_SECTION_HEADER
  30. RtlpFindSectionHeader(
  31. IN PIMAGE_NT_HEADERS NtHeaders,
  32. IN PUCHAR SectionName
  33. );
  34. NTSTATUS
  35. RtlpApplyRelocationFixups (
  36. PRTL_PATCH_HEADER RtlHotpatchHeader,
  37. IN ULONG_PTR PatchOffsetCorrection
  38. );
  39. NTSTATUS
  40. RtlpSingleRangeValidate(
  41. PRTL_PATCH_HEADER RtlHotpatchHeader,
  42. PHOTPATCH_VALIDATION Validation
  43. );
  44. NTSTATUS
  45. RtlpValidateTargetRanges(
  46. PRTL_PATCH_HEADER RtlHotpatchHeader,
  47. BOOLEAN IgnoreHookTargets
  48. );
  49. NTSTATUS
  50. RtlReadSingleHookValidation(
  51. IN PRTL_PATCH_HEADER RtlPatchData,
  52. IN PHOTPATCH_HOOK HookEntry,
  53. IN ULONG BufferSize,
  54. OUT PULONG ValidationSize,
  55. OUT PUCHAR Buffer OPTIONAL,
  56. IN PUCHAR OriginalCodeBuffer OPTIONAL,
  57. IN ULONG OriginalCodeSize OPTIONAL
  58. );
  59. NTSTATUS
  60. RtlpReadSingleHookInformation(
  61. IN PRTL_PATCH_HEADER RtlPatchData,
  62. IN PHOTPATCH_HOOK HookEntry,
  63. IN ULONG BufferSize,
  64. OUT PULONG HookSize,
  65. OUT PUCHAR Buffer OPTIONAL
  66. );
  67. BOOLEAN
  68. RtlpGetColdpatchHashId(
  69. IN PVOID TargetDllBase,
  70. OUT PULONGLONG HashValue
  71. );
  72. #if defined(ALLOC_PRAGMA) && defined(NTOS_KERNEL_RUNTIME)
  73. #pragma alloc_text(PAGE, RtlpAllocateHotpatchMemory)
  74. #pragma alloc_text(PAGE, RtlpFreeHotpatchMemory)
  75. #pragma alloc_text(PAGE, RtlpFindSectionHeader)
  76. #pragma alloc_text(PAGE, RtlGetHotpatchHeader)
  77. #pragma alloc_text(PAGE, RtlpApplyRelocationFixups)
  78. #pragma alloc_text(PAGE, RtlGetHotpatchHeader)
  79. #pragma alloc_text(PAGE, RtlFindRtlPatchHeader)
  80. #pragma alloc_text(PAGE, RtlCreateHotPatch)
  81. #pragma alloc_text(PAGE, RtlFreeHotPatchData)
  82. #pragma alloc_text(PAGE, RtlpSingleRangeValidate)
  83. #pragma alloc_text(PAGE, RtlpValidateTargetRanges)
  84. #pragma alloc_text(PAGE, RtlReadSingleHookValidation)
  85. #pragma alloc_text(PAGE, RtlpReadSingleHookInformation)
  86. #pragma alloc_text(PAGE, RtlReadHookInformation)
  87. #pragma alloc_text(PAGE, RtlInitializeHotPatch)
  88. #pragma alloc_text(PAGE, RtlpIsSameImage)
  89. #pragma alloc_text(PAGE, RtlpGetColdpatchHashId)
  90. #endif // ALLOC_PRAGMA
  91. PVOID
  92. RtlpAllocateHotpatchMemory (
  93. IN SIZE_T BlockSize,
  94. IN BOOLEAN AccessedAtDPC
  95. )
  96. /*++
  97. Routine Description:
  98. Allocates a block of memory from pool in kmode and
  99. process heap in user mode
  100. Arguments:
  101. BlockSize - Receives the size of the block to be allocated
  102. AccessedAtDPC - Used in KMode only, allocates from
  103. the non-paged pool (because a DPC routine is going to use it).
  104. Return Value:
  105. Returns the new memory block
  106. --*/
  107. {
  108. #ifdef NTOS_KERNEL_RUNTIME
  109. return ExAllocatePoolWithTag ( (AccessedAtDPC ? NonPagedPool : PagedPool),
  110. BlockSize,
  111. 'PtoH');
  112. #else
  113. UNREFERENCED_PARAMETER(AccessedAtDPC);
  114. return RtlAllocateHeap (RtlProcessHeap(), 0, BlockSize);
  115. #endif //NTOS_KERNEL_RUNTIME
  116. }
  117. VOID
  118. RtlpFreeHotpatchMemory (
  119. IN PVOID Block
  120. )
  121. /*++
  122. Routine Description:
  123. Frees a memory block allocated with RtlpAllocateHotpatchMemory
  124. Arguments:
  125. Block - Memory block
  126. Return Value:
  127. None.
  128. --*/
  129. {
  130. #ifdef NTOS_KERNEL_RUNTIME
  131. ExFreePoolWithTag (Block, 'PtoH');
  132. #else
  133. RtlFreeHeap (RtlProcessHeap(), 0, Block);
  134. #endif //NTOS_KERNEL_RUNTIME
  135. }
  136. PIMAGE_SECTION_HEADER
  137. RtlpFindSectionHeader(
  138. IN PIMAGE_NT_HEADERS NtHeaders,
  139. IN PUCHAR SectionName
  140. )
  141. /*++
  142. Routine Description:
  143. The function searches a section in a PE image
  144. Arguments:
  145. NtHeaders - Image's header
  146. SectionName - The name of the section to be retrieved
  147. Return Value:
  148. Returns the pointer to the section header in case of success
  149. of NULL if no such section exists.
  150. --*/
  151. {
  152. ULONG i;
  153. PIMAGE_SECTION_HEADER NtSection;
  154. NtSection = IMAGE_FIRST_SECTION( NtHeaders );
  155. for ( i = 0; i < NtHeaders->FileHeader.NumberOfSections; i += 1) {
  156. if ( RtlCompareMemory( NtSection->Name,
  157. SectionName,
  158. IMAGE_SIZEOF_SHORT_NAME) == IMAGE_SIZEOF_SHORT_NAME) {
  159. return NtSection;
  160. }
  161. NtSection += 1;
  162. }
  163. return NULL;
  164. }
  165. PHOTPATCH_HEADER
  166. RtlGetHotpatchHeader(
  167. PVOID ImageBase
  168. )
  169. /*++
  170. Routine Description:
  171. The routine retrieves the hotpatch header from a hotpatch PE image
  172. Arguments:
  173. ImageBase - The base address of the hotpatch image
  174. Return Value:
  175. Returns the pointer to the hotpatch header or NULL in case of failure.
  176. --*/
  177. {
  178. PIMAGE_NT_HEADERS NtHeaders;
  179. PIMAGE_SECTION_HEADER PatchSection;
  180. PHOTPATCH_HEADER HotpatchHeader;
  181. NtHeaders = RtlImageNtHeader(ImageBase);
  182. if (NtHeaders == NULL) {
  183. return NULL;
  184. }
  185. PatchSection = RtlpFindSectionHeader(NtHeaders, HOTP_SECTION_NAME);
  186. if (PatchSection == NULL) {
  187. return NULL;
  188. }
  189. HotpatchHeader = (PHOTPATCH_HEADER)((ULONG_PTR)ImageBase + PatchSection->VirtualAddress);
  190. if ((sizeof( HOTPATCH_HEADER ) > PatchSection->Misc.VirtualSize)
  191. ||
  192. ( HotpatchHeader->Signature != HOTP_SIGNATURE_DWORD )
  193. ||
  194. ( HotpatchHeader->Version != HOTP_HEADER_VERSION_1_0 )){
  195. return NULL;
  196. }
  197. return HotpatchHeader;
  198. }
  199. PRTL_PATCH_HEADER
  200. RtlFindRtlPatchHeader(
  201. IN PLIST_ENTRY PatchList,
  202. IN PPATCH_LDR_DATA_TABLE_ENTRY PatchLdrEntry
  203. )
  204. /*++
  205. Routine Description:
  206. The routine retrieves the rtl patch structure for a specified
  207. patch loader entry.
  208. Arguments:
  209. PatchList - The list with patches to be searched.
  210. PatchLdrEntry - Supplies the requested loader entry
  211. Return Value:
  212. If found, it returns the appropriate patch structure, otherwise
  213. it returns NULL.
  214. --*/
  215. {
  216. PLIST_ENTRY Next = PatchList->Flink;
  217. for ( ; Next != PatchList; Next = Next->Flink) {
  218. PRTL_PATCH_HEADER Entry;
  219. Entry = CONTAINING_RECORD (Next, RTL_PATCH_HEADER, PatchList);
  220. if (Entry->PatchLdrDataTableEntry == PatchLdrEntry) {
  221. return Entry;
  222. }
  223. }
  224. return NULL;
  225. }
  226. NTSTATUS
  227. RtlCreateHotPatch (
  228. OUT PRTL_PATCH_HEADER * RtlPatchData,
  229. IN PHOTPATCH_HEADER Patch,
  230. IN PPATCH_LDR_DATA_TABLE_ENTRY PatchLdrEntry,
  231. IN ULONG PatchFlags
  232. )
  233. /*++
  234. Routine Description:
  235. This is an utility routine used by either user-mode and kernel-mode patching
  236. to process the relocation information and generate the fixup codes. It finally
  237. allocates and initialize a PRTL_PATCH_HEADER structure which is going to be
  238. inserted into the loader data entry for the module being patched.
  239. Arguments:
  240. RtlPatchData - receives the new initialized RTL_PATCH_HEADER structure.
  241. Patch - Points to the patch being applied
  242. PatchLdrEntry - The loader entry for the patch module
  243. PatchFlags - The options for the flags being applied
  244. Return Value:
  245. Returns the appropriate status
  246. --*/
  247. {
  248. ULONG i;
  249. PRTL_PATCH_HEADER NewPatch = NULL;
  250. NTSTATUS Status;
  251. ANSI_STRING AnsiString;
  252. NewPatch = RtlpAllocateHotpatchMemory (sizeof(*NewPatch), FALSE);
  253. if (NewPatch == NULL) {
  254. return STATUS_NO_MEMORY;
  255. }
  256. RtlZeroMemory(NewPatch, sizeof(*NewPatch));
  257. NewPatch->HotpatchHeader = Patch;
  258. NewPatch->PatchLdrDataTableEntry = PatchLdrEntry;
  259. NewPatch->PatchImageBase = PatchLdrEntry->DllBase;
  260. //
  261. // Copy the flags, except the enable which is supposed to be set later
  262. //
  263. NewPatch->PatchFlags = PatchFlags & (~FLG_HOTPATCH_ACTIVE);
  264. InitializeListHead (&NewPatch->PatchList);
  265. RtlInitAnsiString(&AnsiString, (PUCHAR)PatchLdrEntry->DllBase + Patch->TargetNameRva);
  266. Status = RtlAnsiStringToUnicodeString(&NewPatch->TargetDllName, &AnsiString, TRUE);
  267. if (NT_SUCCESS(Status)) {
  268. *RtlPatchData = NewPatch;
  269. } else {
  270. RtlFreeHotPatchData(NewPatch);
  271. }
  272. return Status;
  273. }
  274. VOID
  275. RtlFreeHotPatchData(
  276. IN PRTL_PATCH_HEADER RtlPatchData
  277. )
  278. /*++
  279. Routine Description:
  280. The routine frees the RtlPatchData data structure.
  281. Arguments:
  282. RtlPatchData - receives a properly initialized RTL_PATCH_HEADER structure,
  283. as returned by RtlInitializeHotPatch
  284. Return Value:
  285. None
  286. --*/
  287. {
  288. if (RtlPatchData->CodeInfo) {
  289. RtlpFreeHotpatchMemory( RtlPatchData->CodeInfo );
  290. }
  291. RtlFreeUnicodeString( &RtlPatchData->TargetDllName );
  292. RtlpFreeHotpatchMemory( RtlPatchData );
  293. }
  294. NTSTATUS
  295. RtlpApplyRelocationFixups (
  296. PRTL_PATCH_HEADER RtlHotpatchHeader,
  297. IN ULONG_PTR PatchOffsetCorrection
  298. )
  299. /*++
  300. Routine Description:
  301. This routine applies the fixups for a region of code to the patch module.
  302. Arguments:
  303. RtlHotpatchHeader - Supplies the rtl hotpatch structure
  304. PatchOffsetCorrection - Supplies the relative address of the original module.
  305. Return Value:
  306. NTSTATUS.
  307. --*/
  308. {
  309. ULONG_PTR TargetBase = (ULONG_PTR)RtlHotpatchHeader->TargetDllBase;
  310. ULONG_PTR HotpBase = (ULONG_PTR)RtlHotpatchHeader->PatchImageBase;
  311. ULONG_PTR OrigTargetBase = (ULONG_PTR)RtlHotpatchHeader->HotpatchHeader->OrigTargetBaseAddress;
  312. ULONG_PTR OrigHotpBase = (ULONG_PTR)RtlHotpatchHeader->HotpatchHeader->OrigHotpBaseAddress;
  313. //
  314. // Bias values are positive if actual load address is higher than
  315. // than original load address.
  316. //
  317. ULONG_PTR TargetBias = TargetBase - OrigTargetBase;
  318. ULONG_PTR HotpBias = HotpBase - OrigHotpBase;
  319. ULONG_PTR PcrelBias = TargetBias - HotpBias;
  320. ULONG_PTR NextFixupRegionRva = RtlHotpatchHeader->HotpatchHeader->FixupRgnRva;
  321. ULONG_PTR RegionCount = RtlHotpatchHeader->HotpatchHeader->FixupRgnCount;
  322. PIMAGE_NT_HEADERS NtHotpatchHeader;
  323. if (( TargetBias == 0 ) && ( HotpBias == 0 )) {
  324. return STATUS_SUCCESS; // no fixups are necessary, all loaded where expected.
  325. }
  326. NtHotpatchHeader = RtlImageNtHeader(RtlHotpatchHeader->PatchImageBase);
  327. while ( RegionCount-- ) {
  328. PHOTPATCH_FIXUP_REGION FixupRegion;
  329. ULONG_PTR FixupBaseRva;
  330. PUCHAR FixupBasePtr;
  331. ULONG FixupCount;
  332. ULONG RegionSize;
  333. PHOTPATCH_FIXUP_ENTRY pFixup;
  334. if (( NextFixupRegionRva == 0 ) ||
  335. ( NextFixupRegionRva >= NtHotpatchHeader->OptionalHeader.SizeOfImage )) {
  336. return STATUS_INVALID_IMAGE_FORMAT;;
  337. }
  338. FixupRegion = (PHOTPATCH_FIXUP_REGION)( HotpBase + NextFixupRegionRva );
  339. FixupBaseRva = FixupRegion->RvaHi << 12;
  340. FixupBasePtr = (PUCHAR)HotpBase + FixupBaseRva;
  341. FixupCount = FixupRegion->Count;
  342. RegionSize = sizeof(HOTPATCH_FIXUP_REGION) + sizeof(SHORT) * (FixupCount - 2);
  343. NextFixupRegionRva += RegionSize;
  344. if (( FixupBaseRva >= NtHotpatchHeader->OptionalHeader.SizeOfImage ) ||
  345. ( NextFixupRegionRva >= NtHotpatchHeader->OptionalHeader.SizeOfImage ) ||
  346. ( FixupCount & 1 )) {
  347. DbgPrintEx( DPFLTR_LDR_ID,
  348. DPFLTR_ERROR_LEVEL,
  349. "Invalid fixup information\n" );
  350. return STATUS_INVALID_IMAGE_FORMAT;
  351. }
  352. pFixup = (PHOTPATCH_FIXUP_ENTRY)&FixupRegion->Fixup[ 0 ];
  353. while ( FixupCount-- ) {
  354. PUCHAR FixupPtr = FixupBasePtr + pFixup->RvaOffset;
  355. switch ( pFixup->FixupType ) {
  356. case HOTP_Fixup_None: // No fixup, ignore this entry (alignment, etc)
  357. {
  358. DbgPrintEx( DPFLTR_LDR_ID,
  359. DPFLTR_TRACE_LEVEL,
  360. "\t None%s\n",
  361. FixupCount ? "" : " (padding)" );
  362. break;
  363. }
  364. case HOTP_Fixup_VA32: // 32-bit address in target image
  365. {
  366. DbgPrintEx( DPFLTR_LDR_ID,
  367. DPFLTR_TRACE_LEVEL,
  368. "\t%08I64X: VA32 %08X -> %08X %s\n",
  369. (ULONGLONG)FixupPtr,
  370. *(PULONG)FixupPtr,
  371. *(PULONG)FixupPtr + TargetBias,
  372. TargetBias ? "" : "(no change)"
  373. );
  374. if ( TargetBias != 0 ) {
  375. *(PULONG)(FixupPtr + PatchOffsetCorrection) += (ULONG)TargetBias;
  376. }
  377. break;
  378. }
  379. case HOTP_Fixup_PC32: // 32-bit x86 pc-rel address to target image
  380. {
  381. DbgPrintEx( DPFLTR_LDR_ID,
  382. DPFLTR_TRACE_LEVEL,
  383. "\t%08I64X: PC32 %08X -> %08X (target %08X) %s\n",
  384. (ULONGLONG)FixupPtr,
  385. *(PULONG)FixupPtr,
  386. *(PULONG)FixupPtr + PcrelBias,
  387. (PULONG)(ULONG_PTR)( FixupPtr + 4 + *(ULONG UNALIGNED*)FixupPtr + PcrelBias ),
  388. PcrelBias ? "" : "(no change)"
  389. );
  390. if ( PcrelBias != 0 ) {
  391. *(PULONG)(FixupPtr + PatchOffsetCorrection) += (ULONG)PcrelBias;
  392. }
  393. break;
  394. }
  395. case HOTP_Fixup_VA64: // 64-bit address in target image
  396. {
  397. DbgPrintEx( DPFLTR_LDR_ID,
  398. DPFLTR_TRACE_LEVEL,
  399. "\t%08I64X: VA64 %016I64X -> %016I64X %s\n",
  400. (ULONGLONG)FixupPtr,
  401. *(ULONGLONG UNALIGNED*)FixupPtr,
  402. *(ULONGLONG UNALIGNED*)FixupPtr + TargetBias,
  403. TargetBias ? "" : "(no change)"
  404. );
  405. if ( TargetBias != 0 ) {
  406. *(PULONGLONG)(FixupPtr + PatchOffsetCorrection) += TargetBias;
  407. }
  408. break;
  409. }
  410. default: // unrecognized fixup type
  411. DbgPrintEx( DPFLTR_LDR_ID,
  412. DPFLTR_ERROR_LEVEL,
  413. "\t%08I64X: Unknown\n",
  414. (ULONGLONG)FixupPtr );
  415. return STATUS_INVALID_IMAGE_FORMAT;
  416. }
  417. pFixup += 1;
  418. }
  419. }
  420. return STATUS_SUCCESS;
  421. }
  422. NTSTATUS
  423. RtlpSingleRangeValidate(
  424. PRTL_PATCH_HEADER RtlHotpatchHeader,
  425. PHOTPATCH_VALIDATION Validation
  426. )
  427. /*++
  428. Routine Description:
  429. The routine validates a single code range within the binary.
  430. Arguments:
  431. RtlHotpatchHeader - Supplies the rtl hotpatch header
  432. Validation - Supplies the validation information
  433. Return Value:
  434. NTSTATUS.
  435. --*/
  436. {
  437. ULONG_PTR SourceRva = Validation->SourceRva;
  438. ULONG_PTR TargetRva = Validation->TargetRva;
  439. ULONG_PTR ByteCount = Validation->ByteCount;
  440. PIMAGE_NT_HEADERS NtHotpatchHeader;
  441. PIMAGE_NT_HEADERS NtTargetHeader;
  442. NtHotpatchHeader = RtlImageNtHeader(RtlHotpatchHeader->PatchImageBase);
  443. NtTargetHeader = RtlImageNtHeader(RtlHotpatchHeader->TargetDllBase);
  444. if ((( SourceRva ) >= NtHotpatchHeader->OptionalHeader.SizeOfImage ) ||
  445. (( SourceRva + ByteCount ) >= NtHotpatchHeader->OptionalHeader.SizeOfImage ) ) {
  446. DbgPrintEx( DPFLTR_LDR_ID,
  447. DPFLTR_ERROR_LEVEL,
  448. "Invalid source hotpatch validation range\n" );
  449. return STATUS_INVALID_IMAGE_FORMAT;
  450. }
  451. if ((( TargetRva ) >= NtTargetHeader->OptionalHeader.SizeOfImage ) ||
  452. (( TargetRva + ByteCount ) >= NtTargetHeader->OptionalHeader.SizeOfImage )) {
  453. DbgPrintEx( DPFLTR_LDR_ID,
  454. DPFLTR_ERROR_LEVEL,
  455. "Invalid target validation range\n" );
  456. return STATUS_INVALID_IMAGE_FORMAT;
  457. }
  458. if (RtlCompareMemory((PUCHAR)RtlHotpatchHeader->PatchImageBase + SourceRva,
  459. (PUCHAR)RtlHotpatchHeader->TargetDllBase + TargetRva,
  460. ByteCount ) != ByteCount) {
  461. DbgPrintEx( DPFLTR_LDR_ID,
  462. DPFLTR_TRACE_LEVEL,
  463. "Validation failure. Source = %lx, Target = %lx, Size = %lx\n",
  464. (PUCHAR)RtlHotpatchHeader->PatchImageBase + SourceRva,
  465. (PUCHAR)RtlHotpatchHeader->TargetDllBase + TargetRva,
  466. ByteCount
  467. );
  468. return STATUS_DATA_ERROR;
  469. }
  470. return STATUS_SUCCESS;
  471. }
  472. NTSTATUS
  473. RtlpValidateTargetRanges(
  474. PRTL_PATCH_HEADER RtlHotpatchHeader,
  475. BOOLEAN IgnoreHookTargets
  476. )
  477. /*++
  478. Routine Description:
  479. This routine validate all hotpatch ranges
  480. Arguments:
  481. RtlHotpatchHeader - Supplies the rtl hotpatch header
  482. IgnoreHookTargets - If specified the hook validation are ignored.
  483. Return Value:
  484. NTSTATUS.
  485. --*/
  486. {
  487. ULONG ValidArrayRva = RtlHotpatchHeader->HotpatchHeader->ValidationArrayRva;
  488. ULONG ValidCount = RtlHotpatchHeader->HotpatchHeader->ValidationCount;
  489. ULONG ValidArraySize = ValidCount * sizeof( HOTPATCH_VALIDATION );
  490. PIMAGE_NT_HEADERS NtHotpatchHeader;
  491. PHOTPATCH_VALIDATION ValidArray;
  492. ULONG i;
  493. NtHotpatchHeader = RtlImageNtHeader(RtlHotpatchHeader->PatchImageBase);
  494. if ( ValidCount == 0 ) {
  495. return STATUS_SUCCESS;
  496. }
  497. if (( ValidArrayRva == 0 ) ||
  498. ( ValidArrayRva >= NtHotpatchHeader->OptionalHeader.SizeOfImage ) ||
  499. (( ValidArrayRva + ValidArraySize ) >= NtHotpatchHeader->OptionalHeader.SizeOfImage )) {
  500. DbgPrintEx( DPFLTR_LDR_ID,
  501. DPFLTR_ERROR_LEVEL,
  502. "Invalid hotpatch validation array pointer\n" );
  503. return STATUS_INVALID_IMAGE_FORMAT;
  504. }
  505. ValidArray = (PHOTPATCH_VALIDATION)( (ULONG_PTR)RtlHotpatchHeader->PatchImageBase + ValidArrayRva );
  506. //
  507. // Loop through all validation ranges
  508. //
  509. for ( i = 0; i < ValidCount; i += 1 ) {
  510. NTSTATUS Status;
  511. if (( IgnoreHookTargets ) && ( ValidArray[ i ].OptionFlags == HOTP_Valid_Hook_Target )) {
  512. DbgPrintEx( DPFLTR_LDR_ID,
  513. DPFLTR_TRACE_LEVEL,
  514. "Skipping hook-specific validation range during global validation\n" );
  515. continue;
  516. }
  517. Status = RtlpSingleRangeValidate( RtlHotpatchHeader,
  518. &ValidArray[ i ] );
  519. if ( !NT_SUCCESS(Status) ) {
  520. DbgPrintEx( DPFLTR_LDR_ID,
  521. DPFLTR_ERROR_LEVEL,
  522. "Validation failed for global range %u of %u\n",
  523. i + 1,
  524. ValidCount );
  525. return Status;
  526. }
  527. }
  528. return STATUS_SUCCESS;
  529. }
  530. PRTL_PATCH_HEADER
  531. RtlpSearchValidationCode (
  532. IN PRTL_PATCH_HEADER RtlPatchData,
  533. IN PUCHAR ValidationCode,
  534. IN SIZE_T ValidationSize
  535. )
  536. /*++
  537. Routine Description:
  538. The routine searches a validation range in existing hotpatches. The loader
  539. lock is assumed.
  540. Arguments:
  541. RtlPatchData - Supplies the rtl hotpatch data structure
  542. ValidationCode - Receives the validation data for that hook.
  543. ValidationSize - Receives the actual size of the Validation information
  544. Return Value:
  545. NTSTATUS.
  546. --*/
  547. {
  548. PPATCH_LDR_DATA_TABLE_ENTRY TargetLdrDataTableEntry;
  549. TargetLdrDataTableEntry = RtlPatchData->TargetLdrDataTableEntry;
  550. if (TargetLdrDataTableEntry) {
  551. PRTL_PATCH_HEADER PatchHead = (PRTL_PATCH_HEADER)TargetLdrDataTableEntry->PatchInformation;
  552. while (PatchHead) {
  553. PSYSTEM_HOTPATCH_CODE_INFORMATION PatchInfo;
  554. ULONG i;
  555. PatchInfo = PatchHead->CodeInfo;
  556. for (i = 0; i < PatchInfo->CodeInfo.DescriptorsCount; i += 1) {
  557. if (RtlCompareMemory (ValidationCode,
  558. (PUCHAR)PatchInfo + PatchInfo->CodeInfo.CodeDescriptors[i].CodeOffset,
  559. ValidationSize) == ValidationSize) {
  560. return PatchHead;
  561. }
  562. }
  563. PatchHead = PatchHead->NextPatch;
  564. }
  565. }
  566. return NULL;
  567. }
  568. NTSTATUS
  569. RtlReadSingleHookValidation(
  570. IN PRTL_PATCH_HEADER RtlPatchData,
  571. IN PHOTPATCH_HOOK HookEntry,
  572. IN ULONG BufferSize,
  573. OUT PULONG ValidationSize,
  574. OUT PUCHAR Buffer OPTIONAL,
  575. IN PUCHAR OriginalCodeBuffer OPTIONAL,
  576. IN ULONG OriginalCodeSize OPTIONAL
  577. )
  578. /*++
  579. Routine Description:
  580. This utility function reads the validation data for a hotpatch hook
  581. Arguments:
  582. RtlPatchData - Supplies the rtl hotpatch data structure
  583. HookEntry - Supplies the hook structure
  584. BufferSize - Supplies the available memory in Buffer
  585. ValidationSize - Receives the actual size of the Validation information
  586. Buffer - Receives the validation data for that hook.
  587. Return Value:
  588. NTSTATUS.
  589. --*/
  590. {
  591. PIMAGE_NT_HEADERS NtHotpatchHeader;
  592. ULONG_PTR ValidationRva = HookEntry->ValidationRva;
  593. PHOTPATCH_VALIDATION Validation;
  594. NTSTATUS Status;
  595. if ( ValidationRva == 0 ) {
  596. *ValidationSize = 0;
  597. return STATUS_SUCCESS; // no validation record for this hook entry
  598. }
  599. NtHotpatchHeader = RtlImageNtHeader(RtlPatchData->PatchImageBase);
  600. if (( ValidationRva + sizeof( HOTPATCH_VALIDATION )) >= NtHotpatchHeader->OptionalHeader.SizeOfImage ) {
  601. DbgPrintEx( DPFLTR_LDR_ID,
  602. DPFLTR_ERROR_LEVEL,
  603. "Invalid hotpatch validation pointer in hook record\n" );
  604. return STATUS_INVALID_IMAGE_FORMAT;
  605. }
  606. Validation = (PHOTPATCH_VALIDATION)( (PCHAR)RtlPatchData->PatchImageBase + ValidationRva );
  607. Status = RtlpSingleRangeValidate( RtlPatchData,
  608. Validation
  609. );
  610. *ValidationSize = Validation->ByteCount;
  611. if (ARGUMENT_PRESENT(Buffer)) {
  612. if (BufferSize <= Validation->SourceRva) {
  613. RtlCopyMemory( Buffer,
  614. (PUCHAR)RtlPatchData->PatchImageBase + Validation->SourceRva,
  615. Validation->ByteCount );
  616. } else {
  617. return STATUS_BUFFER_TOO_SMALL;
  618. }
  619. }
  620. if (Status == STATUS_DATA_ERROR) {
  621. //
  622. // We do additional tests in case the validation fails
  623. //
  624. switch ( HookEntry->HookType ) {
  625. case HOTP_Hook_None:
  626. *ValidationSize = 0;
  627. Status = STATUS_SUCCESS;
  628. break;
  629. case HOTP_Hook_X86_JMP:
  630. {
  631. PRTL_PATCH_HEADER ExistingPatchData;
  632. //
  633. // we want to insert a jmp. If the previous code was a jmp too
  634. // then we'll probably patch the same function again
  635. //
  636. if (ARGUMENT_PRESENT(OriginalCodeBuffer)) {
  637. //
  638. // Check whether the previous hook was a jmp or not
  639. //
  640. if ((OriginalCodeSize < 5) || (*OriginalCodeBuffer != 0xE9)) {
  641. return STATUS_DATA_ERROR;
  642. }
  643. //
  644. // Now test if the jmp was written by an existing hotpatch
  645. //
  646. ExistingPatchData = RtlpSearchValidationCode (RtlPatchData,
  647. OriginalCodeBuffer,
  648. OriginalCodeSize
  649. );
  650. if (ExistingPatchData) {
  651. Status = STATUS_SUCCESS;
  652. } else if (RtlPatchData->PatchFlags & FLGP_COLDPATCH_TARGET) {
  653. //
  654. // No hotpatch from the list inserted this jmp. It could be then
  655. // a coldpatch file. Test if the jmp points inside the same binary
  656. //
  657. PIMAGE_NT_HEADERS NtTargetHeader;
  658. LONG Ptr32 = *(LONG UNALIGNED*)(OriginalCodeBuffer + 1);
  659. Ptr32 = Ptr32 + (LONG)HookEntry->HookRva + 5; // 5 == length of jmp instruction
  660. NtTargetHeader = RtlImageNtHeader(RtlPatchData->TargetDllBase);
  661. if ( (Ptr32 > 0) && ((ULONG)Ptr32 < NtTargetHeader->OptionalHeader.SizeOfImage) ) {
  662. Status = STATUS_SUCCESS;
  663. }
  664. }
  665. } else {
  666. //
  667. // The original code has not been supplied. This must be a call
  668. // to query the validation size, so we postpone the actual validation
  669. // for the next time
  670. //
  671. Status = STATUS_SUCCESS;
  672. }
  673. }
  674. break;
  675. case HOTP_Hook_X86_JMP2B:
  676. {
  677. PRTL_PATCH_HEADER ExistingPatchData;
  678. //
  679. // we want to insert a jmp. If the previous code was a jmp too
  680. // then we'll probably patch the same function again
  681. //
  682. if (ARGUMENT_PRESENT(OriginalCodeBuffer)) {
  683. //
  684. // Check whether the previous hook was a short jmp or not
  685. //
  686. if ((OriginalCodeSize < 2) || (*OriginalCodeBuffer != 0xEB)) {
  687. return STATUS_DATA_ERROR;
  688. }
  689. //
  690. // Now test if the jmp was written by an existing hotpatch
  691. //
  692. ExistingPatchData = RtlpSearchValidationCode (RtlPatchData,
  693. OriginalCodeBuffer,
  694. OriginalCodeSize
  695. );
  696. //
  697. // We also allow pass the validation test if the target is a coldpatch
  698. //
  699. if ((ExistingPatchData != NULL)
  700. ||
  701. (RtlPatchData->PatchFlags & FLGP_COLDPATCH_TARGET)) {
  702. Status = STATUS_SUCCESS;
  703. }
  704. } else {
  705. //
  706. // The original code has not been supplied. This must be a call
  707. // to query the validation size, so we postpone the actual validation
  708. // for the next time
  709. //
  710. Status = STATUS_SUCCESS;
  711. }
  712. }
  713. break;
  714. case HOTP_Hook_VA32:
  715. case HOTP_Hook_VA64:
  716. case HOTP_Hook_IA64_BRL:
  717. default:
  718. {
  719. DbgPrintEx( DPFLTR_LDR_ID,
  720. DPFLTR_ERROR_LEVEL,
  721. "Hook type not yet implemented\n" );
  722. }
  723. }
  724. }
  725. return Status;
  726. }
  727. NTSTATUS
  728. RtlpReadSingleHookInformation(
  729. IN PRTL_PATCH_HEADER RtlPatchData,
  730. IN PHOTPATCH_HOOK HookEntry,
  731. IN ULONG BufferSize,
  732. OUT PULONG HookSize,
  733. OUT PUCHAR Buffer OPTIONAL
  734. )
  735. /*++
  736. Routine Description:
  737. Utility procedure to fill up the hook information
  738. Arguments:
  739. RtlPatchData - Supplies the rtl hotpatch information
  740. HookEntry - Supplies the hook entry
  741. BufferSize - Supplies the available memory in the output buffer
  742. HookSize - Receives the actual size of the hook data
  743. Buffer - If specified, contains the hook information
  744. Return Value:
  745. NTSTATUS.
  746. --*/
  747. {
  748. ULONG_PTR HookRva = HookEntry->HookRva; // in target image
  749. ULONG_PTR HotpRva = HookEntry->HotpRva; // in hotpatch image
  750. PIMAGE_NT_HEADERS NtHotpatchHeader;
  751. PIMAGE_NT_HEADERS NtTargetHeader;
  752. PUCHAR HookPtr;
  753. PUCHAR HotpPtr;
  754. NtHotpatchHeader = RtlImageNtHeader(RtlPatchData->PatchImageBase);
  755. NtTargetHeader = RtlImageNtHeader(RtlPatchData->TargetDllBase);
  756. if ( HookRva >= NtTargetHeader->OptionalHeader.SizeOfImage ){
  757. DbgPrintEx( DPFLTR_LDR_ID,
  758. DPFLTR_ERROR_LEVEL,
  759. "Invalid hotpatch hook pointer\n" );
  760. return STATUS_INVALID_IMAGE_FORMAT;
  761. }
  762. HookPtr = (PUCHAR) RtlPatchData->TargetDllBase + HookRva;
  763. HotpPtr = (PUCHAR) RtlPatchData->PatchImageBase + HotpRva;
  764. switch ( HookEntry->HookType )
  765. {
  766. case HOTP_Hook_X86_JMP:
  767. {
  768. ULONG OrigSize = HookEntry->HookOptions & 0x000F;
  769. *HookSize = ( OrigSize > 5 ) ? OrigSize : 5;
  770. if ( HotpRva >= NtHotpatchHeader->OptionalHeader.SizeOfImage ){
  771. DbgPrintEx( DPFLTR_LDR_ID,
  772. DPFLTR_ERROR_LEVEL,
  773. "Invalid hotpatch relative address\n" );
  774. return STATUS_INVALID_IMAGE_FORMAT;
  775. }
  776. if (ARGUMENT_PRESENT(Buffer)) {
  777. ULONG i;
  778. LONG PcRelDisp = (LONG)( HotpPtr - ( HookPtr + 5 ));
  779. PUCHAR pb = Buffer;
  780. if (BufferSize < *HookSize) {
  781. return STATUS_BUFFER_TOO_SMALL;
  782. }
  783. *pb++ = 0xE9;
  784. *(LONG UNALIGNED*)pb = PcRelDisp;
  785. if ( *HookSize > 5 )
  786. {
  787. ULONG FillBytes = *HookSize - 5;
  788. pb += 4;
  789. do
  790. {
  791. *pb++ = 0xCC;
  792. }
  793. while ( --FillBytes );
  794. }
  795. DbgPrintEx( DPFLTR_LDR_ID,
  796. DPFLTR_TRACE_LEVEL,
  797. "\t%08I64X: jmp %08X (PC+%08X) {",
  798. (ULONGLONG)HookPtr,
  799. (ULONG)(ULONGLONG)HotpPtr,
  800. PcRelDisp );
  801. for ( i = 0; i < *HookSize; i += 1 )
  802. {
  803. DbgPrintEx( DPFLTR_LDR_ID,
  804. DPFLTR_TRACE_LEVEL,
  805. " %02X",
  806. HookPtr[ i ] );
  807. }
  808. DbgPrintEx( DPFLTR_LDR_ID,
  809. DPFLTR_TRACE_LEVEL,
  810. " }\n" );
  811. }
  812. break;
  813. }
  814. case HOTP_Hook_X86_JMP2B:
  815. {
  816. ULONG OrigSize = HookEntry->HookOptions & 0x000F;
  817. *HookSize = ( OrigSize > 2 ) ? OrigSize : 2;
  818. if (ARGUMENT_PRESENT(Buffer)) {
  819. PUCHAR pb = Buffer;
  820. if (BufferSize < *HookSize) {
  821. return STATUS_BUFFER_TOO_SMALL;
  822. }
  823. *pb++ = 0xEB;
  824. *pb++ = (UCHAR) (HookEntry->HotpRva & 0x000000FF);
  825. if ( *HookSize > 2 )
  826. {
  827. ULONG FillBytes = *HookSize - 2;
  828. do
  829. {
  830. *pb++ = 0xCC;
  831. }
  832. while ( --FillBytes );
  833. }
  834. }
  835. break;
  836. }
  837. case HOTP_Hook_VA32:
  838. {
  839. *HookSize = 4;
  840. if ( HotpRva >= NtHotpatchHeader->OptionalHeader.SizeOfImage ){
  841. DbgPrintEx( DPFLTR_LDR_ID,
  842. DPFLTR_ERROR_LEVEL,
  843. "Invalid hotpatch relative address\n" );
  844. return STATUS_INVALID_IMAGE_FORMAT;
  845. }
  846. if ( ARGUMENT_PRESENT(Buffer) ) {
  847. if (BufferSize < *HookSize) {
  848. return STATUS_BUFFER_TOO_SMALL;
  849. }
  850. *(ULONG UNALIGNED*)Buffer = (ULONG)(ULONG_PTR)HotpPtr;
  851. }
  852. break;
  853. }
  854. case HOTP_Hook_VA64:
  855. {
  856. *HookSize = 8;
  857. if (ARGUMENT_PRESENT(Buffer)) {
  858. if (BufferSize < *HookSize) {
  859. return STATUS_BUFFER_TOO_SMALL;
  860. }
  861. *(ULONG64 UNALIGNED*)Buffer = (ULONG64)HotpPtr;
  862. }
  863. break;
  864. }
  865. default:
  866. {
  867. DbgPrintEx( DPFLTR_LDR_ID,
  868. DPFLTR_ERROR_LEVEL,
  869. "Invalid hook type specified\n" );
  870. return STATUS_NOT_IMPLEMENTED; // not implemented
  871. }
  872. }
  873. return STATUS_SUCCESS;
  874. }
  875. NTSTATUS
  876. RtlReadHookInformation(
  877. IN PRTL_PATCH_HEADER RtlPatchData
  878. )
  879. /*++
  880. Routine Description:
  881. Utility function to read all hook information contained in
  882. the hotpatch and initialize the SYSTEM_HOTPATCH_CODE_INFORMATION
  883. structure
  884. Arguments:
  885. RtlPatchData - Supplies the rtl hotpatch information
  886. Return Value:
  887. NTSTATUS.
  888. --*/
  889. {
  890. ULONG_PTR HookArrayRva = RtlPatchData->HotpatchHeader->HookArrayRva;
  891. ULONG HookCount = RtlPatchData->HotpatchHeader->HookCount;
  892. ULONG HookArraySize = HookCount * sizeof( HOTPATCH_HOOK );
  893. PIMAGE_NT_HEADERS NtHotpatchHeader;
  894. PHOTPATCH_HOOK HookArray;
  895. ULONG DescriptorsSize;
  896. ULONG i;
  897. PSYSTEM_HOTPATCH_CODE_INFORMATION Buffer;
  898. NTSTATUS Status;
  899. ULONG CodeOffset;
  900. ULONG BufferSize;
  901. NtHotpatchHeader = RtlImageNtHeader(RtlPatchData->PatchImageBase);
  902. if ( HookCount == 0 ) {
  903. DbgPrintEx( DPFLTR_LDR_ID,
  904. DPFLTR_ERROR_LEVEL,
  905. "No hooks defined in hotpatch\n" );
  906. return STATUS_INVALID_IMAGE_FORMAT;
  907. }
  908. if (( HookArrayRva == 0 ) ||
  909. ( HookArrayRva >= NtHotpatchHeader->OptionalHeader.SizeOfImage ) ||
  910. (( HookArrayRva + HookArraySize ) >= NtHotpatchHeader->OptionalHeader.SizeOfImage )) {
  911. DbgPrintEx( DPFLTR_LDR_ID,
  912. DPFLTR_ERROR_LEVEL,
  913. "Invalid hotpatch hook array pointer\n" );
  914. return STATUS_INVALID_IMAGE_FORMAT;
  915. }
  916. HookArray = (PHOTPATCH_HOOK)( (PCHAR)RtlPatchData->PatchImageBase + HookArrayRva );
  917. DbgPrintEx( DPFLTR_LDR_ID,
  918. DPFLTR_TRACE_LEVEL,
  919. "Inserting %u hooks into target image\n",
  920. HookCount );
  921. //
  922. // Walk the hook information to determine the size of the buffer
  923. //
  924. DescriptorsSize = sizeof(SYSTEM_HOTPATCH_CODE_INFORMATION) + (HookCount - 1) * sizeof(HOTPATCH_HOOK_DESCRIPTOR);
  925. CodeOffset = DescriptorsSize;
  926. for ( i = 0; i < HookCount; i += 1 ) {
  927. Status = RtlpReadSingleHookInformation( RtlPatchData,
  928. &HookArray[ i ],
  929. 0,
  930. &BufferSize,
  931. NULL );
  932. if (!NT_SUCCESS(Status)) {
  933. return Status;
  934. }
  935. DescriptorsSize += 2 * BufferSize; // add space for the original code too
  936. if ( HookArray[ i ].ValidationRva != 0 ) {
  937. Status = RtlReadSingleHookValidation( RtlPatchData,
  938. &HookArray[ i ],
  939. 0,
  940. &BufferSize,
  941. NULL,
  942. NULL,
  943. 0 );
  944. if (!NT_SUCCESS(Status)) {
  945. return Status;
  946. }
  947. DescriptorsSize += BufferSize;
  948. }
  949. }
  950. //
  951. // Now that we have size, we can allocate the buffer and fill up
  952. // with the hook information
  953. //
  954. Buffer = RtlpAllocateHotpatchMemory(DescriptorsSize, TRUE);
  955. if (Buffer == NULL) {
  956. return STATUS_NO_MEMORY;
  957. }
  958. Buffer->InfoSize = DescriptorsSize;
  959. Buffer->CodeInfo.DescriptorsCount = HookCount;
  960. Buffer->Flags = 0;
  961. for (i = 0; i < Buffer->CodeInfo.DescriptorsCount; i += 1) {
  962. PUCHAR OrigCodeBuffer;
  963. Buffer->CodeInfo.CodeDescriptors[i].TargetAddress = (ULONG_PTR)RtlPatchData->TargetDllBase + HookArray[ i ].HookRva;
  964. Buffer->CodeInfo.CodeDescriptors[i].CodeOffset = CodeOffset;
  965. Status = RtlpReadSingleHookInformation( RtlPatchData,
  966. &HookArray[ i ],
  967. DescriptorsSize - CodeOffset,
  968. &BufferSize,
  969. (PUCHAR)Buffer + CodeOffset );
  970. if (!NT_SUCCESS(Status)) {
  971. RtlpFreeHotpatchMemory(Buffer);
  972. return Status;
  973. }
  974. Buffer->CodeInfo.CodeDescriptors[i].CodeSize = BufferSize;
  975. CodeOffset += BufferSize;
  976. Buffer->CodeInfo.CodeDescriptors[i].OrigCodeOffset = CodeOffset;
  977. OrigCodeBuffer = (PUCHAR)Buffer + CodeOffset;
  978. RtlCopyMemory (OrigCodeBuffer,
  979. (PVOID)Buffer->CodeInfo.CodeDescriptors[i].TargetAddress,
  980. Buffer->CodeInfo.CodeDescriptors[i].CodeSize );
  981. CodeOffset += BufferSize;
  982. if ( HookArray[ i ].ValidationRva != 0 ) {
  983. Buffer->CodeInfo.CodeDescriptors[i].ValidationOffset = CodeOffset;
  984. Status = RtlReadSingleHookValidation( RtlPatchData,
  985. &HookArray[ i ],
  986. DescriptorsSize - CodeOffset,
  987. &BufferSize,
  988. (PUCHAR)Buffer + CodeOffset,
  989. OrigCodeBuffer,
  990. Buffer->CodeInfo.CodeDescriptors[i].CodeSize );
  991. if (!NT_SUCCESS(Status)) {
  992. RtlpFreeHotpatchMemory(Buffer);
  993. return Status;
  994. }
  995. CodeOffset += BufferSize;
  996. Buffer->CodeInfo.CodeDescriptors[i].ValidationSize = BufferSize;
  997. } else {
  998. Buffer->CodeInfo.CodeDescriptors[i].ValidationOffset = 0;
  999. Buffer->CodeInfo.CodeDescriptors[i].ValidationSize = 0;
  1000. }
  1001. }
  1002. if (RtlPatchData->CodeInfo) {
  1003. RtlpFreeHotpatchMemory(RtlPatchData->CodeInfo);
  1004. }
  1005. RtlPatchData->CodeInfo = Buffer;
  1006. return STATUS_SUCCESS;
  1007. }
  1008. NTSTATUS
  1009. RtlInitializeHotPatch (
  1010. IN PRTL_PATCH_HEADER RtlPatchData,
  1011. IN ULONG_PTR PatchOffsetCorrection
  1012. )
  1013. /*++
  1014. Routine Description:
  1015. This routine is used to initialize the hotpatch module by applying
  1016. the module fixups, validate the target module and initialize the
  1017. hook data.
  1018. Arguments:
  1019. RtlPatchData - Supplies the rtl hotpatch structure
  1020. PatchOffsetCorrection - Correction for the offset where the fixups are applied.
  1021. The fixups are done in locked pages therefore the address being modified is
  1022. different than the actual address (where the module is loaded)
  1023. Return Value:
  1024. None.
  1025. --*/
  1026. {
  1027. NTSTATUS Status;
  1028. Status = RtlpApplyRelocationFixups ( RtlPatchData, PatchOffsetCorrection );
  1029. if (!NT_SUCCESS(Status)) {
  1030. return Status;
  1031. }
  1032. Status = RtlpValidateTargetRanges( RtlPatchData, TRUE );
  1033. if (!NT_SUCCESS(Status)) {
  1034. return Status;
  1035. }
  1036. Status = RtlReadHookInformation( RtlPatchData );
  1037. return Status;
  1038. }
  1039. BOOLEAN
  1040. RtlpNormalizePeHeaderForIdHash(
  1041. PIMAGE_NT_HEADERS NtHeader
  1042. )
  1043. /*++
  1044. Routine Description:
  1045. The purpose of this routine is to zero out (normalize) the PE header
  1046. fields that may be modified during rebase/bind/winalign/localize/etc
  1047. that don't materially affect the functionality of the binary and thus
  1048. the targetability of the hotpatch. The remaining fields should
  1049. uniquely identify the target binary as originating from the same
  1050. binary prior to rebase/bind/localize/etc.
  1051. Arguments:
  1052. NtHeader - Supplies the image header being normalized
  1053. Return Value:
  1054. Returns TRUE if the header is valid, FALSE otherwise
  1055. --*/
  1056. {
  1057. PIMAGE_DATA_DIRECTORY pDirs;
  1058. ULONG nDirs;
  1059. ULONG RvaResource = 0;
  1060. ULONG RvaSecurity = 0;
  1061. ULONG RvaReloc = 0;
  1062. PIMAGE_SECTION_HEADER pSect;
  1063. ULONG nSect;
  1064. ULONG ImageFileCharacteristicsIgnore = (
  1065. IMAGE_FILE_RELOCS_STRIPPED |
  1066. IMAGE_FILE_DEBUG_STRIPPED |
  1067. IMAGE_FILE_LINE_NUMS_STRIPPED |
  1068. IMAGE_FILE_LOCAL_SYMS_STRIPPED |
  1069. IMAGE_FILE_AGGRESIVE_WS_TRIM |
  1070. IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP |
  1071. IMAGE_FILE_NET_RUN_FROM_SWAP
  1072. );
  1073. NtHeader->FileHeader.Characteristics &= ~ImageFileCharacteristicsIgnore;
  1074. NtHeader->FileHeader.TimeDateStamp = 0;
  1075. NtHeader->FileHeader.PointerToSymbolTable = 0;
  1076. switch ( NtHeader->OptionalHeader.Magic )
  1077. {
  1078. case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
  1079. {
  1080. NtHeader->OptionalHeader.CheckSum = 0;
  1081. NtHeader->OptionalHeader.ImageBase = 0;
  1082. NtHeader->OptionalHeader.FileAlignment = 0;
  1083. NtHeader->OptionalHeader.SizeOfCode = 0;
  1084. NtHeader->OptionalHeader.SizeOfInitializedData = 0;
  1085. NtHeader->OptionalHeader.SizeOfUninitializedData = 0;
  1086. NtHeader->OptionalHeader.SizeOfImage = 0;
  1087. NtHeader->OptionalHeader.SizeOfHeaders = 0;
  1088. NtHeader->OptionalHeader.SizeOfStackReserve = 0;
  1089. NtHeader->OptionalHeader.SizeOfStackCommit = 0;
  1090. NtHeader->OptionalHeader.SizeOfHeapReserve = 0;
  1091. NtHeader->OptionalHeader.SizeOfHeapCommit = 0;
  1092. nDirs = NtHeader->OptionalHeader.NumberOfRvaAndSizes;
  1093. pDirs = NtHeader->OptionalHeader.DataDirectory;
  1094. break;
  1095. }
  1096. case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
  1097. {
  1098. PIMAGE_NT_HEADERS64 NtHeader64 = (PIMAGE_NT_HEADERS64) NtHeader;
  1099. NtHeader64->OptionalHeader.CheckSum = 0;
  1100. NtHeader64->OptionalHeader.ImageBase = 0;
  1101. NtHeader64->OptionalHeader.FileAlignment = 0;
  1102. NtHeader64->OptionalHeader.SizeOfCode = 0;
  1103. NtHeader64->OptionalHeader.SizeOfInitializedData = 0;
  1104. NtHeader64->OptionalHeader.SizeOfUninitializedData = 0;
  1105. NtHeader64->OptionalHeader.SizeOfImage = 0;
  1106. NtHeader64->OptionalHeader.SizeOfHeaders = 0;
  1107. NtHeader64->OptionalHeader.SizeOfStackReserve = 0;
  1108. NtHeader64->OptionalHeader.SizeOfStackCommit = 0;
  1109. NtHeader64->OptionalHeader.SizeOfHeapReserve = 0;
  1110. NtHeader64->OptionalHeader.SizeOfHeapCommit = 0;
  1111. nDirs = NtHeader64->OptionalHeader.NumberOfRvaAndSizes;
  1112. pDirs = NtHeader64->OptionalHeader.DataDirectory;
  1113. break;
  1114. }
  1115. default:
  1116. {
  1117. return FALSE;
  1118. }
  1119. }
  1120. if ( IMAGE_DIRECTORY_ENTRY_RESOURCE < nDirs )
  1121. {
  1122. RvaResource = pDirs[ IMAGE_DIRECTORY_ENTRY_RESOURCE ].VirtualAddress;
  1123. pDirs[ IMAGE_DIRECTORY_ENTRY_RESOURCE ].VirtualAddress = 0;
  1124. pDirs[ IMAGE_DIRECTORY_ENTRY_RESOURCE ].Size = 0;
  1125. }
  1126. if ( IMAGE_DIRECTORY_ENTRY_SECURITY < nDirs )
  1127. {
  1128. RvaSecurity = pDirs[ IMAGE_DIRECTORY_ENTRY_SECURITY ].VirtualAddress;
  1129. pDirs[ IMAGE_DIRECTORY_ENTRY_RESOURCE ].VirtualAddress = 0;
  1130. pDirs[ IMAGE_DIRECTORY_ENTRY_RESOURCE ].Size = 0;
  1131. }
  1132. if ( IMAGE_DIRECTORY_ENTRY_BASERELOC < nDirs )
  1133. {
  1134. RvaReloc = pDirs[ IMAGE_DIRECTORY_ENTRY_BASERELOC ].VirtualAddress;
  1135. pDirs[ IMAGE_DIRECTORY_ENTRY_BASERELOC ].VirtualAddress = 0;
  1136. pDirs[ IMAGE_DIRECTORY_ENTRY_BASERELOC ].Size = 0;
  1137. }
  1138. if ( IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT < nDirs )
  1139. {
  1140. pDirs[ IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT ].VirtualAddress = 0;
  1141. pDirs[ IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT ].Size = 0;
  1142. }
  1143. if ( IMAGE_DIRECTORY_ENTRY_DEBUG < nDirs )
  1144. {
  1145. pDirs[ IMAGE_DIRECTORY_ENTRY_DEBUG ].Size = 0;
  1146. }
  1147. pSect = IMAGE_FIRST_SECTION( NtHeader );
  1148. nSect = NtHeader->FileHeader.NumberOfSections;
  1149. while ( nSect-- )
  1150. {
  1151. pSect->SizeOfRawData = 0;
  1152. pSect->PointerToRawData = 0;
  1153. pSect->PointerToRelocations = 0;
  1154. pSect->PointerToLinenumbers = 0;
  1155. pSect->NumberOfRelocations = 0;
  1156. pSect->NumberOfLinenumbers = 0;
  1157. if (( pSect->VirtualAddress == RvaResource ) ||
  1158. ( pSect->VirtualAddress == RvaSecurity ) ||
  1159. ( pSect->VirtualAddress == RvaReloc ))
  1160. {
  1161. pSect->VirtualAddress = 0;
  1162. pSect->Misc.VirtualSize = 0;
  1163. }
  1164. pSect++;
  1165. }
  1166. return TRUE;
  1167. }
  1168. NTSTATUS
  1169. RtlpCopyAndNormalizePeHeaderForHash(
  1170. IN PRTL_PATCH_HEADER RtlPatchData,
  1171. IN PVOID TargetDllBase,
  1172. IN PUCHAR Buffer,
  1173. IN SIZE_T BufferSize,
  1174. OUT PSIZE_T ActualSize )
  1175. /*++
  1176. Routine Description:
  1177. Utility function which copies a normalized image header to a
  1178. supplied buffer.
  1179. Arguments:
  1180. RtlPatchData - Supplies the rtl hotpatch structure
  1181. TargetDllBase - Supplies the base address of the target image
  1182. Buffer - Supplies the buffer, which receives the copy of
  1183. the normalized header
  1184. BufferSize - Supplies the size of the allocated buffer
  1185. ActualSize - Receives the actual size of the buffer needed
  1186. for this copy. If the function fails, the caller can use
  1187. value for the next retry.
  1188. Return Value:
  1189. NTSTATUS
  1190. --*/
  1191. {
  1192. PIMAGE_NT_HEADERS NtHeaders;
  1193. PUCHAR pbHeader;
  1194. PIMAGE_SECTION_HEADER NtSection;
  1195. ULONG SectionCount;
  1196. PUCHAR BytesExtent;
  1197. SIZE_T HeaderSize;
  1198. NTSTATUS Status;
  1199. NtHeaders = RtlImageNtHeader(TargetDllBase);
  1200. pbHeader = (PUCHAR)NtHeaders;
  1201. NtSection = IMAGE_FIRST_SECTION( NtHeaders );
  1202. SectionCount = NtHeaders->FileHeader.NumberOfSections;
  1203. BytesExtent = (PUCHAR) &NtSection[ SectionCount ];
  1204. HeaderSize = ( BytesExtent - pbHeader );
  1205. *ActualSize = HeaderSize;
  1206. if ( HeaderSize <= BufferSize ) {
  1207. //
  1208. // The buffer is large enough to hold the header.
  1209. // Copy the header and clear the fields likely to
  1210. // change with localization.
  1211. //
  1212. memcpy( Buffer, pbHeader, HeaderSize );
  1213. if ( RtlpNormalizePeHeaderForIdHash( (PIMAGE_NT_HEADERS) Buffer ) ) {
  1214. Status = STATUS_SUCCESS;
  1215. } else {
  1216. //
  1217. // The PE header does not look like a valid
  1218. //
  1219. DbgPrintEx( DPFLTR_LDR_ID,
  1220. DPFLTR_ERROR_LEVEL,
  1221. "Failed to normalize PE header for validation\n" );
  1222. Status = STATUS_INVALID_IMAGE_FORMAT;
  1223. }
  1224. } else {
  1225. DbgPrintEx( DPFLTR_LDR_ID,
  1226. DPFLTR_TRACE_LEVEL,
  1227. "Header too large (%u>%u) for copy/normalize/validate\n",
  1228. HeaderSize,
  1229. BufferSize );
  1230. Status = STATUS_BUFFER_TOO_SMALL;
  1231. }
  1232. return Status;
  1233. }
  1234. ULONGLONG
  1235. RtlpPeHeaderHash2(
  1236. IN PUCHAR Buffer,
  1237. IN SIZE_T BufferSize )
  1238. /*++
  1239. Routine Description:
  1240. This function implements a 64 bit hashing algorithm,
  1241. used by the hotpatch to validate regions of the headers that
  1242. do not change with localization.
  1243. Arguments:
  1244. Buffer - Supplies the buffer for wich the hash has to be determined.
  1245. BufferSize - Supplies the size of the buffer
  1246. Return Value:
  1247. Returns the 64-bit hash value of this buffer
  1248. --*/
  1249. {
  1250. PULONG ULongBuffer = (PULONG) Buffer;
  1251. SIZE_T Count = BufferSize / sizeof( ULONG );
  1252. ULONGLONG Hash = ~(ULONGLONG)BufferSize;
  1253. while ( Count-- )
  1254. {
  1255. ULONG Next = *ULongBuffer++ ^ 0x55555555;
  1256. ULONGLONG Temp = (ULONGLONG)Next * ((ULONG)Hash);
  1257. Hash = _rotl64( Hash, 23 ) ^ Temp;
  1258. }
  1259. return Hash;
  1260. }
  1261. PHOTPATCH_DEBUG_DATA
  1262. RtlpGetColdpatchDebugSignature(
  1263. PVOID TargetDllBase
  1264. )
  1265. /*++
  1266. Routine Description:
  1267. This procedure retrieves the 64 bit hash information for the
  1268. original file, if the target is a coldpatch
  1269. Arguments:
  1270. TargetDllBase - Supplies the base address of the target binary
  1271. HashValue - Receives the 64bit hash value of the original file,
  1272. if the function suceeds.
  1273. Return Value:
  1274. BOOLEAN
  1275. --*/
  1276. {
  1277. PIMAGE_DEBUG_DIRECTORY DebugData;
  1278. ULONG DebugSize, i;
  1279. PIMAGE_NT_HEADERS NtTargetHeader;
  1280. NtTargetHeader = RtlImageNtHeader(TargetDllBase);
  1281. DebugData = RtlImageDirectoryEntryToData( TargetDllBase,
  1282. TRUE,
  1283. IMAGE_DIRECTORY_ENTRY_DEBUG,
  1284. &DebugSize);
  1285. if ((DebugData == NULL)
  1286. ||
  1287. (DebugSize < sizeof(IMAGE_DEBUG_DIRECTORY))
  1288. ||
  1289. (DebugSize % sizeof(IMAGE_DEBUG_DIRECTORY))) {
  1290. return NULL;
  1291. }
  1292. for (i = 0; i < DebugSize / sizeof(IMAGE_DEBUG_DIRECTORY); i++) {
  1293. if (DebugData->Type == IMAGE_DEBUG_TYPE_RESERVED10) {
  1294. if (DebugData->AddressOfRawData < (NtTargetHeader->OptionalHeader.SizeOfImage - HASH_INFO_SIZE)) {
  1295. PHOTPATCH_DEBUG_SIGNATURE DebugSignature = (PHOTPATCH_DEBUG_SIGNATURE)((PCHAR)TargetDllBase
  1296. + DebugData->AddressOfRawData);
  1297. if ( DebugSignature->Signature == COLDPATCH_SIGNATURE) {
  1298. return (PHOTPATCH_DEBUG_DATA)(DebugSignature + 1);
  1299. }
  1300. }
  1301. }
  1302. DebugData += 1;
  1303. }
  1304. return NULL;
  1305. }
  1306. BOOLEAN
  1307. RtlpValidatePeHeaderHash2(
  1308. IN PRTL_PATCH_HEADER RtlPatchData,
  1309. IN PVOID TargetDllBase
  1310. )
  1311. /*++
  1312. Routine Description:
  1313. The hotpatch mechanism uses this function to validate the PE header
  1314. for the target module. The hashing algorithm is applied to a
  1315. normalized header (where the fields likely to change with localization
  1316. are cleared).
  1317. Arguments:
  1318. RtlPatchData - Supplies the rtl hotpatch structure
  1319. TargetDllBase - Supplies the base address for the target module
  1320. Return Value:
  1321. Returns the 64-bit hash value of this buffer
  1322. --*/
  1323. {
  1324. PUCHAR Buffer;
  1325. SIZE_T BufferSize = 0x300; // some initial size large enough to cover most cases
  1326. SIZE_T ActualSize;
  1327. NTSTATUS Status;
  1328. Buffer = RtlpAllocateHotpatchMemory(BufferSize, FALSE);
  1329. if (Buffer) {
  1330. Status = RtlpCopyAndNormalizePeHeaderForHash( RtlPatchData,
  1331. TargetDllBase,
  1332. Buffer,
  1333. BufferSize,
  1334. &ActualSize);
  1335. if (Status == STATUS_BUFFER_TOO_SMALL) {
  1336. BufferSize = ActualSize;
  1337. RtlpFreeHotpatchMemory( Buffer );
  1338. Buffer = RtlpAllocateHotpatchMemory( BufferSize, FALSE);
  1339. if (Buffer == NULL) {
  1340. return FALSE;
  1341. }
  1342. Status = RtlpCopyAndNormalizePeHeaderForHash( RtlPatchData,
  1343. TargetDllBase,
  1344. Buffer,
  1345. BufferSize,
  1346. &ActualSize);
  1347. }
  1348. if ( NT_SUCCESS(Status) ) {
  1349. ULONGLONG HashValue = RtlpPeHeaderHash2( Buffer, (ULONG)ActualSize);
  1350. if ( RtlPatchData->HotpatchHeader->TargetModuleIdValue.Quad == HashValue ) {
  1351. RtlpFreeHotpatchMemory( Buffer );
  1352. return TRUE;
  1353. } else {
  1354. PHOTPATCH_DEBUG_DATA DebugSignature = RtlpGetColdpatchDebugSignature(TargetDllBase);
  1355. if (DebugSignature) {
  1356. if ( RtlPatchData->HotpatchHeader->TargetModuleIdValue.Quad == DebugSignature->PEHashData ) {
  1357. RtlPatchData->PatchFlags |= FLGP_COLDPATCH_TARGET;
  1358. RtlpFreeHotpatchMemory( Buffer );
  1359. return TRUE;
  1360. }
  1361. }
  1362. DbgPrintEx( DPFLTR_LDR_ID,
  1363. DPFLTR_ERROR_LEVEL,
  1364. "PE header hash ID comparsion failure (PE2)\n" );
  1365. }
  1366. }
  1367. RtlpFreeHotpatchMemory( Buffer );
  1368. }
  1369. return FALSE;
  1370. }
  1371. BOOLEAN
  1372. RtlpValidatePeChecksum(
  1373. IN PRTL_PATCH_HEADER RtlPatchData,
  1374. IN PVOID TargetDllBase
  1375. )
  1376. {
  1377. PIMAGE_NT_HEADERS NtHeader;
  1378. PHOTPATCH_DEBUG_DATA DebugSignature;
  1379. NtHeader = RtlImageNtHeader(TargetDllBase);
  1380. switch ( NtHeader->OptionalHeader.Magic )
  1381. {
  1382. case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
  1383. if (RtlPatchData->HotpatchHeader->TargetModuleIdValue.Quad ==
  1384. NtHeader->OptionalHeader.CheckSum) {
  1385. return TRUE;
  1386. }
  1387. break;
  1388. case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
  1389. {
  1390. PIMAGE_NT_HEADERS64 NtHeader64 = (PIMAGE_NT_HEADERS64) NtHeader;
  1391. if (RtlPatchData->HotpatchHeader->TargetModuleIdValue.Quad ==
  1392. NtHeader64->OptionalHeader.CheckSum) {
  1393. return TRUE;
  1394. }
  1395. break;
  1396. }
  1397. default:
  1398. {
  1399. return FALSE;
  1400. }
  1401. }
  1402. //
  1403. // we failed to check directly the image checksum. We need to
  1404. // see whether this is a coldpatch and it has the original checksum correct
  1405. //
  1406. DebugSignature = RtlpGetColdpatchDebugSignature(TargetDllBase);
  1407. if (DebugSignature) {
  1408. if ( RtlPatchData->HotpatchHeader->TargetModuleIdValue.Quad == DebugSignature->ChecksumData ) {
  1409. RtlPatchData->PatchFlags |= FLGP_COLDPATCH_TARGET;
  1410. return TRUE;
  1411. }
  1412. }
  1413. return FALSE;
  1414. }
  1415. BOOLEAN
  1416. RtlpValidateTargetModule(
  1417. IN PRTL_PATCH_HEADER RtlPatchData,
  1418. IN PPATCH_LDR_DATA_TABLE_ENTRY LdrDataEntry
  1419. )
  1420. /*++
  1421. Routine Description:
  1422. This routine checks whether the target binary matches
  1423. the hotpatch data.
  1424. Arguments:
  1425. RtlPatchData - Supplies the rtl hotpatch structure
  1426. LdrDataEntry - The loader entry for the target binary.
  1427. Return Value:
  1428. TRUE if successfully matches, FALSE otherwise.
  1429. --*/
  1430. {
  1431. switch ( RtlPatchData->HotpatchHeader->ModuleIdMethod ){
  1432. case HOTP_ID_None: // No ID verification of target module
  1433. DbgPrintEx( DPFLTR_LDR_ID,
  1434. DPFLTR_TRACE_LEVEL,
  1435. "HOTP_ID_None\n" );
  1436. return TRUE;
  1437. case HOTP_ID_PeHeaderHash1: // MD5 of "normalized" IMAGE_NT_HEADERS32/64
  1438. DbgPrintEx( DPFLTR_LDR_ID,
  1439. DPFLTR_TRACE_LEVEL,
  1440. "HOTP_ID_PeHeaderHash1" );
  1441. return FALSE; // not yet implemented
  1442. case HOTP_ID_PeDebugSignature: // pdb signature (GUID,Age)
  1443. DbgPrintEx( DPFLTR_LDR_ID,
  1444. DPFLTR_TRACE_LEVEL,
  1445. "HOTP_ID_PeDebugSignature" );
  1446. return FALSE; // not yet implemented
  1447. case HOTP_ID_PeHeaderHash2: // 64-bit hash of "normalized" IMAGE_NT_HEADERS32/64
  1448. DbgPrintEx( DPFLTR_LDR_ID,
  1449. DPFLTR_TRACE_LEVEL,
  1450. "HOTP_ID_PeHeaderHash2" );
  1451. return RtlpValidatePeHeaderHash2( RtlPatchData, LdrDataEntry->DllBase );
  1452. case HOTP_ID_PeChecksum:
  1453. return RtlpValidatePeChecksum(RtlPatchData, LdrDataEntry->DllBase);
  1454. default: // unrecognized ModuleIdMethod
  1455. DbgPrintEx( DPFLTR_LDR_ID,
  1456. DPFLTR_TRACE_LEVEL,
  1457. "Unrecognized" );
  1458. }
  1459. return FALSE;
  1460. }
  1461. BOOLEAN
  1462. RtlpIsSameImage (
  1463. IN PRTL_PATCH_HEADER RtlPatchData,
  1464. IN PPATCH_LDR_DATA_TABLE_ENTRY LdrDataEntry
  1465. )
  1466. /*++
  1467. Routine Description:
  1468. The function verifies whether the target image is the same as
  1469. the one we built the patch for.
  1470. Arguments:
  1471. RtlPatchData - Supplies the rtl patch data
  1472. LdrDataEntry - Supplies the loader entry for the target module
  1473. Return Value:
  1474. None.
  1475. --*/
  1476. {
  1477. PIMAGE_NT_HEADERS NtHeaders;
  1478. NtHeaders = RtlImageNtHeader (LdrDataEntry->DllBase);
  1479. if (NtHeaders == NULL) {
  1480. return FALSE;
  1481. }
  1482. if ( RtlEqualUnicodeString (&RtlPatchData->TargetDllName, &LdrDataEntry->BaseDllName, TRUE)
  1483. &&
  1484. RtlpValidateTargetModule(RtlPatchData, LdrDataEntry)) {
  1485. RtlPatchData->TargetLdrDataTableEntry = LdrDataEntry;
  1486. RtlPatchData->TargetDllBase = LdrDataEntry->DllBase;
  1487. return TRUE;
  1488. }
  1489. return FALSE;
  1490. }