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.

473 lines
14 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1996 - 1999
  6. //
  7. // File: peimage2.cpp
  8. //
  9. // Contents: Microsoft SIP Provider
  10. //
  11. // History: 14-Mar-1997 pberkman created
  12. //
  13. //--------------------------------------------------------------------------
  14. #include "global.hxx"
  15. __inline DWORD AlignIt (DWORD Value, DWORD Alignment) { return (Value + (Alignment - 1)) & ~(Alignment -1); }
  16. #define InitializeListHead(ListHead) (\
  17. (ListHead)->Flink = (ListHead)->Blink = (ListHead))
  18. #define MAP_READONLY TRUE
  19. #define MAP_READWRITE FALSE
  20. BOOL
  21. CalculateImagePtrs(
  22. PLOADED_IMAGE LoadedImage
  23. )
  24. {
  25. PIMAGE_DOS_HEADER DosHeader;
  26. BOOL fRC = FALSE;
  27. // Everything is mapped. Now check the image and find nt image headers
  28. __try {
  29. DosHeader = (PIMAGE_DOS_HEADER)LoadedImage->MappedAddress;
  30. if ((DosHeader->e_magic != IMAGE_DOS_SIGNATURE) &&
  31. (DosHeader->e_magic != IMAGE_NT_SIGNATURE)) {
  32. __leave;
  33. }
  34. if (DosHeader->e_magic == IMAGE_DOS_SIGNATURE) {
  35. if (DosHeader->e_lfanew == 0) {
  36. __leave;
  37. }
  38. LoadedImage->FileHeader = (PIMAGE_NT_HEADERS)((ULONG_PTR)DosHeader + DosHeader->e_lfanew);
  39. if (
  40. // If IMAGE_NT_HEADERS would extend past the end of file...
  41. (PBYTE)LoadedImage->FileHeader + sizeof(IMAGE_NT_HEADERS) >
  42. (PBYTE)LoadedImage->MappedAddress + LoadedImage->SizeOfImage ||
  43. // ..or if it would begin in, or before the IMAGE_DOS_HEADER...
  44. (PBYTE)LoadedImage->FileHeader <
  45. (PBYTE)LoadedImage->MappedAddress + sizeof(IMAGE_DOS_HEADER) )
  46. {
  47. // ...then e_lfanew is not as expected.
  48. // (Several Win95 files are in this category.)
  49. __leave;
  50. }
  51. } else {
  52. // No DOS header indicates an image built w/o a dos stub
  53. LoadedImage->FileHeader = (PIMAGE_NT_HEADERS)DosHeader;
  54. }
  55. if ( LoadedImage->FileHeader->Signature != IMAGE_NT_SIGNATURE ) {
  56. __leave;
  57. }
  58. // No optional header indicates an object...
  59. if ( !LoadedImage->FileHeader->FileHeader.SizeOfOptionalHeader ) {
  60. __leave;
  61. }
  62. // Check for versions < 2.50
  63. if ( LoadedImage->FileHeader->OptionalHeader.MajorLinkerVersion < 3 &&
  64. LoadedImage->FileHeader->OptionalHeader.MinorLinkerVersion < 5 ) {
  65. __leave;
  66. }
  67. InitializeListHead( &LoadedImage->Links );
  68. LoadedImage->NumberOfSections = LoadedImage->FileHeader->FileHeader.NumberOfSections;
  69. LoadedImage->Sections = IMAGE_FIRST_SECTION(LoadedImage->FileHeader);
  70. fRC = TRUE;
  71. } __except ( EXCEPTION_EXECUTE_HANDLER ) { }
  72. return fRC;
  73. }
  74. BOOL
  75. MapIt(
  76. HANDLE hFile,
  77. PLOADED_IMAGE LoadedImage
  78. )
  79. {
  80. HANDLE hMappedFile;
  81. hMappedFile = CreateFileMapping(
  82. hFile,
  83. NULL,
  84. PAGE_READONLY,
  85. 0,
  86. 0,
  87. NULL
  88. );
  89. if ( !hMappedFile ) {
  90. return FALSE;
  91. }
  92. LoadedImage->MappedAddress = (PUCHAR) MapViewOfFile(
  93. hMappedFile,
  94. FILE_MAP_READ,
  95. 0,
  96. 0,
  97. 0
  98. );
  99. CloseHandle(hMappedFile);
  100. LoadedImage->SizeOfImage = GetFileSize(hFile, NULL);
  101. if (!LoadedImage->MappedAddress) {
  102. return (FALSE);
  103. }
  104. if (!CalculateImagePtrs(LoadedImage)) {
  105. UnmapViewOfFile(LoadedImage->MappedAddress);
  106. return(FALSE);
  107. }
  108. LoadedImage->hFile = INVALID_HANDLE_VALUE;
  109. return(TRUE);
  110. }
  111. typedef struct _EXCLUDE_RANGE {
  112. PBYTE Offset;
  113. DWORD Size;
  114. struct _EXCLUDE_RANGE *Next;
  115. } EXCLUDE_RANGE;
  116. class EXCLUDE_LIST
  117. {
  118. public:
  119. EXCLUDE_LIST() {
  120. m_Image = NULL;
  121. m_ExRange = new EXCLUDE_RANGE;
  122. if(m_ExRange)
  123. memset(m_ExRange, 0x00, sizeof(EXCLUDE_RANGE));
  124. }
  125. ~EXCLUDE_LIST() {
  126. EXCLUDE_RANGE *pTmp;
  127. pTmp = m_ExRange->Next;
  128. while (pTmp)
  129. {
  130. DELETE_OBJECT(m_ExRange);
  131. m_ExRange = pTmp;
  132. pTmp = m_ExRange->Next;
  133. }
  134. DELETE_OBJECT(m_ExRange);
  135. }
  136. void Init(LOADED_IMAGE * Image, DIGEST_FUNCTION pFunc, DIGEST_HANDLE dh) {
  137. m_Image = Image;
  138. m_ExRange->Offset = NULL;
  139. m_ExRange->Size = 0;
  140. m_pFunc = pFunc;
  141. m_dh = dh;
  142. return;
  143. }
  144. void Add(DWORD_PTR Offset, DWORD Size);
  145. BOOL Emit(PBYTE Offset, DWORD Size);
  146. private:
  147. LOADED_IMAGE * m_Image;
  148. EXCLUDE_RANGE * m_ExRange;
  149. DIGEST_FUNCTION m_pFunc;
  150. DIGEST_HANDLE m_dh;
  151. };
  152. void
  153. EXCLUDE_LIST::Add(
  154. DWORD_PTR Offset,
  155. DWORD Size
  156. )
  157. {
  158. EXCLUDE_RANGE *pTmp, *pExRange;
  159. pExRange = m_ExRange;
  160. while (pExRange->Next && (pExRange->Next->Offset < (PBYTE)Offset)) {
  161. pExRange = pExRange->Next;
  162. }
  163. pTmp = new EXCLUDE_RANGE;
  164. if(pTmp)
  165. {
  166. pTmp->Next = pExRange->Next;
  167. pTmp->Offset = (PBYTE)Offset;
  168. pTmp->Size = Size;
  169. pExRange->Next = pTmp;
  170. }
  171. return;
  172. }
  173. BOOL
  174. EXCLUDE_LIST::Emit(
  175. PBYTE Offset,
  176. DWORD Size
  177. )
  178. {
  179. BOOL rc;
  180. EXCLUDE_RANGE *pExRange;
  181. DWORD EmitSize, ExcludeSize;
  182. pExRange = m_ExRange->Next;
  183. while (pExRange && (Size > 0)) {
  184. if (pExRange->Offset >= Offset) {
  185. // Emit what's before the exclude list.
  186. EmitSize = min((DWORD)(pExRange->Offset - Offset), Size);
  187. if (EmitSize) {
  188. rc = (*m_pFunc)(m_dh, Offset, EmitSize);
  189. if (rc == FALSE)
  190. return rc;
  191. Size -= EmitSize;
  192. Offset += EmitSize;
  193. }
  194. }
  195. if (Size) {
  196. if (pExRange->Offset + pExRange->Size >= Offset) {
  197. // Skip over what's in the exclude list.
  198. ExcludeSize = min(Size, (DWORD)(pExRange->Offset + pExRange->Size - Offset));
  199. Size -= ExcludeSize;
  200. Offset += ExcludeSize;
  201. }
  202. }
  203. pExRange = pExRange->Next;
  204. }
  205. // Emit what's left.
  206. if (Size) {
  207. rc = (*m_pFunc)(m_dh, Offset, Size);
  208. }
  209. return rc;
  210. }
  211. BOOL
  212. imagehack_IsImagePEOnly(
  213. IN HANDLE FileHandle
  214. )
  215. /*
  216. What we're looking for here is if there's data outside the exe.
  217. To do so, find the highest section header offset. To that, find the
  218. highest debug directory offset. Finally, round up to the file alignment
  219. size, add in the cert size, and compare to the reported image size...
  220. */
  221. {
  222. LOADED_IMAGE LoadedImage;
  223. DWORD HighOffset;
  224. DWORD i, Offset, Size;
  225. LONG DebugDirectorySize, CertSize;
  226. PIMAGE_DEBUG_DIRECTORY DebugDirectory;
  227. PVOID CertDir;
  228. BOOL rc;
  229. DWORD FileAlignment;
  230. DWORD NumberOfSections;
  231. if (MapIt(FileHandle, &LoadedImage) == FALSE) {
  232. return(FALSE);
  233. }
  234. rc = FALSE;
  235. __try {
  236. if (LoadedImage.FileHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
  237. FileAlignment = ((PIMAGE_NT_HEADERS32)LoadedImage.FileHeader)->OptionalHeader.FileAlignment;
  238. } else if (LoadedImage.FileHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
  239. FileAlignment = ((PIMAGE_NT_HEADERS64)LoadedImage.FileHeader)->OptionalHeader.FileAlignment;
  240. } else {
  241. __leave;
  242. }
  243. NumberOfSections = LoadedImage.FileHeader->FileHeader.NumberOfSections;
  244. HighOffset = 0;
  245. for (i = 0; i < NumberOfSections; i++) {
  246. Offset = LoadedImage.Sections[i].PointerToRawData;
  247. Size = LoadedImage.Sections[i].SizeOfRawData;
  248. HighOffset = max(HighOffset, (Offset + Size));
  249. }
  250. DebugDirectory = (PIMAGE_DEBUG_DIRECTORY)
  251. ImageDirectoryEntryToData(
  252. LoadedImage.MappedAddress,
  253. FALSE,
  254. IMAGE_DIRECTORY_ENTRY_DEBUG,
  255. (ULONG *) &DebugDirectorySize
  256. );
  257. while (DebugDirectorySize > 0) {
  258. Offset = DebugDirectory->PointerToRawData;
  259. Size = DebugDirectory->SizeOfData;
  260. HighOffset = max(HighOffset, (Offset + Size));
  261. DebugDirectorySize -= sizeof(IMAGE_DEBUG_DIRECTORY);
  262. DebugDirectory++;
  263. }
  264. HighOffset = AlignIt(HighOffset, FileAlignment);
  265. CertDir = (PVOID) ImageDirectoryEntryToData(
  266. LoadedImage.MappedAddress,
  267. FALSE,
  268. IMAGE_DIRECTORY_ENTRY_SECURITY,
  269. (ULONG *) &CertSize
  270. );
  271. if (LoadedImage.SizeOfImage <= (HighOffset + CertSize)) {
  272. rc = TRUE;
  273. }
  274. } __except(EXCEPTION_EXECUTE_HANDLER) { }
  275. UnmapViewOfFile(LoadedImage.MappedAddress);
  276. return(rc);
  277. }
  278. BOOL
  279. imagehack_AuImageGetDigestStream(
  280. IN HANDLE FileHandle,
  281. IN DWORD DigestLevel,
  282. IN DIGEST_FUNCTION DigestFunction,
  283. IN DIGEST_HANDLE DigestHandle
  284. )
  285. /*++
  286. Routine Description:
  287. Given an image, return the bytes necessary to construct a certificate.
  288. Only PE images are supported at this time.
  289. Arguments:
  290. FileHandle - Handle to the file in question. The file should be opened
  291. with at least GENERIC_READ access.
  292. DigestLevel - Indicates what data will be included in the returned buffer.
  293. Valid values are:
  294. CERT_PE_IMAGE_DIGEST_ALL_BUT_CERTS - Include data outside the PE image itself
  295. (may include non-mapped debug symbolic)
  296. DigestFunction - User supplied routine that will process the data.
  297. DigestHandle - User supplied handle to identify the digest. Passed as the first
  298. argument to the DigestFunction.
  299. Return Value:
  300. TRUE - Success.
  301. FALSE - There was some error. Call GetLastError for more information. Possible
  302. values are ERROR_INVALID_PARAMETER or ERROR_OPERATION_ABORTED.
  303. --*/
  304. {
  305. LOADED_IMAGE LoadedImage;
  306. BOOL rc;
  307. EXCLUDE_LIST ExList;
  308. if (MapIt(FileHandle, &LoadedImage) == FALSE) {
  309. // Unable to map the image or invalid digest level.
  310. SetLastError(ERROR_INVALID_PARAMETER);
  311. return(FALSE);
  312. }
  313. rc = ERROR_INVALID_PARAMETER;
  314. __try {
  315. PIMAGE_DATA_DIRECTORY CertDirectory;
  316. DWORD HeaderEndOffset = 0;
  317. if ((LoadedImage.FileHeader->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) &&
  318. (LoadedImage.FileHeader->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC))
  319. {
  320. __leave;
  321. }
  322. ExList.Init(&LoadedImage, DigestFunction, DigestHandle);
  323. if (LoadedImage.FileHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
  324. PIMAGE_NT_HEADERS32 NtHeader32 = (PIMAGE_NT_HEADERS32)(LoadedImage.FileHeader);
  325. // Exclude the checksum.
  326. ExList.Add(((DWORD_PTR) &NtHeader32->OptionalHeader.CheckSum),
  327. sizeof(NtHeader32->OptionalHeader.CheckSum));
  328. CertDirectory = &NtHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY];
  329. HeaderEndOffset = NtHeader32->OptionalHeader.SizeOfHeaders;
  330. } else {
  331. PIMAGE_NT_HEADERS64 NtHeader64 = (PIMAGE_NT_HEADERS64)(LoadedImage.FileHeader);
  332. // Exclude the checksum.
  333. ExList.Add(((DWORD_PTR) &NtHeader64->OptionalHeader.CheckSum),
  334. sizeof(NtHeader64->OptionalHeader.CheckSum));
  335. CertDirectory = &NtHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY];
  336. HeaderEndOffset = NtHeader64->OptionalHeader.SizeOfHeaders;
  337. }
  338. DWORD CertFileOffset = CertDirectory->VirtualAddress;
  339. DWORD CertFileSize = CertDirectory->Size;
  340. if (CertFileOffset && CertFileSize) {
  341. DWORD i;
  342. if (CertFileOffset > LoadedImage.SizeOfImage) {
  343. __leave; // Start of certs is past end of image
  344. }
  345. if ((CertFileOffset + CertFileSize) != LoadedImage.SizeOfImage) {
  346. __leave; // Certs not at end of image
  347. }
  348. if ((CertFileOffset + CertFileSize) < CertFileOffset) {
  349. __leave; // cert end is before cert start (start + size wraps)
  350. }
  351. if (CertFileOffset < HeaderEndOffset) {
  352. __leave; // Certs are in the header space
  353. }
  354. // See if the certs are in the section data
  355. for (i = 0; i < LoadedImage.NumberOfSections; i++) {
  356. DWORD SectionFileOffsetStart = LoadedImage.Sections[i].PointerToRawData;
  357. DWORD SectionFileOffsetEnd = SectionFileOffsetStart + LoadedImage.Sections[i].SizeOfRawData;
  358. if (SectionFileOffsetStart && (CertFileOffset < SectionFileOffsetEnd)) {
  359. __leave; // CertData starts before this section - not allowed
  360. }
  361. }
  362. }
  363. // Exclude the Security directory.
  364. ExList.Add((DWORD_PTR) CertDirectory, sizeof(IMAGE_DATA_DIRECTORY));
  365. // Exclude the certs.
  366. ExList.Add((DWORD_PTR)CertFileOffset + (DWORD_PTR)LoadedImage.MappedAddress, CertFileSize);
  367. ExList.Emit((PBYTE) (LoadedImage.MappedAddress), LoadedImage.SizeOfImage);
  368. rc = ERROR_SUCCESS;
  369. } __except(EXCEPTION_EXECUTE_HANDLER) { }
  370. UnmapViewOfFile(LoadedImage.MappedAddress);
  371. SetLastError(rc);
  372. return(rc == ERROR_SUCCESS ? TRUE : FALSE);
  373. }