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.

641 lines
16 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. Exports.cpp
  5. Abstract:
  6. Helper functions for enumerating module exports.
  7. Notes:
  8. Although only used by the stack swapping shim, it may later be included in
  9. the library, since it's general.
  10. Most of these routines are copied out of the source for imagehlp.dll. We
  11. are not including this dll since it doesn't work in the Win2K shim layer.
  12. History:
  13. 05/10/2000 linstev Created
  14. --*/
  15. #include "precomp.h"
  16. IMPLEMENT_SHIM_BEGIN(StackSwap)
  17. #include "StackSwap_Exports.h"
  18. // User APIs
  19. BOOL LoadModule(PCSTR lpName, PLOADED_IMAGE lpImage);
  20. BOOL UnloadModule(PLOADED_IMAGE lpImage);
  21. BOOL EnumFirstExport(PLOADED_IMAGE lpImage, PEXPORT_ENUM lpExports);
  22. BOOL EnumNextExport(PEXPORT_ENUM lpExports);
  23. // Internal APIs
  24. BOOL CalculateImagePtrs(PLOADED_IMAGE lpImage);
  25. PIMAGE_SECTION_HEADER ImageRvaToSection(PIMAGE_NT_HEADERS NtHeaders, PVOID Base, ULONG Rva);
  26. PVOID ImageRvaToVa(PIMAGE_NT_HEADERS NtHeaders, PVOID Base, ULONG Rva, PIMAGE_SECTION_HEADER *LastRvaSection OPTIONAL);
  27. PVOID ImageDirectoryEntryToData32(PVOID Base, BOOLEAN MappedAsImage, USHORT DirectoryEntry, PULONG Size, PIMAGE_SECTION_HEADER *FoundSection OPTIONAL, PIMAGE_FILE_HEADER FileHeader, PIMAGE_OPTIONAL_HEADER32 OptionalHeader);
  28. PVOID ImageDirectoryEntryToData(PVOID Base, BOOLEAN MappedAsImage, USHORT DirectoryEntry, PULONG Size);
  29. /*++
  30. Open a file handle to a module and map it's image.
  31. --*/
  32. BOOL
  33. LoadModule(
  34. PCSTR lpName,
  35. PLOADED_IMAGE lpImage
  36. )
  37. {
  38. HANDLE hFile;
  39. CHAR szSearchBuffer[MAX_PATH];
  40. DWORD dwLen;
  41. LPSTR lpFilePart;
  42. LPSTR lpOpenName;
  43. BOOL bRet = FALSE;
  44. ZeroMemory(lpImage, sizeof(LOADED_IMAGE));
  45. lpOpenName = (PSTR)lpName;
  46. dwLen = 0;
  47. Retry:
  48. hFile = CreateFileA(
  49. lpOpenName,
  50. GENERIC_READ,
  51. FILE_SHARE_READ,
  52. NULL,
  53. OPEN_EXISTING,
  54. 0,
  55. NULL);
  56. if (hFile == INVALID_HANDLE_VALUE)
  57. {
  58. if (!dwLen)
  59. {
  60. //
  61. // open failed try to find the file on the search path
  62. //
  63. dwLen = SearchPathA(
  64. NULL,
  65. lpName,
  66. ".DLL",
  67. MAX_PATH,
  68. szSearchBuffer,
  69. &lpFilePart
  70. );
  71. if (dwLen && dwLen < MAX_PATH)
  72. {
  73. lpOpenName = szSearchBuffer;
  74. goto Retry;
  75. }
  76. }
  77. goto Exit;
  78. }
  79. lpImage->hFile = hFile;
  80. HANDLE hFileMap;
  81. hFileMap = CreateFileMapping(
  82. hFile,
  83. NULL,
  84. PAGE_READONLY,
  85. 0,
  86. 0,
  87. NULL);
  88. if (!hFileMap)
  89. {
  90. goto Exit;
  91. }
  92. lpImage->MappedAddress = (PUCHAR) MapViewOfFile(
  93. hFileMap,
  94. FILE_MAP_READ,
  95. 0,
  96. 0,
  97. 0
  98. );
  99. CloseHandle(hFileMap);
  100. lpImage->SizeOfImage = GetFileSize(hFile, NULL);
  101. if (!lpImage->MappedAddress ||
  102. !CalculateImagePtrs(lpImage))
  103. {
  104. goto Exit;
  105. }
  106. bRet = TRUE;
  107. Exit:
  108. if (bRet == FALSE)
  109. {
  110. CloseHandle(hFile);
  111. UnmapViewOfFile(lpImage->MappedAddress);
  112. }
  113. return bRet;
  114. }
  115. /*++
  116. Helper function for LoadImage. Fill in all the pointers in a LOADED_IMAGE
  117. structure.
  118. --*/
  119. BOOL
  120. CalculateImagePtrs(
  121. PLOADED_IMAGE lpImage
  122. )
  123. {
  124. PIMAGE_DOS_HEADER DosHeader;
  125. PIMAGE_NT_HEADERS NtHeaders;
  126. PIMAGE_FILE_HEADER FileHeader;
  127. BOOL bRet;
  128. // Everything is mapped. Now check the image and find nt image headers
  129. bRet = TRUE; // Assume the best
  130. __try
  131. {
  132. DosHeader = (PIMAGE_DOS_HEADER)lpImage->MappedAddress;
  133. if ((DosHeader->e_magic != IMAGE_DOS_SIGNATURE) &&
  134. (DosHeader->e_magic != IMAGE_NT_SIGNATURE))
  135. {
  136. bRet = FALSE;
  137. goto tryout;
  138. }
  139. if (DosHeader->e_magic == IMAGE_DOS_SIGNATURE)
  140. {
  141. if (DosHeader->e_lfanew == 0)
  142. {
  143. lpImage->fDOSImage = TRUE;
  144. bRet = FALSE;
  145. goto tryout;
  146. }
  147. lpImage->FileHeader = (PIMAGE_NT_HEADERS)((ULONG_PTR)DosHeader + DosHeader->e_lfanew);
  148. // If IMAGE_NT_HEADERS would extend past the end of file...
  149. if ((PBYTE)lpImage->FileHeader + sizeof(IMAGE_NT_HEADERS) >
  150. (PBYTE)lpImage->MappedAddress + lpImage->SizeOfImage ||
  151. // ..or if it would begin in, or before the IMAGE_DOS_HEADER...
  152. (PBYTE)lpImage->FileHeader <
  153. (PBYTE)lpImage->MappedAddress + sizeof(IMAGE_DOS_HEADER))
  154. {
  155. // ...then e_lfanew is not as expected.
  156. // (Several Win95 files are in this category.)
  157. bRet = FALSE;
  158. goto tryout;
  159. }
  160. }
  161. else
  162. {
  163. // No DOS header indicates an image built w/o a dos stub
  164. lpImage->FileHeader = (PIMAGE_NT_HEADERS)((ULONG_PTR)DosHeader);
  165. }
  166. NtHeaders = lpImage->FileHeader;
  167. if ( NtHeaders->Signature != IMAGE_NT_SIGNATURE )
  168. {
  169. if ((USHORT)NtHeaders->Signature == (USHORT)IMAGE_OS2_SIGNATURE ||
  170. (USHORT)NtHeaders->Signature == (USHORT)IMAGE_OS2_SIGNATURE_LE)
  171. {
  172. lpImage->fDOSImage = TRUE;
  173. }
  174. bRet = FALSE;
  175. goto tryout;
  176. }
  177. else
  178. {
  179. lpImage->fDOSImage = FALSE;
  180. }
  181. FileHeader = &NtHeaders->FileHeader;
  182. // No optional header indicates an object...
  183. if (FileHeader->SizeOfOptionalHeader == 0)
  184. {
  185. bRet = FALSE;
  186. goto tryout;
  187. }
  188. if (NtHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
  189. {
  190. // 32-bit image. Do some tests.
  191. if (((PIMAGE_NT_HEADERS32)NtHeaders)->OptionalHeader.ImageBase >= 0x80000000)
  192. {
  193. lpImage->fSystemImage = TRUE;
  194. }
  195. else
  196. {
  197. lpImage->fSystemImage = FALSE;
  198. }
  199. if (((PIMAGE_NT_HEADERS32)NtHeaders)->OptionalHeader.MajorLinkerVersion < 3 &&
  200. ((PIMAGE_NT_HEADERS32)NtHeaders)->OptionalHeader.MinorLinkerVersion < 5)
  201. {
  202. bRet = FALSE;
  203. goto tryout;
  204. }
  205. }
  206. else
  207. {
  208. lpImage->fSystemImage = FALSE;
  209. }
  210. lpImage->Sections = IMAGE_FIRST_SECTION(NtHeaders);
  211. lpImage->Characteristics = FileHeader->Characteristics;
  212. lpImage->NumberOfSections = FileHeader->NumberOfSections;
  213. lpImage->LastRvaSection = lpImage->Sections;
  214. tryout:
  215. ;
  216. }
  217. __except ( EXCEPTION_EXECUTE_HANDLER )
  218. {
  219. bRet = FALSE;
  220. }
  221. return bRet;
  222. }
  223. /*++
  224. Unmap the loaded image.
  225. --*/
  226. BOOL
  227. UnloadModule(
  228. PLOADED_IMAGE lpImage
  229. )
  230. {
  231. UnmapViewOfFile(lpImage->MappedAddress);
  232. CloseHandle(lpImage->hFile);
  233. return TRUE;
  234. }
  235. /*++
  236. Description:
  237. Locates an RVA within the image header of a file that is mapped as a file and
  238. returns a pointer to the section table entry for that virtual address.
  239. Arguments:
  240. NtHeaders - pointer to the image or data file
  241. Base - base of the image or data file
  242. Rva - relative virtual address (RVA) to locate
  243. Returns:
  244. NULL - no data for the specified directory entry
  245. NON-NULL - pointer of the section entry containing the data
  246. --*/
  247. PIMAGE_SECTION_HEADER
  248. ImageRvaToSection(
  249. IN PIMAGE_NT_HEADERS NtHeaders,
  250. IN PVOID /*Base*/,
  251. IN ULONG Rva
  252. )
  253. {
  254. ULONG i;
  255. PIMAGE_SECTION_HEADER NtSection;
  256. NtSection = IMAGE_FIRST_SECTION(NtHeaders);
  257. for (i=0; i<NtHeaders->FileHeader.NumberOfSections; i++)
  258. {
  259. if (Rva >= NtSection->VirtualAddress &&
  260. Rva < NtSection->VirtualAddress + NtSection->SizeOfRawData)
  261. {
  262. return NtSection;
  263. }
  264. ++NtSection;
  265. }
  266. return NULL;
  267. }
  268. /*++
  269. Description:
  270. This function locates an RVA within the image header of a file that is
  271. mapped as a file and returns the virtual addrees of the corresponding
  272. byte in the file.
  273. Arguments:
  274. NtHeaders - pointer to the image or data file.
  275. Base - base of the image or data file.
  276. Rva - relative virtual address (RVA) to locate.
  277. LastRvaSection - optional parameter that if specified, points to a variable
  278. that contains the last section value used for the specified
  279. image to translate and RVA to a VA.
  280. Returns:
  281. NULL - does not contain the specified RVA
  282. NON-NULL - virtual address in the mapped file.
  283. --*/
  284. PVOID
  285. ImageRvaToVa(
  286. IN PIMAGE_NT_HEADERS NtHeaders,
  287. IN PVOID Base,
  288. IN ULONG Rva,
  289. IN OUT PIMAGE_SECTION_HEADER *LastRvaSection OPTIONAL
  290. )
  291. {
  292. PIMAGE_SECTION_HEADER NtSection;
  293. if (LastRvaSection == NULL ||
  294. (NtSection = *LastRvaSection) == NULL ||
  295. NtSection == NULL ||
  296. Rva < NtSection->VirtualAddress ||
  297. Rva >= NtSection->VirtualAddress + NtSection->SizeOfRawData)
  298. {
  299. NtSection = NS_StackSwap::ImageRvaToSection(
  300. NtHeaders,
  301. Base,
  302. Rva);
  303. }
  304. if (NtSection != NULL)
  305. {
  306. if (LastRvaSection != NULL)
  307. {
  308. *LastRvaSection = NtSection;
  309. }
  310. return (PVOID)((ULONG_PTR)Base +
  311. (Rva - NtSection->VirtualAddress) +
  312. NtSection->PointerToRawData);
  313. }
  314. else
  315. {
  316. return NULL;
  317. }
  318. }
  319. /*++
  320. See ImageDirectoryEntryToData.
  321. --*/
  322. PVOID
  323. ImageDirectoryEntryToData32(
  324. IN PVOID Base,
  325. IN BOOLEAN MappedAsImage,
  326. IN USHORT DirectoryEntry,
  327. OUT PULONG Size,
  328. OUT PIMAGE_SECTION_HEADER *FoundSection OPTIONAL,
  329. IN PIMAGE_FILE_HEADER FileHeader,
  330. IN PIMAGE_OPTIONAL_HEADER32 OptionalHeader
  331. )
  332. {
  333. ULONG i;
  334. PIMAGE_SECTION_HEADER NtSection;
  335. ULONG DirectoryAddress;
  336. if (DirectoryEntry >= OptionalHeader->NumberOfRvaAndSizes)
  337. {
  338. *Size = 0;
  339. return( NULL );
  340. }
  341. if (!(DirectoryAddress = OptionalHeader->DataDirectory[ DirectoryEntry ].VirtualAddress))
  342. {
  343. *Size = 0;
  344. return( NULL );
  345. }
  346. *Size = OptionalHeader->DataDirectory[ DirectoryEntry ].Size;
  347. if (MappedAsImage || DirectoryAddress < OptionalHeader->SizeOfHeaders)
  348. {
  349. if (FoundSection)
  350. {
  351. *FoundSection = NULL;
  352. }
  353. return ((PVOID)((ULONG_PTR)Base + DirectoryAddress));
  354. }
  355. NtSection = (PIMAGE_SECTION_HEADER)((ULONG_PTR)OptionalHeader +
  356. FileHeader->SizeOfOptionalHeader);
  357. for (i=0; i<FileHeader->NumberOfSections; i++)
  358. {
  359. if (DirectoryAddress >= NtSection->VirtualAddress &&
  360. DirectoryAddress < NtSection->VirtualAddress + NtSection->SizeOfRawData)
  361. {
  362. if (FoundSection)
  363. {
  364. *FoundSection = NtSection;
  365. }
  366. return( (PVOID)((ULONG_PTR)Base + (DirectoryAddress - NtSection->VirtualAddress) + NtSection->PointerToRawData) );
  367. }
  368. ++NtSection;
  369. }
  370. return( NULL );
  371. }
  372. /*++
  373. Description:
  374. This function locates a directory entry within the image header and returns
  375. either the virtual address or seek address of the data the Directory
  376. describes. It may optionally return the section header, if any, for the
  377. found data.
  378. Arguments:
  379. Base - base of the image or data file.
  380. MappedAsImage - FALSE if the file is mapped as a data file.
  381. - TRUE if the file is mapped as an image.
  382. DirectoryEntry - directory entry to locate.
  383. Size - return the size of the directory.
  384. FoundSection - Returns the section header, if any, for the data
  385. Returns:
  386. NULL - The file does not contain data for the specified directory entry.
  387. NON-NULL - Returns the address of the raw data the directory describes.
  388. --*/
  389. PVOID
  390. ImageDirectoryEntryToData(
  391. IN PVOID Base,
  392. IN BOOLEAN MappedAsImage,
  393. IN USHORT DirectoryEntry,
  394. OUT PULONG Size
  395. )
  396. {
  397. PIMAGE_NT_HEADERS NtHeader;
  398. PIMAGE_FILE_HEADER FileHeader;
  399. PIMAGE_OPTIONAL_HEADER OptionalHeader;
  400. if ((ULONG_PTR)Base & 0x00000001)
  401. {
  402. Base = (PVOID)((ULONG_PTR)Base & ~0x1);
  403. MappedAsImage = FALSE;
  404. }
  405. NtHeader = RtlpImageNtHeader(Base);
  406. if (NtHeader)
  407. {
  408. FileHeader = &NtHeader->FileHeader;
  409. OptionalHeader = &NtHeader->OptionalHeader;
  410. }
  411. else
  412. {
  413. // Handle case where Image passed in doesn't have a dos stub (ROM images for instance);
  414. FileHeader = (PIMAGE_FILE_HEADER)Base;
  415. OptionalHeader = (PIMAGE_OPTIONAL_HEADER) ((ULONG_PTR)Base + IMAGE_SIZEOF_FILE_HEADER);
  416. }
  417. if (OptionalHeader->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
  418. {
  419. return (ImageDirectoryEntryToData32(
  420. Base,
  421. MappedAsImage,
  422. DirectoryEntry,
  423. Size,
  424. NULL,
  425. FileHeader,
  426. (PIMAGE_OPTIONAL_HEADER32)OptionalHeader));
  427. }
  428. else
  429. {
  430. return NULL;
  431. }
  432. }
  433. /*++
  434. Enumerate the first exported function.
  435. --*/
  436. BOOL
  437. EnumFirstExport(
  438. PLOADED_IMAGE lpImage,
  439. PEXPORT_ENUM lpExports
  440. )
  441. {
  442. ULONG imageSize;
  443. ZeroMemory (lpExports, sizeof (EXPORT_ENUM));
  444. lpExports->Image = lpImage;
  445. lpExports->ImageDescriptor = (PIMAGE_EXPORT_DIRECTORY)
  446. ImageDirectoryEntryToData(
  447. lpImage->MappedAddress,
  448. FALSE,
  449. IMAGE_DIRECTORY_ENTRY_EXPORT,
  450. &imageSize);
  451. if (!lpExports->ImageDescriptor)
  452. {
  453. //DPF(eDbgLevelError, "Cannot load export directory for %s", lpImage->ModuleName);
  454. return FALSE;
  455. }
  456. if (lpExports->ImageDescriptor->NumberOfNames == 0)
  457. {
  458. return FALSE;
  459. }
  460. lpExports->ExportNamesAddr = (PDWORD) NS_StackSwap::ImageRvaToVa(
  461. lpExports->Image->FileHeader,
  462. lpExports->Image->MappedAddress,
  463. lpExports->ImageDescriptor->AddressOfNames,
  464. NULL);
  465. lpExports->ExportOrdAddr = (PUSHORT) NS_StackSwap::ImageRvaToVa(
  466. lpExports->Image->FileHeader,
  467. lpExports->Image->MappedAddress,
  468. lpExports->ImageDescriptor->AddressOfNameOrdinals,
  469. NULL
  470. );
  471. lpExports->CurrExportNr = 0;
  472. return EnumNextExport(lpExports);
  473. }
  474. /*++
  475. Enumerate the next exported function.
  476. --*/
  477. BOOL
  478. EnumNextExport(
  479. IN OUT PEXPORT_ENUM lpExports
  480. )
  481. {
  482. if (lpExports->CurrExportNr >= lpExports->ImageDescriptor->NumberOfNames)
  483. {
  484. return FALSE;
  485. }
  486. if (*lpExports->ExportNamesAddr == 0)
  487. {
  488. return FALSE;
  489. }
  490. lpExports->ExportFunction = (CHAR *)NS_StackSwap::ImageRvaToVa(
  491. lpExports->Image->FileHeader,
  492. lpExports->Image->MappedAddress,
  493. *lpExports->ExportNamesAddr,
  494. NULL);
  495. lpExports->ExportFunctionOrd = *lpExports->ExportOrdAddr +
  496. lpExports->ImageDescriptor->Base;
  497. lpExports->ExportNamesAddr++;
  498. lpExports->ExportOrdAddr++;
  499. lpExports->CurrExportNr++;
  500. return (lpExports->ExportFunction != NULL);
  501. }
  502. IMPLEMENT_SHIM_END