Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1022 lines
32 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. dice.cxx
  5. Abstract:
  6. This file implements the Image Integrity API's.
  7. Author:
  8. Bryan Tuttle (bryant) 7-Dec-1995
  9. Environment:
  10. User Mode
  11. --*/
  12. #include <private.h>
  13. BOOL
  14. FindCertificate(
  15. IN PLOADED_IMAGE LoadedImage,
  16. IN DWORD Index,
  17. LPWIN_CERTIFICATE * Certificate
  18. )
  19. {
  20. PIMAGE_DATA_DIRECTORY pDataDir;
  21. DWORD_PTR CurrentCert;
  22. BOOL rc;
  23. if (LoadedImage->fDOSImage) {
  24. // No way this could have a certificate;
  25. return(FALSE);
  26. }
  27. rc = FALSE;
  28. __try {
  29. if (LoadedImage->FileHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
  30. pDataDir = &((PIMAGE_NT_HEADERS32)(LoadedImage->FileHeader))->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY];
  31. } else if (LoadedImage->FileHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
  32. pDataDir = &((PIMAGE_NT_HEADERS64)(LoadedImage->FileHeader))->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY];
  33. } else {
  34. __leave; // Not an interesting file type.
  35. }
  36. // Check if the cert pointer is at least reasonable.
  37. if (!pDataDir->VirtualAddress ||
  38. !pDataDir->Size ||
  39. (pDataDir->VirtualAddress + pDataDir->Size > LoadedImage->SizeOfImage))
  40. {
  41. __leave;
  42. }
  43. // We're not looking at an empty security slot or an invalid (past the image boundary) value.
  44. // Let's see if we can find it.
  45. DWORD CurrentIdx = 0;
  46. DWORD_PTR LastCert;
  47. CurrentCert = (DWORD_PTR)(LoadedImage->MappedAddress) + pDataDir->VirtualAddress;
  48. LastCert = CurrentCert + pDataDir->Size;
  49. while (CurrentCert < LastCert ) {
  50. if (CurrentIdx == Index) {
  51. rc = TRUE;
  52. __leave;
  53. }
  54. CurrentIdx++;
  55. CurrentCert += ((LPWIN_CERTIFICATE)CurrentCert)->dwLength;
  56. CurrentCert = (CurrentCert + 7) & ~7; // align it.
  57. }
  58. } __except(EXCEPTION_EXECUTE_HANDLER) { }
  59. if (rc == TRUE) {
  60. *Certificate = (LPWIN_CERTIFICATE)CurrentCert;
  61. }
  62. return(rc);
  63. }
  64. typedef struct _EXCLUDE_RANGE {
  65. PBYTE Offset;
  66. DWORD Size;
  67. struct _EXCLUDE_RANGE *Next;
  68. } EXCLUDE_RANGE;
  69. typedef enum {
  70. Raw,
  71. Virtual
  72. } ADDRTYPE;
  73. class EXCLUDE_LIST
  74. {
  75. public:
  76. EXCLUDE_LIST() {
  77. m_Image = NULL;
  78. m_ExRange = (EXCLUDE_RANGE *)MemAlloc(sizeof(EXCLUDE_RANGE));
  79. }
  80. ~EXCLUDE_LIST() {
  81. EXCLUDE_RANGE *pTmp;
  82. pTmp = m_ExRange->Next;
  83. while (pTmp) {
  84. MemFree(m_ExRange);
  85. m_ExRange = pTmp;
  86. pTmp = m_ExRange->Next;
  87. }
  88. MemFree(m_ExRange);
  89. }
  90. void Init(LOADED_IMAGE * Image, DIGEST_FUNCTION pFunc, DIGEST_HANDLE dh) {
  91. m_Image = Image;
  92. m_ExRange->Offset = NULL;
  93. m_ExRange->Size = 0;
  94. m_pFunc = pFunc;
  95. m_dh = dh;
  96. return;
  97. }
  98. void Add(DWORD_PTR Offset, DWORD Size, ADDRTYPE AddrType);
  99. BOOL Emit(PBYTE Offset, DWORD Size);
  100. private:
  101. LOADED_IMAGE * m_Image;
  102. EXCLUDE_RANGE * m_ExRange;
  103. DIGEST_FUNCTION m_pFunc;
  104. DIGEST_HANDLE m_dh;
  105. };
  106. void
  107. EXCLUDE_LIST::Add(
  108. DWORD_PTR Offset,
  109. DWORD Size,
  110. ADDRTYPE AddrType
  111. )
  112. {
  113. if (AddrType == Virtual) {
  114. // Always save raw offsets
  115. DWORD_PTR RawOffset;
  116. // Note: it's O.K. to cast down to a dword here. Offset is really a Rva from the start
  117. // of the image (always limited to 4G).
  118. RawOffset = (DWORD_PTR)ImageRvaToVa((PIMAGE_NT_HEADERS)m_Image->FileHeader, m_Image->MappedAddress, (DWORD)Offset, NULL);
  119. Offset = RawOffset;
  120. }
  121. EXCLUDE_RANGE *pTmp, *pExRange;
  122. pExRange = m_ExRange;
  123. while (pExRange->Next && (pExRange->Next->Offset < (PBYTE)Offset)) {
  124. pExRange = pExRange->Next;
  125. }
  126. pTmp = (EXCLUDE_RANGE *) MemAlloc(sizeof(EXCLUDE_RANGE));
  127. pTmp->Next = pExRange->Next;
  128. pTmp->Offset = (PBYTE)Offset;
  129. pTmp->Size = Size;
  130. pExRange->Next = pTmp;
  131. return;
  132. }
  133. BOOL
  134. EXCLUDE_LIST::Emit(
  135. PBYTE Offset,
  136. DWORD Size
  137. )
  138. {
  139. BOOL rc;
  140. EXCLUDE_RANGE *pExRange;
  141. DWORD EmitSize, ExcludeSize;
  142. pExRange = m_ExRange->Next;
  143. while (pExRange && (Size > 0)) {
  144. if (pExRange->Offset >= Offset) {
  145. // Emit what's before the exclude list.
  146. EmitSize = __min((DWORD)(pExRange->Offset - Offset), Size);
  147. if (EmitSize) {
  148. rc = (*m_pFunc)(m_dh, Offset, EmitSize);
  149. Size -= EmitSize;
  150. Offset += EmitSize;
  151. }
  152. }
  153. if (Size) {
  154. if (pExRange->Offset + pExRange->Size >= Offset) {
  155. // Skip over what's in the exclude list.
  156. ExcludeSize = __min(Size, (DWORD)(pExRange->Offset + pExRange->Size - Offset));
  157. Size -= ExcludeSize;
  158. Offset += ExcludeSize;
  159. }
  160. }
  161. pExRange = pExRange->Next;
  162. }
  163. // Emit what's left.
  164. if (Size) {
  165. rc = (*m_pFunc)(m_dh, Offset, Size);
  166. }
  167. return rc;
  168. }
  169. BOOL
  170. IMAGEAPI
  171. ImageGetDigestStream(
  172. IN HANDLE FileHandle,
  173. IN DWORD DigestLevel,
  174. IN DIGEST_FUNCTION DigestFunction,
  175. IN DIGEST_HANDLE DigestHandle
  176. )
  177. /*++
  178. Routine Description:
  179. Given an image, return the bytes necessary to construct a certificate.
  180. Only PE images are supported at this time.
  181. Arguments:
  182. FileHandle - Handle to the file in question. The file should be opened
  183. with at least GENERIC_READ access.
  184. DigestLevel - Indicates what data will be included in the returned buffer.
  185. Valid values are:
  186. CERT_PE_IMAGE_DIGEST_DEBUG_INFO - Include Debug symbolic (if mapped)
  187. CERT_PE_IMAGE_DIGEST_RESOURCES - Include Resource info
  188. CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO - Include ALL the import information
  189. By default, neither Debug Symbolic, Resources, nor import information affected
  190. by binding are returned.
  191. DigestFunction - User supplied routine that will process the data.
  192. DigestHandle - User supplied handle to identify the digest. Passed as the first
  193. argument to the DigestFunction.
  194. Return Value:
  195. TRUE - Success.
  196. FALSE - There was some error. Call GetLastError for more information. Possible
  197. values are ERROR_INVALID_PARAMETER or ERROR_OPERATION_ABORTED.
  198. --*/
  199. {
  200. LOADED_IMAGE LoadedImage;
  201. BOOL rc, fAddThisSection, fDebugAdded;
  202. DWORD i;
  203. EXCLUDE_LIST ExList;
  204. PIMAGE_SECTION_HEADER SectionHeaders;
  205. ULONG ResourceOffset, ResourceSize, DebugOffset, DebugSize, RelocOffset, RelocSize, SectionHeaderSize;
  206. PIMAGE_FILE_HEADER FileHeader;
  207. PIMAGE_DATA_DIRECTORY pDataDir;
  208. INT RelocHdr;
  209. union {
  210. IMAGE_NT_HEADERS32 PE32;
  211. IMAGE_NT_HEADERS64 PE64;
  212. }Hdr;
  213. BOOL f32;
  214. if (MapIt(FileHandle, &LoadedImage, MAP_READONLY) == FALSE) {
  215. // Unable to map the image.
  216. SetLastError(ERROR_INVALID_PARAMETER);
  217. return(FALSE);
  218. }
  219. rc = ERROR_INVALID_PARAMETER;
  220. __try {
  221. if (LoadedImage.fDOSImage) {
  222. __leave;
  223. }
  224. if (LoadedImage.FileHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
  225. f32 = TRUE;
  226. } else if (LoadedImage.FileHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
  227. f32 = FALSE;
  228. } else {
  229. __leave;
  230. }
  231. ExList.Init(&LoadedImage, DigestFunction, DigestHandle);
  232. // Return all the interesting stuff from the image. First, the common stuff.
  233. // 1. Add the DOS stub (if it exists).
  234. if ((ULONG_PTR)LoadedImage.FileHeader - (ULONG_PTR) LoadedImage.MappedAddress) {
  235. if (!ExList.Emit((PBYTE) LoadedImage.MappedAddress,
  236. (DWORD)((ULONG_PTR) LoadedImage.FileHeader - (ULONG_PTR) LoadedImage.MappedAddress)))
  237. {
  238. rc = ERROR_OPERATION_ABORTED;
  239. __leave;
  240. }
  241. }
  242. // Add the headers, but not the checksum and not the security Data directory entry.
  243. if (f32) {
  244. Hdr.PE32 = *((PIMAGE_NT_HEADERS32)LoadedImage.FileHeader);
  245. pDataDir = &Hdr.PE32.OptionalHeader.DataDirectory[0];
  246. Hdr.PE32.OptionalHeader.CheckSum = 0;
  247. } else {
  248. Hdr.PE64 = *((PIMAGE_NT_HEADERS64)LoadedImage.FileHeader);
  249. pDataDir = &Hdr.PE64.OptionalHeader.DataDirectory[0];
  250. Hdr.PE64.OptionalHeader.CheckSum = 0;
  251. }
  252. pDataDir[IMAGE_DIRECTORY_ENTRY_SECURITY].Size = 0;
  253. pDataDir[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress = 0;
  254. SectionHeaderSize = sizeof(IMAGE_SECTION_HEADER) * LoadedImage.NumberOfSections;
  255. SectionHeaders = (PIMAGE_SECTION_HEADER) MemAlloc(SectionHeaderSize);
  256. if (SectionHeaders == NULL)
  257. {
  258. rc = ERROR_OPERATION_ABORTED;
  259. __leave;
  260. }
  261. ResourceOffset = pDataDir[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
  262. ResourceSize = pDataDir[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size;
  263. RelocOffset = pDataDir[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;
  264. RelocSize = pDataDir[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
  265. fDebugAdded = TRUE;
  266. DebugOffset = 0xFFFFFFFF;
  267. RelocHdr = -1;
  268. for (i = 0; i < LoadedImage.NumberOfSections; i++) {
  269. SectionHeaders[i] = LoadedImage.Sections[i];
  270. // Keep track of the reloc section header. We may need to adjust it later.
  271. if (RelocSize &&
  272. ((LoadedImage.Sections[i].VirtualAddress <= RelocOffset) &&
  273. (LoadedImage.Sections[i].VirtualAddress +
  274. LoadedImage.Sections[i].Misc.VirtualSize >= RelocOffset + RelocSize))
  275. )
  276. {
  277. RelocHdr = i;
  278. }
  279. // If resources aren't in the digest, we need to clear the resource section header
  280. if (ResourceSize && !(DigestLevel & CERT_PE_IMAGE_DIGEST_RESOURCES)) {
  281. if (((LoadedImage.Sections[i].VirtualAddress <= ResourceOffset) &&
  282. (LoadedImage.Sections[i].VirtualAddress +
  283. LoadedImage.Sections[i].Misc.VirtualSize >= ResourceOffset + ResourceSize))
  284. )
  285. {
  286. // Found the resource section header. Zero it out.
  287. SectionHeaders[i].Misc.VirtualSize = 0;
  288. SectionHeaders[i].VirtualAddress = 0;
  289. SectionHeaders[i].SizeOfRawData = 0;
  290. SectionHeaders[i].PointerToRawData = 0;
  291. }
  292. }
  293. if (!(DigestLevel & CERT_PE_IMAGE_DIGEST_DEBUG_INFO)) {
  294. // Same with mapped debug info.
  295. if (!strncmp((char *)LoadedImage.Sections[i].Name, ".debug", sizeof(".debug"))) {
  296. DebugOffset = SectionHeaders[i].VirtualAddress;
  297. DebugSize = SectionHeaders[i].SizeOfRawData;
  298. ExList.Add(SectionHeaders[i].PointerToRawData + (DWORD_PTR) LoadedImage.MappedAddress, DebugSize, Raw);
  299. SectionHeaders[i].Misc.VirtualSize = 0;
  300. SectionHeaders[i].VirtualAddress = 0;
  301. SectionHeaders[i].SizeOfRawData = 0;
  302. SectionHeaders[i].PointerToRawData = 0;
  303. fDebugAdded = FALSE;
  304. }
  305. }
  306. }
  307. // The first pass on the section headers is finished. See it we need to adjust the
  308. // reloc dir or the image headers.
  309. if (!(DigestLevel & CERT_PE_IMAGE_DIGEST_RESOURCES)) {
  310. // If the resources aren't in the digest, don't add the base reloc address or the
  311. // resource address/size to the digest. This allows subsequent tools to add/subtract
  312. // resource info w/o effecting the digest.
  313. if ((ResourceOffset < RelocOffset) && (RelocHdr != -1))
  314. {
  315. pDataDir[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = 0;
  316. SectionHeaders[RelocHdr].PointerToRawData = 0;
  317. SectionHeaders[RelocHdr].VirtualAddress = 0;
  318. }
  319. pDataDir[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = 0;
  320. pDataDir[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = 0;
  321. if (f32) {
  322. Hdr.PE32.OptionalHeader.SizeOfImage = 0;
  323. Hdr.PE32.OptionalHeader.SizeOfInitializedData = 0;
  324. } else {
  325. Hdr.PE64.OptionalHeader.SizeOfImage = 0;
  326. Hdr.PE64.OptionalHeader.SizeOfInitializedData = 0;
  327. }
  328. ExList.Add(ResourceOffset, ResourceSize, Virtual);
  329. }
  330. if (!(DigestLevel & CERT_PE_IMAGE_DIGEST_DEBUG_INFO) &&
  331. (fDebugAdded == FALSE))
  332. {
  333. // Debug wasn't added to the image and IS mapped in. Allow these to grow also.
  334. if (f32) {
  335. Hdr.PE32.OptionalHeader.SizeOfImage = 0;
  336. Hdr.PE32.OptionalHeader.SizeOfInitializedData = 0;
  337. } else {
  338. Hdr.PE64.OptionalHeader.SizeOfImage = 0;
  339. Hdr.PE64.OptionalHeader.SizeOfInitializedData = 0;
  340. }
  341. if ((DebugOffset < RelocOffset) && (RelocHdr != -1))
  342. {
  343. pDataDir[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = 0;
  344. SectionHeaders[RelocHdr].PointerToRawData = 0;
  345. SectionHeaders[RelocHdr].VirtualAddress = 0;
  346. }
  347. }
  348. // Looks good. Send the headers to the digest function.
  349. if (f32) {
  350. if (!ExList.Emit((PBYTE) &Hdr.PE32, sizeof(Hdr.PE32))) {
  351. rc = ERROR_OPERATION_ABORTED;
  352. __leave;
  353. }
  354. } else {
  355. if (!ExList.Emit((PBYTE) &Hdr.PE64, sizeof(Hdr.PE64))) {
  356. rc = ERROR_OPERATION_ABORTED;
  357. __leave;
  358. }
  359. }
  360. // Then the section headers.
  361. if (!ExList.Emit((PBYTE) SectionHeaders, SectionHeaderSize)) {
  362. rc = ERROR_OPERATION_ABORTED;
  363. __leave;
  364. }
  365. MemFree(SectionHeaders);
  366. // The headers are done. Now let's see what we need to do with the import information.
  367. if (!(DigestLevel & CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO)) {
  368. // The user didn't explicitly ask for all import info.
  369. // Add the info modified by bind to the exclude list.
  370. PIMAGE_IMPORT_DESCRIPTOR ImportDesc;
  371. DWORD ImportDescSize, IATSize;
  372. PVOID IAT;
  373. ImportDesc = (PIMAGE_IMPORT_DESCRIPTOR) ImageDirectoryEntryToData(
  374. LoadedImage.MappedAddress,
  375. FALSE,
  376. IMAGE_DIRECTORY_ENTRY_IMPORT,
  377. &ImportDescSize);
  378. if (ImportDescSize) {
  379. IAT = ImageDirectoryEntryToData(LoadedImage.MappedAddress,
  380. FALSE,
  381. IMAGE_DIRECTORY_ENTRY_IAT,
  382. &IATSize);
  383. if (IAT) {
  384. // Easy case. All the IATs are grouped together.
  385. ExList.Add((DWORD_PTR) IAT, IATSize, Raw);
  386. // Add the TimeDateStamp and ForwarderChain fields in the Import Descriptors
  387. while (ImportDesc->Characteristics) {
  388. ExList.Add((DWORD_PTR) &ImportDesc->TimeDateStamp, 8, Raw);
  389. ImportDesc++;
  390. }
  391. } else {
  392. // Not so easy. Need to walk each Import descriptor to find the bounds of the IAT
  393. // (note, there's no requirement that all the IAT's for all descriptors be contiguous).
  394. while (ImportDesc->Characteristics) {
  395. PIMAGE_THUNK_DATA ThunkStart;
  396. ExList.Add((DWORD_PTR)&ImportDesc->TimeDateStamp, 8, Raw);
  397. ThunkStart = (PIMAGE_THUNK_DATA) ImageRvaToVa((PIMAGE_NT_HEADERS)LoadedImage.FileHeader,
  398. LoadedImage.MappedAddress,
  399. (ULONG) ImportDesc->OriginalFirstThunk,
  400. NULL);
  401. if (f32) {
  402. PIMAGE_THUNK_DATA32 Thunk = (PIMAGE_THUNK_DATA32)ThunkStart;
  403. while (Thunk->u1.AddressOfData) {
  404. Thunk++;
  405. }
  406. ExList.Add( (DWORD)ImportDesc->FirstThunk,
  407. (DWORD)((DWORD_PTR)Thunk - (DWORD_PTR) ThunkStart + sizeof(IMAGE_THUNK_DATA32)), Virtual);
  408. } else {
  409. PIMAGE_THUNK_DATA64 Thunk = (PIMAGE_THUNK_DATA64)ThunkStart;
  410. while (Thunk->u1.AddressOfData) {
  411. Thunk++;
  412. }
  413. ExList.Add( (DWORD)ImportDesc->FirstThunk,
  414. (DWORD)((DWORD_PTR)Thunk - (DWORD_PTR) ThunkStart + sizeof(IMAGE_THUNK_DATA64)), Virtual);
  415. }
  416. ImportDesc++;
  417. }
  418. }
  419. }
  420. }
  421. // Add each section header followed by the data from that section.
  422. for (i = 0; i < LoadedImage.NumberOfSections; i++) {
  423. if (!ExList.Emit((PBYTE) (LoadedImage.MappedAddress + LoadedImage.Sections[i].PointerToRawData),
  424. LoadedImage.Sections[i].SizeOfRawData))
  425. {
  426. rc = ERROR_OPERATION_ABORTED;
  427. __leave;
  428. }
  429. }
  430. rc = ERROR_SUCCESS;
  431. } __except(EXCEPTION_EXECUTE_HANDLER) { }
  432. UnMapIt(&LoadedImage);
  433. SetLastError(rc);
  434. return(rc == ERROR_SUCCESS ? TRUE : FALSE);
  435. }
  436. BOOL
  437. IMAGEAPI
  438. ImageAddCertificate(
  439. IN HANDLE FileHandle,
  440. IN LPWIN_CERTIFICATE Certificate,
  441. OUT PDWORD Index
  442. )
  443. /*++
  444. Routine Description:
  445. Add a certificate to the image. There is no checking to ensure there are no
  446. duplicate types.
  447. Arguments:
  448. FileHandle - Handle to the file in question. The file should be opened
  449. with at least GENERIC_WRITE access.
  450. Certificate - Pointer to a WIN_CERTIFICATE structure.
  451. Index - After adding the Certificate to the image, this is the index
  452. you can use for later references to that certificate.
  453. Return Value:
  454. TRUE - Success
  455. FALSE - There was some error. Call GetLastError() for more information.
  456. --*/
  457. {
  458. LOADED_IMAGE LoadedImage;
  459. DWORD rc;
  460. LPWIN_CERTIFICATE pCert;
  461. DWORD OnDiskCertLength;
  462. DWORD_PTR NewCertLocation;
  463. DWORD OriginalImageSize;
  464. PIMAGE_DATA_DIRECTORY pDataDir;
  465. BOOL f32, fSkipUnMap;
  466. if (MapIt(FileHandle, &LoadedImage, MAP_READWRITE) == FALSE) {
  467. // Unable to map the image.
  468. SetLastError(ERROR_INVALID_PARAMETER);
  469. return(FALSE);
  470. }
  471. rc = ERROR_INVALID_PARAMETER;
  472. fSkipUnMap = FALSE;
  473. __try {
  474. if (LoadedImage.fDOSImage) {
  475. __leave;
  476. }
  477. if (LoadedImage.FileHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
  478. f32 = TRUE;
  479. pDataDir = &((PIMAGE_NT_HEADERS32)(LoadedImage.FileHeader))->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY];
  480. } else if (LoadedImage.FileHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
  481. f32 = FALSE;
  482. pDataDir = &((PIMAGE_NT_HEADERS64)(LoadedImage.FileHeader))->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY];
  483. } else {
  484. __leave;
  485. }
  486. pCert = (LPWIN_CERTIFICATE) Certificate;
  487. // Test the output parameter and the the cert.
  488. *Index = (DWORD) -1;
  489. OnDiskCertLength = pCert->dwLength;
  490. OnDiskCertLength = (OnDiskCertLength + 7) & ~7; // Round the size of cert.
  491. // Grow the image.
  492. OriginalImageSize = LoadedImage.SizeOfImage;
  493. OriginalImageSize = (OriginalImageSize + 7) & ~7; // Round the size of Image.
  494. // Check if the cert pointer is at least reasonable.
  495. if (pDataDir->VirtualAddress &&
  496. (pDataDir->VirtualAddress + pDataDir->Size) > LoadedImage.SizeOfImage)
  497. {
  498. __leave;
  499. }
  500. // Looks good now.
  501. *Index = 0;
  502. if (pDataDir->VirtualAddress == 0) {
  503. pDataDir->VirtualAddress = OriginalImageSize;
  504. pDataDir->Size = 0;
  505. NewCertLocation = OriginalImageSize;
  506. } else {
  507. LPWIN_CERTIFICATE CurrentCert;
  508. NewCertLocation = pDataDir->VirtualAddress + pDataDir->Size + (DWORD_PTR) LoadedImage.MappedAddress;
  509. CurrentCert = (LPWIN_CERTIFICATE) (LoadedImage.MappedAddress + pDataDir->VirtualAddress);
  510. while (((DWORD_PTR)CurrentCert) < NewCertLocation) {
  511. if (CurrentCert->dwLength == 0) {
  512. __leave;
  513. }
  514. CurrentCert = (LPWIN_CERTIFICATE)(((DWORD_PTR)CurrentCert + CurrentCert->dwLength + 7) & ~7);
  515. (*Index)++;
  516. }
  517. NewCertLocation -= (DWORD_PTR) LoadedImage.MappedAddress;
  518. }
  519. if (!GrowMap (&LoadedImage, OnDiskCertLength + (OriginalImageSize - LoadedImage.SizeOfImage))) {
  520. fSkipUnMap = TRUE;
  521. __leave;
  522. }
  523. if (NewCertLocation < OriginalImageSize) {
  524. // There's data after the current security data. Move it down.
  525. memmove(LoadedImage.MappedAddress + NewCertLocation + pCert->dwLength,
  526. LoadedImage.MappedAddress + NewCertLocation,
  527. (unsigned) (OriginalImageSize - NewCertLocation));
  528. }
  529. memmove(LoadedImage.MappedAddress + NewCertLocation,
  530. pCert,
  531. pCert->dwLength);
  532. // GrowMap may have moved the dirs.
  533. if (f32) {
  534. pDataDir = &((PIMAGE_NT_HEADERS32)(LoadedImage.FileHeader))->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY];
  535. } else {
  536. pDataDir = &((PIMAGE_NT_HEADERS64)(LoadedImage.FileHeader))->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY];
  537. }
  538. pDataDir->Size += OnDiskCertLength;
  539. rc = ERROR_SUCCESS;
  540. } __except(EXCEPTION_EXECUTE_HANDLER) { }
  541. if (!fSkipUnMap)
  542. UnMapIt(&LoadedImage);
  543. SetLastError(rc);
  544. return(rc == ERROR_SUCCESS ? TRUE : FALSE);
  545. }
  546. BOOL
  547. IMAGEAPI
  548. ImageRemoveCertificate(
  549. IN HANDLE FileHandle,
  550. IN DWORD Index
  551. )
  552. /*++
  553. Routine Description:
  554. Remove a certificate from an image.
  555. Arguments:
  556. FileHandle - Handle to the file in question. The file should be opened
  557. with at least GENERIC_WRITE access.
  558. Index - The index to remove from the image.
  559. Return Value:
  560. TRUE - Successful
  561. FALSE - There was some error. Call GetLastError() for more information.
  562. --*/
  563. {
  564. LOADED_IMAGE LoadedImage;
  565. LPWIN_CERTIFICATE CurrentCert;
  566. DWORD rc;
  567. DWORD OldCertLength;
  568. if (MapIt(FileHandle, &LoadedImage, MAP_READWRITE) == FALSE) {
  569. // Unable to map the image.
  570. SetLastError(ERROR_INVALID_PARAMETER);
  571. return(FALSE);
  572. }
  573. rc = ERROR_INVALID_PARAMETER;
  574. __try {
  575. if (FindCertificate(&LoadedImage, Index, &CurrentCert) == FALSE) {
  576. __leave;
  577. }
  578. OldCertLength = CurrentCert->dwLength;
  579. OldCertLength = (OldCertLength + 7) & ~7; // The disk size is actually a multiple of 8
  580. memmove(CurrentCert,
  581. ((PCHAR)CurrentCert) + OldCertLength,
  582. (size_t)(LoadedImage.SizeOfImage - (((DWORD_PTR)CurrentCert) - (DWORD_PTR)LoadedImage.MappedAddress) - OldCertLength));
  583. if (LoadedImage.FileHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
  584. ((PIMAGE_NT_HEADERS32)LoadedImage.FileHeader)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size -= OldCertLength;
  585. if (!((PIMAGE_NT_HEADERS32)LoadedImage.FileHeader)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size) {
  586. // Last one removed. Clear the pointer
  587. ((PIMAGE_NT_HEADERS32)LoadedImage.FileHeader)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress = 0;
  588. }
  589. } else {
  590. ((PIMAGE_NT_HEADERS64)LoadedImage.FileHeader)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size -= OldCertLength;
  591. if (!((PIMAGE_NT_HEADERS64)LoadedImage.FileHeader)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size) {
  592. // Last one removed. Clear the pointer
  593. ((PIMAGE_NT_HEADERS64)LoadedImage.FileHeader)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress = 0;
  594. }
  595. }
  596. LoadedImage.SizeOfImage -= OldCertLength;
  597. rc = ERROR_SUCCESS;
  598. } __except(EXCEPTION_EXECUTE_HANDLER) { }
  599. UnMapIt(&LoadedImage);
  600. SetLastError(rc);
  601. return(rc == ERROR_SUCCESS ? TRUE : FALSE);
  602. }
  603. BOOL
  604. IMAGEAPI
  605. ImageEnumerateCertificates(
  606. IN HANDLE FileHandle,
  607. IN WORD TypeFilter,
  608. OUT PDWORD CertificateCount,
  609. IN OUT PDWORD Indices OPTIONAL,
  610. IN DWORD IndexCount OPTIONAL
  611. )
  612. /*++
  613. Routine Description:
  614. Enumerate the certificates in an image.
  615. Arguments:
  616. FileHandle - Handle to the file in question. The file should be opened
  617. with at least GENERIC_READ access.
  618. TypeFilter - The filter to apply when enumertating the certificates.
  619. Valid values are:
  620. CERT_SECTION_TYPE_ANY - Enumerate all certificate types
  621. in the image.
  622. CertificateCount - How many certificates are in the image.
  623. Indices - An array of indexes that match the filter type.
  624. IndexCount - The number of indexes in the indices array.
  625. Return Value:
  626. TRUE - Successful
  627. FALSE - There was some error. Call GetLastError() for more information.
  628. --*/
  629. {
  630. LOADED_IMAGE LoadedImage;
  631. BOOL rc;
  632. PIMAGE_DATA_DIRECTORY pDataDir;
  633. LPWIN_CERTIFICATE CurrentCert, LastCert;
  634. PIMAGE_OPTIONAL_HEADER32 OptionalHeader32 = NULL;
  635. PIMAGE_OPTIONAL_HEADER64 OptionalHeader64 = NULL;
  636. if (MapIt(FileHandle, &LoadedImage, MAP_READONLY) == FALSE) {
  637. // Unable to map the image.
  638. SetLastError(ERROR_INVALID_PARAMETER);
  639. return(FALSE);
  640. }
  641. rc = ERROR_INVALID_PARAMETER;
  642. __try {
  643. if (LoadedImage.fDOSImage) {
  644. __leave;
  645. }
  646. if (LoadedImage.FileHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
  647. pDataDir = &((PIMAGE_NT_HEADERS32)(LoadedImage.FileHeader))->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY];
  648. } else if (LoadedImage.FileHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
  649. pDataDir = &((PIMAGE_NT_HEADERS64)(LoadedImage.FileHeader))->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY];
  650. } else {
  651. __leave;
  652. }
  653. if ((pDataDir->VirtualAddress + pDataDir->Size) > LoadedImage.SizeOfImage) {
  654. *CertificateCount = 0;
  655. __leave;
  656. }
  657. if (!pDataDir->VirtualAddress || !pDataDir->Size) {
  658. *CertificateCount = 0;
  659. } else {
  660. DWORD MatchedIndex = 0;
  661. DWORD ActualIndex = 0;
  662. CurrentCert = (LPWIN_CERTIFICATE)((DWORD_PTR)LoadedImage.MappedAddress + pDataDir->VirtualAddress);
  663. LastCert = (LPWIN_CERTIFICATE)((DWORD_PTR)CurrentCert + pDataDir->Size);
  664. while (CurrentCert < LastCert ) {
  665. if ((TypeFilter == CERT_SECTION_TYPE_ANY) || (TypeFilter == CurrentCert->wCertificateType)) {
  666. if (Indices && (MatchedIndex < IndexCount)) {
  667. Indices[MatchedIndex] = ActualIndex;
  668. }
  669. MatchedIndex++;
  670. }
  671. ActualIndex++;
  672. CurrentCert = (LPWIN_CERTIFICATE)((((DWORD_PTR)CurrentCert + CurrentCert->dwLength) +7) & ~7);
  673. }
  674. *CertificateCount = MatchedIndex;
  675. }
  676. rc = ERROR_SUCCESS;
  677. } __except(EXCEPTION_EXECUTE_HANDLER) { }
  678. UnMapIt(&LoadedImage);
  679. SetLastError(rc);
  680. return(rc == ERROR_SUCCESS ? TRUE : FALSE);
  681. }
  682. BOOL
  683. IMAGEAPI
  684. ImageGetCertificateData(
  685. IN HANDLE FileHandle,
  686. IN DWORD CertificateIndex,
  687. OUT LPWIN_CERTIFICATE Certificate,
  688. IN OUT PDWORD RequiredLength
  689. )
  690. /*++
  691. Routine Description:
  692. Given a specific certificate index, retrieve the certificate data.
  693. Arguments:
  694. FileHandle - Handle to the file in question. The file should be opened
  695. with at least GENERIC_READ access.
  696. CertificateIndex - Index to retrieve
  697. Certificate - Output buffer where the certificate is to be stored.
  698. RequiredLength - Size of the certificate buffer (input). On return, is
  699. set to the actual certificate length. NULL can be used
  700. to determine the size of a certificate.
  701. Return Value:
  702. TRUE - Successful
  703. FALSE - There was some error. Call GetLastError() for more information.
  704. --*/
  705. {
  706. LOADED_IMAGE LoadedImage;
  707. DWORD ErrorCode;
  708. LPWIN_CERTIFICATE ImageCert;
  709. if (MapIt(FileHandle, &LoadedImage, MAP_READONLY) == FALSE) {
  710. // Unable to map the image.
  711. SetLastError(ERROR_INVALID_PARAMETER);
  712. return(FALSE);
  713. }
  714. ErrorCode = ERROR_INVALID_PARAMETER;
  715. __try {
  716. if (FindCertificate(&LoadedImage, CertificateIndex, &ImageCert) == FALSE) {
  717. __leave;
  718. }
  719. if (*RequiredLength < ImageCert->dwLength) {
  720. *RequiredLength = ImageCert->dwLength;
  721. ErrorCode = ERROR_INSUFFICIENT_BUFFER;
  722. } else {
  723. memcpy(Certificate, (PUCHAR)ImageCert, ImageCert->dwLength);
  724. ErrorCode = ERROR_SUCCESS;
  725. }
  726. } __except(EXCEPTION_EXECUTE_HANDLER) { }
  727. UnMapIt(&LoadedImage);
  728. SetLastError(ErrorCode);
  729. return(ErrorCode == ERROR_SUCCESS ? TRUE: FALSE);
  730. }
  731. BOOL
  732. IMAGEAPI
  733. ImageGetCertificateHeader(
  734. IN HANDLE FileHandle,
  735. IN DWORD CertificateIndex,
  736. IN OUT LPWIN_CERTIFICATE CertificateHeader
  737. )
  738. /*++
  739. Routine Description:
  740. Given a specific certificate index, retrieve the certificate data.
  741. Arguments:
  742. FileHandle - Handle to the file in question. The file should be opened
  743. with at least GENERIC_READ access.
  744. CertificateIndex - Index to retrieve.
  745. CertificateHeader - Pointer to a WIN_CERTIFICATE to fill in.
  746. Return Value:
  747. TRUE - Success
  748. FALSE - There was some error. Call GetLastError() for more information.
  749. --*/
  750. {
  751. LOADED_IMAGE LoadedImage;
  752. LPWIN_CERTIFICATE ImageCert;
  753. BOOL rc;
  754. if (MapIt(FileHandle, &LoadedImage, MAP_READONLY) == FALSE) {
  755. // Unable to map the image.
  756. SetLastError(ERROR_INVALID_PARAMETER);
  757. return(FALSE);
  758. }
  759. if (FindCertificate(&LoadedImage, CertificateIndex, &ImageCert) == FALSE) {
  760. rc = FALSE;
  761. goto Exit;
  762. }
  763. __try {
  764. memcpy(CertificateHeader, ImageCert, sizeof(WIN_CERTIFICATE));
  765. rc = TRUE;
  766. } __except(EXCEPTION_EXECUTE_HANDLER) {
  767. rc = FALSE;
  768. }
  769. Exit:
  770. UnMapIt(&LoadedImage);
  771. if (rc == FALSE) {
  772. SetLastError(ERROR_INVALID_PARAMETER);
  773. }
  774. return(rc);
  775. }