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.

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