Source code of Windows XP (NT5)
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.

1293 lines
46 KiB

  1. #include <objbase.h>
  2. #include <delayimp.h>
  3. #include "depends.h"
  4. #include "resource.h"
  5. // stuff for finding out architecture type of a file
  6. #define IMAGE_BASE_TO_DOS_HEADER(b) ((PIMAGE_DOS_HEADER)(b))
  7. #define IMAGE_BASE_TO_NT_HEADERS(b) ((PIMAGE_NT_HEADERS)( (DWORD_PTR)(b) + ((PIMAGE_DOS_HEADER)(b))->e_lfanew ))
  8. #define IMAGE_BASE_TO_FILE_HEADER(b) ((PIMAGE_FILE_HEADER)( &IMAGE_BASE_TO_NT_HEADERS(b)->FileHeader ))
  9. //******************************************************************************
  10. // CDepends :: Constructor/Destructor
  11. //******************************************************************************
  12. CDepends::CDepends() :
  13. m_hFile(NULL),
  14. m_lpvFile(NULL),
  15. m_pIFH(NULL),
  16. m_pIOH(NULL),
  17. m_pISH(NULL),
  18. m_fOutOfMemory(FALSE),
  19. m_fCircularError(FALSE),
  20. m_fMixedMachineError(FALSE),
  21. m_dwMachineType((DWORD)-1),
  22. m_pModuleRoot(NULL),
  23. m_cxOrdinal(0),
  24. m_cxHint(0),
  25. m_cImports(0),
  26. m_cExports(0)
  27. {
  28. }
  29. //******************************************************************************
  30. CDepends::~CDepends() {
  31. }
  32. //******************************************************************************
  33. BOOL CDepends::SetInitialFilename(LPCSTR szPath) {
  34. // Set our current directory to the directory that the file is in. We need to
  35. // do this so our file search can find dependents that happen to be in the
  36. // same directory that our target file is in.
  37. //CString strDir(szPath);
  38. //strDir = strDir.Left(strDir.ReverseFind('\\') + 1);
  39. //SetCurrentDirectory(strDir);
  40. SetCurrentDirectory(szPath);
  41. // Create our root module node.
  42. if (m_pModuleRoot = CreateModule(szPath, 0))
  43. {
  44. // Start the recursion on the head module to process all modules.
  45. ProcessModule(m_pModuleRoot);
  46. }
  47. else
  48. {
  49. m_fOutOfMemory = TRUE;
  50. }
  51. // If we ran out of memory while processing the module, then free our
  52. // document data, display an error, and fail the document from loading.
  53. // Out of memory is a fairly major error. If this should occur, MFC will
  54. // most likely notice and report the problem before we do.
  55. if (m_fOutOfMemory)
  56. {
  57. DeleteContents();
  58. //CString strError("Not enough memory to process \"");
  59. //strError += m_pModuleRoot->m_pData->m_szPath;
  60. //strError += "\"!";
  61. //MessageBox(strError, "Dependency Walker Error", MB_ICONERROR | MB_OK);
  62. return FALSE;
  63. }
  64. // Display a message if the module contains a circular dependency error.
  65. if (m_fCircularError)
  66. {
  67. //CString strError("\"");
  68. //strError += m_pModuleRoot->m_pData->m_szPath;
  69. //strError += "\" will fail to load due to circular dependencies.";
  70. //g_pMainFrame->MessageBox(strError, "Dependency Walker Module Error",MB_ICONERROR | MB_OK);
  71. }
  72. // Display a message if the module contains a mixed machine error.
  73. if (m_fMixedMachineError) {
  74. //CString strError("\"");
  75. //strError += m_pModuleRoot->m_pData->m_szPath;
  76. //strError += "\" will fail to load due to a mismatched machine type with "
  77. // "one or more of the dependent modules.";
  78. //g_pMainFrame->MessageBox(strError, "Dependency Walker Module Error", MB_ICONERROR | MB_OK);
  79. }
  80. return TRUE;
  81. }
  82. CModule* CDepends::LoopThruAndPrintLosers(CModule *pModuleCur)
  83. {
  84. //
  85. // loop thru the linked list and look for
  86. // items marked with m_fExportError
  87. //
  88. if (!pModuleCur) {
  89. return NULL;
  90. }
  91. // check to see if our current module is marked with m_fExportError
  92. // Check to see if our current module matches our search module.
  93. if (pModuleCur->m_fExportError == TRUE)
  94. {
  95. char szMyBigString[_MAX_PATH + 50];
  96. char szMyPrintString[_MAX_PATH + 50];
  97. MyLoadString(IDS_STRING7, szMyBigString);
  98. sprintf(szMyPrintString, szMyBigString,(LPSTR) pModuleCur->m_pData->m_szPath);
  99. printf(szMyPrintString);
  100. // Convert the filename to unicode.
  101. //LPWSTR pwszModuleName = NULL;
  102. //pwszModuleName = MakeWideStrFromAnsi( (LPSTR)(pModuleCur->m_pData->m_szPath) );
  103. //g_MyLogFile.PrintToLog(_T(" %s"), pwszModuleName);
  104. //if (pwszModuleName){CoTaskMemFree(pwszModuleName);}
  105. }
  106. if (pModuleCur->m_pData->m_fFileNotFound == TRUE)
  107. {
  108. char szMyBigString[_MAX_PATH + 50];
  109. char szMyPrintString[_MAX_PATH + 50];
  110. MyLoadString(IDS_STRING8, szMyBigString);
  111. sprintf(szMyPrintString, szMyBigString,(LPSTR) pModuleCur->m_pData->m_szPath);
  112. printf(szMyPrintString);
  113. // Convert the filename to unicode.
  114. //LPWSTR pwszModuleName = NULL;
  115. //pwszModuleName = MakeWideStrFromAnsi( (LPSTR)(pModuleCur->m_pData->m_szPath) );
  116. //g_MyLogFile.PrintToLog(_T(" %s"), pwszModuleName);
  117. //if (pwszModuleName){CoTaskMemFree(pwszModuleName);}
  118. }
  119. // Recurse into LoopThruAndPrintLosers() for each dependent module.
  120. pModuleCur = pModuleCur->m_pDependents;
  121. while (pModuleCur)
  122. {
  123. CModule *pModuleFound = LoopThruAndPrintLosers(pModuleCur);
  124. if (pModuleFound) {
  125. return pModuleFound;
  126. }
  127. pModuleCur = pModuleCur->m_pNext;
  128. }
  129. return NULL;
  130. }
  131. void CDepends::DeleteContents() {
  132. // Delete all modules by recursing into DeleteModule() with our root module.
  133. if (m_pModuleRoot) {
  134. DeleteModule(m_pModuleRoot);
  135. m_pModuleRoot = NULL;
  136. }
  137. // Clear our memory error flag.
  138. m_fOutOfMemory = FALSE;
  139. // Clear our circular dependency error flag.
  140. m_fCircularError = FALSE;
  141. // Clear our mixed machine error flag.
  142. m_fMixedMachineError = FALSE;
  143. m_dwMachineType = (DWORD)-1;
  144. }
  145. //******************************************************************************
  146. // CDepends :: Internal functions
  147. //******************************************************************************
  148. CModule* CDepends::CreateModule(LPCSTR szFile, int depth) {
  149. CHAR szPath[16384] = "", *pszFile = NULL;
  150. // Attempt to find the file in our search path. This will mimic what the OS
  151. // loader does when looking for a module. Our OnOpenDocument() function sets
  152. // the current directory to the module directory, so SearchPath() will first
  153. // look in the module directory.
  154. //SearchPath(NULL, szFile, NULL, sizeof(szPath), szPath, &pszFile);
  155. SearchPathA(NULL, szFile, NULL, sizeof(szPath), szPath, &pszFile);
  156. // If we don't have a path, then just copy the file name into our path string
  157. // and set the file pointer to the character following the last wack "\".
  158. if (!*szPath) {
  159. strcpy(szPath, szFile);
  160. LPSTR pszWack = strrchr(szPath, '\\');
  161. pszFile = (pszWack && *(pszWack + 1)) ? (pszWack + 1) : szPath;
  162. }
  163. // If our file name pointer is invalid, then just point it to our path.
  164. if (pszFile < szPath) {
  165. pszFile = szPath;
  166. }
  167. // Create a new CModule object
  168. CModule *pModule = new CModule();
  169. if (!pModule) {
  170. return NULL;
  171. }
  172. ZeroMemory(pModule, sizeof(CModule));
  173. // Store our module's depth for later recursion overflow checks.
  174. pModule->m_depth = depth;
  175. // Recurse our module tree to see if this module is a duplicate of another.
  176. pModule->m_pModuleOriginal = FindModule(m_pModuleRoot, szPath);
  177. // Check to see if a duplicate was found.
  178. if (pModule->m_pModuleOriginal) {
  179. // If the module is a duplicate, then just point our data field to the
  180. // original module's data field.
  181. pModule->m_pData = pModule->m_pModuleOriginal->m_pData;
  182. } else {
  183. // If this module is not a duplicate, then create a new CModuleData object.
  184. pModule->m_pData = (CModuleData*)new BYTE[sizeof(CModuleData) + strlen(szPath)];
  185. if (!pModule->m_pData) {
  186. delete pModule;
  187. return NULL;
  188. }
  189. // Clear the object, copy the path string to it, and set the file pointer.
  190. ZeroMemory(pModule->m_pData, sizeof(CModuleData));
  191. strcpy(pModule->m_pData->m_szPath, szPath);
  192. pModule->m_pData->m_szFile = pModule->m_pData->m_szPath + (pszFile - szPath);
  193. // For readability, make path lowercase and file uppercase.
  194. _strlwr(pModule->m_pData->m_szPath);
  195. _strupr(pModule->m_pData->m_szFile);
  196. }
  197. // Return our new module object.
  198. return pModule;
  199. }
  200. //******************************************************************************
  201. CFunction* CDepends::CreateFunction(int ordinal, int hint, LPCSTR szName,
  202. DWORD_PTR dwAddress, LPCSTR szForward)
  203. {
  204. // Create a CFunction object.
  205. CFunction *pFunction = (CFunction*)new BYTE[sizeof(CFunction) + strlen(szName)];
  206. if (!pFunction) {
  207. return NULL;
  208. }
  209. // Clear the function object and fill in its members.
  210. ZeroMemory(pFunction, sizeof(CFunction));
  211. strcpy(pFunction->m_szName, szName);
  212. pFunction->m_ordinal = ordinal;
  213. pFunction->m_hint = hint;
  214. pFunction->m_dwAddress = dwAddress;
  215. // If a forward string exists, then allocate a buffer and store a pointer to
  216. // it in our CFunction's m_dwExtra member. See the CFunction class for more
  217. // info on m_dwExtra.
  218. if (szForward) {
  219. if (pFunction->m_dwExtra = (DWORD_PTR)new CHAR[strlen(szForward) + 1]) {
  220. strcpy((LPSTR)pFunction->m_dwExtra, szForward);
  221. } else {
  222. delete[] (BYTE*)pFunction;
  223. return NULL;
  224. }
  225. }
  226. // Return our new function object.
  227. return pFunction;
  228. }
  229. //******************************************************************************
  230. void CDepends::DeleteModule(CModule *pModule) {
  231. // Recurse into DeleteModule() to delete all our dependent modules first.
  232. CModule *pModuleCur = pModule->m_pDependents;
  233. while (pModuleCur) {
  234. CModule *pModuleNext = pModuleCur->m_pNext;
  235. DeleteModule(pModuleCur);
  236. pModuleCur = pModuleNext;
  237. }
  238. // Delete all of our current module's parent import functions.
  239. CFunction *pFunctionCur = pModule->m_pParentImports;
  240. while (pFunctionCur) {
  241. CFunction *pFunctionNext = pFunctionCur->m_pNext;
  242. delete[] (BYTE*)pFunctionCur;
  243. pFunctionCur = pFunctionNext;
  244. }
  245. // If we are not marked as a duplicate, then free our CModuleData.
  246. if (!pModule->m_pModuleOriginal) {
  247. // Delete all of our current module's export functions.
  248. CFunction *pFunctionCur = pModule->m_pData->m_pExports;
  249. while (pFunctionCur) {
  250. // Delete our forward string if we allocated one.
  251. if (pFunctionCur->GetForwardString()) {
  252. delete[] (CHAR*)pFunctionCur->GetForwardString();
  253. }
  254. // Delete the export node itself.
  255. CFunction *pFunctionNext = pFunctionCur->m_pNext;
  256. delete[] (BYTE*)pFunctionCur;
  257. pFunctionCur = pFunctionNext;
  258. }
  259. // Delete any error string that may have been allocated.
  260. if (pModule->m_pData->m_pszError) {
  261. delete[] (CHAR*)pModule->m_pData->m_pszError;
  262. }
  263. // Delete our current module's CModuleData object.
  264. delete[] (BYTE*)pModule->m_pData;
  265. }
  266. // Delete our current module object itself.
  267. delete pModule;
  268. }
  269. //******************************************************************************
  270. CModule* CDepends::FindModule(CModule *pModuleCur, LPCSTR szPath) {
  271. if (!pModuleCur) {
  272. return NULL;
  273. }
  274. // Check to see if our current module matches our search module.
  275. if (!_stricmp(pModuleCur->m_pData->m_szPath, szPath)) {
  276. return (pModuleCur->m_pModuleOriginal ? pModuleCur->m_pModuleOriginal : pModuleCur);
  277. }
  278. // Recurse into FindModule() for each dependent module.
  279. pModuleCur = pModuleCur->m_pDependents;
  280. while (pModuleCur) {
  281. CModule *pModuleFound = FindModule(pModuleCur, szPath);
  282. if (pModuleFound) {
  283. return pModuleFound;
  284. }
  285. pModuleCur = pModuleCur->m_pNext;
  286. }
  287. return NULL;
  288. }
  289. //******************************************************************************
  290. BOOL CDepends::VerifyModule(CModule *pModule) {
  291. // Map an IMAGE_DOS_HEADER structure onto our module file mapping.
  292. PIMAGE_DOS_HEADER pIDH = (PIMAGE_DOS_HEADER)m_lpvFile;
  293. // Check for the DOS signature ("MZ").
  294. if (pIDH->e_magic != IMAGE_DOS_SIGNATURE) {
  295. //SetModuleError(pModule, "No DOS signature found. This file is not a valid Win32 module.");
  296. return FALSE;
  297. }
  298. // Map an IMAGE_NT_HEADERS structure onto our module file mapping.
  299. PIMAGE_NT_HEADERS pINTH = (PIMAGE_NT_HEADERS)((DWORD_PTR)m_lpvFile + pIDH->e_lfanew);
  300. // Check for NT/PE signature ("PE\0\0").
  301. if (pINTH->Signature != IMAGE_NT_SIGNATURE) {
  302. //SetModuleError(pModule, "No PE signature found. This file is not a valid Win32 module.");
  303. return FALSE;
  304. }
  305. // Map our IMAGE_FILE_HEADER structure onto our module file mapping.
  306. m_pIFH = &pINTH->FileHeader;
  307. // Map our IMAGE_OPTIONAL_HEADER structure onto our module file mapping.
  308. m_pIOH = &pINTH->OptionalHeader;
  309. // Map our IMAGE_SECTION_HEADER structure array onto our module file mapping
  310. m_pISH = IMAGE_FIRST_SECTION(pINTH);
  311. return TRUE;
  312. }
  313. char *MachineToString(DWORD Machine)
  314. {
  315. switch( Machine )
  316. {
  317. case IMAGE_FILE_MACHINE_UNKNOWN :
  318. return "Unknown";
  319. case IMAGE_FILE_MACHINE_I386 :
  320. return "x86";
  321. case IMAGE_FILE_MACHINE_R3000 :
  322. return "MIPS";
  323. case IMAGE_FILE_MACHINE_R4000 :
  324. return "MIPS";
  325. case IMAGE_FILE_MACHINE_R10000 :
  326. return "MIPS";
  327. case IMAGE_FILE_MACHINE_ALPHA :
  328. return "Alpha";
  329. case IMAGE_FILE_MACHINE_POWERPC :
  330. return "PPC"; //IBM PowerPC
  331. }
  332. return "INVALID";
  333. }
  334. //******************************************************************************
  335. BOOL CDepends::GetModuleInfo(CModule *pModule) {
  336. // Store the machine type.
  337. pModule->m_pData->m_dwMachine = m_pIFH->Machine;
  338. // Check for a mismatched machine error.
  339. if (m_dwMachineType == (DWORD)-1) {
  340. m_dwMachineType = pModule->m_pData->m_dwMachine;
  341. } else if (m_dwMachineType != pModule->m_pData->m_dwMachine) {
  342. m_fMixedMachineError = TRUE;
  343. char szMyBigString[_MAX_PATH + 50];
  344. char szMyPrintString[_MAX_PATH + 50];
  345. MyLoadString(IDS_STRING9, szMyBigString);
  346. sprintf(szMyPrintString, szMyBigString, MachineToString(pModule->m_pData->m_dwMachine), (LPSTR) pModule->m_pData->m_szPath);
  347. printf(szMyPrintString);
  348. }
  349. // Store the subsystem type
  350. pModule->m_pData->m_dwSubsystem = m_pIOH->Subsystem;
  351. // Store the preferred base address
  352. pModule->m_pData->m_dwBaseAddress = m_pIOH->ImageBase;
  353. // Store the image version
  354. pModule->m_pData->m_dwImageVersion =
  355. MAKELONG(m_pIOH->MinorImageVersion, m_pIOH->MajorImageVersion);
  356. // Store the linker version
  357. pModule->m_pData->m_dwLinkerVersion =
  358. MAKELONG(m_pIOH->MinorLinkerVersion, m_pIOH->MajorLinkerVersion);
  359. // Store the OS version
  360. pModule->m_pData->m_dwOSVersion =
  361. MAKELONG(m_pIOH->MinorOperatingSystemVersion, m_pIOH->MajorOperatingSystemVersion);
  362. // Store the subsystem version
  363. pModule->m_pData->m_dwSubsystemVersion = MAKELONG(m_pIOH->MinorSubsystemVersion, m_pIOH->MajorSubsystemVersion);
  364. return TRUE;
  365. }
  366. BOOL
  367. CDepends::WalkIAT(
  368. PIMAGE_THUNK_DATA pITDF,
  369. PIMAGE_THUNK_DATA pITDA,
  370. CModule *pModule,
  371. DWORD_PTR dwBase
  372. )
  373. {
  374. CFunction *pFunctionLast = NULL, *pFunctionNew;
  375. // Loop through all the Image Thunk Data structures in the function array.
  376. while (pITDF->u1.Ordinal) {
  377. LPCSTR szFunction = "";
  378. int ordinal = -1, hint = -1;
  379. // Check to see if this function is by ordinal or by name. If the
  380. // function is by ordinal, the ordinal's high bit will be set. If the
  381. // the high bit is not set, then the ordinal value is really a virtual
  382. // address of an IMAGE_IMPORT_BY_NAME structure.
  383. if (IMAGE_SNAP_BY_ORDINAL(pITDF->u1.Ordinal)) {
  384. ordinal = (int)IMAGE_ORDINAL(pITDF->u1.Ordinal);
  385. } else {
  386. PIMAGE_IMPORT_BY_NAME pIIBN =
  387. (PIMAGE_IMPORT_BY_NAME)(dwBase + (DWORD_PTR)pITDF->u1.AddressOfData);
  388. szFunction = (LPCSTR)pIIBN->Name;
  389. hint = (int)pIIBN->Hint;
  390. }
  391. // If this import module has been pre-bound, then get this function's
  392. // entrypoint memory address.
  393. DWORD_PTR dwAddress = (DWORD_PTR)(pITDA ? pITDA->u1.Function : (DWORD_PTR)INVALID_HANDLE_VALUE);
  394. // Create a new CFunction object for this function.
  395. if (!(pFunctionNew = CreateFunction(ordinal, hint, szFunction, dwAddress))) {
  396. m_fOutOfMemory = TRUE;
  397. return FALSE;
  398. }
  399. // Add the function to the end of our module's function linked list
  400. if (pFunctionLast) {
  401. pFunctionLast->m_pNext = pFunctionNew;
  402. } else {
  403. pModule->m_pParentImports = pFunctionNew;
  404. }
  405. pFunctionLast = pFunctionNew;
  406. // Increment to the next function and address.
  407. pITDF++;
  408. if (pITDA) {
  409. pITDA++;
  410. }
  411. }
  412. return TRUE;
  413. }
  414. //******************************************************************************
  415. BOOL CDepends::BuildImports(CModule *pModule) {
  416. // If this module has no imports (like NTDLL.DLL), then just return success.
  417. if (m_pIOH->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size == 0) {
  418. return TRUE;
  419. }
  420. // Locate our Import Image Directory's relative virtual address
  421. DWORD VAImageDir = m_pIOH->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
  422. PIMAGE_SECTION_HEADER pISH = NULL;
  423. // Locate the section that contains this Image Directory. We do this by
  424. // walking through all of our sections until we find the one that specifies
  425. // an address range that our Image Directory fits in.
  426. for (int i = 0; i < m_pIFH->NumberOfSections; i++) {
  427. if ((VAImageDir >= m_pISH[i].VirtualAddress) &&
  428. (VAImageDir < (m_pISH[i].VirtualAddress + m_pISH[i].SizeOfRawData)))
  429. {
  430. pISH = &m_pISH[i];
  431. break;
  432. }
  433. }
  434. // Bail out if we could not find a section that owns our Image Directory.
  435. if (!pISH) {
  436. //SetModuleError(pModule, "Could not find the section that owns the Import Directory.");
  437. return FALSE;
  438. }
  439. // Compute our base that everything else is an offset from. We do this by
  440. // taking our base file pointer and adding our section's PointerToRawData,
  441. // which is an absolute offset value into our file. We then subtract off our
  442. // Virtual Address since the offsets we are going to be adding later will be
  443. // relative to the this Virtual Address
  444. DWORD_PTR dwBase = (DWORD_PTR)m_lpvFile + pISH->PointerToRawData - pISH->VirtualAddress;
  445. // To locate the beginning of our Image Import Descriptor array, we add our
  446. // Image Directory offset to our base.
  447. PIMAGE_IMPORT_DESCRIPTOR pIID = (PIMAGE_IMPORT_DESCRIPTOR)(dwBase + VAImageDir);
  448. CModule *pModuleLast = NULL, *pModuleNew;
  449. CFunction *pFunctionLast = NULL, *pFunctionNew;
  450. // Loop through all the Image Import Descriptors in the array.
  451. while (pIID->OriginalFirstThunk || pIID->FirstThunk) {
  452. // Locate our module name string and create the module object.
  453. if (!(pModuleNew = CreateModule((LPCSTR)(dwBase + pIID->Name),
  454. pModule->m_depth + 1)))
  455. {
  456. m_fOutOfMemory = TRUE;
  457. return FALSE;
  458. }
  459. // Add the module to the end of our module linked list.
  460. if (pModuleLast) {
  461. pModuleLast->m_pNext = pModuleNew;
  462. } else {
  463. pModule->m_pDependents = pModuleNew;
  464. }
  465. pModuleLast = pModuleNew;
  466. // Locate the beginning of our function array and address array. The
  467. // function array (pITDF) is an array of IMAGE_THUNK_DATA structures that
  468. // contains all the exported functions, both by name and by ordinal. The
  469. // address array (pITDA) is an parallel array of IMAGE_THUNK_DATA
  470. // structures that is used to store the all the function's entrypoint
  471. // addresses. Usually the address array contains the exact same values
  472. // the function array contains until the OS loader actually loads all the
  473. // modules. At that time, the loader will set (bind) these addresses to
  474. // the actual addresses that the given functions reside at in memory. Some
  475. // modules have their exports pre-bound which can provide a speed increase
  476. // when loading the module. If a module is pre-bound (often seen with
  477. // system modules), the TimeDateStamp field of our IMAGE_IMPORT_DESCRIPTOR
  478. // structure will be set and the address array will contain the actual
  479. // memory addresses that the functions will reside at, assuming that the
  480. // imported module loads at its preferred base address.
  481. PIMAGE_THUNK_DATA pITDF = NULL, pITDA = NULL;
  482. // Check to see if module is Microsoft format or Borland format.
  483. if (pIID->OriginalFirstThunk) {
  484. // Microsoft uses the OriginalFirstThunk field for the function array.
  485. pITDF = (PIMAGE_THUNK_DATA)(dwBase + (DWORD)pIID->OriginalFirstThunk);
  486. // Microsoft optionally uses the FirstThunk as a bound address array.
  487. // If the TimeDateStamp field is set, then the module has been bound.
  488. if (pIID->TimeDateStamp) {
  489. pITDA = (PIMAGE_THUNK_DATA)(dwBase + (DWORD)pIID->FirstThunk);
  490. }
  491. } else {
  492. // Borland uses the FirstThunk field for the function array.
  493. pITDF = (PIMAGE_THUNK_DATA)(dwBase + (DWORD)pIID->FirstThunk);;
  494. }
  495. // Find imports
  496. if (!WalkIAT(pITDF, pITDA, pModuleLast, dwBase)) {
  497. return FALSE;
  498. }
  499. // Increment to the next import module
  500. pIID++;
  501. }
  502. return TRUE;
  503. }
  504. BOOL CDepends::BuildDelayImports(CModule *pModule) {
  505. // If this module has no delay imports just return success.
  506. if (m_pIOH->DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].Size == 0) {
  507. return TRUE;
  508. }
  509. // Locate our Import Image Directory's relative virtual address
  510. DWORD VAImageDir = m_pIOH->DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress;
  511. PIMAGE_SECTION_HEADER pISH = NULL;
  512. // Locate the section that contains this Image Directory. We do this by
  513. // walking through all of our sections until we find the one that specifies
  514. // an address range that our Image Directory fits in.
  515. for (int i = 0; i < m_pIFH->NumberOfSections; i++) {
  516. if ((VAImageDir >= m_pISH[i].VirtualAddress) &&
  517. (VAImageDir < (m_pISH[i].VirtualAddress + m_pISH[i].SizeOfRawData)))
  518. {
  519. pISH = &m_pISH[i];
  520. break;
  521. }
  522. }
  523. // Bail out if we could not find a section that owns our Image Directory.
  524. if (!pISH) {
  525. //SetModuleError(pModule, "Could not find the section that owns the Import Directory.");
  526. return FALSE;
  527. }
  528. // Compute our base that everything else is an offset from. We do this by
  529. // taking our base file pointer and adding our section's PointerToRawData,
  530. // which is an absolute offset value into our file. We then subtract off our
  531. // Virtual Address since the offsets we are going to be adding later will be
  532. // relative to the this Virtual Address
  533. DWORD_PTR dwBase = (DWORD_PTR)m_lpvFile + pISH->PointerToRawData - pISH->VirtualAddress;
  534. // To locate the beginning of our Image Import Descriptor array, we add our
  535. // Image Directory offset to our base.
  536. PImgDelayDescr pIDD = (PImgDelayDescr)(dwBase + VAImageDir);
  537. CModule *pModuleLast = NULL, *pModuleNew;
  538. CFunction *pFunctionLast = NULL, *pFunctionNew;
  539. if (pIDD->grAttrs & dlattrRva) {
  540. PImgDelayDescrV2 pIDDv2 = (PImgDelayDescrV2)pIDD;
  541. // Loop through all the Image Import Descriptors in the array.
  542. while (pIDDv2->rvaINT && pIDDv2->rvaIAT && pIDDv2->rvaHmod) {
  543. DWORD_PTR dwNameBase = 0, dwINTBase = 0;
  544. // Locate the section that contains this Image Directory. We do this by
  545. // walking through all of our sections until we find the one that specifies
  546. // an address range that our Image Directory fits in.
  547. for (int i = 0; i < m_pIFH->NumberOfSections; i++) {
  548. if (((DWORD_PTR)pIDDv2->rvaDLLName >= m_pISH[i].VirtualAddress) &&
  549. ((DWORD_PTR)pIDDv2->rvaDLLName < (m_pISH[i].VirtualAddress + m_pISH[i].SizeOfRawData)))
  550. {
  551. dwNameBase = ((DWORD_PTR)m_lpvFile + m_pISH[i].PointerToRawData - m_pISH[i].VirtualAddress);
  552. }
  553. if (((DWORD_PTR)pIDDv2->rvaINT >= (m_pISH[i].VirtualAddress)) &&
  554. ((DWORD_PTR)pIDDv2->rvaINT < (m_pISH[i].VirtualAddress + m_pISH[i].SizeOfRawData)))
  555. {
  556. dwINTBase = ((DWORD_PTR)m_lpvFile + m_pISH[i].PointerToRawData - m_pISH[i].VirtualAddress);
  557. }
  558. }
  559. if (!dwINTBase) {
  560. //SetModuleError(pModule, "Could not find the section that owns the Delay Import INT.");
  561. return FALSE;
  562. }
  563. if (!dwNameBase) {
  564. //SetModuleError(pModule, "Could not find the section that owns the Delay Import DllName.");
  565. return FALSE;
  566. }
  567. // Locate our module name string and create the module object.
  568. if (!(pModuleNew = CreateModule((LPCSTR)(dwNameBase + pIDDv2->rvaDLLName),
  569. pModule->m_depth + 1)))
  570. {
  571. m_fOutOfMemory = TRUE;
  572. return FALSE;
  573. }
  574. // Add the module to the end of our module linked list.
  575. if (pModuleLast) {
  576. pModuleLast->m_pNext = pModuleNew;
  577. } else {
  578. if (pModule->m_pDependents) {
  579. pModuleLast = pModule->m_pDependents;
  580. while (pModuleLast->m_pNext) {
  581. pModuleLast = pModuleLast->m_pNext;
  582. }
  583. pModuleLast->m_pNext = pModuleNew;
  584. } else {
  585. pModule->m_pDependents = pModuleNew;
  586. }
  587. }
  588. pModuleLast = pModuleNew;
  589. pModuleLast->m_fDelayLoad = TRUE;
  590. // For now, don't worry about bound imports.
  591. PIMAGE_THUNK_DATA pITDF = NULL;
  592. pITDF = (PIMAGE_THUNK_DATA)(dwINTBase + (DWORD_PTR)pIDDv2->rvaINT);
  593. // Find imports
  594. if (!WalkIAT(pITDF, NULL, pModuleLast, dwNameBase)) {
  595. return FALSE;
  596. }
  597. // Increment to the next import module
  598. pIDDv2++;
  599. }
  600. } else {
  601. PImgDelayDescrV1 pIDDv1 = (PImgDelayDescrV1)pIDD;
  602. // Loop through all the Image Import Descriptors in the array.
  603. while (pIDDv1->pINT && pIDDv1->pIAT && pIDDv1->phmod) {
  604. DWORD_PTR dwNameBase = 0, dwINTBase = 0;
  605. // Locate the section that contains this Image Directory. We do this by
  606. // walking through all of our sections until we find the one that specifies
  607. // an address range that our Image Directory fits in.
  608. for (int i = 0; i < m_pIFH->NumberOfSections; i++) {
  609. if (((DWORD_PTR)pIDDv1->szName >= (m_pIOH->ImageBase + m_pISH[i].VirtualAddress)) &&
  610. ((DWORD_PTR)pIDDv1->szName < (m_pIOH->ImageBase + m_pISH[i].VirtualAddress + m_pISH[i].SizeOfRawData)))
  611. {
  612. dwNameBase = ((DWORD_PTR)m_lpvFile + m_pISH[i].PointerToRawData - m_pISH[i].VirtualAddress - m_pIOH->ImageBase);
  613. }
  614. if (((DWORD_PTR)pIDDv1->pINT >= (m_pIOH->ImageBase + m_pISH[i].VirtualAddress)) &&
  615. ((DWORD_PTR)pIDDv1->pINT < (m_pIOH->ImageBase + m_pISH[i].VirtualAddress + m_pISH[i].SizeOfRawData)))
  616. {
  617. dwINTBase = ((DWORD_PTR)m_lpvFile + m_pISH[i].PointerToRawData - m_pISH[i].VirtualAddress - m_pIOH->ImageBase);
  618. }
  619. }
  620. if (!dwINTBase) {
  621. //SetModuleError(pModule, "Could not find the section that owns the Delay Import INT.");
  622. return FALSE;
  623. }
  624. if (!dwNameBase) {
  625. //SetModuleError(pModule, "Could not find the section that owns the Delay Import DllName.");
  626. return FALSE;
  627. }
  628. // Locate our module name string and create the module object.
  629. if (!(pModuleNew = CreateModule((LPCSTR)(dwNameBase + pIDDv1->szName),
  630. pModule->m_depth + 1)))
  631. {
  632. m_fOutOfMemory = TRUE;
  633. return FALSE;
  634. }
  635. // Add the module to the end of our module linked list.
  636. if (pModuleLast) {
  637. pModuleLast->m_pNext = pModuleNew;
  638. } else {
  639. if (pModule->m_pDependents) {
  640. pModuleLast = pModule->m_pDependents;
  641. while (pModuleLast->m_pNext) {
  642. pModuleLast = pModuleLast->m_pNext;
  643. }
  644. pModuleLast->m_pNext = pModuleNew;
  645. } else {
  646. pModule->m_pDependents = pModuleNew;
  647. }
  648. }
  649. pModuleLast = pModuleNew;
  650. pModuleLast->m_fDelayLoad = TRUE;
  651. // For now, don't worry about bound imports.
  652. PIMAGE_THUNK_DATA pITDF = NULL;
  653. pITDF = (PIMAGE_THUNK_DATA)(dwINTBase + (DWORD_PTR)pIDDv1->pINT);
  654. // Find imports
  655. if (!WalkIAT(pITDF, NULL, pModuleLast, dwNameBase)) {
  656. return FALSE;
  657. }
  658. // Increment to the next import module
  659. pIDDv1++;
  660. }
  661. }
  662. return TRUE;
  663. }
  664. //******************************************************************************
  665. BOOL CDepends::BuildExports(CModule *pModule) {
  666. // If this module has no exports, then just return success.
  667. if (m_pIOH->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size == 0) {
  668. return TRUE;
  669. }
  670. // Locate our Export Image Directory's relative virtual address
  671. DWORD VAImageDir = m_pIOH->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
  672. PIMAGE_SECTION_HEADER pISH = NULL;
  673. // Locate the section that contains this Image Directory. We do this by
  674. // walking through all of our sections until we find the one that specifies
  675. // an address range that our Image Directory fits in.
  676. for (int i = 0; i < m_pIFH->NumberOfSections; i++) {
  677. if ((VAImageDir >= m_pISH[i].VirtualAddress) &&
  678. (VAImageDir < (m_pISH[i].VirtualAddress + m_pISH[i].SizeOfRawData)))
  679. {
  680. pISH = &m_pISH[i];
  681. break;
  682. }
  683. }
  684. // Bail out if we could not find a section that owns our Image Directory.
  685. if (!pISH) {
  686. //SetModuleError(pModule, "Could not find the section that owns the Export Directory.");
  687. return FALSE;
  688. }
  689. // Compute our base that everything else is an offset from. We do this by
  690. // taking our base file pointer and adding our section's PointerToRawData,
  691. // which is an absolute offset value into our file. We then subtract off our
  692. // Virtual Address since the offsets we are going to be adding later will be
  693. // relative to the this Virtual Address
  694. DWORD_PTR dwBase = (DWORD_PTR)m_lpvFile + pISH->PointerToRawData - pISH->VirtualAddress;
  695. // To locate the beginning of our Image Export Directory, we add our
  696. // Image Directory offset to our base.
  697. PIMAGE_EXPORT_DIRECTORY pIED = (PIMAGE_EXPORT_DIRECTORY)(dwBase + VAImageDir);
  698. // pdwNames is a DWORD array of size pIED->NumberOfNames, which contains VA
  699. // pointers to all the function name strings. pwOrdinals is a WORD array of
  700. // size pIED->NumberOfNames, which contains all the ordinal values for each
  701. // function exported by name. pdwNames and pwOrdinals are parallel arrays,
  702. // meaning that the ordinal in pwOrdinals[x] goes with the function name
  703. // pointed to by pdwNames[x]. The value used to index these arrays is
  704. // referred to as the "hint".
  705. // pdwAddresses is a DWORD array of size pIED->NumberOfFunctions, which
  706. // contains the entrypoint addresses for all functions exported by the
  707. // module. Contrary to several PE format documents, this array is *not*
  708. // parallel with pdwNames and pwOrdinals. The index used for this array is
  709. // the ordinal value of the function you are interested in, minus the base
  710. // ordinal specified in pIED->Base. Another common mistake is to assume that
  711. // pIED->NumberOfFunctions is always equal to pIED->AddressOfNames. If the
  712. // module exports function by ordinal only, then pIED->NumberOfFunctions
  713. // will be greater than pIED->NumberOfNames.
  714. DWORD *pdwNames = (DWORD*)(dwBase + (DWORD)pIED->AddressOfNames);
  715. WORD *pwOrdinals = (WORD* )(dwBase + (DWORD)pIED->AddressOfNameOrdinals);
  716. DWORD *pdwAddresses = (DWORD*)(dwBase + (DWORD)pIED->AddressOfFunctions);
  717. CFunction *pFunctionLast = NULL, *pFunctionNew;
  718. // Loop through all the "exported by name" functions.
  719. for (int hint = 0; hint < (int)pIED->NumberOfNames; hint++) {
  720. // Get our ordinal value, function name, and entrypoint address
  721. int ordinal = pIED->Base + (DWORD)pwOrdinals[hint];
  722. LPCSTR szFunction = (LPCSTR)(dwBase + pdwNames[hint]);
  723. DWORD dwAddress = pdwAddresses[ordinal - pIED->Base];
  724. LPCSTR szForward = NULL;
  725. // Certain modules, such as NTDLL.DLL and MSVCRT40.DLL, have what are
  726. // known as forwarded functions. Forwarded functions are functions that
  727. // are exported from one module, but the code actually lives in another
  728. // module. We can check to see if a function is forwarded by looking at
  729. // its address pointer. If the address pointer points to the character
  730. // immediately following the NULL character in its function name string,
  731. // then this address pointer is really a pointer to a forward string in
  732. // the string table. Some documents state that if the address points to
  733. // a RVA in our current section, then the address must point to a forward
  734. // string. This is not true since the function code can (and sometimes
  735. // does) live in the same section that we are currently in.
  736. if (((DWORD_PTR)szFunction + strlen(szFunction) + 1) == (dwBase + dwAddress)) {
  737. szForward = (LPCSTR)(dwBase + dwAddress);
  738. }
  739. // Create a new CFunction object for this function.
  740. if (!(pFunctionNew = CreateFunction(ordinal, hint, szFunction, dwAddress, szForward))) {
  741. m_fOutOfMemory = TRUE;
  742. return FALSE;
  743. }
  744. // Add the function to the end of our module's export function linked list
  745. if (pFunctionLast) {
  746. pFunctionLast->m_pNext = pFunctionNew;
  747. } else {
  748. pModule->m_pData->m_pExports = pFunctionNew;
  749. }
  750. pFunctionLast = pFunctionNew;
  751. }
  752. // Loop through all the "exported by ordinal" functions. This module has
  753. // pIED->NumberOfFunctions functions with consecutive ordinals starting
  754. // with the ordinal specified by pIED->Base. We need to loop through all
  755. // these ordinal values and add any to our list that have not already been
  756. // added by name.
  757. for (int ordinal = pIED->Base;
  758. ordinal < (int)(pIED->NumberOfFunctions + pIED->Base); ordinal++) {
  759. // Loop through our current list to make sure we haven't already added
  760. // this function during our "exported by name" search above.
  761. CFunction *pFunctionCur = pModule->m_pData->m_pExports;
  762. while (pFunctionCur) {
  763. if (pFunctionCur->m_ordinal == ordinal) {
  764. break;
  765. }
  766. pFunctionCur = pFunctionCur->m_pNext;
  767. }
  768. // If this ordinal is not currently in our list, then add it to our list.
  769. if (!pFunctionCur) {
  770. // Get this function's entrypoint address.
  771. DWORD dwAddress = pdwAddresses[ordinal - pIED->Base];
  772. // Create a new CFunction object for this function.
  773. if (!(pFunctionNew = CreateFunction(ordinal, -1, "", dwAddress))) {
  774. m_fOutOfMemory = TRUE;
  775. return FALSE;
  776. }
  777. // Add the function to the end of our module's export function linked list
  778. if (pFunctionLast) {
  779. pFunctionLast->m_pNext = pFunctionNew;
  780. } else {
  781. pModule->m_pData->m_pExports = pFunctionNew;
  782. }
  783. pFunctionLast = pFunctionNew;
  784. }
  785. }
  786. return TRUE;
  787. }
  788. //******************************************************************************
  789. BOOL CDepends::VerifyParentImports(CModule *pModule) {
  790. CModule *pModuleHead = NULL, *pModuleLast, *pModuleCur;
  791. // Loop through each of our parent import functions.
  792. CFunction *pImport = pModule->m_pParentImports;
  793. while (pImport) {
  794. // Mark this parent import function as not resolved before starting search.
  795. pImport->m_dwExtra = 0;
  796. // Loop through all our exports, looking for a match with our current import.
  797. CFunction *pExport = pModule->m_pData->m_pExports;
  798. while (pExport) {
  799. // If we have a name, then check for the match by name.
  800. if (*pImport->m_szName) {
  801. if (!strcmp(pImport->m_szName, pExport->m_szName)) {
  802. // We found a match. Link this parent import to its associated
  803. // export, break out of loop, and move on to handling our next
  804. // parent import.
  805. pImport->m_dwExtra = (DWORD_PTR)pExport;
  806. break;
  807. }
  808. // If we don't have a name, then check for the match by name.
  809. } else if (pImport->m_ordinal == pExport->m_ordinal) {
  810. // We found a match. Link this parent import to its associated
  811. // export, break out of loop, and move on to handling our next
  812. // parent import.
  813. pImport->m_dwExtra = (DWORD_PTR)pExport;
  814. break;
  815. }
  816. // Move to the next export
  817. pExport = pExport->m_pNext;
  818. }
  819. // Check to see if an export match was found.
  820. if (pImport->GetAssociatedExport()) {
  821. CHAR szFile[1024];
  822. LPCSTR szFunction;
  823. // If an export was found, check to see if it is a forwarded function.
  824. // If it is forwarded, then we need to make sure we consider the
  825. // forwarded module as a new dependent of the current module.
  826. LPCSTR szForward = pImport->GetAssociatedExport()->GetForwardString();
  827. if (szForward) {
  828. // Extract and build the DLL name from the forward string.
  829. LPCSTR pszDot = strchr(szForward, '.');
  830. if (pszDot) {
  831. strncpy(szFile, szForward, (size_t)(pszDot - szForward));
  832. strcpy(szFile + (pszDot - szForward), ".DLL");
  833. szFunction = pszDot + 1;
  834. } else {
  835. strcpy(szFile, "Invalid");
  836. szFunction = szForward;
  837. }
  838. // Search our local forward module list to see if we have already
  839. // created a forward CModoule for this DLL file.
  840. for (pModuleLast = NULL, pModuleCur = pModuleHead; pModuleCur;
  841. pModuleLast = pModuleCur, pModuleCur = pModuleCur->m_pNext)
  842. {
  843. if (!_stricmp(pModuleCur->m_pData->m_szFile, szFile)) {
  844. break;
  845. }
  846. }
  847. // If we have not created a forward module for this file yet, then
  848. // create it now and add it to the end of our list.
  849. if (!pModuleCur) {
  850. if (!(pModuleCur = CreateModule(szFile, pModule->m_depth + 1))) {
  851. m_fOutOfMemory = TRUE;
  852. return FALSE;
  853. }
  854. pModuleCur->m_fForward = TRUE;
  855. // Add the new module to our local forward module list.
  856. if (pModuleLast) {
  857. pModuleLast->m_pNext = pModuleCur;
  858. } else {
  859. pModuleHead = pModuleCur;
  860. }
  861. }
  862. // Create a new CFunction object for this function.
  863. CFunction *pFunction = CreateFunction(-1, -1, szFunction, (DWORD)-1);
  864. if (!pFunction) {
  865. m_fOutOfMemory = TRUE;
  866. return FALSE;
  867. }
  868. // Insert this function object into our forward module's import list.
  869. pFunction->m_pNext = pModuleCur->m_pParentImports;
  870. pModuleCur->m_pParentImports = pFunction;
  871. }
  872. } else {
  873. // If we could not find an import/export match, then flag the module
  874. // as having an export error.
  875. pModule->m_fExportError = TRUE;
  876. }
  877. // Move to the next parent import function.
  878. pImport = pImport->m_pNext;
  879. }
  880. // If we created any forward modules during our entire import verify, then
  881. // add them to the end of our module's dependent module list.
  882. if (pModuleHead) {
  883. // Walk to end of our module's dependent module list.
  884. for (pModuleLast = pModule->m_pDependents;
  885. pModuleLast && pModuleLast->m_pNext;
  886. pModuleLast = pModuleLast->m_pNext)
  887. {}
  888. // Add our local list to the end of our module's dependent module list.
  889. if (pModuleLast) {
  890. pModuleLast->m_pNext = pModuleHead;
  891. } else {
  892. pModule->m_pDependents = pModuleHead;
  893. }
  894. }
  895. return TRUE;
  896. }
  897. //******************************************************************************
  898. BOOL CDepends::ProcessModule(CModule *pModule) {
  899. BOOL fResult = FALSE;
  900. // First check to see if this module is a duplicate. If it is, make sure the
  901. // original instance of this module has been processed and then just perform
  902. // the Parent Import Verify. If the module being passed in is an original,
  903. // then just ensure that we haven't already processed this module.
  904. if (pModule->m_pModuleOriginal) {
  905. // Process the original module and its subtree.
  906. fResult = ProcessModule(pModule->m_pModuleOriginal);
  907. if (!fResult && m_fOutOfMemory) {
  908. return FALSE;
  909. }
  910. // Exit now if we have already processed this original module in the past.
  911. } else if (pModule->m_pData->m_fProcessed) {
  912. return TRUE;
  913. } else {
  914. // Mark this module as processed.
  915. pModule->m_pData->m_fProcessed = TRUE;
  916. // Open the file for read.
  917. //m_hFile = CreateFile(pModule->m_pData->m_szPath, GENERIC_READ,
  918. m_hFile = CreateFileA(pModule->m_pData->m_szPath, GENERIC_READ,
  919. FILE_SHARE_READ, NULL, OPEN_EXISTING,
  920. FILE_ATTRIBUTE_NORMAL, NULL);
  921. // Exit now if the file failed to open.
  922. if (m_hFile == INVALID_HANDLE_VALUE) {
  923. DWORD dwGLE = GetLastError();
  924. if (dwGLE == ERROR_FILE_NOT_FOUND) {
  925. //SetModuleError(pModule, "File not found in local directory or search path.");
  926. pModule->m_pData->m_fFileNotFound = TRUE;
  927. } else if (dwGLE == ERROR_PATH_NOT_FOUND) {
  928. //SetModuleError(pModule, "Invalid path or file name.");
  929. pModule->m_pData->m_fFileNotFound = TRUE;
  930. } else {
  931. //SetModuleError(pModule, "CreateFile() failed (%u).", dwGLE);
  932. }
  933. return FALSE;
  934. }
  935. // Create a file mapping object for the open module.
  936. HANDLE hMap = CreateFileMapping(m_hFile, NULL, PAGE_READONLY, 0, 0, NULL);
  937. // Exit now if the file failed to map.
  938. if (hMap == NULL) {
  939. //SetModuleError(pModule, "CreateFileMapping() failed (%u).", GetLastError());
  940. CloseHandle(m_hFile);
  941. m_hFile = NULL;
  942. return FALSE;
  943. }
  944. // Create a file mapping view for the open module.
  945. m_lpvFile = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
  946. // Exit now if the mapped view failed to create.
  947. if (m_lpvFile == NULL) {
  948. //SetModuleError(pModule, "MapViewOfFile() failed (%u).", GetLastError());
  949. CloseHandle(hMap);
  950. CloseHandle(m_hFile);
  951. m_hFile = NULL;
  952. return FALSE;
  953. }
  954. __try {
  955. // Everything from here on is pretty much relying on the file being a
  956. // valid binary with valid pointers and offsets. It is fairly safe to
  957. // just wrap everything in exception handling and then blindly access
  958. // the file. Anything that causes us to move outside our file mapping
  959. // will generate an exception and bring us back here to fail the file.
  960. fResult = (VerifyModule(pModule) &&
  961. GetModuleInfo(pModule) &&
  962. BuildImports(pModule) &&
  963. BuildDelayImports(pModule) &&
  964. BuildExports(pModule));
  965. } __except(EXCEPTION_EXECUTE_HANDLER) {
  966. //SetModuleError(pModule, "Module does not appear to be a valid Win32 module.");
  967. }
  968. // Close our map view pointer, our map handle, and our file handle.
  969. UnmapViewOfFile(m_lpvFile);
  970. CloseHandle(hMap);
  971. CloseHandle(m_hFile);
  972. // Clear our file handles and pointers.
  973. m_hFile = NULL;
  974. m_lpvFile = NULL;
  975. m_pIFH = NULL;
  976. m_pIOH = NULL;
  977. m_pISH = NULL;
  978. }
  979. // Compare our parent imports with our exports to make sure they all match up.
  980. if (!VerifyParentImports(pModule)) {
  981. return FALSE;
  982. }
  983. // Safeguard to ensure that we don't get stuck in some recursize loop. This
  984. // can occur if there is a circular dependency with forwarded functions. This
  985. // is extremely rare and would require someone to design it, but we need
  986. // to handle this case to prevent us from crashing on it. When NT encounters
  987. // a module like this, it fails the load with exception 0xC00000FD which is
  988. // defined as STATUS_STACK_OVERFLOW in WINNT.H. We use 255 as our max depth
  989. // because the several versions of the tree control crash if more than 256
  990. // depths are displayed.
  991. if (pModule->m_depth >= 255) {
  992. // If this module has dependents, then delete them.
  993. if (pModule->m_pDependents) {
  994. DeleteModule(pModule->m_pDependents);
  995. pModule->m_pDependents = NULL;
  996. }
  997. // Flag this document as having a circular dependency error.
  998. m_fCircularError = TRUE;
  999. return FALSE;
  1000. }
  1001. // Recurse into ProcessModule() to handle all our dependent modules.
  1002. pModule = pModule->m_pDependents;
  1003. while (pModule) {
  1004. if (!ProcessModule(pModule) && m_fOutOfMemory) {
  1005. return FALSE;
  1006. }
  1007. pModule = pModule->m_pNext;
  1008. }
  1009. return fResult;
  1010. }
  1011. LPWSTR MakeWideStrFromAnsi(LPSTR psz)
  1012. {
  1013. LPWSTR pwsz;
  1014. int i;
  1015. // arg checking.
  1016. //
  1017. if (!psz)
  1018. return NULL;
  1019. // compute the length
  1020. //
  1021. i = MultiByteToWideChar(CP_ACP, 0, psz, -1, NULL, 0);
  1022. if (i <= 0) return NULL;
  1023. pwsz = (LPWSTR) CoTaskMemAlloc(i * sizeof(WCHAR));
  1024. if (!pwsz) return NULL;
  1025. MultiByteToWideChar(CP_ACP, 0, psz, -1, pwsz, i);
  1026. pwsz[i - 1] = 0;
  1027. return pwsz;
  1028. }