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.

698 lines
22 KiB

  1. /* dlcheck - verify that a DLL using delay-load calls APIs that have
  2. * stubs in kernel32.dll (aka dload.lib)
  3. *
  4. * HISTORY:
  5. * 25-Nov-98 barrybo Wrote it.
  6. */
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <windows.h>
  10. #include <imagehlp.h>
  11. #include <delayimp.h>
  12. #include <dloaddef.h>
  13. #include <shlwapi.h>
  14. #include <strsafe.h>
  15. #define ARRAYSIZE(x) (sizeof(x) / sizeof(x[0]))
  16. // Function Forward Parameters...
  17. void Usage( void );
  18. int __cdecl main( int, char ** );
  19. int DloadBreakOnFail = FALSE;
  20. extern int DloadDbgPrint = FALSE;
  21. // implemented in kernel32p.lib
  22. FARPROC
  23. WINAPI
  24. DelayLoadFailureHook (
  25. LPCSTR pszDllName,
  26. LPCSTR pszProcName
  27. );
  28. typedef FARPROC (WINAPI *PfnKernel32HookProc)(
  29. LPCSTR pszDllName,
  30. LPCSTR pszProcName
  31. );
  32. PfnKernel32HookProc __pfnFailureProc = DelayLoadFailureHook;
  33. const char rgstrUsage[] = {
  34. "Verify that delayloaded imports all have failure handlers in kernel32.\n"
  35. "usage: dlcheck [switches] image-name\n"
  36. "where: [-?] display this message\n"
  37. " [-l] use the live version of kernel32.dll on the machine\n"
  38. " [-s] use the static dload.lib linked into dlcheck\n"
  39. " [-t] test the static dload.lib linked into dlcheck and exit\n"
  40. " [-i <inifile>] use the information in inifile to check a binary\n"
  41. " [-f] force check the binary (assumes -s)\n"
  42. "\n"
  43. };
  44. HANDLE BaseDllHandle;
  45. PLOADED_IMAGE g_pli;
  46. PIMAGE_SECTION_HEADER g_DelaySection;
  47. //
  48. // Convert an absolute pointer that points into the image if the image
  49. // was loaded as a DLL at its preferred base, into a pointer into the
  50. // DLL as it was mapped by imagehlp.
  51. //
  52. void *
  53. ConvertImagePointer(void * p)
  54. {
  55. if (!p) {
  56. return NULL;
  57. } else {
  58. return (void *)((ULONG_PTR)(p) -
  59. (ULONG_PTR)g_pli->FileHeader->OptionalHeader.ImageBase +
  60. (ULONG_PTR)g_pli->MappedAddress -
  61. (ULONG_PTR)g_DelaySection->VirtualAddress +
  62. (ULONG_PTR)g_DelaySection->PointerToRawData);
  63. }
  64. }
  65. void *
  66. RvaToPtr(DWORD_PTR rva)
  67. {
  68. DWORD i;
  69. PIMAGE_SECTION_HEADER pSect;
  70. if (!rva)
  71. return NULL;
  72. for (i = 0; i < g_pli->NumberOfSections; i++) {
  73. pSect = g_pli->Sections+i;
  74. if (rva >= g_pli->Sections[i].VirtualAddress &&
  75. rva <= (g_pli->Sections[i].VirtualAddress + g_pli->Sections[i].Misc.VirtualSize))
  76. {
  77. return (PVOID)
  78. (g_pli->MappedAddress +
  79. g_pli->Sections[i].PointerToRawData +
  80. (rva - g_pli->Sections[i].VirtualAddress));
  81. }
  82. }
  83. return NULL;
  84. }
  85. void Usage( void )
  86. {
  87. puts(rgstrUsage);
  88. exit (1);
  89. }
  90. BOOLEAN ImageLinksToKernel32Handler( void )
  91. {
  92. PIMAGE_IMPORT_DESCRIPTOR Imports;
  93. ULONG ImportSize;
  94. PULONG_PTR pIAT;
  95. PIMAGE_IMPORT_BY_NAME pImport;
  96. Imports = (PIMAGE_IMPORT_DESCRIPTOR)
  97. ImageDirectoryEntryToData(g_pli->MappedAddress,
  98. FALSE,
  99. IMAGE_DIRECTORY_ENTRY_IMPORT,
  100. &ImportSize
  101. );
  102. if (!Imports) {
  103. // Image has delayload imports, but no true imports.
  104. return FALSE;
  105. }
  106. while (Imports->Name) {
  107. char *szName;
  108. szName = ImageRvaToVa(g_pli->FileHeader, (PVOID)g_pli->MappedAddress, Imports->Name, NULL);
  109. if (szName && _stricmp(szName, "KERNEL32.DLL") == 0) {
  110. pIAT = ImageRvaToVa(g_pli->FileHeader,
  111. (PVOID)g_pli->MappedAddress,
  112. Imports->OriginalFirstThunk,
  113. NULL);
  114. while (pIAT && *pIAT) {
  115. pImport = ImageRvaToVa(g_pli->FileHeader,
  116. (PVOID)g_pli->MappedAddress,
  117. (ULONG) *pIAT,
  118. NULL);
  119. if (pImport && _stricmp(pImport->Name, "DelayLoadFailureHook") == 0) {
  120. return TRUE;
  121. }
  122. pIAT++;
  123. }
  124. }
  125. Imports++;
  126. }
  127. return FALSE;
  128. }
  129. //
  130. // Validate that the statically-linked delayload stub table is not
  131. // blatantly broken. The most common error is not listing the functions
  132. // in the correct order so the binary search fails.
  133. //
  134. int ValidateStaticDelayloadStubs()
  135. {
  136. extern const DLOAD_DLL_MAP g_DllMap;
  137. UINT i, j;
  138. int Errors = 0;
  139. //
  140. // Ensure that the DLL map is in alphabetical order.
  141. //
  142. for (i = 1; i < g_DllMap.NumberOfEntries; i++)
  143. {
  144. if (strcmp(g_DllMap.pDllEntry[i-1].pszDll,
  145. g_DllMap.pDllEntry[i].pszDll) >= 0)
  146. {
  147. fprintf(stderr, "DLCHECK : error DL000001 : Static delayload table is corrupted\n"
  148. " %s and %s not in alphabetical order\n",
  149. g_DllMap.pDllEntry[i-1].pszDll,
  150. g_DllMap.pDllEntry[i].pszDll);
  151. Errors = 1;
  152. }
  153. }
  154. // For each DLL...
  155. for (i = 0; i < g_DllMap.NumberOfEntries; i++)
  156. {
  157. const DLOAD_DLL_ENTRY *pEntry = &g_DllMap.pDllEntry[i];
  158. //
  159. // Name must be lowercase.
  160. //
  161. char szLower[MAX_PATH];
  162. StringCchCopy(szLower, ARRAYSIZE(szLower), pEntry->pszDll);
  163. _strlwr(szLower);
  164. if (strcmp(szLower, pEntry->pszDll) != 0)
  165. {
  166. fprintf(stderr, "DLCHECK : error DL000002 : Static delayload table is corrupted\n"
  167. " %s must be all-lowercase\n",
  168. pEntry->pszDll);
  169. Errors = 1;
  170. }
  171. //
  172. // Ensure that the exports are in alphabetical order
  173. //
  174. {
  175. const DLOAD_PROCNAME_MAP *pProcNameMap = pEntry->pProcNameMap;
  176. if (pProcNameMap)
  177. {
  178. const DLOAD_PROCNAME_ENTRY *pProcNameEntry = pProcNameMap->pProcNameEntry;
  179. for (j = 1; j < pProcNameMap->NumberOfEntries; j++)
  180. {
  181. if (strcmp(pProcNameEntry[j-1].pszProcName,
  182. pProcNameEntry[j].pszProcName) >= 0)
  183. {
  184. fprintf(stderr, "DLCHECK : error DL000003 : Static delayload table is corrupted\n"
  185. " %s.%s and %s.%s not in alphabetical order\n",
  186. g_DllMap.pDllEntry[i].pszDll,
  187. pProcNameEntry[j-1].pszProcName,
  188. g_DllMap.pDllEntry[i].pszDll,
  189. pProcNameEntry[j].pszProcName);
  190. Errors = 1;
  191. }
  192. }
  193. }
  194. }
  195. //
  196. // Ensure that the ordinals are in alphabetical order
  197. //
  198. {
  199. const DLOAD_ORDINAL_MAP *pOrdinalMap = pEntry->pOrdinalMap;
  200. if (pOrdinalMap)
  201. {
  202. const DLOAD_ORDINAL_ENTRY *pOrdinalEntry = pOrdinalMap->pOrdinalEntry;
  203. for (j = 1; j < pOrdinalMap->NumberOfEntries; j++)
  204. {
  205. if (pOrdinalEntry[j-1].dwOrdinal >= pOrdinalEntry[j].dwOrdinal)
  206. {
  207. fprintf(stderr, "DLCHECK : error DL000001 : Static delayload table is corrupted\n"
  208. " %s.%d and %s.%d not in numeric order\n",
  209. g_DllMap.pDllEntry[i].pszDll,
  210. pOrdinalEntry[j-1].dwOrdinal,
  211. g_DllMap.pDllEntry[i].pszDll,
  212. pOrdinalEntry[j-1].dwOrdinal);
  213. Errors = 1;
  214. }
  215. }
  216. }
  217. }
  218. }
  219. return Errors;
  220. }
  221. int CheckImage(char *szImageName, BOOL fForceCheckImage)
  222. {
  223. PImgDelayDescr Imports;
  224. ULONG ImportSize;
  225. char *szName;
  226. PIMAGE_THUNK_DATA pINT;
  227. DelayLoadInfo dlinfo;
  228. FARPROC fp;
  229. int ReturnValue;
  230. BOOL fCallHandler;
  231. BOOL fPE32;
  232. g_pli = ImageLoad(szImageName, NULL);
  233. if (!g_pli) {
  234. fprintf(stderr, "DLCHECK : fatal error %d: loading '%s'\n", GetLastError(), szImageName);
  235. return 1;
  236. }
  237. Imports = (PImgDelayDescr)
  238. ImageDirectoryEntryToDataEx(g_pli->MappedAddress,
  239. FALSE,
  240. IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT,
  241. &ImportSize,
  242. &g_DelaySection
  243. );
  244. if (!Imports) {
  245. fprintf(stdout, "DLCHECK : warning DL000000: image '%s' has no delayload imports\n", szImageName);
  246. return 0;
  247. }
  248. fPE32 = g_pli->FileHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC ? TRUE : FALSE;
  249. if (fForceCheckImage)
  250. {
  251. fCallHandler = TRUE;
  252. }
  253. else
  254. {
  255. fCallHandler = ImageLinksToKernel32Handler();
  256. }
  257. if (!fCallHandler) {
  258. fprintf(stderr, "DLCHECK : fatal errror : image '%s' doesn't import kernel32!DelayLoadFailureHook.\n"
  259. "(use -f option to override)\n"
  260. "\n", szImageName);
  261. return 1;
  262. }
  263. //
  264. // Walk each delayloaded DLL
  265. //
  266. ReturnValue = 0; // assume success
  267. if (Imports->grAttrs & dlattrRva) {
  268. PImgDelayDescrV2 pImportsV2 = (PImgDelayDescrV2)Imports;
  269. szName = (char *)RvaToPtr(pImportsV2->rvaDLLName);
  270. pINT = (PIMAGE_THUNK_DATA)RvaToPtr(pImportsV2->rvaINT);
  271. } else {
  272. PImgDelayDescrV1 pImportsV1 = (PImgDelayDescrV1)Imports;
  273. szName = (char *)ConvertImagePointer((void *)pImportsV1->szName);
  274. pINT = (PIMAGE_THUNK_DATA)ConvertImagePointer((void *)pImportsV1->pINT);
  275. }
  276. while (szName) {
  277. // printf("DelayLoad DLL %s\n", szName);
  278. char szModuleName[MAX_PATH];
  279. char szImportName[MAX_PATH];
  280. {
  281. char* p;
  282. // change "module.dll" to just "module"
  283. StringCchCopy(szModuleName, ARRAYSIZE(szModuleName), szName);
  284. p = szModuleName;
  285. while (*p != '\0')
  286. {
  287. if (*p == '.')
  288. {
  289. *p = '\0';
  290. break;
  291. }
  292. p++;
  293. }
  294. }
  295. //
  296. // Walk each function called from the delayloaded DLL
  297. //
  298. while (pINT->u1.AddressOfData) {
  299. dlinfo.cb = sizeof(dlinfo);
  300. dlinfo.pidd = NULL;
  301. dlinfo.ppfn = NULL;
  302. dlinfo.szDll = szName;
  303. dlinfo.pfnCur = NULL;
  304. dlinfo.dwLastError = ERROR_NOT_ENOUGH_MEMORY;
  305. dlinfo.dlp.szProcName = NULL; // Make sure the upper 32 bits are zeroed out on win64.
  306. if (
  307. ( fPE32 && IMAGE_SNAP_BY_ORDINAL32(((PIMAGE_THUNK_DATA32)pINT)->u1.AddressOfData)) ||
  308. (!fPE32 && IMAGE_SNAP_BY_ORDINAL64(((PIMAGE_THUNK_DATA64)pINT)->u1.AddressOfData))
  309. )
  310. {
  311. StringCchPrintf(szImportName, ARRAYSIZE(szImportName), TEXT("Ordinal%d"), IMAGE_ORDINAL(pINT->u1.AddressOfData));
  312. dlinfo.dlp.fImportByName = FALSE;
  313. dlinfo.dlp.dwOrdinal = IMAGE_ORDINAL((ULONG)pINT->u1.AddressOfData);
  314. } else {
  315. PIMAGE_IMPORT_BY_NAME pImport;
  316. if (Imports->grAttrs & dlattrRva) {
  317. pImport = (PIMAGE_IMPORT_BY_NAME)RvaToPtr(pINT->u1.AddressOfData);
  318. } else {
  319. pImport = (PIMAGE_IMPORT_BY_NAME)ConvertImagePointer((void *)pINT->u1.AddressOfData);
  320. }
  321. StringCchCopy(szImportName, ARRAYSIZE(szImportName), pImport->Name);
  322. dlinfo.dlp.fImportByName = TRUE;
  323. dlinfo.dlp.szProcName = pImport->Name;
  324. }
  325. if (fCallHandler) {
  326. //
  327. // Call the delayload handler and see what it does.
  328. //
  329. try {
  330. fp = (*__pfnFailureProc)(dlinfo.szDll, dlinfo.dlp.szProcName);
  331. if (!fp) {
  332. fprintf(stderr, "DLCHECK : error DL000000: %s imports %s!%s which is not handled.\n", szImageName, szModuleName, szImportName);
  333. ReturnValue = 1;
  334. } else {
  335. // printing success takes too much time
  336. // printf("DLCHECK : %s imports %s!%s - OK.\n", szImageName, szModuleName, szImportName);
  337. }
  338. } except (EXCEPTION_EXECUTE_HANDLER) {
  339. fprintf(stderr, "DLCHECK : error %x: %s imports %s!%s - handler threw an exception.\n", GetExceptionCode(), szImageName, szModuleName, szImportName);
  340. ReturnValue = 1;
  341. }
  342. }
  343. else
  344. {
  345. printf("DLCHECK : %s imports %s!%s - not checked.\n", szImageName, szModuleName, szImportName);
  346. }
  347. if (fPE32) {
  348. pINT = (PIMAGE_THUNK_DATA)(((PIMAGE_THUNK_DATA32)pINT)++);
  349. } else {
  350. pINT = (PIMAGE_THUNK_DATA)(((PIMAGE_THUNK_DATA64)pINT)++);
  351. }
  352. }
  353. if (Imports->grAttrs & dlattrRva) {
  354. PImgDelayDescrV2 pImportsV2 = (PImgDelayDescrV2)Imports;
  355. pImportsV2++;
  356. Imports = (PImgDelayDescr)pImportsV2;
  357. szName = (char *)RvaToPtr(pImportsV2->rvaDLLName);
  358. pINT = (PIMAGE_THUNK_DATA)RvaToPtr(pImportsV2->rvaINT);
  359. } else {
  360. PImgDelayDescrV1 pImportsV1 = (PImgDelayDescrV1)Imports;
  361. pImportsV1++;
  362. Imports = (PImgDelayDescr)pImportsV1;
  363. szName = (char *)ConvertImagePointer((void *)pImportsV1->szName);
  364. pINT = (PIMAGE_THUNK_DATA)ConvertImagePointer((void *)pImportsV1->pINT);
  365. }
  366. }
  367. if (ReturnValue == 0)
  368. {
  369. printf("DLCHECK : succeeded on %s\n", szImageName);
  370. }
  371. else
  372. {
  373. fprintf(stderr, "DLCHECK : failed on %s\n", szImageName);
  374. }
  375. return ReturnValue;
  376. }
  377. int CheckIniFile(char *pszFile, BOOL fForceCheckImage)
  378. {
  379. char szIniFile[MAX_PATH];
  380. char szTemp[MAX_PATH];
  381. char szTemp2[MAX_PATH];
  382. char szImageName[MAX_PATH];
  383. char szDelayLoadHandler[MAX_PATH];
  384. int ReturnValue;
  385. LPTSTR psz;
  386. if ((GetFullPathName(pszFile, ARRAYSIZE(szIniFile), szIniFile, &psz) == 0) ||
  387. (GetPrivateProfileString("Default",
  388. "DelayLoadHandler",
  389. "",
  390. szDelayLoadHandler,
  391. ARRAYSIZE(szDelayLoadHandler),
  392. szIniFile) == 0))
  393. {
  394. fprintf(stderr, "DLCHECK : fatal error : failed to load %s\n", szIniFile);
  395. return 1;
  396. }
  397. // foomodule.dll.ini -> foomodule.dll
  398. StringCchCopy(szImageName, ARRAYSIZE(szImageName), psz);
  399. _strlwr(szImageName);
  400. psz = strstr(szImageName, ".ini");
  401. if (psz)
  402. {
  403. *psz = '\0';
  404. }
  405. if (_stricmp(szDelayLoadHandler, "FORCE") == 0)
  406. {
  407. // if the delayload handler is set to FORCE, we check the binary as if it were
  408. // using kernel32
  409. fForceCheckImage = TRUE;
  410. }
  411. if ((_stricmp(szDelayLoadHandler, "kernel32") != 0) &&
  412. (_stricmp(szDelayLoadHandler, "FORCE") != 0))
  413. {
  414. // currently only able to check dll's who use kernel32.dll for their delayload handler
  415. fprintf(stdout, "DLCHECK : warning DL000000 : Unable to check delayload failure behavior\n"
  416. " %s uses %s as a handler, not kernel32\n", szImageName, szDelayLoadHandler);
  417. return 0;
  418. }
  419. // foomodule.dll -> d:\binaries.x86chk\foomodule.dll
  420. if (ExpandEnvironmentStrings("%_NTPostBld%", szTemp, ARRAYSIZE(szTemp)) == 0)
  421. {
  422. fprintf(stderr, "DLCHECK : fatal error : _NTPostBld environment variable not set\n");
  423. return 1;
  424. }
  425. if (GetPrivateProfileString("Default",
  426. "DestinationDir",
  427. "",
  428. szTemp2,
  429. ARRAYSIZE(szTemp2),
  430. szIniFile) == 0)
  431. {
  432. fprintf(stderr, "DLCHECK : fatal error : failed to read 'DestinationDir' from %s\n", szIniFile);
  433. return 1;
  434. }
  435. StringCchCat(szTemp, ARRAYSIZE(szTemp), TEXT("\\"));
  436. StringCchCat(szTemp, ARRAYSIZE(szTemp), szTemp2);
  437. StringCchCat(szTemp, ARRAYSIZE(szTemp), szImageName);
  438. GetFullPathName(szTemp, ARRAYSIZE(szImageName), szImageName, NULL);
  439. // Heck, lets always validate the static delay load stubs, its fast
  440. ReturnValue = ValidateStaticDelayloadStubs();
  441. if (szImageName[0] != '\0')
  442. {
  443. ReturnValue += CheckImage(szImageName, fForceCheckImage);
  444. }
  445. return ReturnValue;
  446. }
  447. BOOL PathIsDotOrDotDot(LPCSTR pszPath)
  448. {
  449. return ((pszPath[0] == '.') &&
  450. ((pszPath[1] == '\0') || ((pszPath[1] == '.') && (pszPath[2] == '\0'))));
  451. }
  452. BOOL PathIsWild(LPCSTR pszPath)
  453. {
  454. while (*pszPath)
  455. {
  456. if (*pszPath == TEXT('?') || *pszPath == TEXT('*'))
  457. return TRUE;
  458. pszPath = CharNext(pszPath);
  459. }
  460. return FALSE;
  461. }
  462. int CheckImageOrIniFileRecursive(char *szName, BOOL fForceCheckImage, BOOL fIniFile, int *piFiles)
  463. {
  464. HANDLE hfind;
  465. WIN32_FIND_DATA fd;
  466. char szPathName[MAX_PATH];
  467. char *pszFileSpec;
  468. int ReturnValue = 0;
  469. pszFileSpec = PathFindFileName(szName);
  470. // First find all files that match the file spec, ignoring directories
  471. hfind = FindFirstFile(szName, &fd);
  472. if (hfind != INVALID_HANDLE_VALUE)
  473. {
  474. do {
  475. if (!PathIsDotOrDotDot(fd.cFileName))
  476. {
  477. StrCpyN(szPathName, szName, sizeof(szPathName));
  478. PathRemoveFileSpec(szPathName);
  479. PathAppend(szPathName, fd.cFileName);
  480. if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  481. {
  482. // Ignore directories
  483. }
  484. else
  485. {
  486. (*piFiles)++;
  487. if (fIniFile)
  488. {
  489. ReturnValue += CheckIniFile(szPathName, fForceCheckImage);
  490. }
  491. else
  492. {
  493. ReturnValue += CheckImage(szPathName, fForceCheckImage);
  494. }
  495. }
  496. }
  497. } while (FindNextFile(hfind, &fd));
  498. FindClose(hfind);
  499. }
  500. if (PathIsWild(szName))
  501. {
  502. char szPathSearch[MAX_PATH];
  503. // Now do all directories
  504. StrCpyN(szPathSearch,szName,sizeof(szPathSearch));
  505. PathRemoveFileSpec(szPathSearch);
  506. PathAppend(szPathSearch,"*.*");
  507. hfind = FindFirstFile(szPathSearch, &fd);
  508. if (hfind != INVALID_HANDLE_VALUE)
  509. {
  510. do {
  511. if (!PathIsDotOrDotDot(fd.cFileName))
  512. {
  513. StrCpyN(szPathName, szPathSearch, sizeof(szPathName));
  514. PathRemoveFileSpec(szPathName);
  515. PathAppend(szPathName, fd.cFileName);
  516. if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  517. {
  518. PathAppend(szPathName,pszFileSpec);
  519. ReturnValue += CheckImageOrIniFileRecursive(szPathName, fForceCheckImage, fIniFile, piFiles);
  520. }
  521. else
  522. {
  523. // Only process directories
  524. }
  525. }
  526. } while (FindNextFile(hfind, &fd));
  527. FindClose(hfind);
  528. }
  529. }
  530. return ReturnValue;
  531. }
  532. int
  533. __cdecl
  534. main (
  535. int c,
  536. char *v[]
  537. )
  538. {
  539. int ReturnValue;
  540. BOOL fIniFile = FALSE;
  541. char szImageName[MAX_PATH];
  542. BOOL fForceCheckImage = FALSE;
  543. if (c < 2) {
  544. Usage();
  545. }
  546. if (*v[1] == '-' || *v[1] == '/') {
  547. switch ( *(v[1]+1) ) {
  548. case 's':
  549. case 'S':
  550. if (c != 3) {
  551. Usage();
  552. }
  553. StringCchCopy(szImageName, ARRAYSIZE(szImageName), v[2]);
  554. break; // nothing needs to be done.
  555. case 'l':
  556. case 'L':
  557. __pfnFailureProc = (PfnKernel32HookProc)GetProcAddress(GetModuleHandleA("kernel32.dll"), "DelayLoadFailureHook");
  558. if (!__pfnFailureProc) {
  559. fprintf(stderr, "DLCHECK : fatal error %d: looking up kernel32 delayload hook\n", GetLastError());
  560. return 1;
  561. }
  562. if (c != 3) {
  563. Usage();
  564. }
  565. StringCchCopy(szImageName, ARRAYSIZE(szImageName), v[2]);
  566. break;
  567. case 'i':
  568. case 'I':
  569. if (c != 3) {
  570. Usage();
  571. }
  572. fIniFile = TRUE;
  573. StringCchCopy(szImageName, ARRAYSIZE(szImageName), v[2]);
  574. break;
  575. case 't':
  576. case 'T':
  577. if (c != 2) {
  578. Usage();
  579. }
  580. StringCchCopy(szImageName, ARRAYSIZE(szImageName), "");
  581. break;
  582. case 'f':
  583. case 'F':
  584. if (c != 3)
  585. {
  586. Usage();
  587. }
  588. fForceCheckImage = TRUE;
  589. StringCchCopy(szImageName, ARRAYSIZE(szImageName), v[2]);
  590. break; // nothing needs to be done.
  591. default:
  592. Usage();
  593. }
  594. } else {
  595. Usage();
  596. }
  597. // Heck, lets always validate the static delay load stubs, its fast
  598. ReturnValue = ValidateStaticDelayloadStubs();
  599. if (szImageName[0] != '\0')
  600. {
  601. int iFiles = 0;
  602. ReturnValue += CheckImageOrIniFileRecursive(szImageName, fForceCheckImage, fIniFile, &iFiles);
  603. if (iFiles == 0)
  604. {
  605. fprintf(stderr, "DLCHECK : fatal error : no files found to process\n");
  606. }
  607. }
  608. return ReturnValue;
  609. }