Windows NT 4.0 source code leak
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.

1231 lines
38 KiB

4 years ago
  1. #ifdef __cplusplus
  2. extern "C" {
  3. #endif
  4. #include <nt.h>
  5. #include <ntrtl.h>
  6. #include <nturtl.h>
  7. #ifdef __cplusplus
  8. }
  9. #endif
  10. #include <errno.h>
  11. #include <direct.h>
  12. #include <cvinfo.h>
  13. #include <private.h>
  14. typedef struct List {
  15. char Name[40];
  16. unsigned long Attributes;
  17. } List, *pList;
  18. VOID FindFiles();
  19. VOID Imagechk(List *rgpList, TCHAR *szDirectory);
  20. VOID ParseArgs(int *pargc, char **argv);
  21. int __cdecl CompFileAndDir( const void *elem1 , const void *elem2);
  22. int __cdecl CompName( const void *elem1 , const void *elem2);
  23. VOID Usage(VOID);
  24. int _cdecl _cwild(VOID);
  25. BOOL
  26. VerifyVersionResource(
  27. PCHAR FileName
  28. );
  29. NTSTATUS
  30. MiVerifyImageHeader (
  31. IN PIMAGE_NT_HEADERS NtHeader,
  32. IN PIMAGE_DOS_HEADER DosHeader,
  33. IN DWORD NtHeaderSize
  34. );
  35. ULONG PageSize = 4096;
  36. ULONG PageShift = 12;
  37. #define X64K (64*1024)
  38. #define MM_SIZE_OF_LARGEST_IMAGE ((ULONG)0x10000000)
  39. #define MM_MAXIMUM_IMAGE_HEADER (2 * PageSize)
  40. #define MM_HIGHEST_USER_ADDRESS ((PVOID)0x7FFE0000)
  41. #define MM_MAXIMUM_IMAGE_SECTIONS \
  42. ((MM_MAXIMUM_IMAGE_HEADER - (4096 + sizeof(IMAGE_NT_HEADERS))) / \
  43. sizeof(IMAGE_SECTION_HEADER))
  44. #define MMSECTOR_SHIFT 9 //MUST BE LESS THAN OR EQUAL TO PageShift
  45. #define MMSECTOR_MASK 0x1ff
  46. #define MI_ROUND_TO_SIZE(LENGTH,ALIGNMENT) \
  47. (((ULONG)LENGTH + ALIGNMENT - 1) & ~(ALIGNMENT - 1))
  48. #define BYTES_TO_PAGES(Size) (((ULONG)(Size) >> PageShift) + \
  49. (((ULONG)(Size) & (PageSize - 1)) != 0))
  50. BOOL fRecurse;
  51. BOOL fFileOut;
  52. BOOL fNotCurrent;
  53. BOOL fPattern;
  54. BOOL fSingleFile;
  55. BOOL fPathOverride;
  56. BOOL fSingleSlash;
  57. BOOL fDebugMapped;
  58. BOOL fcheckbase = TRUE;
  59. FILE* fout;
  60. CHAR *szFileName = {"*.*"};
  61. CHAR *pszRootDir;
  62. CHAR *pszFileOut;
  63. CHAR szDirectory[MAX_PATH] = {"."};
  64. CHAR *szPattern;
  65. int endpath, DirNum=1, ProcessedFiles;
  66. typedef
  67. NTSTATUS
  68. (NTAPI *LPLDRVERIFYIMAGECHKSUM)(
  69. IN HANDLE ImageFileHandle
  70. );
  71. LPLDRVERIFYIMAGECHKSUM lpOldLdrVerifyImageMatchesChecksum;
  72. VOID __cdecl
  73. main(
  74. int argc,
  75. char *argv[],
  76. char *envp[]
  77. )
  78. {
  79. OSVERSIONINFO VersionInformation;
  80. TCHAR CWD[MAX_PATH];
  81. int dirlen=0;
  82. if (argc < 2) {
  83. Usage();
  84. }
  85. ParseArgs(&argc, argv);
  86. GetCurrentDirectory(MAX_PATH, CWD);
  87. VersionInformation.dwOSVersionInfoSize = sizeof(VersionInformation);
  88. if (!GetVersionEx( &VersionInformation ) ||
  89. VersionInformation.dwPlatformId != VER_PLATFORM_WIN32_NT ||
  90. VersionInformation.dwBuildNumber < 1230
  91. ) {
  92. lpOldLdrVerifyImageMatchesChecksum = (LPLDRVERIFYIMAGECHKSUM)
  93. GetProcAddress(LoadLibrary(TEXT("NTDLL.DLL")), TEXT("LdrVerifyImageMatchesChecksum"));
  94. if (lpOldLdrVerifyImageMatchesChecksum == NULL) {
  95. fprintf(stderr, "Incorrect operating system version.\n" );
  96. exit(1);
  97. }
  98. } else {
  99. lpOldLdrVerifyImageMatchesChecksum = NULL;
  100. }
  101. if (fPathOverride) {
  102. if (_chdir(szDirectory) == -1){ // cd to dir
  103. fprintf(stderr, "Path not found: %s\n", szDirectory);
  104. Usage();
  105. }
  106. }
  107. // remove trailing '\' needed only for above chdir, not for output formatting
  108. if (fSingleSlash) {
  109. dirlen = strlen(szDirectory);
  110. szDirectory[dirlen-1] = '\0';
  111. }
  112. FindFiles();
  113. fprintf(stdout, "%d files processed in %d directories\n", ProcessedFiles, DirNum);
  114. }
  115. VOID FindFiles(){
  116. HANDLE fh;
  117. TCHAR CWD[MAX_PATH];
  118. char *q;
  119. WIN32_FIND_DATA *pfdata;
  120. BOOL fFilesInDir=FALSE;
  121. BOOL fDirsFound=FALSE;
  122. int dnCounter=0, cNumDir=0, i=0, Length=0, NameSize=0, total=0, cNumFiles=0;
  123. pList rgpList[5000];
  124. pfdata = (WIN32_FIND_DATA*)malloc(sizeof(WIN32_FIND_DATA));
  125. if (!pfdata) {
  126. fprintf(stderr, "Not enough memory.\n");
  127. return;
  128. }
  129. if (!fRecurse) {
  130. fh = FindFirstFile(szFileName, pfdata); // find only filename (pattern) if not recursive
  131. } else {
  132. fh = FindFirstFile("*.*", pfdata); // find all if recursive in order to determine subdirectory names
  133. }
  134. if (fh == INVALID_HANDLE_VALUE) {
  135. fprintf(fout==NULL? stderr : fout , "File not found: %s\n", szFileName);
  136. return;
  137. }
  138. // loop to find all files and directories in current directory
  139. // and copy pertinent data to individual List structures.
  140. do {
  141. if (strcmp(pfdata->cFileName, ".") && strcmp(pfdata->cFileName, "..")) { // skip . and ..
  142. rgpList[dnCounter] = (pList)malloc(sizeof(List)); // allocate the memory
  143. if (!rgpList[dnCounter]) {
  144. fprintf(stderr, "Not enough memory.\n");
  145. return;
  146. }
  147. if (!(pfdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { // if file
  148. fFilesInDir=TRUE;
  149. // see if given pattern wildcard extension matches pfdata->cFileName extension
  150. if (fPattern) {
  151. q = strchr(pfdata->cFileName, 46); // find first instance of "." in filename
  152. if (q == NULL) goto blah; // "." not found
  153. _strlwr(q); // lowercase before compare
  154. if (strcmp(q, szPattern)) goto blah; // if pattern and name doesn't match goto
  155. } // OK, I used a goto, get over it.
  156. if (fSingleFile) {
  157. _strlwr(pfdata->cFileName);
  158. _strlwr(szFileName);
  159. if (strcmp(pfdata->cFileName, szFileName)) goto blah;
  160. }
  161. // if pattern && match || no pattern
  162. strcpy(rgpList[dnCounter]->Name, pfdata->cFileName);
  163. _strlwr(rgpList[dnCounter]->Name); // all lowercase for strcmp in CompName
  164. memcpy(&(rgpList[dnCounter]->Attributes), &pfdata->dwFileAttributes, 4);
  165. dnCounter++;
  166. cNumFiles++;
  167. } else {
  168. if (pfdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { // if dir
  169. fDirsFound=TRUE;
  170. //cNumDir++;
  171. if (fRecurse) {
  172. strcpy(rgpList[dnCounter]->Name, pfdata->cFileName);
  173. _strlwr(rgpList[dnCounter]->Name); // all lowercase for strcmp in CompName
  174. memcpy(&(rgpList[dnCounter]->Attributes), &pfdata->dwFileAttributes, 4);
  175. cNumDir++;
  176. dnCounter++;
  177. }
  178. }
  179. }
  180. }
  181. blah: ;
  182. } while (FindNextFile(fh, pfdata));
  183. FindClose(fh); // close the file handle
  184. // Sort Array arranging FILE entries at top
  185. qsort( (void *)rgpList, dnCounter, sizeof(List *), CompFileAndDir);
  186. // Sort Array alphabetizing only FILE names
  187. qsort( (void *)rgpList, dnCounter-cNumDir, sizeof(List *), CompName);
  188. // Sort Array alphabetizing only DIRectory names
  189. if (fRecurse) {
  190. qsort( (void *)&rgpList[dnCounter-cNumDir], cNumDir, sizeof(List *), CompName);
  191. }
  192. // Process newly sorted structures.
  193. for (i=0; i < dnCounter; ++i) {
  194. if (rgpList[i]->Attributes & FILE_ATTRIBUTE_DIRECTORY) { // if Dir
  195. if (fRecurse) {
  196. if (_chdir(rgpList[i]->Name) == -1){ // cd into subdir and check for error
  197. fprintf(stderr, "Unable to change directory: %s\n", rgpList[i]->Name);
  198. } else {
  199. NameSize = strlen(rgpList[i]->Name);
  200. strcat(szDirectory, "\\");
  201. strcat(szDirectory, rgpList[i]->Name); //append name to directory path
  202. total = strlen(szDirectory);
  203. DirNum++; // directory counter
  204. // start another iteration of FindFiles
  205. FindFiles();
  206. // get back to previous directory when above iteration returns
  207. _chdir("..");
  208. // cut off previously appended directory name - for output only
  209. szDirectory[total-(NameSize+1)]='\0';
  210. }
  211. }
  212. } else {
  213. if (!(rgpList[i]->Attributes & FILE_ATTRIBUTE_DIRECTORY)) // check image if not dir
  214. Imagechk(rgpList[i], szDirectory);
  215. }
  216. }
  217. } // end FindFiles
  218. /*************************************************************************************\
  219. * Imagechk
  220. \*************************************************************************************/
  221. VOID
  222. Imagechk(
  223. List *rgpList,
  224. TCHAR *szDirectory
  225. )
  226. {
  227. HANDLE File;
  228. HANDLE MemMap;
  229. PIMAGE_DOS_HEADER DosHeader;
  230. PIMAGE_NT_HEADERS NtHeader;
  231. NTSTATUS Status;
  232. BY_HANDLE_FILE_INFORMATION FileInfo;
  233. ULONG NumberOfPtes;
  234. ULONG SectionVirtualSize;
  235. ULONG i;
  236. PIMAGE_SECTION_HEADER SectionTableEntry;
  237. ULONG SectorOffset;
  238. ULONG NumberOfSubsections;
  239. PCHAR ExtendedHeader = NULL;
  240. ULONG PreferredImageBase;
  241. ULONG NextVa;
  242. ULONG ImageFileSize;
  243. ULONG OffsetToSectionTable;
  244. ULONG ImageAlignment;
  245. ULONG PtesInSubsection;
  246. ULONG StartingSector;
  247. ULONG EndingSector;
  248. LPSTR ImageName;
  249. LPSTR MachineType;
  250. BOOL MachineTypeMismatch;
  251. BOOL ImageOk;
  252. ImageName = rgpList->Name;
  253. fprintf(stderr,"ImageChk: %s\\%s ", szDirectory, ImageName);
  254. ProcessedFiles++;
  255. DosHeader = NULL;
  256. ImageOk = TRUE;
  257. File = CreateFile (ImageName,
  258. GENERIC_READ | FILE_EXECUTE,
  259. FILE_SHARE_READ | FILE_SHARE_DELETE,
  260. NULL,
  261. OPEN_EXISTING,
  262. FILE_ATTRIBUTE_NORMAL,
  263. NULL);
  264. if (File == INVALID_HANDLE_VALUE) {
  265. fprintf(stderr, "Error, CreateFile() %d\n", GetLastError());
  266. ImageOk = FALSE; goto NextImage;
  267. }
  268. MemMap = CreateFileMapping (File,
  269. NULL, // default security.
  270. PAGE_READONLY, // file protection.
  271. 0, // high-order file size.
  272. 0,
  273. NULL);
  274. if (!GetFileInformationByHandle(File, &FileInfo)) {
  275. fprintf(stderr,"Error, GetFileInfo() %d\n", GetLastError());
  276. CloseHandle(File);
  277. ImageOk = FALSE; goto NextImage;
  278. }
  279. DosHeader = (PIMAGE_DOS_HEADER) MapViewOfFile(MemMap,
  280. FILE_MAP_READ,
  281. 0, // high
  282. 0, // low
  283. 0 // whole file
  284. );
  285. CloseHandle(MemMap);
  286. if (!DosHeader) {
  287. fprintf(stderr,"Error, MapViewOfFile() %d\n", GetLastError());
  288. ImageOk = FALSE; goto NextImage;
  289. }
  290. //
  291. // Check to determine if this is an NT image (PE format) or
  292. // a DOS image, Win-16 image, or OS/2 image. If the image is
  293. // not NT format, return an error indicating which image it
  294. // appears to be.
  295. //
  296. if (DosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
  297. fprintf(stderr, "MZ header not found\n");
  298. ImageOk = FALSE;
  299. goto NeImage;
  300. }
  301. if (((ULONG)DosHeader->e_lfanew & 3) != 0) {
  302. //
  303. // The image header is not aligned on a long boundary.
  304. // Report this as an invalid protect mode image.
  305. //
  306. fprintf(stderr, "Image header not on Long boundary\n");
  307. ImageOk = FALSE;
  308. goto NeImage;
  309. }
  310. if ((ULONG)DosHeader->e_lfanew > FileInfo.nFileSizeLow) {
  311. fprintf(stderr, "Image size bigger than size of file\n");
  312. ImageOk = FALSE;
  313. goto NeImage;
  314. }
  315. NtHeader = (PIMAGE_NT_HEADERS)((ULONG)DosHeader + (ULONG)DosHeader->e_lfanew);
  316. if (NtHeader->Signature != IMAGE_NT_SIGNATURE) { //if not PE image
  317. fprintf(stderr, "Non 32-bit image");
  318. ImageOk = TRUE;
  319. goto NeImage;
  320. }
  321. //
  322. // Check to see if this is an NT image or a DOS or OS/2 image.
  323. //
  324. Status = MiVerifyImageHeader (NtHeader, DosHeader, 50000);
  325. if (Status != STATUS_SUCCESS) {
  326. ImageOk = FALSE; //continue checking the image but don't print "OK"
  327. }
  328. //
  329. // Verify machine type.
  330. //
  331. switch (NtHeader->FileHeader.Machine) {
  332. case IMAGE_FILE_MACHINE_I386:
  333. MachineType = "x86";
  334. break;
  335. case IMAGE_FILE_MACHINE_R3000:
  336. MachineType = "MIPS R3000";
  337. break;
  338. case IMAGE_FILE_MACHINE_R4000:
  339. MachineType = "MIPS R4000";
  340. break;
  341. case IMAGE_FILE_MACHINE_R10000:
  342. MachineType = "MIPS R10000";
  343. break;
  344. case IMAGE_FILE_MACHINE_ALPHA:
  345. MachineType = "Alpha";
  346. PageSize = 8192;
  347. PageShift = 13;
  348. break;
  349. case IMAGE_FILE_MACHINE_POWERPC:
  350. MachineType = "PowerPC";
  351. break;
  352. default:
  353. fprintf(stderr, "Unrecognized machine type x%lx\n",
  354. NtHeader->FileHeader.Machine);
  355. ImageOk = FALSE;
  356. break;
  357. }
  358. if ((NtHeader->FileHeader.Machine < USER_SHARED_DATA->ImageNumberLow) ||
  359. (NtHeader->FileHeader.Machine > USER_SHARED_DATA->ImageNumberHigh)) {
  360. MachineTypeMismatch = TRUE;
  361. } else {
  362. MachineTypeMismatch = FALSE;
  363. }
  364. ImageAlignment = NtHeader->OptionalHeader.SectionAlignment;
  365. NumberOfPtes = BYTES_TO_PAGES (NtHeader->OptionalHeader.SizeOfImage);
  366. NextVa = NtHeader->OptionalHeader.ImageBase;
  367. if ((NextVa & (X64K - 1)) != 0) {
  368. //
  369. // Image header is not aligned on a 64k boundary.
  370. //
  371. fprintf(stderr, "image base not on 64k boundary %lx\n",NextVa);
  372. ImageOk = FALSE;
  373. goto BadPeImageSegment;
  374. }
  375. //BasedAddress = (PVOID)NextVa;
  376. PtesInSubsection = MI_ROUND_TO_SIZE (
  377. NtHeader->OptionalHeader.SizeOfHeaders,
  378. ImageAlignment
  379. ) >> PageShift;
  380. if (ImageAlignment >= PageSize) {
  381. //
  382. // Aligmment is PageSize of greater.
  383. //
  384. if (PtesInSubsection > NumberOfPtes) {
  385. //
  386. // Inconsistent image, size does not agree with header.
  387. //
  388. fprintf(stderr, "Image size in header (%ld.) not consistent with sections (%ld.)\n",
  389. NumberOfPtes, PtesInSubsection);
  390. ImageOk = FALSE;
  391. goto BadPeImageSegment;
  392. }
  393. NumberOfPtes -= PtesInSubsection;
  394. EndingSector =
  395. NtHeader->OptionalHeader.SizeOfHeaders >> MMSECTOR_SHIFT;
  396. for (i = 0; i < PtesInSubsection; i++) {
  397. SectorOffset += PageSize;
  398. NextVa += PageSize;
  399. }
  400. }
  401. //
  402. // Build the next subsections.
  403. //
  404. NumberOfSubsections = NtHeader->FileHeader.NumberOfSections;
  405. PreferredImageBase = NtHeader->OptionalHeader.ImageBase;
  406. //
  407. // At this point the object table is read in (if it was not
  408. // already read in) and may displace the image header.
  409. //
  410. OffsetToSectionTable = sizeof(ULONG) +
  411. sizeof(IMAGE_FILE_HEADER) +
  412. NtHeader->FileHeader.SizeOfOptionalHeader;
  413. SectionTableEntry = (PIMAGE_SECTION_HEADER)((ULONG)NtHeader +
  414. OffsetToSectionTable);
  415. if (ImageAlignment < PageSize) {
  416. // The image header is no longer valid, TempPte is
  417. // used to indicate that this image alignment is
  418. // less than a PageSize.
  419. //
  420. // Loop through all sections and make sure there is no
  421. // unitialized data.
  422. //
  423. while (NumberOfSubsections > 0) {
  424. if (SectionTableEntry->Misc.VirtualSize == 0) {
  425. SectionVirtualSize = SectionTableEntry->SizeOfRawData;
  426. } else {
  427. SectionVirtualSize = SectionTableEntry->Misc.VirtualSize;
  428. }
  429. //
  430. // If the pointer to raw data is zero and the virtual size
  431. // is zero, OR, the section goes past the end of file, OR
  432. // the virtual size does not match the size of raw data, then
  433. // return an error.
  434. //
  435. if (((SectionTableEntry->PointerToRawData !=
  436. SectionTableEntry->VirtualAddress))
  437. ||
  438. ((SectionTableEntry->SizeOfRawData +
  439. SectionTableEntry->PointerToRawData) >
  440. FileInfo.nFileSizeLow)
  441. ||
  442. (SectionVirtualSize > SectionTableEntry->SizeOfRawData)) {
  443. fprintf(stderr, "invalid BSS/Trailingzero section/file size\n");
  444. ImageOk = FALSE;
  445. goto NeImage;
  446. }
  447. SectionTableEntry += 1;
  448. NumberOfSubsections -= 1;
  449. }
  450. goto PeReturnSuccess;
  451. }
  452. while (NumberOfSubsections > 0) {
  453. //
  454. // Handle case where virtual size is 0.
  455. //
  456. if (SectionTableEntry->Misc.VirtualSize == 0) {
  457. SectionVirtualSize = SectionTableEntry->SizeOfRawData;
  458. } else {
  459. SectionVirtualSize = SectionTableEntry->Misc.VirtualSize;
  460. }
  461. if (!strcmp(SectionTableEntry->Name, ".debug")) {
  462. fDebugMapped = TRUE;
  463. }
  464. if (SectionVirtualSize == 0) {
  465. //
  466. // The specified virtual address does not align
  467. // with the next prototype PTE.
  468. //
  469. fprintf(stderr, "Section virtual size is 0, NextVa for section %lx %lx\n",
  470. SectionTableEntry->VirtualAddress, NextVa);
  471. ImageOk = FALSE;
  472. goto BadPeImageSegment;
  473. }
  474. if (NextVa !=
  475. (PreferredImageBase + SectionTableEntry->VirtualAddress)) {
  476. //
  477. // The specified virtual address does not align
  478. // with the next prototype PTE.
  479. //
  480. fprintf(stderr, "Section Va not set to alignment, NextVa for section %lx %lx\n",
  481. SectionTableEntry->VirtualAddress, NextVa);
  482. ImageOk = FALSE;
  483. goto BadPeImageSegment;
  484. }
  485. PtesInSubsection =
  486. MI_ROUND_TO_SIZE (SectionVirtualSize, ImageAlignment) >> PageShift;
  487. if (PtesInSubsection > NumberOfPtes) {
  488. //
  489. // Inconsistent image, size does not agree with object tables.
  490. //
  491. fprintf(stderr, "Image size in header not consistent with sections, needs %ld. pages\n",
  492. PtesInSubsection - NumberOfPtes);
  493. fprintf(stderr, "va of bad section %lx\n",SectionTableEntry->VirtualAddress);
  494. ImageOk = FALSE;
  495. goto BadPeImageSegment;
  496. }
  497. NumberOfPtes -= PtesInSubsection;
  498. StartingSector =
  499. SectionTableEntry->PointerToRawData >> MMSECTOR_SHIFT;
  500. EndingSector =
  501. (SectionTableEntry->PointerToRawData +
  502. SectionVirtualSize);
  503. EndingSector = EndingSector >> MMSECTOR_SHIFT;
  504. ImageFileSize = SectionTableEntry->PointerToRawData +
  505. SectionTableEntry->SizeOfRawData;
  506. SectorOffset = 0;
  507. for (i = 0; i < PtesInSubsection; i++) {
  508. //
  509. // Set all the prototype PTEs to refer to the control section.
  510. //
  511. SectorOffset += PageSize;
  512. NextVa += PageSize;
  513. }
  514. SectionTableEntry += 1;
  515. NumberOfSubsections -= 1;
  516. }
  517. //
  518. // If the file size is not as big as the image claimed to be,
  519. // return an error.
  520. //
  521. if (ImageFileSize > FileInfo.nFileSizeLow) {
  522. //
  523. // Invalid image size.
  524. //
  525. fprintf(stderr, "invalid image size - file size %lx - image size %lx\n",
  526. FileInfo.nFileSizeLow, ImageFileSize);
  527. ImageOk = FALSE;
  528. goto BadPeImageSegment;
  529. }
  530. {
  531. // Validate the debug information (as much as we can).
  532. PVOID ImageBase;
  533. ULONG DebugDirectorySize, NumberOfDebugDirectories, i;
  534. PIMAGE_DEBUG_DIRECTORY DebugDirectory;
  535. ImageBase = (PVOID) DosHeader;
  536. DebugDirectory = (PIMAGE_DEBUG_DIRECTORY)
  537. ImageDirectoryEntryToData(
  538. ImageBase,
  539. FALSE,
  540. IMAGE_DIRECTORY_ENTRY_DEBUG,
  541. &DebugDirectorySize );
  542. if (!DebugDirectoryIsUseful(DebugDirectory, DebugDirectorySize)) {
  543. // Not useful. Are they valid? (both s/b zero)
  544. if (DebugDirectory || DebugDirectorySize) {
  545. fprintf(stderr,
  546. "Debug directory values [%x, %x] are invalid\n",
  547. DebugDirectory,
  548. DebugDirectorySize);
  549. ImageOk = FALSE;
  550. }
  551. goto DebugDirsDone;
  552. }
  553. NumberOfDebugDirectories = DebugDirectorySize / sizeof( IMAGE_DEBUG_DIRECTORY );
  554. for (i=0; i < NumberOfDebugDirectories; i++) {
  555. if (DebugDirectory->PointerToRawData > FileInfo.nFileSizeLow) {
  556. fprintf(stderr,
  557. "Invalid debug directory entry[%d] - File Offset %x is beyond the end of the file\n",
  558. i,
  559. DebugDirectory->PointerToRawData
  560. );
  561. ImageOk = FALSE;
  562. goto BadPeImageSegment;
  563. }
  564. if ((DebugDirectory->PointerToRawData + DebugDirectory->SizeOfData) > FileInfo.nFileSizeLow) {
  565. fprintf(stderr,
  566. "Invalid debug directory entry[%d] - File Offset (%X) + Size (%X) is beyond the end of the file (filesize: %X)\n",
  567. i,
  568. DebugDirectory->PointerToRawData,
  569. DebugDirectory->SizeOfData,
  570. FileInfo.nFileSizeLow
  571. );
  572. ImageOk = FALSE;
  573. goto BadPeImageSegment;
  574. }
  575. if (DebugDirectory->AddressOfRawData != 0) {
  576. if (!fDebugMapped) {
  577. fprintf(stderr,
  578. "Invalid debug directory entry[%d] - VA is non-zero (%X), but no .debug section exists\n",
  579. i,
  580. DebugDirectory->AddressOfRawData);
  581. ImageOk = FALSE;
  582. goto BadPeImageSegment;
  583. }
  584. if (DebugDirectory->AddressOfRawData > ImageFileSize){
  585. fprintf(stderr,
  586. "Invalid debug directory entry[%d] - VA (%X) is beyond the end of the image VA (%X)\n",
  587. i,
  588. DebugDirectory->AddressOfRawData,
  589. ImageFileSize);
  590. ImageOk = FALSE;
  591. goto BadPeImageSegment;
  592. }
  593. if ((DebugDirectory->AddressOfRawData + DebugDirectory->SizeOfData )> ImageFileSize){
  594. fprintf(stderr,
  595. "Invalid debug directory entry[%d] - VA (%X) + size (%X) is beyond the end of the image VA (%X)\n",
  596. i,
  597. DebugDirectory->AddressOfRawData,
  598. DebugDirectory->SizeOfData,
  599. ImageFileSize);
  600. ImageOk = FALSE;
  601. goto BadPeImageSegment;
  602. }
  603. }
  604. if (DebugDirectory->Type <= 0x7fffffff) {
  605. switch (DebugDirectory->Type) {
  606. case IMAGE_DEBUG_TYPE_MISC:
  607. {
  608. PIMAGE_DEBUG_MISC pDebugMisc;
  609. // MISC should point to an IMAGE_DEBUG_MISC structure
  610. pDebugMisc = (PIMAGE_DEBUG_MISC)((DWORD)ImageBase + DebugDirectory->PointerToRawData);
  611. if (pDebugMisc->DataType != IMAGE_DEBUG_MISC_EXENAME) {
  612. fprintf(stderr, "MISC Debug has an invalid DataType\n");
  613. ImageOk = FALSE;
  614. goto BadPeImageSegment;
  615. }
  616. if (pDebugMisc->Length != DebugDirectory->SizeOfData) {
  617. fprintf(stderr, "MISC Debug has an invalid size.\n");
  618. ImageOk = FALSE;
  619. goto BadPeImageSegment;
  620. }
  621. if (!pDebugMisc->Unicode) {
  622. i= 0;
  623. while (i < pDebugMisc->Length - sizeof(IMAGE_DEBUG_MISC)) {
  624. if (!isprint(pDebugMisc->Data[i]) &&
  625. (pDebugMisc->Data[i] != '\0') )
  626. {
  627. fprintf(stderr, "MISC Debug has unprintable characters... Possibly corrupt\n");
  628. ImageOk = FALSE;
  629. goto BadPeImageSegment;
  630. }
  631. i++;
  632. }
  633. // The data must be a null terminated string.
  634. if (strlen(pDebugMisc->Data) > (pDebugMisc->Length - sizeof(IMAGE_DEBUG_MISC))) {
  635. fprintf(stderr, "MISC Debug has invalid data... Possibly corrupt\n");
  636. ImageOk = FALSE;
  637. goto BadPeImageSegment;
  638. }
  639. }
  640. }
  641. break;
  642. case IMAGE_DEBUG_TYPE_CODEVIEW:
  643. // CV will point to either a NB09 or an NB10 signature. Make sure it does.
  644. {
  645. OMFSignature * CVDebug;
  646. CVDebug = (OMFSignature *)((DWORD)ImageBase + DebugDirectory->PointerToRawData);
  647. if (((*(PULONG)(CVDebug->Signature)) != '90BN') &&
  648. ((*(PULONG)(CVDebug->Signature)) != '01BN'))
  649. {
  650. fprintf(stderr, "CV Debug has an invalid signature\n");
  651. ImageOk = FALSE;
  652. goto BadPeImageSegment;
  653. }
  654. }
  655. break;
  656. case IMAGE_DEBUG_TYPE_COFF:
  657. case IMAGE_DEBUG_TYPE_FPO:
  658. case IMAGE_DEBUG_TYPE_EXCEPTION:
  659. case IMAGE_DEBUG_TYPE_FIXUP:
  660. case IMAGE_DEBUG_TYPE_OMAP_TO_SRC:
  661. case IMAGE_DEBUG_TYPE_OMAP_FROM_SRC:
  662. // Not much we can do about these now.
  663. break;
  664. default:
  665. fprintf(stderr, "Invalid debug directory type: %d\n", DebugDirectory->Type);
  666. ImageOk = FALSE;
  667. goto BadPeImageSegment;
  668. break;
  669. }
  670. }
  671. }
  672. }
  673. DebugDirsDone:
  674. //
  675. // The total number of PTEs was decremented as sections were built,
  676. // make sure that there are less than 64ks worth at this point.
  677. //
  678. if (NumberOfPtes >= (ImageAlignment >> PageShift)) {
  679. //
  680. // Inconsistent image, size does not agree with object tables.
  681. //
  682. fprintf(stderr, "invalid image - PTEs left %lx\n",
  683. NumberOfPtes);
  684. ImageOk = FALSE;
  685. goto BadPeImageSegment;
  686. }
  687. //
  688. // check checksum.
  689. //
  690. PeReturnSuccess:
  691. if (NtHeader->OptionalHeader.CheckSum == 0) {
  692. fprintf(stderr, "(checksum is zero) ");
  693. } else {
  694. __try {
  695. if (lpOldLdrVerifyImageMatchesChecksum != NULL)
  696. Status = (*lpOldLdrVerifyImageMatchesChecksum)(File);
  697. else
  698. Status = LdrVerifyImageMatchesChecksum (File, NULL, NULL, NULL);
  699. if (NT_ERROR(Status)) {
  700. fprintf(stderr, "checksum mismatch\n");
  701. ImageOk = FALSE;
  702. }
  703. } __except (EXCEPTION_EXECUTE_HANDLER) {
  704. ImageOk = FALSE;
  705. fprintf(stderr, "checksum mismatch\n");
  706. }
  707. }
  708. ImageOk = VerifyVersionResource(ImageName);
  709. NextImage:
  710. BadPeImageSegment:
  711. NeImage:
  712. if ( ImageOk ) {
  713. if (MachineTypeMismatch) {
  714. fprintf(stderr," OK [%s]\n", MachineType);
  715. } else {
  716. fprintf(stderr," OK\n");
  717. }
  718. }
  719. if ( File != INVALID_HANDLE_VALUE ) {
  720. CloseHandle(File);
  721. }
  722. if ( DosHeader ) {
  723. UnmapViewOfFile(DosHeader);
  724. }
  725. }
  726. NTSTATUS
  727. MiVerifyImageHeader (
  728. IN PIMAGE_NT_HEADERS NtHeader,
  729. IN PIMAGE_DOS_HEADER DosHeader,
  730. IN ULONG NtHeaderSize
  731. )
  732. /*++
  733. Routine Description:
  734. Checks image header for consistency.
  735. Arguments:
  736. Return Value:
  737. Returns the status value.
  738. TBS
  739. --*/
  740. {
  741. if ((NtHeader->FileHeader.Machine == 0) &&
  742. (NtHeader->FileHeader.SizeOfOptionalHeader == 0)) {
  743. //
  744. // This is a bogus DOS app which has a 32-bit portion
  745. // mascarading as a PE image.
  746. //
  747. fprintf(stderr, "Image machine type and size of optional header bad\n");
  748. return STATUS_INVALID_IMAGE_PROTECT;
  749. }
  750. if (!(NtHeader->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE)) {
  751. fprintf(stderr, "Characteristics not image file executable\n");
  752. return STATUS_INVALID_IMAGE_FORMAT;
  753. }
  754. #ifdef i386
  755. //
  756. // Make sure the image header is aligned on a Long word boundary.
  757. //
  758. if (((ULONG)NtHeader & 3) != 0) {
  759. fprintf(stderr, "NtHeader is not aligned on longword boundary\n");
  760. return STATUS_INVALID_IMAGE_FORMAT;
  761. }
  762. #endif
  763. // Non-driver code must have file alignment set to a multiple of 512
  764. if (((NtHeader->OptionalHeader.FileAlignment & 511) != 0) &&
  765. (NtHeader->OptionalHeader.FileAlignment !=
  766. NtHeader->OptionalHeader.SectionAlignment)) {
  767. fprintf(stderr, "file alignment is not multiple of 512 and power of 2\n");
  768. return STATUS_INVALID_IMAGE_FORMAT;
  769. }
  770. //
  771. // File aligment must be power of 2.
  772. //
  773. if ((((NtHeader->OptionalHeader.FileAlignment << 1) - 1) &
  774. NtHeader->OptionalHeader.FileAlignment) !=
  775. NtHeader->OptionalHeader.FileAlignment) {
  776. fprintf(stderr, "file alignment not power of 2\n");
  777. return STATUS_INVALID_IMAGE_FORMAT;
  778. }
  779. if (NtHeader->OptionalHeader.SectionAlignment < NtHeader->OptionalHeader.FileAlignment) {
  780. fprintf(stderr, "SectionAlignment < FileAlignment\n");
  781. return STATUS_INVALID_IMAGE_FORMAT;
  782. }
  783. if (NtHeader->OptionalHeader.SizeOfImage > MM_SIZE_OF_LARGEST_IMAGE) {
  784. fprintf(stderr, "Image too big %lx\n",NtHeader->OptionalHeader.SizeOfImage);
  785. return STATUS_INVALID_IMAGE_FORMAT;
  786. }
  787. if (NtHeader->FileHeader.NumberOfSections > MM_MAXIMUM_IMAGE_SECTIONS) {
  788. fprintf(stderr, "Too many image sections %ld.\n",
  789. NtHeader->FileHeader.NumberOfSections);
  790. return STATUS_INVALID_IMAGE_FORMAT;
  791. }
  792. if (fcheckbase) {
  793. if ((PVOID)NtHeader->OptionalHeader.ImageBase >= MM_HIGHEST_USER_ADDRESS) {
  794. fprintf(stderr, "Image base is invalid %lx\n",
  795. NtHeader->OptionalHeader.ImageBase);
  796. return STATUS_INVALID_IMAGE_FORMAT;
  797. }
  798. }
  799. return STATUS_SUCCESS;
  800. }
  801. VOID
  802. ParseArgs(
  803. int *pargc,
  804. char **argv
  805. )
  806. {
  807. CHAR cswitch, c, *p;
  808. CHAR sztmp[MAX_PATH];
  809. int argnum = 1, i=0, len=0, count=0;
  810. BOOL fslashfound = FALSE;
  811. while ( argnum < *pargc ) {
  812. _strlwr(argv[argnum]);
  813. cswitch = *(argv[argnum]+1);
  814. if (cswitch == '/' || cswitch == '-') {
  815. c = *(argv[argnum]+2);
  816. switch (c) {
  817. case '?':
  818. Usage();
  819. case 'r':
  820. fRecurse = TRUE;
  821. if (argv[argnum+1]) {
  822. fPathOverride=TRUE;
  823. strcpy(szDirectory, (argv[argnum+1]+1));
  824. if (!(strcmp(szDirectory, "\\"))) { // if just '\'
  825. fSingleSlash=TRUE;
  826. }
  827. //fprintf(stdout, "dir %s\n", szDirectory);
  828. argnum++;
  829. }
  830. break;
  831. case 'b':
  832. fcheckbase = FALSE;
  833. break;
  834. default:
  835. fprintf(stderr, "Invalid argument.\n");
  836. Usage();
  837. }
  838. } else {
  839. // Check for path\filename or wildcards
  840. // begin at argv[argnum]+1 because first char is repeated
  841. // Search for '\' in string
  842. strcpy(sztmp, (argv[argnum]+1));
  843. len = strlen(sztmp);
  844. for (i=0; i < len; i++) {
  845. if (sztmp[i]=='\\') {
  846. count++;
  847. endpath=i; // mark last '\' char found
  848. fslashfound=TRUE; // found backslash, so must be a path\filename combination
  849. }
  850. }
  851. if (fslashfound && !fRecurse) { // if backslash found and not a recursive operation
  852. // seperate the directory and filename into two strings
  853. fPathOverride=TRUE;
  854. strcpy(szDirectory, sztmp);
  855. if (!(strcmp(szDirectory, "\\"))) {
  856. Usage();
  857. }
  858. szFileName = _strdup(&(sztmp[endpath+1]));
  859. if (count == 1) { //&& szDirectory[1] == ':') { // if only one '\' char and drive letter indicated
  860. fSingleSlash=TRUE;
  861. szDirectory[endpath+1]='\0'; // keep trailing '\' in order to chdir properly
  862. } else {
  863. szDirectory[endpath]='\0';
  864. }
  865. if (szFileName[0] == '*' && szFileName[1] == '.' && szFileName[2] != '*') {
  866. _strlwr(szFileName);
  867. szPattern = strchr(szFileName, 46); //search for '.'
  868. fPattern = TRUE;
  869. }
  870. } else { // no backslash found, assume filename without preceeding path
  871. //
  872. // filename or wildcard
  873. //
  874. if ( (*(argv[argnum]+1) == '*') && (*(argv[argnum]+2) == '.') && (*(argv[argnum]+3) != '*') ){
  875. // *.xxx
  876. szFileName = _strdup(argv[argnum]+1);
  877. _strlwr(szFileName);
  878. szPattern = strchr(szFileName, 46); //search for '.'
  879. fPattern = TRUE;
  880. } else if ( (*(argv[argnum]+1) == '*') && (*(argv[argnum]+2) == '.') && (*(argv[argnum]+3) == '*') ) {
  881. // *.*
  882. strcpy(szFileName, "*.*");
  883. } else {
  884. // probably a single filename
  885. szFileName = _strdup(argv[argnum]+1);
  886. _strlwr(szFileName);
  887. fSingleFile = TRUE;
  888. }
  889. if (fRecurse && strchr(szFileName, 92) ) { // don't want path\filename when recursing
  890. Usage();
  891. }
  892. }
  893. //fprintf(stdout, "dir %s\nfile %s\n", szDirectory, szFileName);
  894. }
  895. ++argnum;
  896. }
  897. if (szFileName[0] == '\0') {
  898. Usage();
  899. }
  900. } // parseargs
  901. /********************************************************************************************\
  902. * CompFileAndDir
  903. * Purpose: a comparision routine passed to QSort. It compares elem1 and elem2
  904. * based upon their attribute, i.e., is it a file or directory.
  905. \********************************************************************************************/
  906. int __cdecl
  907. CompFileAndDir(
  908. const void *elem1,
  909. const void *elem2
  910. )
  911. {
  912. pList p1, p2;
  913. // qsort passes a void universal pointer. Use a typecast (List**)
  914. // so the compiler recognizes the data as a List structure.
  915. // Typecast pointer-to-pointer-to-List and dereference ONCE
  916. // leaving a pList. I don't dereference the remaining pointer
  917. // in the p1 and p2 definitions to avoid copying the structure.
  918. p1 = (*(List**)elem1);
  919. p2 = (*(List**)elem2);
  920. if ( (p1->Attributes & FILE_ATTRIBUTE_DIRECTORY) && (p2->Attributes & FILE_ATTRIBUTE_DIRECTORY))
  921. return 0;
  922. //both dirs
  923. if (!(p1->Attributes & FILE_ATTRIBUTE_DIRECTORY) && !(p2->Attributes & FILE_ATTRIBUTE_DIRECTORY))
  924. return 0;
  925. //both files
  926. if ( (p1->Attributes & FILE_ATTRIBUTE_DIRECTORY) && !(p2->Attributes & FILE_ATTRIBUTE_DIRECTORY))
  927. return 1;
  928. // elem1 is dir and elem2 is file
  929. if (!(p1->Attributes & FILE_ATTRIBUTE_DIRECTORY) && (p2->Attributes & FILE_ATTRIBUTE_DIRECTORY))
  930. return -1;
  931. // elem1 is file and elem2 is dir
  932. return 0; // if none of the above
  933. }
  934. /********************************************************************************************\
  935. * CompName is another compare routine passed to QSort that compares the two Name strings *
  936. \********************************************************************************************/
  937. int __cdecl
  938. CompName(
  939. const void *elem1,
  940. const void *elem2
  941. )
  942. {
  943. return strcmp( (*(List**)elem1)->Name, (*(List**)elem2)->Name );
  944. }
  945. LPSTR pszUsage =
  946. "Usage: imagechk [/?] displays this message\n"
  947. " [/r dir] recurse from directory dir\n"
  948. " [/b] don't check image base address\n"
  949. " [filename] file to check\n"
  950. " Accepts wildcard extensions such as *.exe\n"
  951. " imagechk /r . *.exe check all *.exe recursing on current directory\n"
  952. " imagechk /r \\ *.exe check all *.exe recursing from root of current drive\n"
  953. " imagechk *.exe check all *.exe in current directory\n"
  954. " imagechk c:\\bar.exe check c:\\bar.exe only\n"
  955. "";
  956. VOID
  957. Usage(VOID)
  958. {
  959. fprintf(stderr, pszUsage);
  960. exit(1);
  961. }
  962. int __cdecl
  963. _cwild()
  964. {
  965. return(0);
  966. }
  967. typedef DWORD (WINAPI *PFNGVS)(LPSTR, LPDWORD);
  968. BOOL
  969. VerifyVersionResource(
  970. PCHAR FileName
  971. )
  972. {
  973. HINSTANCE hVersion;
  974. PFNGVS pfnGetFileVersionInfoSize;
  975. DWORD dwSize;
  976. DWORD dwReturn;
  977. BOOL rc;
  978. hVersion = LoadLibraryA("VERSION.DLL");
  979. if (hVersion == NULL) {
  980. return TRUE;
  981. }
  982. pfnGetFileVersionInfoSize = (PFNGVS) GetProcAddress(hVersion, "GetFileVersionInfoSizeA");
  983. if (pfnGetFileVersionInfoSize == NULL) {
  984. FreeLibrary(hVersion);
  985. return TRUE;
  986. }
  987. if ((dwReturn = (*pfnGetFileVersionInfoSize)(FileName, &dwSize)) == 0) {
  988. fprintf(stderr, "No version resource detected\n");
  989. rc = FALSE;
  990. } else {
  991. rc = TRUE;
  992. }
  993. FreeLibrary(hVersion);
  994. return(rc);
  995. }