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.

2529 lines
71 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. imagechk.c
  5. Abstract:
  6. this module implements a sanity check of certain image characteristics
  7. Author:
  8. NT Base
  9. Revision History:
  10. Notes:
  11. --*/
  12. #ifdef __cplusplus
  13. extern "C" {
  14. #endif
  15. #include <nt.h>
  16. #include <ntrtl.h>
  17. #include <nturtl.h>
  18. #ifdef __cplusplus
  19. }
  20. #endif
  21. //
  22. // Calculate the size of a field in a structure of type type, without
  23. // knowing or stating the type of the field.
  24. //
  25. #define RTL_FIELD_SIZE(type, field) (sizeof(((type *)0)->field))
  26. //
  27. // Calculate the size of a structure of type type up through and
  28. // including a field.
  29. //
  30. #define RTL_SIZEOF_THROUGH_FIELD(type, field) \
  31. (FIELD_OFFSET(type, field) + RTL_FIELD_SIZE(type, field))
  32. #include <errno.h>
  33. #include <direct.h>
  34. #include <cvinfo.h>
  35. #include <private.h>
  36. typedef struct _SYMMODLIST{
  37. char *ModName;
  38. void *ModBase;
  39. struct _SYMMODLIST *Next;
  40. } SYMMODLIST, *PSYMMODLIST;
  41. typedef struct List {
  42. char Name[40];
  43. unsigned long Attributes;
  44. } List, *pList;
  45. typedef struct _LogListItem {
  46. char *LogLine;
  47. struct _LogListItem *Next;
  48. } LogListItem, *pLogListItem;
  49. //
  50. // decarations
  51. //
  52. VOID
  53. FindFiles();
  54. VOID
  55. Imagechk(
  56. List *rgpList,
  57. TCHAR *szDirectory
  58. );
  59. VOID
  60. ParseArgs(
  61. int *pargc,
  62. char **argv
  63. );
  64. int
  65. __cdecl
  66. CompFileAndDir(
  67. const void *elem1,
  68. const void *elem2
  69. );
  70. int
  71. __cdecl
  72. CompName(
  73. const void *elem1,
  74. const void *elem2
  75. );
  76. VOID
  77. Usage(
  78. VOID
  79. );
  80. int
  81. _cdecl
  82. _cwild(
  83. VOID
  84. );
  85. PSYMMODLIST
  86. MakeModList(
  87. HANDLE
  88. );
  89. void
  90. FreeModList(
  91. PSYMMODLIST
  92. );
  93. BOOL
  94. CALLBACK
  95. SymEnumerateModulesCallback(
  96. LPSTR,
  97. ULONG64,
  98. PVOID
  99. );
  100. void *
  101. GetModAddrFromName(
  102. PSYMMODLIST,
  103. char *
  104. );
  105. BOOL
  106. VerifyVersionResource(
  107. PCHAR FileName,
  108. BOOL fSelfRegister
  109. );
  110. BOOL
  111. ValidatePdata(
  112. PIMAGE_DOS_HEADER DosHeader
  113. );
  114. BOOL
  115. ImageNeedsOleSelfRegister(
  116. PIMAGE_DOS_HEADER DosHeader
  117. );
  118. NTSTATUS
  119. MiVerifyImageHeader (
  120. IN PIMAGE_NT_HEADERS NtHeader,
  121. IN PIMAGE_DOS_HEADER DosHeader,
  122. IN DWORD NtHeaderSize
  123. );
  124. pLogListItem
  125. LogAppend(
  126. char *,
  127. pLogListItem
  128. );
  129. void
  130. LogOutAndClean(
  131. BOOL
  132. );
  133. void
  134. __cdecl
  135. LogPrintf(
  136. const char *format,
  137. ...
  138. );
  139. #define X64K (64*1024)
  140. #define MM_SIZE_OF_LARGEST_IMAGE ((ULONG)0x10000000)
  141. #define MM_MAXIMUM_IMAGE_HEADER (2 * PageSize)
  142. #define MM_MAXIMUM_IMAGE_SECTIONS \
  143. ((MM_MAXIMUM_IMAGE_HEADER - (4096 + sizeof(IMAGE_NT_HEADERS))) / \
  144. sizeof(IMAGE_SECTION_HEADER))
  145. #define MMSECTOR_SHIFT 9 //MUST BE LESS THAN OR EQUAL TO PageShift
  146. #define MMSECTOR_MASK 0x1ff
  147. #define MI_ROUND_TO_SIZE(LENGTH,ALIGNMENT) \
  148. (((ULONG)LENGTH + ALIGNMENT - 1) & ~(ALIGNMENT - 1))
  149. #define BYTES_TO_PAGES(Size) (((ULONG)(Size) >> PageShift) + \
  150. (((ULONG)(Size) & (PageSize - 1)) != 0))
  151. #define ArgFlag_OK 1
  152. #define ArgFlag_CKMZ 2
  153. #define ArgFlag_SymCK 4
  154. #define ArgFlag_OLESelf 8
  155. #define ArgFlag_CKBase 16
  156. //
  157. // file global data
  158. //
  159. BOOL fRecurse;
  160. BOOL fFileOut;
  161. BOOL fNotCurrent;
  162. BOOL fPattern;
  163. BOOL fSingleFile;
  164. BOOL fPathOverride;
  165. BOOL fSingleSlash;
  166. BOOL fDebugMapped;
  167. FILE* fout;
  168. CHAR *szFileName = {"*.*"};
  169. CHAR *pszRootDir;
  170. CHAR *pszFileOut;
  171. CHAR szDirectory[MAX_PATH] = {"."};
  172. CHAR szSympath[MAX_PATH] = {0};
  173. CHAR *szPattern;
  174. int endpath, DirNum=1, ProcessedFiles;
  175. ULONG PageSize;
  176. ULONG PageShift;
  177. PVOID HighestUserAddress;
  178. USHORT ValidMachineIDMin;
  179. USHORT ValidMachineIDMax;
  180. DWORD ArgFlag;
  181. //
  182. // logging support
  183. //
  184. pLogListItem pLogList = NULL;
  185. pLogListItem pLogListTmp = NULL;
  186. typedef
  187. NTSTATUS
  188. (NTAPI *LPLDRVERIFYIMAGECHKSUM)(
  189. IN HANDLE ImageFileHandle
  190. );
  191. LPLDRVERIFYIMAGECHKSUM lpOldLdrVerifyImageMatchesChecksum;
  192. typedef
  193. NTSTATUS
  194. (NTAPI *LPLDRVERIFYIMAGEMATCHESCHECKSUM) (
  195. IN HANDLE ImageFileHandle,
  196. IN PLDR_IMPORT_MODULE_CALLBACK ImportCallbackRoutine OPTIONAL,
  197. IN PVOID ImportCallbackParameter,
  198. OUT PUSHORT ImageCharacteristics OPTIONAL
  199. );
  200. LPLDRVERIFYIMAGEMATCHESCHECKSUM lpNewLdrVerifyImageMatchesChecksum;
  201. typedef
  202. NTSTATUS
  203. (NTAPI *LPNTQUERYSYSTEMINFORMATION) (
  204. IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
  205. OUT PVOID SystemInformation,
  206. IN ULONG SystemInformationLength,
  207. OUT PULONG ReturnLength OPTIONAL
  208. );
  209. LPNTQUERYSYSTEMINFORMATION lpNtQuerySystemInformation;
  210. OSVERSIONINFO VersionInformation;
  211. //
  212. // function definitions
  213. //
  214. VOID __cdecl
  215. main(
  216. int argc,
  217. char *argv[],
  218. char *envp[]
  219. )
  220. /*++
  221. Routine Description:
  222. program entry
  223. Arguments:
  224. int argc,
  225. char *argv[]
  226. char *envp[]
  227. Return Value:
  228. none
  229. Notes:
  230. --*/
  231. {
  232. TCHAR CWD[MAX_PATH];
  233. int dirlen=0;
  234. if (argc < 2) {
  235. Usage();
  236. }
  237. ParseArgs(&argc, argv);
  238. GetCurrentDirectory(MAX_PATH, CWD);
  239. VersionInformation.dwOSVersionInfoSize = sizeof(VersionInformation);
  240. if (!GetVersionEx( &VersionInformation )) {
  241. fprintf(stderr, "Unable to detect OS version. Terminating.\n" );
  242. exit(1);
  243. }
  244. if ((VersionInformation.dwPlatformId != VER_PLATFORM_WIN32_NT) ||
  245. (VersionInformation.dwBuildNumber < 1230))
  246. {
  247. lpOldLdrVerifyImageMatchesChecksum = (LPLDRVERIFYIMAGECHKSUM)
  248. GetProcAddress(GetModuleHandle(TEXT("NTDLL.DLL")), TEXT("LdrVerifyImageMatchesChecksum"));
  249. if (lpOldLdrVerifyImageMatchesChecksum == NULL) {
  250. fprintf(stderr, "Incorrect operating system version.\n" );
  251. exit(1);
  252. }
  253. } else {
  254. lpOldLdrVerifyImageMatchesChecksum = NULL;
  255. if ((VersionInformation.dwPlatformId == VER_PLATFORM_WIN32_NT) &&
  256. (VersionInformation.dwBuildNumber >= 1230))
  257. {
  258. lpNewLdrVerifyImageMatchesChecksum = (LPLDRVERIFYIMAGEMATCHESCHECKSUM)
  259. GetProcAddress(GetModuleHandle(TEXT("NTDLL.DLL")), TEXT("LdrVerifyImageMatchesChecksum"));
  260. if (lpNewLdrVerifyImageMatchesChecksum == NULL) {
  261. fprintf(stderr, "OS is screwed up. NTDLL doesn't export LdrVerifyImageMatchesChecksum.\n" );
  262. exit(1);
  263. }
  264. }
  265. }
  266. if (VersionInformation.dwPlatformId == VER_PLATFORM_WIN32_NT) {
  267. SYSTEM_BASIC_INFORMATION SystemInformation;
  268. if (VersionInformation.dwBuildNumber <= 1465) {
  269. goto UseWin9x;
  270. }
  271. ValidMachineIDMin = USER_SHARED_DATA->ImageNumberLow;
  272. ValidMachineIDMax = USER_SHARED_DATA->ImageNumberHigh;
  273. lpNtQuerySystemInformation = (LPNTQUERYSYSTEMINFORMATION)
  274. GetProcAddress(GetModuleHandle(TEXT("NTDLL.DLL")), TEXT("NtQuerySystemInformation"));
  275. if (!lpNtQuerySystemInformation) {
  276. fprintf(stderr, "Incorrect operation system version.\n");
  277. exit(1);
  278. }
  279. if (!NT_SUCCESS((*lpNtQuerySystemInformation)(SystemBasicInformation,
  280. &SystemInformation,
  281. sizeof(SystemInformation),
  282. NULL))) {
  283. fprintf(stderr, "OS is screwed up. NtQuerySystemInformation failed.\n");
  284. exit(1);
  285. }
  286. HighestUserAddress = (PVOID)SystemInformation.MaximumUserModeAddress;
  287. } else {
  288. UseWin9x:
  289. HighestUserAddress = (PVOID) 0x7FFE0000;
  290. #ifdef _M_IX86
  291. ValidMachineIDMin = IMAGE_FILE_MACHINE_I386;
  292. ValidMachineIDMax = IMAGE_FILE_MACHINE_I386;
  293. #elif defined(_M_AMD64)
  294. ValidMachineIDMin = IMAGE_FILE_MACHINE_AMD64;
  295. ValidMachineIDMax = IMAGE_FILE_MACHINE_AMD64;
  296. #elif defined(_M_IA64)
  297. ValidMachineIDMin = IMAGE_FILE_MACHINE_IA64;
  298. ValidMachineIDMax = IMAGE_FILE_MACHINE_IA64;
  299. #else
  300. #error("Unknown machine type")
  301. #endif
  302. }
  303. if (fPathOverride) {
  304. if (_chdir(szDirectory) == -1){ // cd to dir
  305. fprintf(stderr, "Path not found: %s\n", szDirectory);
  306. Usage();
  307. }
  308. }
  309. // remove trailing '\' needed only for above chdir, not for output formatting
  310. if (fSingleSlash) {
  311. dirlen = strlen(szDirectory);
  312. szDirectory[dirlen-1] = '\0';
  313. }
  314. FindFiles();
  315. fprintf(stdout, "%d files processed in %d directories\n", ProcessedFiles, DirNum);
  316. }
  317. VOID
  318. FindFiles()
  319. /*++
  320. Routine Description:
  321. make list of files to check, then check them
  322. Arguments:
  323. none
  324. Return Value:
  325. none
  326. Notes:
  327. --*/
  328. {
  329. HANDLE fh;
  330. TCHAR CWD[MAX_PATH];
  331. char *q;
  332. WIN32_FIND_DATA *pfdata;
  333. BOOL fFilesInDir=FALSE;
  334. BOOL fDirsFound=FALSE;
  335. int dnCounter=0, cNumDir=0, i=0, Length=0, NameSize=0, total=0, cNumFiles=0;
  336. pList rgpList[5000];
  337. pfdata = (WIN32_FIND_DATA*)malloc(sizeof(WIN32_FIND_DATA));
  338. if (!pfdata) {
  339. fprintf(stderr, "Not enough memory.\n");
  340. return;
  341. }
  342. if (!fRecurse) {
  343. fh = FindFirstFile(szFileName, pfdata); // find only filename (pattern) if not recursive
  344. } else {
  345. fh = FindFirstFile("*.*", pfdata); // find all if recursive in order to determine subdirectory names
  346. }
  347. if (fh == INVALID_HANDLE_VALUE) {
  348. fprintf(fout==NULL? stderr : fout , "File not found: %s\n", szFileName);
  349. return;
  350. }
  351. // loop to find all files and directories in current directory
  352. // and copy pertinent data to individual List structures.
  353. do {
  354. if (strcmp(pfdata->cFileName, ".") && strcmp(pfdata->cFileName, "..")) { // skip . and ..
  355. rgpList[dnCounter] = (pList)malloc(sizeof(List)); // allocate the memory
  356. if (!rgpList[dnCounter]) {
  357. fprintf(stderr, "Not enough memory.\n");
  358. return;
  359. }
  360. if (!(pfdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { // if file
  361. fFilesInDir=TRUE;
  362. // see if given pattern wildcard extension matches pfdata->cFileName extension
  363. if (fPattern) {
  364. q = strchr(pfdata->cFileName, '.'); // find first instance of "." in filename
  365. if (q == NULL) goto blah; // "." not found
  366. _strlwr(q); // lowercase before compare
  367. if (strcmp(q, szPattern)) goto blah; // if pattern and name doesn't match goto
  368. } // OK, I used a goto, get over it.
  369. if (fSingleFile) {
  370. _strlwr(pfdata->cFileName);
  371. _strlwr(szFileName);
  372. if (strcmp(pfdata->cFileName, szFileName)) goto blah;
  373. }
  374. // if pattern && match || no pattern
  375. strcpy(rgpList[dnCounter]->Name, pfdata->cFileName);
  376. _strlwr(rgpList[dnCounter]->Name); // all lowercase for strcmp in CompName
  377. memcpy(&(rgpList[dnCounter]->Attributes), &pfdata->dwFileAttributes, 4);
  378. dnCounter++;
  379. cNumFiles++;
  380. } else {
  381. if (pfdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { // if dir
  382. fDirsFound=TRUE;
  383. //cNumDir++;
  384. if (fRecurse) {
  385. strcpy(rgpList[dnCounter]->Name, pfdata->cFileName);
  386. _strlwr(rgpList[dnCounter]->Name); // all lowercase for strcmp in CompName
  387. memcpy(&(rgpList[dnCounter]->Attributes), &pfdata->dwFileAttributes, 4);
  388. cNumDir++;
  389. dnCounter++;
  390. }
  391. }
  392. }
  393. }
  394. blah: ;
  395. } while (FindNextFile(fh, pfdata));
  396. FindClose(fh); // close the file handle
  397. // Sort Array arranging FILE entries at top
  398. qsort( (void *)rgpList, dnCounter, sizeof(List *), CompFileAndDir);
  399. // Sort Array alphabetizing only FILE names
  400. qsort( (void *)rgpList, dnCounter-cNumDir, sizeof(List *), CompName);
  401. // Sort Array alphabetizing only DIRectory names
  402. if (fRecurse) {
  403. qsort( (void *)&rgpList[dnCounter-cNumDir], cNumDir, sizeof(List *), CompName);
  404. }
  405. // Process newly sorted structures.
  406. for (i=0; i < dnCounter; ++i) {
  407. if (rgpList[i]->Attributes & FILE_ATTRIBUTE_DIRECTORY) { // if Dir
  408. if (fRecurse) {
  409. if (_chdir(rgpList[i]->Name) == -1){ // cd into subdir and check for error
  410. fprintf(stderr, "Unable to change directory: %s\n", rgpList[i]->Name);
  411. } else {
  412. NameSize = strlen(rgpList[i]->Name);
  413. strcat(szDirectory, "\\");
  414. strcat(szDirectory, rgpList[i]->Name); //append name to directory path
  415. total = strlen(szDirectory);
  416. DirNum++; // directory counter
  417. // start another iteration of FindFiles
  418. FindFiles();
  419. // get back to previous directory when above iteration returns
  420. _chdir("..");
  421. // cut off previously appended directory name - for output only
  422. szDirectory[total-(NameSize+1)]='\0';
  423. }
  424. }
  425. } else {
  426. if (!(rgpList[i]->Attributes & FILE_ATTRIBUTE_DIRECTORY)) // check image if not dir
  427. Imagechk(rgpList[i], szDirectory);
  428. }
  429. }
  430. } // end FindFiles
  431. VOID
  432. Imagechk(
  433. List *rgpList,
  434. TCHAR *szDirectory
  435. )
  436. /*++
  437. Routine Description:
  438. check various things, including:
  439. image type, header alignment, image size, machine type
  440. alignment, some properties of various sections, checksum integrity
  441. symbol / image file checksum agreement, existence of symbols, etc
  442. Arguments:
  443. List * rgpList,
  444. TCHAR * szDirectory
  445. Return Value:
  446. none
  447. Notes:
  448. --*/
  449. {
  450. HANDLE File;
  451. HANDLE MemMap;
  452. PIMAGE_DOS_HEADER DosHeader;
  453. PIMAGE_NT_HEADERS NtHeader;
  454. NTSTATUS Status;
  455. BY_HANDLE_FILE_INFORMATION FileInfo;
  456. ULONG NumberOfPtes;
  457. ULONG SectionVirtualSize = 0;
  458. ULONG i;
  459. PIMAGE_SECTION_HEADER SectionTableEntry;
  460. ULONG NumberOfSubsections;
  461. PCHAR ExtendedHeader = NULL;
  462. ULONG_PTR PreferredImageBase;
  463. ULONG_PTR NextVa;
  464. ULONG ImageFileSize;
  465. ULONG OffsetToSectionTable;
  466. ULONG ImageAlignment;
  467. ULONG PtesInSubsection;
  468. ULONG StartingSector;
  469. ULONG EndingSector;
  470. LPSTR ImageName;
  471. LPSTR MachineType = "Unknown";
  472. BOOL MachineTypeMismatch;
  473. BOOL ImageOk;
  474. BOOL fHasPdata;
  475. OSVERSIONINFO OSVerInfo;
  476. ImageName = rgpList->Name;
  477. OSVerInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  478. GetVersionEx(&OSVerInfo);
  479. LogPrintf("ImageChk: %s\\%s \n", szDirectory, ImageName);
  480. ProcessedFiles++;
  481. DosHeader = NULL;
  482. ImageOk = TRUE;
  483. File = CreateFile (ImageName,
  484. GENERIC_READ | FILE_EXECUTE,
  485. OSVerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT ? (FILE_SHARE_READ | FILE_SHARE_DELETE) : FILE_SHARE_READ,
  486. NULL,
  487. OPEN_EXISTING,
  488. FILE_ATTRIBUTE_NORMAL,
  489. NULL);
  490. if (File == INVALID_HANDLE_VALUE) {
  491. LogPrintf("Error, CreateFile() %d\n", GetLastError());
  492. ImageOk = FALSE;
  493. goto NextImage;
  494. }
  495. MemMap = CreateFileMapping (File,
  496. NULL, // default security.
  497. PAGE_READONLY, // file protection.
  498. 0, // high-order file size.
  499. 0,
  500. NULL);
  501. if (!GetFileInformationByHandle(File, &FileInfo)) {
  502. fprintf(stderr,"Error, GetFileInfo() %d\n", GetLastError());
  503. CloseHandle(File);
  504. ImageOk = FALSE; goto NextImage;
  505. }
  506. DosHeader = (PIMAGE_DOS_HEADER) MapViewOfFile(MemMap,
  507. FILE_MAP_READ,
  508. 0, // high
  509. 0, // low
  510. 0 // whole file
  511. );
  512. CloseHandle(MemMap);
  513. if (!DosHeader) {
  514. fprintf(stderr,"Error, MapViewOfFile() %d\n", GetLastError());
  515. ImageOk = FALSE; goto NextImage;
  516. }
  517. //
  518. // Check to determine if this is an NT image (PE format) or
  519. // a DOS image, Win-16 image, or OS/2 image. If the image is
  520. // not NT format, return an error indicating which image it
  521. // appears to be.
  522. //
  523. if (DosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
  524. if (ArgFlag & ArgFlag_CKMZ) {
  525. LogPrintf("MZ header not found\n");
  526. ImageOk = FALSE;
  527. }
  528. goto NeImage;
  529. }
  530. if (((ULONG)DosHeader->e_lfanew & 3) != 0) {
  531. //
  532. // The image header is not aligned on a long boundary.
  533. // Report this as an invalid protect mode image.
  534. //
  535. LogPrintf("Image header not on Long boundary\n");
  536. ImageOk = FALSE;
  537. goto NeImage;
  538. }
  539. if ((ULONG)DosHeader->e_lfanew > FileInfo.nFileSizeLow) {
  540. LogPrintf("Image size bigger than size of file\n");
  541. ImageOk = FALSE;
  542. goto NeImage;
  543. }
  544. NtHeader = (PIMAGE_NT_HEADERS)((PCHAR)DosHeader + (ULONG)DosHeader->e_lfanew);
  545. if (NtHeader->Signature != IMAGE_NT_SIGNATURE) { //if not PE image
  546. LogPrintf("Non 32-bit image");
  547. ImageOk = TRUE;
  548. goto NeImage;
  549. }
  550. //
  551. // Check to see if this is an NT image or a DOS or OS/2 image.
  552. //
  553. Status = MiVerifyImageHeader (NtHeader, DosHeader, 50000);
  554. if (Status != STATUS_SUCCESS) {
  555. ImageOk = FALSE; //continue checking the image but don't print "OK"
  556. }
  557. //
  558. // Verify machine type.
  559. //
  560. fHasPdata = TRUE; // Most do
  561. switch (NtHeader->FileHeader.Machine) {
  562. case IMAGE_FILE_MACHINE_I386:
  563. MachineType = "x86";
  564. PageSize = 4096;
  565. PageShift = 12;
  566. fHasPdata = FALSE;
  567. break;
  568. case IMAGE_FILE_MACHINE_ALPHA:
  569. MachineType = "Alpha";
  570. PageSize = 8192;
  571. PageShift = 13;
  572. break;
  573. case IMAGE_FILE_MACHINE_IA64:
  574. MachineType = "Intel64";
  575. PageSize = 8192;
  576. PageShift = 13;
  577. break;
  578. case IMAGE_FILE_MACHINE_ALPHA64:
  579. MachineType = "Alpha64";
  580. PageSize = 8192;
  581. PageShift = 13;
  582. break;
  583. default:
  584. LogPrintf("Unrecognized machine type x%lx\n",
  585. NtHeader->FileHeader.Machine);
  586. ImageOk = FALSE;
  587. break;
  588. }
  589. if ((NtHeader->FileHeader.Machine < ValidMachineIDMin) ||
  590. (NtHeader->FileHeader.Machine > ValidMachineIDMax)) {
  591. MachineTypeMismatch = TRUE;
  592. } else {
  593. MachineTypeMismatch = FALSE;
  594. }
  595. ImageAlignment = NtHeader->OptionalHeader.SectionAlignment;
  596. NumberOfPtes = BYTES_TO_PAGES (NtHeader->OptionalHeader.SizeOfImage);
  597. NextVa = NtHeader->OptionalHeader.ImageBase;
  598. if ((NextVa & (X64K - 1)) != 0) {
  599. //
  600. // Image header is not aligned on a 64k boundary.
  601. //
  602. LogPrintf("image base not on 64k boundary %lx\n",NextVa);
  603. ImageOk = FALSE;
  604. goto BadPeImageSegment;
  605. }
  606. //BasedAddress = (PVOID)NextVa;
  607. PtesInSubsection = MI_ROUND_TO_SIZE (
  608. NtHeader->OptionalHeader.SizeOfHeaders,
  609. ImageAlignment
  610. ) >> PageShift;
  611. if (ImageAlignment >= PageSize) {
  612. //
  613. // Aligmment is PageSize of greater.
  614. //
  615. if (PtesInSubsection > NumberOfPtes) {
  616. //
  617. // Inconsistent image, size does not agree with header.
  618. //
  619. LogPrintf("Image size in header (%ld.) not consistent with sections (%ld.)\n",
  620. NumberOfPtes, PtesInSubsection);
  621. ImageOk = FALSE;
  622. goto BadPeImageSegment;
  623. }
  624. NumberOfPtes -= PtesInSubsection;
  625. EndingSector = NtHeader->OptionalHeader.SizeOfHeaders >> MMSECTOR_SHIFT;
  626. for (i = 0; i < PtesInSubsection; i++) {
  627. NextVa += PageSize;
  628. }
  629. }
  630. //
  631. // Build the next subsections.
  632. //
  633. NumberOfSubsections = NtHeader->FileHeader.NumberOfSections;
  634. PreferredImageBase = NtHeader->OptionalHeader.ImageBase;
  635. //
  636. // At this point the object table is read in (if it was not
  637. // already read in) and may displace the image header.
  638. //
  639. OffsetToSectionTable = sizeof(ULONG) +
  640. sizeof(IMAGE_FILE_HEADER) +
  641. NtHeader->FileHeader.SizeOfOptionalHeader;
  642. SectionTableEntry = (PIMAGE_SECTION_HEADER)((PCHAR)NtHeader + OffsetToSectionTable);
  643. if (ImageAlignment < PageSize) {
  644. // The image header is no longer valid, TempPte is
  645. // used to indicate that this image alignment is
  646. // less than a PageSize.
  647. //
  648. // Loop through all sections and make sure there is no
  649. // unitialized data.
  650. //
  651. while (NumberOfSubsections > 0) {
  652. if (SectionTableEntry->Misc.VirtualSize == 0) {
  653. SectionVirtualSize = SectionTableEntry->SizeOfRawData;
  654. } else {
  655. SectionVirtualSize = SectionTableEntry->Misc.VirtualSize;
  656. }
  657. //
  658. // If the pointer to raw data is zero and the virtual size
  659. // is zero, OR, the section goes past the end of file, OR
  660. // the virtual size does not match the size of raw data, then
  661. // return an error.
  662. //
  663. if (((SectionTableEntry->PointerToRawData !=
  664. SectionTableEntry->VirtualAddress))
  665. ||
  666. ((SectionTableEntry->SizeOfRawData +
  667. SectionTableEntry->PointerToRawData) >
  668. FileInfo.nFileSizeLow)
  669. ||
  670. (SectionVirtualSize > SectionTableEntry->SizeOfRawData)) {
  671. LogPrintf("invalid BSS/Trailingzero section/file size\n");
  672. ImageOk = FALSE;
  673. goto NeImage;
  674. }
  675. SectionTableEntry += 1;
  676. NumberOfSubsections -= 1;
  677. }
  678. goto PeReturnSuccess;
  679. }
  680. while (NumberOfSubsections > 0) {
  681. //
  682. // Handle case where virtual size is 0.
  683. //
  684. if (SectionTableEntry->Misc.VirtualSize == 0) {
  685. SectionVirtualSize = SectionTableEntry->SizeOfRawData;
  686. } else {
  687. SectionVirtualSize = SectionTableEntry->Misc.VirtualSize;
  688. }
  689. if (!strcmp(SectionTableEntry->Name, ".debug")) {
  690. fDebugMapped = TRUE;
  691. }
  692. if (SectionVirtualSize == 0) {
  693. //
  694. // The specified virtual address does not align
  695. // with the next prototype PTE.
  696. //
  697. LogPrintf("Section virtual size is 0, NextVa for section %lx %lx\n",
  698. SectionTableEntry->VirtualAddress, NextVa);
  699. ImageOk = FALSE;
  700. goto BadPeImageSegment;
  701. }
  702. if (NextVa !=
  703. (PreferredImageBase + SectionTableEntry->VirtualAddress)) {
  704. //
  705. // The specified virtual address does not align
  706. // with the next prototype PTE.
  707. //
  708. LogPrintf("Section Va not set to alignment, NextVa for section %lx %lx\n",
  709. SectionTableEntry->VirtualAddress, NextVa);
  710. ImageOk = FALSE;
  711. goto BadPeImageSegment;
  712. }
  713. PtesInSubsection =
  714. MI_ROUND_TO_SIZE (SectionVirtualSize, ImageAlignment) >> PageShift;
  715. if (PtesInSubsection > NumberOfPtes) {
  716. //
  717. // Inconsistent image, size does not agree with object tables.
  718. //
  719. LogPrintf("Image size in header not consistent with sections, needs %ld. pages\n",
  720. PtesInSubsection - NumberOfPtes);
  721. LogPrintf("va of bad section %lx\n",SectionTableEntry->VirtualAddress);
  722. ImageOk = FALSE;
  723. goto BadPeImageSegment;
  724. }
  725. NumberOfPtes -= PtesInSubsection;
  726. StartingSector = SectionTableEntry->PointerToRawData >> MMSECTOR_SHIFT;
  727. EndingSector =
  728. (SectionTableEntry->PointerToRawData +
  729. SectionVirtualSize);
  730. EndingSector = EndingSector >> MMSECTOR_SHIFT;
  731. ImageFileSize = SectionTableEntry->PointerToRawData +
  732. SectionTableEntry->SizeOfRawData;
  733. for (i = 0; i < PtesInSubsection; i++) {
  734. //
  735. // Set all the prototype PTEs to refer to the control section.
  736. //
  737. NextVa += PageSize;
  738. }
  739. SectionTableEntry += 1;
  740. NumberOfSubsections -= 1;
  741. }
  742. //
  743. // If the file size is not as big as the image claimed to be,
  744. // return an error.
  745. //
  746. if (ImageFileSize > FileInfo.nFileSizeLow) {
  747. //
  748. // Invalid image size.
  749. //
  750. LogPrintf("invalid image size - file size %lx - image size %lx\n",
  751. FileInfo.nFileSizeLow, ImageFileSize);
  752. ImageOk = FALSE;
  753. goto BadPeImageSegment;
  754. }
  755. {
  756. // Validate the debug information (as much as we can).
  757. PVOID ImageBase;
  758. ULONG DebugDirectorySize, NumberOfDebugDirectories;
  759. PIMAGE_DEBUG_DIRECTORY DebugDirectory;
  760. ImageBase = (PVOID) DosHeader;
  761. DebugDirectory = (PIMAGE_DEBUG_DIRECTORY)
  762. ImageDirectoryEntryToData(
  763. ImageBase,
  764. FALSE,
  765. IMAGE_DIRECTORY_ENTRY_DEBUG,
  766. &DebugDirectorySize );
  767. if (!DebugDirectoryIsUseful(DebugDirectory, DebugDirectorySize)) {
  768. // Not useful. Are they valid? (both s/b zero)
  769. if (DebugDirectory || DebugDirectorySize) {
  770. LogPrintf("Debug directory values [%x, %x] are invalid\n",
  771. DebugDirectory,
  772. DebugDirectorySize);
  773. ImageOk = FALSE;
  774. }
  775. goto DebugDirsDone;
  776. }
  777. NumberOfDebugDirectories = DebugDirectorySize / sizeof( IMAGE_DEBUG_DIRECTORY );
  778. for (i=0; i < NumberOfDebugDirectories; i++) {
  779. if (DebugDirectory->PointerToRawData > FileInfo.nFileSizeLow) {
  780. LogPrintf("Invalid debug directory entry[%d] - File Offset %x is beyond the end of the file\n",
  781. i,
  782. DebugDirectory->PointerToRawData
  783. );
  784. ImageOk = FALSE;
  785. goto BadPeImageSegment;
  786. }
  787. if ((DebugDirectory->PointerToRawData + DebugDirectory->SizeOfData) > FileInfo.nFileSizeLow) {
  788. LogPrintf("Invalid debug directory entry[%d] - File Offset (%X) + Size (%X) is beyond the end of the file (filesize: %X)\n",
  789. i,
  790. DebugDirectory->PointerToRawData,
  791. DebugDirectory->SizeOfData,
  792. FileInfo.nFileSizeLow
  793. );
  794. ImageOk = FALSE;
  795. goto BadPeImageSegment;
  796. }
  797. #if 0
  798. if (DebugDirectory->AddressOfRawData != 0) {
  799. if (DebugDirectory->AddressOfRawData > ImageFileSize){
  800. LogPrintf("Invalid debug directory entry[%d] - VA (%X) is beyond the end of the image VA (%X)\n",
  801. i,
  802. DebugDirectory->AddressOfRawData,
  803. ImageFileSize);
  804. ImageOk = FALSE;
  805. goto BadPeImageSegment;
  806. }
  807. if ((DebugDirectory->AddressOfRawData + DebugDirectory->SizeOfData )> ImageFileSize){
  808. LogPrintf("Invalid debug directory entry[%d] - VA (%X) + size (%X) is beyond the end of the image VA (%X)\n",
  809. i,
  810. DebugDirectory->AddressOfRawData,
  811. DebugDirectory->SizeOfData,
  812. ImageFileSize);
  813. ImageOk = FALSE;
  814. goto BadPeImageSegment;
  815. }
  816. }
  817. #endif
  818. if (DebugDirectory->Type <= 0x7fffffff) {
  819. switch (DebugDirectory->Type) {
  820. case IMAGE_DEBUG_TYPE_MISC:
  821. {
  822. PIMAGE_DEBUG_MISC pDebugMisc;
  823. // MISC should point to an IMAGE_DEBUG_MISC structure
  824. pDebugMisc = (PIMAGE_DEBUG_MISC)((PCHAR)ImageBase + DebugDirectory->PointerToRawData);
  825. if (pDebugMisc->DataType != IMAGE_DEBUG_MISC_EXENAME) {
  826. LogPrintf("MISC Debug has an invalid DataType\n");
  827. ImageOk = FALSE;
  828. goto BadPeImageSegment;
  829. }
  830. if (pDebugMisc->Length != DebugDirectory->SizeOfData) {
  831. LogPrintf("MISC Debug has an invalid size.\n");
  832. ImageOk = FALSE;
  833. goto BadPeImageSegment;
  834. }
  835. if (!pDebugMisc->Unicode) {
  836. i= 0;
  837. while (i < pDebugMisc->Length - sizeof(IMAGE_DEBUG_MISC)) {
  838. if (!isprint(pDebugMisc->Data[i]) &&
  839. (pDebugMisc->Data[i] != '\0') )
  840. {
  841. LogPrintf("MISC Debug has unprintable characters... Possibly corrupt\n");
  842. ImageOk = FALSE;
  843. goto BadPeImageSegment;
  844. }
  845. i++;
  846. }
  847. // The data must be a null terminated string.
  848. if (strlen(pDebugMisc->Data) > (pDebugMisc->Length - sizeof(IMAGE_DEBUG_MISC))) {
  849. LogPrintf("MISC Debug has invalid data... Possibly corrupt\n");
  850. ImageOk = FALSE;
  851. goto BadPeImageSegment;
  852. }
  853. }
  854. }
  855. break;
  856. case IMAGE_DEBUG_TYPE_CODEVIEW:
  857. // CV will point to either a NB09 or an NB10 signature. Make sure it does.
  858. {
  859. OMFSignature * CVDebug;
  860. CVDebug = (OMFSignature *)((PCHAR)ImageBase + DebugDirectory->PointerToRawData);
  861. if (((*(PULONG)(CVDebug->Signature)) != '90BN') &&
  862. ((*(PULONG)(CVDebug->Signature)) != '01BN') &&
  863. ((*(PULONG)(CVDebug->Signature)) != 'SDSR'))
  864. {
  865. LogPrintf("CV Debug has an invalid signature\n");
  866. ImageOk = FALSE;
  867. goto BadPeImageSegment;
  868. }
  869. }
  870. break;
  871. case IMAGE_DEBUG_TYPE_COFF:
  872. case IMAGE_DEBUG_TYPE_FPO:
  873. case IMAGE_DEBUG_TYPE_EXCEPTION:
  874. case IMAGE_DEBUG_TYPE_FIXUP:
  875. case IMAGE_DEBUG_TYPE_OMAP_TO_SRC:
  876. case IMAGE_DEBUG_TYPE_OMAP_FROM_SRC:
  877. // Not much we can do about these now.
  878. break;
  879. default:
  880. LogPrintf("Invalid debug directory type: %d\n", DebugDirectory->Type);
  881. ImageOk = FALSE;
  882. goto BadPeImageSegment;
  883. break;
  884. }
  885. }
  886. }
  887. }
  888. DebugDirsDone:
  889. //
  890. // The total number of PTEs was decremented as sections were built,
  891. // make sure that there are less than 64ks worth at this point.
  892. //
  893. if (NumberOfPtes >= (ImageAlignment >> PageShift)) {
  894. //
  895. // Inconsistent image, size does not agree with object tables.
  896. //
  897. LogPrintf("invalid image - PTEs left %lx\n",
  898. NumberOfPtes);
  899. ImageOk = FALSE;
  900. goto BadPeImageSegment;
  901. }
  902. // Verify LoadConfig data (if available)
  903. {
  904. PIMAGE_LOAD_CONFIG_DIRECTORY LoadConfigDirectory;
  905. ULONG LoadConfigDirectorySize;
  906. LoadConfigDirectory = (PIMAGE_LOAD_CONFIG_DIRECTORY)
  907. ImageDirectoryEntryToData(
  908. (PVOID) DosHeader,
  909. FALSE,
  910. IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
  911. &LoadConfigDirectorySize );
  912. if (LoadConfigDirectory) {
  913. if (!LoadConfigDirectorySize) {
  914. // LOAD_CONFIG directory size in the image header is not set (s/b 0x40 on X86)
  915. LogPrintf("LoadConfig pointer set, but size is not\n");
  916. ImageOk = FALSE;
  917. goto BadPeImageSegment;
  918. }
  919. if (LoadConfigDirectory->Size) {
  920. // Version 2 load config - check the SEH fields.
  921. if (LoadConfigDirectory->Size == RTL_SIZEOF_THROUGH_FIELD(IMAGE_LOAD_CONFIG_DIRECTORY, SEHandlerTable)) {
  922. // SEH Handler table is on, but count isn't. Bad.
  923. LogPrintf("LoadConfig pointer set, but size is not\n");
  924. ImageOk = FALSE;
  925. goto BadPeImageSegment;
  926. }
  927. if (LoadConfigDirectory->Size >= RTL_SIZEOF_THROUGH_FIELD(IMAGE_LOAD_CONFIG_DIRECTORY, SEHandlerCount)) {
  928. // Have both a count and table - check them
  929. if (LoadConfigDirectory->SEHandlerTable) {
  930. // Table exists.
  931. if (!LoadConfigDirectory->SEHandlerCount) {
  932. LogPrintf("Loadconfig structure invalid - SEH table pointer exists, but count is zero\n");
  933. ImageOk = FALSE;
  934. goto BadPeImageSegment;
  935. }
  936. if (LoadConfigDirectory->SEHandlerTable < NtHeader->OptionalHeader.ImageBase ||
  937. (LoadConfigDirectory->SEHandlerTable > (NtHeader->OptionalHeader.ImageBase + NtHeader->OptionalHeader.SizeOfImage))){
  938. // SEH handler table isn't within the image bounds
  939. LogPrintf("Loadconfig structure invalid - SEH table pointer exists, but count is zero\n");
  940. ImageOk = FALSE;
  941. goto BadPeImageSegment;
  942. }
  943. if (NtHeader->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NO_SEH) {
  944. LogPrintf("Image is marked as NO_SEH, yet SEH pointer is non-null\n");
  945. ImageOk = FALSE;
  946. goto BadPeImageSegment;
  947. }
  948. }
  949. if (LoadConfigDirectory->SEHandlerCount) {
  950. // Count is non-zero
  951. if (!LoadConfigDirectory->SEHandlerTable) {
  952. LogPrintf("Loadconfig structure invalid - SEH count is non-zero but table pointer is null\n");
  953. ImageOk = FALSE;
  954. goto BadPeImageSegment;
  955. }
  956. if (NtHeader->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NO_SEH) {
  957. LogPrintf("Image is marked as NO_SEH, yet SEH count is non-zero\n");
  958. ImageOk = FALSE;
  959. goto BadPeImageSegment;
  960. }
  961. }
  962. }
  963. }
  964. }
  965. }
  966. //
  967. // check checksum.
  968. //
  969. PeReturnSuccess:
  970. if (NtHeader->OptionalHeader.CheckSum == 0) {
  971. LogPrintf("(checksum is zero)\n");
  972. } else {
  973. __try {
  974. if (lpOldLdrVerifyImageMatchesChecksum == NULL) {
  975. if (lpNewLdrVerifyImageMatchesChecksum == NULL) {
  976. Status = STATUS_SUCCESS;
  977. LogPrintf("Unable to validate checksum\n");
  978. } else {
  979. Status = (*lpNewLdrVerifyImageMatchesChecksum)(File, NULL, NULL, NULL);
  980. }
  981. } else {
  982. Status = (*lpOldLdrVerifyImageMatchesChecksum)(File);
  983. }
  984. if (NT_ERROR(Status)) {
  985. DWORD HeaderSum, CheckSum;
  986. MapFileAndCheckSum(ImageName, &HeaderSum, &CheckSum);
  987. LogPrintf("checksum mismatch\tis: %x\ts/b: %x\n", NtHeader->OptionalHeader.CheckSum, CheckSum);
  988. ImageOk = FALSE;
  989. }
  990. } __except (EXCEPTION_EXECUTE_HANDLER) {
  991. ImageOk = FALSE;
  992. LogPrintf("checksum mismatch\n");
  993. LogPrintf("LdrVerifyImageMatchesCheckSum AV'd\n");
  994. }
  995. }
  996. if (fHasPdata && ImageOk) {
  997. ImageOk = ValidatePdata(DosHeader);
  998. }
  999. if (ImageOk) {
  1000. ImageOk = VerifyVersionResource(ImageName, ImageNeedsOleSelfRegister(DosHeader));
  1001. }
  1002. //
  1003. // sanity test for symbols
  1004. // basically : if this does not work, debugging probably will not either
  1005. // these high-level debugging api's will also call a pdb validation routine
  1006. //
  1007. if(ArgFlag & ArgFlag_SymCK)
  1008. {
  1009. HANDLE hProcess = 0;
  1010. char Target[MAX_PATH] = {0};
  1011. char drive[_MAX_DRIVE];
  1012. char dir[_MAX_DIR];
  1013. char fname[_MAX_FNAME];
  1014. char ext[_MAX_EXT];
  1015. IMAGEHLP_MODULE64 ModuleInfo = {0};
  1016. PSYMMODLIST ModList = 0;
  1017. void *vpAddr;
  1018. PLOADED_IMAGE pLImage = NULL;
  1019. DWORD64 symLMflag;
  1020. strcpy(Target, szDirectory);
  1021. strcat(Target, "\\");
  1022. strcat(Target, ImageName);
  1023. //
  1024. // set up for debugging
  1025. //
  1026. hProcess = GetCurrentProcess();
  1027. if(!SymInitialize(hProcess, szSympath, FALSE))
  1028. {
  1029. LogPrintf("ERROR:SymInitialize failed!\n");
  1030. hProcess = 0;
  1031. goto symckend;
  1032. }
  1033. //
  1034. // attempt to use symbols
  1035. //
  1036. _splitpath(Target, drive, dir, fname, ext );
  1037. symLMflag = SymLoadModule64(hProcess, NULL, Target, fname, 0, 0);
  1038. if(!symLMflag)
  1039. {
  1040. LogPrintf("ERROR:SymLoadModule failed! last error:0x%x\n", GetLastError());
  1041. goto symckend;
  1042. }
  1043. //
  1044. // identify module type
  1045. // find module, symgetmoduleinfo, check dbg type
  1046. //
  1047. ModuleInfo.SizeOfStruct = sizeof(ModuleInfo);
  1048. ModList = MakeModList(hProcess);
  1049. vpAddr = GetModAddrFromName(ModList, fname);
  1050. if(!SymGetModuleInfo64(hProcess, (DWORD64)vpAddr, &ModuleInfo))
  1051. {
  1052. LogPrintf("ERROR:SymGetModuleInfo failed! last error:0x%x\n", GetLastError());
  1053. goto symckend;
  1054. }
  1055. if(ModuleInfo.SymType != SymPdb)
  1056. {
  1057. LogPrintf("WARNING: No pdb info for file!\n");
  1058. switch(ModuleInfo.SymType){
  1059. case SymNone:
  1060. LogPrintf("symtype: SymNone\n");
  1061. break;
  1062. case SymCoff:
  1063. LogPrintf("symtype: SymCoff\n");
  1064. break;
  1065. case SymCv:
  1066. LogPrintf("symtype: SymCv\n");
  1067. break;
  1068. case SymPdb:
  1069. LogPrintf("symtype: SymPdb\n");
  1070. break;
  1071. case SymExport:
  1072. LogPrintf("symtype: SymExport\n");
  1073. break;
  1074. case SymDeferred:
  1075. LogPrintf("symtype: SymDeferred\n");
  1076. break;
  1077. case SymSym:
  1078. LogPrintf("symtype: SymSym\n");
  1079. break;
  1080. }
  1081. }
  1082. //
  1083. // get image, symbol checksum, compare
  1084. //
  1085. pLImage = ImageLoad(Target, NULL);
  1086. {
  1087. CHAR szDbgPath[_MAX_PATH];
  1088. HANDLE DbgFileHandle;
  1089. DbgFileHandle = FindDebugInfoFile(Target, szSympath, szDbgPath);
  1090. if (DbgFileHandle != INVALID_HANDLE_VALUE) {
  1091. IMAGE_SEPARATE_DEBUG_HEADER DbgHeader;
  1092. DWORD BytesRead;
  1093. BOOL ReadSuccess;
  1094. SetFilePointer(DbgFileHandle, 0, 0, FILE_BEGIN);
  1095. ReadSuccess = ReadFile(DbgFileHandle, &DbgHeader, sizeof(DbgHeader), &BytesRead, NULL);
  1096. if (ReadSuccess && (BytesRead == sizeof(DbgHeader))) {
  1097. // Got enough to check if it's a valid dbg file.
  1098. if(((PIMAGE_NT_HEADERS)pLImage->FileHeader)->OptionalHeader.CheckSum != DbgHeader.CheckSum) {
  1099. LogPrintf("ERROR! image / debug file checksum not equal\n");
  1100. ImageOk = FALSE;
  1101. }
  1102. }
  1103. CloseHandle(DbgFileHandle);
  1104. }
  1105. }
  1106. //
  1107. // cleanup
  1108. //
  1109. symckend:
  1110. if(ModList)
  1111. {
  1112. FreeModList(ModList);
  1113. }
  1114. if(pLImage)
  1115. {
  1116. ImageUnload(pLImage);
  1117. }
  1118. if(symLMflag)
  1119. {
  1120. SymUnloadModule64(hProcess, (DWORD)symLMflag);
  1121. }
  1122. if(hProcess)
  1123. {
  1124. SymCleanup(hProcess);
  1125. }
  1126. }
  1127. NextImage:
  1128. BadPeImageSegment:
  1129. NeImage:
  1130. if ( ImageOk && (ArgFlag & ArgFlag_OK)) {
  1131. if (MachineTypeMismatch) {
  1132. LogPrintf(" OK [%s]\n", MachineType);
  1133. } else {
  1134. LogPrintf(" OK\n");
  1135. }
  1136. }
  1137. //
  1138. // print out results
  1139. //
  1140. if (ImageOk)
  1141. {
  1142. LogOutAndClean((ArgFlag & ArgFlag_OK) ? TRUE : FALSE);
  1143. } else {
  1144. LogOutAndClean(TRUE);
  1145. }
  1146. if ( File != INVALID_HANDLE_VALUE ) {
  1147. CloseHandle(File);
  1148. }
  1149. if ( DosHeader ) {
  1150. UnmapViewOfFile(DosHeader);
  1151. }
  1152. }
  1153. NTSTATUS
  1154. MiVerifyImageHeader (
  1155. IN PIMAGE_NT_HEADERS NtHeader,
  1156. IN PIMAGE_DOS_HEADER DosHeader,
  1157. IN ULONG NtHeaderSize
  1158. )
  1159. /*++
  1160. Routine Description:
  1161. Checks image header for consistency.
  1162. Arguments:
  1163. IN PIMAGE_NT_HEADERS NtHeader
  1164. IN PIMAGE_DOS_HEADER DosHeader
  1165. IN ULONG NtHeaderSize
  1166. Return Value:
  1167. Returns the status value.
  1168. TBS
  1169. --*/
  1170. {
  1171. if ((NtHeader->FileHeader.Machine == 0) &&
  1172. (NtHeader->FileHeader.SizeOfOptionalHeader == 0)) {
  1173. //
  1174. // This is a bogus DOS app which has a 32-bit portion
  1175. // mascarading as a PE image.
  1176. //
  1177. LogPrintf("Image machine type and size of optional header bad\n");
  1178. return STATUS_INVALID_IMAGE_PROTECT;
  1179. }
  1180. if (!(NtHeader->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE)) {
  1181. LogPrintf("Characteristics not image file executable\n");
  1182. return STATUS_INVALID_IMAGE_FORMAT;
  1183. }
  1184. #ifdef i386
  1185. //
  1186. // Make sure the image header is aligned on a Long word boundary.
  1187. //
  1188. if (((ULONG)NtHeader & 3) != 0) {
  1189. LogPrintf("NtHeader is not aligned on longword boundary\n");
  1190. return STATUS_INVALID_IMAGE_FORMAT;
  1191. }
  1192. #endif
  1193. // Non-driver code must have file alignment set to a multiple of 512
  1194. if (((NtHeader->OptionalHeader.FileAlignment & 511) != 0) &&
  1195. (NtHeader->OptionalHeader.FileAlignment !=
  1196. NtHeader->OptionalHeader.SectionAlignment)) {
  1197. LogPrintf("file alignment is not multiple of 512 and power of 2\n");
  1198. return STATUS_INVALID_IMAGE_FORMAT;
  1199. }
  1200. //
  1201. // File aligment must be power of 2.
  1202. //
  1203. if ((((NtHeader->OptionalHeader.FileAlignment << 1) - 1) &
  1204. NtHeader->OptionalHeader.FileAlignment) !=
  1205. NtHeader->OptionalHeader.FileAlignment) {
  1206. LogPrintf("file alignment not power of 2\n");
  1207. return STATUS_INVALID_IMAGE_FORMAT;
  1208. }
  1209. if (NtHeader->OptionalHeader.SectionAlignment < NtHeader->OptionalHeader.FileAlignment) {
  1210. LogPrintf("SectionAlignment < FileAlignment\n");
  1211. return STATUS_INVALID_IMAGE_FORMAT;
  1212. }
  1213. if (NtHeader->OptionalHeader.SizeOfImage > MM_SIZE_OF_LARGEST_IMAGE) {
  1214. LogPrintf("Image too big %lx\n",NtHeader->OptionalHeader.SizeOfImage);
  1215. return STATUS_INVALID_IMAGE_FORMAT;
  1216. }
  1217. if (NtHeader->FileHeader.NumberOfSections > MM_MAXIMUM_IMAGE_SECTIONS) {
  1218. LogPrintf("Too many image sections %ld.\n",
  1219. NtHeader->FileHeader.NumberOfSections);
  1220. return STATUS_INVALID_IMAGE_FORMAT;
  1221. }
  1222. if (ArgFlag & ArgFlag_CKBase) {
  1223. if ((PVOID)NtHeader->OptionalHeader.ImageBase >= HighestUserAddress) {
  1224. LogPrintf("Image base (%lx) is invalid on this machine\n",
  1225. NtHeader->OptionalHeader.ImageBase);
  1226. return STATUS_SUCCESS;
  1227. }
  1228. }
  1229. return STATUS_SUCCESS;
  1230. }
  1231. VOID
  1232. ParseArgs(
  1233. int *pargc,
  1234. char **argv
  1235. )
  1236. /*++
  1237. Routine Description:
  1238. parse arguments to this program
  1239. Arguments:
  1240. int *pargc
  1241. char **argv
  1242. Return Value:
  1243. none
  1244. Notes:
  1245. command line args:
  1246. (original)
  1247. case '?': call usage and exit
  1248. case 'b': check whether base address of image is in user space for this machine
  1249. case 's': /s <sympath> check symbols
  1250. case 'p': PE Errors only
  1251. case 'r': recurse subdirectories
  1252. (new)
  1253. case 'v': verbose - output "OK"
  1254. case 'o': output "OleSelfRegister not set"
  1255. --*/
  1256. {
  1257. CHAR cswitch, c, *p;
  1258. CHAR sztmp[MAX_PATH];
  1259. int argnum = 1, i=0, len=0, count=0;
  1260. BOOL fslashfound = FALSE;
  1261. //
  1262. // set default flags here
  1263. //
  1264. ArgFlag |= ArgFlag_CKBase;
  1265. while ( argnum < *pargc ) {
  1266. _strlwr(argv[argnum]);
  1267. cswitch = *(argv[argnum]);
  1268. if (cswitch == '/' || cswitch == '-') {
  1269. c = *(argv[argnum]+1);
  1270. switch (c) {
  1271. case 'o':
  1272. ArgFlag |= ArgFlag_OLESelf;
  1273. break;
  1274. case 'v':
  1275. ArgFlag |= ArgFlag_OK | ArgFlag_CKMZ | ArgFlag_OLESelf;
  1276. break;
  1277. case '?':
  1278. Usage();
  1279. break;
  1280. case 'b':
  1281. ArgFlag ^= ArgFlag_CKBase;
  1282. break;
  1283. case 's':
  1284. if (argv[argnum+1]) {
  1285. strcpy(szSympath, (argv[argnum+1]));
  1286. ArgFlag |= ArgFlag_SymCK;
  1287. argnum++;
  1288. }
  1289. break;
  1290. case 'p':
  1291. ArgFlag |= ArgFlag_CKMZ;
  1292. break;
  1293. case 'r':
  1294. fRecurse = TRUE;
  1295. if (argv[argnum+1]) {
  1296. fPathOverride=TRUE;
  1297. strcpy(szDirectory, (argv[argnum+1]));
  1298. if (!(strcmp(szDirectory, "\\"))) { // if just '\'
  1299. fSingleSlash=TRUE;
  1300. }
  1301. //LogPrintf("dir %s\n", szDirectory);
  1302. argnum++;
  1303. }
  1304. break;
  1305. default:
  1306. fprintf(stderr, "Invalid argument.\n");
  1307. Usage();
  1308. }
  1309. } else {
  1310. // Check for path\filename or wildcards
  1311. // Search for '\' in string
  1312. strcpy(sztmp, (argv[argnum]));
  1313. len = strlen(sztmp);
  1314. for (i=0; i < len; i++) {
  1315. if (sztmp[i]=='\\') {
  1316. count++;
  1317. endpath=i; // mark last '\' char found
  1318. fslashfound=TRUE; // found backslash, so must be a path\filename combination
  1319. }
  1320. }
  1321. if (fslashfound && !fRecurse) { // if backslash found and not a recursive operation
  1322. // seperate the directory and filename into two strings
  1323. fPathOverride=TRUE;
  1324. strcpy(szDirectory, sztmp);
  1325. if (!(strcmp(szDirectory, "\\"))) {
  1326. Usage();
  1327. }
  1328. szFileName = _strdup(&(sztmp[endpath+1]));
  1329. if (count == 1) { //&& szDirectory[1] == ':') { // if only one '\' char and drive letter indicated
  1330. fSingleSlash=TRUE;
  1331. szDirectory[endpath+1]='\0'; // keep trailing '\' in order to chdir properly
  1332. } else {
  1333. szDirectory[endpath]='\0';
  1334. }
  1335. if (szFileName[0] == '*' && szFileName[1] == '.' && szFileName[2] != '*') {
  1336. _strlwr(szFileName);
  1337. szPattern = strchr(szFileName, '.'); //search for '.'
  1338. fPattern = TRUE;
  1339. }
  1340. } else { // no backslash found, assume filename without preceeding path
  1341. szFileName = _strdup(argv[argnum]);
  1342. if (!szFileName) {
  1343. // drastic error, just bail
  1344. szFileName = "";
  1345. return;
  1346. }
  1347. //
  1348. // filename or wildcard
  1349. //
  1350. if ( (*(argv[argnum]) == '*') && (*(argv[argnum]+1) == '.') && (*(argv[argnum]+2) != '*') ){
  1351. // *.xxx
  1352. _strlwr(szFileName);
  1353. szPattern = strchr(szFileName, '.'); //search for '.'
  1354. fPattern = TRUE;
  1355. } else if ( (*(argv[argnum]) == '*') && (*(argv[argnum]+1) == '.') && (*(argv[argnum]+2) == '*') ) {
  1356. // *.*
  1357. } else {
  1358. // probably a single filename
  1359. _strlwr(szFileName);
  1360. fSingleFile = TRUE;
  1361. }
  1362. if (fRecurse && strchr(szFileName, '\\') ) { // don't want path\filename when recursing
  1363. Usage();
  1364. }
  1365. }
  1366. //fprintf(stdout, "dir %s\nfile %s\n", szDirectory, szFileName);
  1367. }
  1368. ++argnum;
  1369. }
  1370. if (szFileName[0] == '\0') {
  1371. Usage();
  1372. }
  1373. } // parseargs
  1374. int
  1375. __cdecl
  1376. CompFileAndDir(
  1377. const void *elem1,
  1378. const void *elem2
  1379. )
  1380. /*++
  1381. Routine Description:
  1382. Purpose: a comparision routine passed to QSort. It compares elem1 and elem2
  1383. based upon their attribute, i.e., is it a file or directory.
  1384. Arguments:
  1385. const void *elem1,
  1386. const void *elem2
  1387. Return Value:
  1388. result of comparison function
  1389. Notes:
  1390. --*/
  1391. {
  1392. pList p1, p2;
  1393. // qsort passes a void universal pointer. Use a typecast (List**)
  1394. // so the compiler recognizes the data as a List structure.
  1395. // Typecast pointer-to-pointer-to-List and dereference ONCE
  1396. // leaving a pList. I don't dereference the remaining pointer
  1397. // in the p1 and p2 definitions to avoid copying the structure.
  1398. p1 = (*(List**)elem1);
  1399. p2 = (*(List**)elem2);
  1400. if ( (p1->Attributes & FILE_ATTRIBUTE_DIRECTORY) && (p2->Attributes & FILE_ATTRIBUTE_DIRECTORY))
  1401. return 0;
  1402. //both dirs
  1403. if (!(p1->Attributes & FILE_ATTRIBUTE_DIRECTORY) && !(p2->Attributes & FILE_ATTRIBUTE_DIRECTORY))
  1404. return 0;
  1405. //both files
  1406. if ( (p1->Attributes & FILE_ATTRIBUTE_DIRECTORY) && !(p2->Attributes & FILE_ATTRIBUTE_DIRECTORY))
  1407. return 1;
  1408. // elem1 is dir and elem2 is file
  1409. if (!(p1->Attributes & FILE_ATTRIBUTE_DIRECTORY) && (p2->Attributes & FILE_ATTRIBUTE_DIRECTORY))
  1410. return -1;
  1411. // elem1 is file and elem2 is dir
  1412. return 0; // if none of the above
  1413. }
  1414. int
  1415. __cdecl
  1416. CompName(
  1417. const void *elem1,
  1418. const void *elem2
  1419. )
  1420. /*++
  1421. Routine Description:
  1422. another compare routine passed to QSort that compares the two Name strings
  1423. Arguments:
  1424. const void *elem1,
  1425. const void *elem2
  1426. Return Value:
  1427. result of comparison function
  1428. Notes:
  1429. this uses a noignore-case strcmp
  1430. --*/
  1431. {
  1432. return strcmp( (*(List**)elem1)->Name, (*(List**)elem2)->Name );
  1433. }
  1434. VOID
  1435. Usage(
  1436. VOID
  1437. )
  1438. /*++
  1439. Routine Description:
  1440. Arguments:
  1441. Return Value:
  1442. Notes:
  1443. --*/
  1444. {
  1445. fputs("Usage: imagechk [/?] displays this message\n"
  1446. " [/r dir] recurse from directory dir\n"
  1447. " [/b] don't check image base address\n"
  1448. " [/v] verbose - output everything\n"
  1449. " [/o] output \"OleSelfRegister not set\" warning\n"
  1450. " [/p] output \"MZ header not found\"\n"
  1451. " [/s <sympath>] check pdb symbols\n"
  1452. " [filename] file to check\n"
  1453. " Accepts wildcard extensions such as *.exe\n"
  1454. " imagechk /r . \"*.exe\" check all *.exe recursing on current directory\n"
  1455. " imagechk /r \\ \"*.exe\" check all *.exe recursing from root of current drive\n"
  1456. " imagechk \"*.exe\" check all *.exe in current directory\n"
  1457. " imagechk c:\\bar.exe check c:\\bar.exe only\n",
  1458. stderr);
  1459. exit(1);
  1460. }
  1461. int
  1462. __cdecl
  1463. _cwild()
  1464. /*++
  1465. Routine Description:
  1466. Arguments:
  1467. Return Value:
  1468. Notes:
  1469. --*/
  1470. {
  1471. return(0);
  1472. }
  1473. typedef DWORD (WINAPI *PFNGVS)(LPSTR, LPDWORD);
  1474. typedef BOOL (WINAPI *PFNGVI)(LPTSTR, DWORD, DWORD, LPVOID);
  1475. typedef BOOL (WINAPI *PFNVQV)(const LPVOID, LPTSTR, LPVOID *, PUINT);
  1476. BOOL
  1477. VerifyVersionResource(
  1478. PCHAR FileName,
  1479. BOOL fSelfRegister
  1480. )
  1481. /*++
  1482. Routine Description:
  1483. validate the version resource in a file
  1484. Arguments:
  1485. PCHAR FileName
  1486. BOOL fSelfRegister
  1487. Return Value:
  1488. TRUE if: no version.dll found
  1489. FALSE if: version resource missing
  1490. Notes:
  1491. --*/
  1492. {
  1493. static HINSTANCE hVersion = NULL;
  1494. static PFNGVS pfnGetFileVersionInfoSize = NULL;
  1495. static PFNGVI pfnGetFileVersionInfo = NULL;
  1496. static PFNVQV pfnVerQueryValue = NULL;
  1497. DWORD dwSize;
  1498. DWORD lpInfoSize;
  1499. LPVOID lpData = NULL, lpInfo;
  1500. BOOL rc = FALSE;
  1501. DWORD dwDefLang = 0x00000409;
  1502. DWORD *pdwTranslation, uLen;
  1503. CHAR buf[60];
  1504. CHAR szVersionDll[_MAX_PATH];
  1505. if (GetSystemDirectory(szVersionDll, sizeof(szVersionDll))) {
  1506. strcat(szVersionDll, "\\version.dll");
  1507. } else {
  1508. strcpy(szVersionDll, "version.dll");
  1509. }
  1510. if (!hVersion) {
  1511. hVersion = LoadLibraryA(szVersionDll);
  1512. if (hVersion == NULL) {
  1513. return TRUE;
  1514. }
  1515. pfnGetFileVersionInfoSize = (PFNGVS) GetProcAddress(hVersion, "GetFileVersionInfoSizeA");
  1516. pfnGetFileVersionInfo = (PFNGVI) GetProcAddress(hVersion, "GetFileVersionInfoA");
  1517. pfnVerQueryValue = (PFNVQV) GetProcAddress(hVersion, "VerQueryValueA");
  1518. }
  1519. if (!pfnGetFileVersionInfoSize || !pfnGetFileVersionInfo || !pfnVerQueryValue) {
  1520. rc = TRUE;
  1521. goto cleanup;
  1522. }
  1523. if ((dwSize = (*pfnGetFileVersionInfoSize)(FileName, &dwSize)) == 0){
  1524. LogPrintf("No version resource detected\n");
  1525. goto cleanup;
  1526. }
  1527. if (!fSelfRegister) {
  1528. // All we need to do is see if the version resource exists. Ole Self Register not necessary.
  1529. rc = TRUE;
  1530. goto cleanup;
  1531. }
  1532. if ((lpData = malloc(dwSize)) == NULL) {
  1533. LogPrintf("Out of memory\n");
  1534. goto cleanup;
  1535. }
  1536. if (!(*pfnGetFileVersionInfo)(FileName, 0, dwSize, lpData)) {
  1537. LogPrintf("Unable to read version info\n - %d", GetLastError());
  1538. goto cleanup;
  1539. }
  1540. if(!pfnVerQueryValue(lpData, "\\VarFileInfo\\Translation", &pdwTranslation, &uLen)) {
  1541. pdwTranslation = &dwDefLang;
  1542. uLen = sizeof(DWORD);
  1543. }
  1544. sprintf(buf, "\\StringFileInfo\\%04x%04x\\OleSelfRegister", LOWORD(*pdwTranslation), HIWORD(*pdwTranslation));
  1545. if (!pfnVerQueryValue(lpData, buf, &lpInfo, &lpInfoSize) && (ArgFlag & ArgFlag_OLESelf )) {
  1546. LogPrintf("OleSelfRegister not set\n");
  1547. } else {
  1548. rc = TRUE;
  1549. }
  1550. cleanup:
  1551. if (lpData) {
  1552. free(lpData);
  1553. }
  1554. // No need to free the hVersion
  1555. return(rc);
  1556. }
  1557. BOOL
  1558. ValidatePdata(
  1559. PIMAGE_DOS_HEADER DosHeader
  1560. )
  1561. /*++
  1562. Routine Description:
  1563. validates the PIMAGE_RUNTIME_FUNCTION_ENTRY in the executable
  1564. Arguments:
  1565. PIMAGE_DOS_HEADER DosHeader
  1566. Return Value:
  1567. TRUE if:
  1568. FALSE if: no exception data
  1569. exception table size incorrect
  1570. exception table corrupt
  1571. Notes:
  1572. --*/
  1573. {
  1574. // The machine type indicates this image should have pdata (an exception table).
  1575. // Ensure it looks reasonable.
  1576. // Todo: Add a range check for exception handler and data
  1577. PIMAGE_RUNTIME_FUNCTION_ENTRY ExceptionTable;
  1578. DWORD ExceptionTableSize, i;
  1579. DWORD_PTR LastEnd;
  1580. BOOL fRc;
  1581. PIMAGE_NT_HEADERS NtHeader = (PIMAGE_NT_HEADERS)((PCHAR)DosHeader + (ULONG)DosHeader->e_lfanew);
  1582. ULONG_PTR ImageBase = NtHeader->OptionalHeader.ImageBase;
  1583. DWORD PDataStart = NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress;
  1584. DWORD PDataSize = NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size;
  1585. ExceptionTable = (PIMAGE_RUNTIME_FUNCTION_ENTRY)
  1586. ImageDirectoryEntryToData(
  1587. DosHeader,
  1588. FALSE,
  1589. IMAGE_DIRECTORY_ENTRY_EXCEPTION,
  1590. &ExceptionTableSize );
  1591. if (!ExceptionTable ||
  1592. (ExceptionTable && (ExceptionTableSize == 0)))
  1593. {
  1594. // No Exception table.
  1595. return(TRUE);
  1596. }
  1597. if (ExceptionTableSize % sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY)) {
  1598. // The size isn't an even multiple.
  1599. LogPrintf("exception table size is not correct\n");
  1600. return(FALSE);
  1601. }
  1602. LastEnd = 0;
  1603. fRc = TRUE;
  1604. for (i=0; i < (ExceptionTableSize / sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY)); i++) {
  1605. if (!ExceptionTable[i].BeginAddress) {
  1606. if (fRc != FALSE) {
  1607. LogPrintf("exception table is corrupt.\n");
  1608. }
  1609. LogPrintf("PDATA Entry[%d]: zero value for BeginAddress\n",
  1610. i);
  1611. fRc = FALSE;
  1612. }
  1613. if (!ExceptionTable[i].EndAddress) {
  1614. if (fRc != FALSE) {
  1615. LogPrintf("exception table is corrupt.\n");
  1616. }
  1617. LogPrintf("PDATA Entry[%d]: zero value for EndAddress\n",
  1618. i);
  1619. fRc = FALSE;
  1620. }
  1621. #if defined(_IA64_)
  1622. if (!ExceptionTable[i].UnwindInfoAddress) {
  1623. if (fRc != FALSE) {
  1624. LogPrintf("exception table is corrupt.\n");
  1625. }
  1626. LogPrintf("PDATA Entry[%d]: zero value for UnwindInfoAddress\n",
  1627. i);
  1628. fRc = FALSE;
  1629. }
  1630. #elif defined(_ALPHA_) || defined(_AXP64_)
  1631. if (!ExceptionTable[i].PrologEndAddress) {
  1632. if (fRc != FALSE) {
  1633. LogPrintf("exception table is corrupt.\n");
  1634. }
  1635. LogPrintf("PDATA Entry[%d]: zero value for PrologEndAddress\n",
  1636. i);
  1637. fRc = FALSE;
  1638. }
  1639. #endif // defined(_IA64_)
  1640. if (ExceptionTable[i].BeginAddress < LastEnd) {
  1641. if (fRc != FALSE) {
  1642. LogPrintf("exception table is corrupt.\n");
  1643. }
  1644. LogPrintf("PDATA Entry[%d]: the begin address [%8.8x] is out of sequence. Prior end was [%8.8x]\n",
  1645. i,
  1646. ExceptionTable[i].BeginAddress,
  1647. LastEnd);
  1648. fRc = FALSE;
  1649. }
  1650. if (ExceptionTable[i].EndAddress < ExceptionTable[i].BeginAddress) {
  1651. if (fRc != FALSE) {
  1652. LogPrintf("exception table is corrupt.\n");
  1653. }
  1654. LogPrintf("PDATA Entry[%d]: the end address [%8.8x] is before the begin address[%8.8X]\n",
  1655. i,
  1656. ExceptionTable[i].EndAddress,
  1657. ExceptionTable[i].BeginAddress);
  1658. fRc = FALSE;
  1659. }
  1660. #if defined(_ALPHA_) || defined(_AXP64_)
  1661. if (!((ExceptionTable[i].PrologEndAddress >= ExceptionTable[i].BeginAddress) &&
  1662. (ExceptionTable[i].PrologEndAddress <= ExceptionTable[i].EndAddress)))
  1663. {
  1664. if (NtHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_ALPHA) {
  1665. // Change this test. On Alpha, the PrologEndAddress is allowed to be
  1666. // outside the Function Start/End range. If this is true, the PrologEnd
  1667. // - ImageBase - pdata section VA s/b divisible by sizeof IMAGE_RUNTIME_FUNCTION_ENTRY
  1668. // AND within the bounds of the PdataSize. It's supposed to be an index into the
  1669. // pdata data that descibes the real scoping function.
  1670. LONG PrologAddress;
  1671. PrologAddress = (LONG) (ExceptionTable[i].PrologEndAddress - ImageBase - PDataStart);
  1672. if (PrologAddress % sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY)) {
  1673. if (fRc != FALSE) {
  1674. LogPrintf("exception table is corrupt.\n");
  1675. }
  1676. LogPrintf("PDATA Entry[%d]: the secondary prolog end address[%8.8x] does not evenly index into the exception table.\n",
  1677. i,
  1678. ExceptionTable[i].PrologEndAddress,
  1679. ExceptionTable[i].BeginAddress,
  1680. ExceptionTable[i].EndAddress
  1681. );
  1682. fRc = FALSE;
  1683. } else {
  1684. if ((PrologAddress < 0) || (PrologAddress > (LONG)(PDataStart - sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY)))) {
  1685. if (fRc != FALSE) {
  1686. LogPrintf("exception table is corrupt.\n");
  1687. }
  1688. LogPrintf("PDATA Entry[%d]: the secondary prolog end address[%8.8x] does not index into the exception table.\n",
  1689. i,
  1690. ExceptionTable[i].PrologEndAddress,
  1691. ExceptionTable[i].BeginAddress,
  1692. ExceptionTable[i].EndAddress
  1693. );
  1694. fRc = FALSE;
  1695. }
  1696. }
  1697. } else {
  1698. if (fRc != FALSE) {
  1699. LogPrintf("exception table is corrupt.\n");
  1700. }
  1701. LogPrintf("PDATA Entry[%d]: the prolog end address[%8.8x] is not within the bounds of the frame [%8.8X] - [%8.8X]\n",
  1702. i,
  1703. ExceptionTable[i].PrologEndAddress,
  1704. ExceptionTable[i].BeginAddress,
  1705. ExceptionTable[i].EndAddress
  1706. );
  1707. fRc = FALSE;
  1708. }
  1709. }
  1710. #endif // !defined(_IA64_)
  1711. LastEnd = ExceptionTable[i].EndAddress;
  1712. }
  1713. return(fRc);
  1714. }
  1715. BOOL
  1716. ImageNeedsOleSelfRegister(
  1717. PIMAGE_DOS_HEADER DosHeader
  1718. )
  1719. /*++
  1720. Routine Description:
  1721. Arguments:
  1722. PIMAGE_DOS_HEADER DosHeader
  1723. Return Value:
  1724. TRUE if DllRegisterServer or DllUnRegisterServer is exported
  1725. --*/
  1726. {
  1727. PIMAGE_EXPORT_DIRECTORY ExportDirectory;
  1728. PIMAGE_NT_HEADERS NtHeader;
  1729. PIMAGE_SECTION_HEADER SectionHeader;
  1730. DWORD ExportDirectorySize, i;
  1731. USHORT x;
  1732. PCHAR rvaDelta;
  1733. PULONG NameTable;
  1734. ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)
  1735. ImageDirectoryEntryToData(
  1736. DosHeader,
  1737. FALSE,
  1738. IMAGE_DIRECTORY_ENTRY_EXPORT,
  1739. &ExportDirectorySize );
  1740. if (!ExportDirectory ||
  1741. !ExportDirectorySize ||
  1742. !ExportDirectory->NumberOfNames)
  1743. {
  1744. // No exports (no directory, no size, or no names).
  1745. return(FALSE);
  1746. }
  1747. // Walk the section headers and find the va/raw offsets.
  1748. NtHeader = (PIMAGE_NT_HEADERS)((PCHAR)DosHeader + (ULONG)DosHeader->e_lfanew);
  1749. SectionHeader = IMAGE_FIRST_SECTION(NtHeader);
  1750. for (x = 0; x < NtHeader->FileHeader.NumberOfSections; x++) {
  1751. if (((ULONG)((PCHAR)ExportDirectory - (PCHAR)DosHeader) >= SectionHeader->PointerToRawData) &&
  1752. ((ULONG)((PCHAR)ExportDirectory - (PCHAR)DosHeader) <
  1753. (SectionHeader->PointerToRawData + SectionHeader->SizeOfRawData))) {
  1754. break;
  1755. } else {
  1756. SectionHeader++;
  1757. }
  1758. }
  1759. if (x == NtHeader->FileHeader.NumberOfSections) {
  1760. // We didn't find the section that contained the export table. Assume it's not there.
  1761. return(FALSE);
  1762. }
  1763. rvaDelta = (PCHAR)DosHeader + SectionHeader->PointerToRawData - SectionHeader->VirtualAddress;
  1764. NameTable = (PULONG)(rvaDelta + ExportDirectory->AddressOfNames);
  1765. for (i = 0; i < ExportDirectory->NumberOfNames; i++) {
  1766. if (!strcmp("DllRegisterServer", rvaDelta + NameTable[i]) ||
  1767. !strcmp("DllUnRegisterServer", rvaDelta + NameTable[i]))
  1768. {
  1769. return(TRUE);
  1770. }
  1771. }
  1772. return(FALSE);
  1773. }
  1774. //
  1775. // support routines for symbol checker - could all
  1776. // be done without this using lower-level internal api's
  1777. //
  1778. PSYMMODLIST
  1779. MakeModList(
  1780. HANDLE hProcess
  1781. )
  1782. /*++
  1783. Routine Description:
  1784. build a list of loaded symbol modules and addresses
  1785. Arguments:
  1786. HANDLE hProcess
  1787. Return Value:
  1788. PSYMMODLIST
  1789. Notes:
  1790. --*/
  1791. {
  1792. PSYMMODLIST ModList;
  1793. ModList = (PSYMMODLIST)calloc(1, sizeof(SYMMODLIST));
  1794. SymEnumerateModules64(hProcess, SymEnumerateModulesCallback, ModList);
  1795. return(ModList);
  1796. }
  1797. BOOL
  1798. CALLBACK
  1799. SymEnumerateModulesCallback(
  1800. LPSTR ModuleName,
  1801. ULONG64 BaseOfDll,
  1802. PVOID UserContext
  1803. )
  1804. /*++
  1805. Routine Description:
  1806. callback routine for SymEnumerateModules
  1807. in this case, UserContext is a pointer to a head of a _SYMMODLIST struct
  1808. that will have a new item appended
  1809. We are avoiding global state for these lists so we can use several at once,
  1810. they will be short, so we will find the end each time we want to add
  1811. runs slower, simpler to maintain
  1812. Arguments:
  1813. LPSTR ModuleName
  1814. ULONG64 BaseOfDll
  1815. PVOID UserContext
  1816. Return Value:
  1817. TRUE
  1818. Notes:
  1819. --*/
  1820. {
  1821. PSYMMODLIST pSymModList;
  1822. //
  1823. // find end of list, key on pSymModList->ModBase
  1824. //
  1825. pSymModList = (PSYMMODLIST)UserContext;
  1826. while (pSymModList->ModBase)
  1827. {
  1828. pSymModList = pSymModList->Next;
  1829. }
  1830. //
  1831. // append entry
  1832. //
  1833. pSymModList->ModName = malloc(strlen(ModuleName) + 1);
  1834. if (!pSymModList->ModName)
  1835. return FALSE;
  1836. strcpy(pSymModList->ModName, ModuleName);
  1837. pSymModList->ModBase = (void *)BaseOfDll;
  1838. pSymModList->Next = (PSYMMODLIST)calloc(1, sizeof(SYMMODLIST));
  1839. return(TRUE);
  1840. }
  1841. void *
  1842. GetModAddrFromName(
  1843. PSYMMODLIST ModList,
  1844. char *ModName
  1845. )
  1846. /*++
  1847. Routine Description:
  1848. gets module address from a SYMMODLIST given module base name
  1849. Arguments:
  1850. PSYMMODLIST ModList
  1851. char * ModName
  1852. Return Value:
  1853. module address
  1854. --*/
  1855. {
  1856. while (ModList->Next != 0)
  1857. {
  1858. if (strcmp(ModList->ModName, ModName) == 0)
  1859. {
  1860. break;
  1861. }
  1862. ModList = ModList->Next;
  1863. }
  1864. return(ModList->ModBase);
  1865. }
  1866. void
  1867. FreeModList(
  1868. PSYMMODLIST ModList
  1869. )
  1870. /*++
  1871. Routine Description:
  1872. free a list of loaded symbol modules and addresses
  1873. Arguments:
  1874. PSYMMODLIST ModList
  1875. Return Value:
  1876. none
  1877. --*/
  1878. {
  1879. PSYMMODLIST ModListNext;
  1880. while (ModList)
  1881. {
  1882. if(ModList->ModName)
  1883. {
  1884. free(ModList->ModName);
  1885. }
  1886. ModListNext = ModList->Next;
  1887. free(ModList);
  1888. ModList = ModListNext;
  1889. }
  1890. }
  1891. pLogListItem LogAppend(
  1892. char *logitem,
  1893. pLogListItem plog
  1894. )
  1895. /*++
  1896. Routine Description:
  1897. add a log line to the linked list of log lines
  1898. Arguments:
  1899. char * logitem - a formatted line of text to be logged
  1900. pLogListItem plog - pointer to LogListItem
  1901. Return Value:
  1902. a pointer to the LogListItem allocated
  1903. the first call to this function should save this pointer and use
  1904. it for the head of the list, and it should be used when calling
  1905. LogOutAndClean() to print the list and free all the memory
  1906. you can call this with plog == head of list, or == to last item
  1907. if plog == 0, this means that the item being allocated is the head
  1908. of the list.
  1909. If plog == head of list, search for end of list
  1910. if plog == last item allocated, then the search is much faster
  1911. --*/
  1912. {
  1913. pLogListItem ptemp;
  1914. ptemp = plog;
  1915. if(plog)
  1916. {
  1917. while(ptemp->Next)
  1918. {
  1919. ptemp = ptemp->Next;
  1920. }
  1921. }
  1922. if(!ptemp)
  1923. {
  1924. ptemp = (pLogListItem)calloc(sizeof(LogListItem), 1);
  1925. if (!ptemp)
  1926. return NULL;
  1927. } else {
  1928. ptemp->Next = (pLogListItem)calloc(sizeof(LogListItem), 1);
  1929. if (!ptemp->Next)
  1930. return NULL;
  1931. ptemp = ptemp->Next;
  1932. }
  1933. ptemp->LogLine = (char *)malloc(strlen(logitem) + 1);
  1934. if (!ptemp->LogLine)
  1935. return NULL;
  1936. strcpy(ptemp->LogLine, logitem);
  1937. return (ptemp);
  1938. }
  1939. void LogOutAndClean(
  1940. BOOL print
  1941. )
  1942. /*++
  1943. Routine Description:
  1944. output the log output, and free all the items in the list
  1945. Arguments:
  1946. none
  1947. Return Value:
  1948. none
  1949. --*/
  1950. {
  1951. pLogListItem ptemp;
  1952. pLogListItem plog = pLogList;
  1953. while(plog)
  1954. {
  1955. ptemp = plog;
  1956. if(print)
  1957. {
  1958. fputs(plog->LogLine, stderr);
  1959. }
  1960. plog = plog->Next;
  1961. free(ptemp->LogLine);
  1962. free(ptemp);
  1963. }
  1964. if(print)
  1965. {
  1966. fprintf(stderr, "\n");
  1967. }
  1968. pLogListTmp = pLogList = NULL;
  1969. }
  1970. void
  1971. __cdecl
  1972. LogPrintf(
  1973. const char *format,
  1974. ...
  1975. )
  1976. /*++
  1977. Routine Description:
  1978. logging wrapper for fprintf
  1979. Arguments:
  1980. none
  1981. Return Value:
  1982. none
  1983. --*/
  1984. {
  1985. va_list arglist;
  1986. char LogStr[1024];
  1987. va_start(arglist, format);
  1988. vsprintf(LogStr, format, arglist);
  1989. if(pLogList == NULL)
  1990. {
  1991. //
  1992. // initialize log
  1993. //
  1994. pLogListTmp = pLogList = LogAppend(LogStr, NULL);
  1995. } else {
  1996. //
  1997. // append to log
  1998. //
  1999. pLogListTmp = LogAppend(LogStr, pLogListTmp);
  2000. }
  2001. }