CnSMRPEUtils.pas 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. unit CnSMRPEUtils;
  2. interface
  3. {$I CnWizards.inc}
  4. uses
  5. SysUtils, Windows, Classes;
  6. procedure GetImportTable(ss: TStrings; const PEFile: String);
  7. procedure GetDelayImportTable(ss: TStrings; const PEFile: String);
  8. procedure GetExportTable(ss: TStrings; const PEFile: String);
  9. implementation
  10. {$RANGECHECKS OFF}
  11. {$IFDEF DELPHI7_UP}
  12. {$WARN SYMBOL_PLATFORM OFF}
  13. {$WARN UNIT_PLATFORM OFF}
  14. {$ENDIF}
  15. const
  16. IMAGE_ORDINAL_FLAG = DWORD($80000000);
  17. IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT = 11;
  18. IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13;
  19. type
  20. PIMAGE_IMPORT_BY_NAME = ^IMAGE_IMPORT_BY_NAME;
  21. {$EXTERNALSYM PIMAGE_IMPORT_BY_NAME}
  22. _IMAGE_IMPORT_BY_NAME = record
  23. Hint: Word;
  24. Name: array [0..0] of Char;
  25. end;
  26. {$EXTERNALSYM _IMAGE_IMPORT_BY_NAME}
  27. IMAGE_IMPORT_BY_NAME = _IMAGE_IMPORT_BY_NAME;
  28. {$EXTERNALSYM IMAGE_IMPORT_BY_NAME}
  29. TImageImportByName = IMAGE_IMPORT_BY_NAME;
  30. PImageImportByName = PIMAGE_IMPORT_BY_NAME;
  31. PIMAGE_THUNK_DATA32 = ^IMAGE_THUNK_DATA32;
  32. {$EXTERNALSYM PIMAGE_THUNK_DATA32}
  33. _IMAGE_THUNK_DATA32 = record
  34. case Integer of
  35. 0: (ForwarderString: PBYTE);
  36. 1: (Function_: PDWORD);
  37. 2: (Ordinal: DWORD);
  38. 3: (AddressOfData: PIMAGE_IMPORT_BY_NAME);
  39. end;
  40. {$EXTERNALSYM _IMAGE_THUNK_DATA32}
  41. IMAGE_THUNK_DATA32 = _IMAGE_THUNK_DATA32;
  42. {$EXTERNALSYM IMAGE_THUNK_DATA32}
  43. TImageThunkData32 = IMAGE_THUNK_DATA32;
  44. PImageThunkData32 = PIMAGE_THUNK_DATA32;
  45. TIIDUnion = record
  46. case Integer of
  47. 0: (Characteristics: DWORD);
  48. 1: (OriginalFirstThunk: PIMAGE_THUNK_DATA32);
  49. end;
  50. PIMAGE_IMPORT_DESCRIPTOR = ^IMAGE_IMPORT_DESCRIPTOR;
  51. {$EXTERNALSYM PIMAGE_IMPORT_DESCRIPTOR}
  52. _IMAGE_IMPORT_DESCRIPTOR = record
  53. Union: TIIDUnion;
  54. TimeDateStamp: DWORD;
  55. ForwarderChain: DWORD;
  56. Name: DWORD;
  57. FirstThunk: PIMAGE_THUNK_DATA32;
  58. end;
  59. {$EXTERNALSYM _IMAGE_IMPORT_DESCRIPTOR}
  60. IMAGE_IMPORT_DESCRIPTOR = _IMAGE_IMPORT_DESCRIPTOR;
  61. {$EXTERNALSYM IMAGE_IMPORT_DESCRIPTOR}
  62. TImageImportDescriptor = IMAGE_IMPORT_DESCRIPTOR;
  63. PImageImportDescriptor = PIMAGE_IMPORT_DESCRIPTOR;
  64. {$EXTERNALSYM ImgDelayDescr}
  65. ImgDelayDescr = packed record
  66. grAttrs: DWORD;
  67. szName: DWORD;
  68. phmod: PDWORD;
  69. pIAT: TImageThunkData32;
  70. pINT: TImageThunkData32;
  71. pBoundIAT: TImageThunkData32;
  72. pUnloadIAT: TImageThunkData32;
  73. dwTimeStamp: DWORD;
  74. end;
  75. TImgDelayDescr = ImgDelayDescr;
  76. PImgDelayDescr = ^ImgDelayDescr;
  77. PloadedImage = ^TLoadedImage;
  78. {$EXTERNALSYM _LOADED_IMAGE}
  79. _LOADED_IMAGE = record
  80. ModuleName: LPSTR;
  81. hFile: THandle;
  82. MappedAddress: PChar;
  83. FileHeader: PImageNtHeaders;
  84. LastRvaSection: PImageSectionHeader;
  85. NumberOfSections: ULONG;
  86. Sections: PImageSectionHeader;
  87. Characteristics: ULONG;
  88. fSystemImage: ByteBool;
  89. fDOSImage: ByteBool;
  90. Links: TListEntry;
  91. SizeOfImage: ULONG;
  92. end;
  93. {$EXTERNALSYM LOADED_IMAGE}
  94. LOADED_IMAGE = _LOADED_IMAGE;
  95. LoadedImage = _LOADED_IMAGE;
  96. TLoadedImage = _Loaded_IMAGE;
  97. type
  98. TFWOrdinalData = record
  99. FuncName: ShortString;
  100. Ordinal: DWORD;
  101. Addr: String[10];
  102. end;
  103. TFWOrdinalDataArray = array of TFWOrdinalData;
  104. var
  105. OrdinalData: TFWOrdinalDataArray;
  106. function MapAndLoad(ImageName, DllPath: LPSTR; LoadedImage: PLoadedImage;
  107. DotDll, ReadOnly: Bool): Bool; stdcall; external 'Imagehlp.dll';
  108. function UnMapAndLoad(LoadedImage: PLoadedImage): Bool; stdcall;
  109. external 'Imagehlp.dll';
  110. function FieldOffset(const Struc; const Field): Cardinal;
  111. begin
  112. Result := Cardinal(@Field) - Cardinal(@Struc);
  113. end;
  114. function IMAGE_FIRST_SECTION(NtHeader: PImageNtHeaders): PImageSectionHeader;
  115. begin
  116. Result := PImageSectionHeader(Cardinal(NtHeader) +
  117. FieldOffset(NtHeader^, NtHeader^.OptionalHeader) +
  118. NtHeader^.FileHeader.SizeOfOptionalHeader);
  119. end;
  120. function ImageRvaToSection(NtHeaders: PImageNtHeaders; Base: Pointer;
  121. Rva: ULONG): PImageSectionHeader;
  122. var
  123. NtSection: PImageSectionHeader;
  124. I: Integer;
  125. begin
  126. Result := nil;
  127. NtSection := IMAGE_FIRST_SECTION(NtHeaders);
  128. for I := 0 to NtHeaders^.FileHeader.NumberOfSections - 1 do
  129. if (Rva >= NtSection.VirtualAddress) and
  130. (Rva < NtSection.VirtualAddress + NtSection.SizeOfRawData) then
  131. begin
  132. Result := NtSection;
  133. Exit;
  134. end
  135. else
  136. Inc(NtSection);
  137. end;
  138. function ImageRvaToVa(NtHeaders: PImageNtHeaders; Base: Pointer;
  139. Rva: ULONG; var LastRvaSection: PImageSectionHeader): Pointer;
  140. var
  141. NtSection: PImageSectionHeader;
  142. begin
  143. Result := nil;
  144. NtSection := LastRvaSection;
  145. if (LastRvaSection = nil) or (Rva < NtSection^.VirtualAddress) or
  146. (Rva < NtSection^.VirtualAddress + NtSection^.SizeOfRawData) then
  147. NtSection := ImageRvaToSection(NtHeaders, Base, Rva);
  148. if NtSection = nil then Exit;
  149. if LastRvaSection <> nil then
  150. LastRvaSection := NtSection;
  151. Result := Pointer(DWORD(Base) + (Rva - NtSection^.VirtualAddress) +
  152. NtSection^.PointerToRawData);
  153. end;
  154. function ImageDirectoryEntryToData(Base: Pointer; MappedAsImage: ByteBool;
  155. DirectoryEntry: Word; var Size: ULONG): Pointer;
  156. const
  157. IMAGE_NT_OPTIONAL_HDR32_MAGIC = $10B;
  158. IMAGE_NT_OPTIONAL_HDR64_MAGIC = $20B;
  159. IMAGE_ROM_OPTIONAL_HDR_MAGIC = $107;
  160. var
  161. DOSHeader: PImageDosHeader;
  162. NTHeader: PImageNtHeaders;
  163. FileHeader: TImageFileHeader;
  164. NtSection: PImageSectionHeader;
  165. OptionalHeader: TImageOptionalHeader;
  166. DirectoryAddress: DWORD;
  167. I: Integer;
  168. begin
  169. Result := nil;
  170. if (DWORD(Base) and 1) = 1 then
  171. Base := Pointer((DWORD(Base) and not 1));
  172. DOSHeader := PImageDosHeader(Base);
  173. if IsBadReadPtr(Pointer(Base), SizeOf(TImageNtHeaders)) then Exit;
  174. if (DOSHeader^.e_magic <> IMAGE_DOS_SIGNATURE) then Exit;
  175. NTHeader := PImageNtHeaders(DWORD(DOSHeader) + DWORD(DOSHeader^._lfanew));
  176. if NTHeader^.Signature <> IMAGE_NT_SIGNATURE then Exit;
  177. FileHeader := NTHeader^.FileHeader;
  178. if FileHeader.Machine <> IMAGE_FILE_MACHINE_I386 then Exit;
  179. OptionalHeader := NTHeader^.OptionalHeader;
  180. if OptionalHeader.Magic <> IMAGE_NT_OPTIONAL_HDR32_MAGIC then Exit;
  181. if DirectoryEntry >= OptionalHeader.NumberOfRvaAndSizes then
  182. begin
  183. Size := 0;
  184. Exit;
  185. end;
  186. DirectoryAddress :=
  187. OptionalHeader.DataDirectory[DirectoryEntry].VirtualAddress;
  188. if DirectoryAddress = 0 then
  189. begin
  190. Size := 0;
  191. Exit;
  192. end;
  193. Size := OptionalHeader.DataDirectory[DirectoryEntry].Size;
  194. if MappedAsImage and (DirectoryAddress < OptionalHeader.SizeOfHeaders) then
  195. begin
  196. Result := Pointer(DWORD(Base) + DirectoryAddress);
  197. Exit;
  198. end;
  199. NtSection := ImageRvaToSection(NTHeader, Base, DirectoryAddress);
  200. if NtSection = nil then
  201. begin
  202. Size := 0;
  203. Exit;
  204. end;
  205. for I := 0 to FileHeader.NumberOfSections - 1 do
  206. if (DirectoryAddress >= NtSection^.VirtualAddress) and
  207. (DirectoryAddress < NtSection^.VirtualAddress + NtSection^.SizeOfRawData) then
  208. begin
  209. Result := Pointer(DWORD(Base) +
  210. (DirectoryAddress - NtSection^.VirtualAddress) + NtSection^.PointerToRawData);
  211. Break;
  212. end
  213. else
  214. Inc(NtSection);
  215. end;
  216. procedure MapAndLoadModuleForReadOrdinalFuncName(const ModuleName: String);
  217. type
  218. PDWORDArray = ^TDWORDArray;
  219. TDWORDArray = array [0..MaxInt div SizeOf(DWORD) - 1] of DWORD;
  220. var
  221. liImageInfo: LoadedImage;
  222. pExportDirectory: PImageExportDirectory;
  223. nDirSize: Cardinal;
  224. pDummy: PImageSectionHeader;
  225. I: Cardinal;
  226. pNameRVAs: PDWORDArray;
  227. FuncName, FuncAddr: String;
  228. Ordinal: PWORD;
  229. begin
  230. SetLength(OrdinalData, 0);
  231. if MapAndLoad(PAnsiChar(AnsiString(ModuleName)), nil, @liImageInfo, True, True) then
  232. begin
  233. try
  234. pExportDirectory := ImageDirectoryEntryToData(liImageInfo.MappedAddress,
  235. False, IMAGE_DIRECTORY_ENTRY_EXPORT, nDirSize);
  236. if (pExportDirectory <> nil) then
  237. begin
  238. pDummy := nil;
  239. pNameRVAs := ImageRvaToVa(liImageInfo.FileHeader,
  240. liImageInfo.MappedAddress,
  241. DWORD(pExportDirectory^.AddressOfNames), pDummy);
  242. pDummy := nil;
  243. Ordinal := ImageRvaToVa(liImageInfo.FileHeader,
  244. liImageInfo.MappedAddress,
  245. DWORD(pExportDirectory^.AddressOfNameOrdinals), pDummy);
  246. for I := 0 to pExportDirectory^.NumberOfNames - 1 do
  247. begin
  248. SetLength(OrdinalData, Length(OrdinalData) + 1);
  249. pDummy := nil;
  250. FuncName := PChar(ImageRvaToVa(liImageInfo.FileHeader,
  251. liImageInfo.MappedAddress, pNameRVAs^[i], pDummy));
  252. FuncAddr := PChar('0x' + IntToHex(Integer(pNameRVAs^[I]), 8));
  253. OrdinalData[Length(OrdinalData) - 1].FuncName := FuncName;
  254. OrdinalData[Length(OrdinalData) - 1].Addr := FuncAddr;
  255. OrdinalData[Length(OrdinalData) - 1].Ordinal := Ordinal^ + pExportDirectory^.Base;
  256. Inc(Ordinal);
  257. end;
  258. end;
  259. finally
  260. UnMapAndLoad(@liImageInfo);
  261. end;
  262. end;
  263. end;
  264. function ReadOrdinalFuncName(const Ordinal: DWORD): String;
  265. var
  266. I: Integer;
  267. begin
  268. Result := '';
  269. for I := 0 to Length(OrdinalData) - 1 do
  270. if OrdinalData[I].Ordinal = Ordinal then
  271. begin
  272. Result := OrdinalData[I].FuncName;
  273. Break;
  274. end;
  275. end;
  276. function ReadOrdinalFuncAddr(const Ordinal: DWORD): String;
  277. var
  278. I: Integer;
  279. begin
  280. Result := '';
  281. for I := 0 to Length(OrdinalData) - 1 do
  282. if OrdinalData[I].Ordinal = Ordinal then
  283. begin
  284. Result := OrdinalData[I].Addr;
  285. Break;
  286. end;
  287. end;
  288. procedure GetImportTable(ss: TStrings; const PEFile: String);
  289. var
  290. ImageInfo: LOADED_IMAGE;
  291. DirSize: Cardinal;
  292. pDummy: PImageSectionHeader;
  293. Image: PIMAGE_IMPORT_DESCRIPTOR;
  294. ModuleName: PAnsiChar;
  295. Thunk: PImageThunkData32;
  296. begin
  297. ss.BeginUpdate;
  298. try
  299. if MapAndLoad(PAnsiChar(AnsiString(PEFile)), nil, @ImageInfo, True, True) then
  300. begin
  301. try
  302. Image := ImageDirectoryEntryToData(ImageInfo.MappedAddress,
  303. False, IMAGE_DIRECTORY_ENTRY_IMPORT, DirSize);
  304. if (Image <> nil) then
  305. begin
  306. while Image^.Name <> 0 do
  307. begin
  308. pDummy := nil;
  309. ModuleName := ImageRvaToVa(ImageInfo.FileHeader,
  310. ImageInfo.MappedAddress, Image^.Name, pDummy);
  311. ss.Add(ModuleName);
  312. if Image^.Union.OriginalFirstThunk <> nil then
  313. Thunk := PImageThunkData32(ImageRvaToVa(ImageInfo.FileHeader,
  314. ImageInfo.MappedAddress, Image^.Union.Characteristics, pDummy))
  315. else
  316. Thunk := PImageThunkData32(ImageRvaToVa(ImageInfo.FileHeader,
  317. ImageInfo.MappedAddress, DWORD(Image^.FirstThunk), pDummy));
  318. if Thunk <> nil then
  319. try
  320. while Thunk^.Function_ <> nil do
  321. begin
  322. if (DWORD(Thunk^.Function_) and IMAGE_ORDINAL_FLAG) = IMAGE_ORDINAL_FLAG then
  323. begin
  324. if Length(OrdinalData) = 0 then
  325. MapAndLoadModuleForReadOrdinalFuncName(ModuleName);
  326. end;
  327. ss.Add(ModuleName);
  328. Inc(Thunk);
  329. end;
  330. Inc(Image);
  331. finally
  332. SetLength(OrdinalData, 0);
  333. end;
  334. end;
  335. end;
  336. finally
  337. UnMapAndLoad(@ImageInfo);
  338. end;
  339. end;
  340. finally
  341. ss.EndUpdate;
  342. end;
  343. end;
  344. procedure GetDelayImportTable(ss: TStrings; const PEFile: String);
  345. var
  346. ImageInfo: LOADED_IMAGE;
  347. DirSize: Cardinal;
  348. Image: PImgDelayDescr;
  349. ModuleName: PAnsiChar;
  350. Thunk: PImageThunkData32;
  351. function RvaToVaWithAmendment(Value: DWORD): Pointer;
  352. var
  353. pDummy: PImageSectionHeader;
  354. begin
  355. if (Value > ImageInfo.SizeOfImage) and
  356. (Value > ImageInfo.FileHeader^.OptionalHeader.ImageBase) then
  357. Dec(Value, ImageInfo.FileHeader^.OptionalHeader.ImageBase);
  358. pDummy := nil;
  359. Result := ImageRvaToVa(ImageInfo.FileHeader, ImageInfo.MappedAddress,
  360. Value, pDummy);
  361. end;
  362. begin
  363. ss.BeginUpdate;
  364. try
  365. if MapAndLoad(PAnsiChar(AnsiString(PEFile)), nil, @ImageInfo, True, True) then
  366. begin
  367. try
  368. Image := ImageDirectoryEntryToData(ImageInfo.MappedAddress,
  369. False, IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT, DirSize);
  370. if (Image <> nil) then
  371. begin
  372. while Image^.szName <> 0 do
  373. begin
  374. ModuleName := RvaToVaWithAmendment(DWORD(Image^.szName));
  375. ss.Add(ModuleName);
  376. Thunk := PImageThunkData32(RvaToVaWithAmendment(DWORD(Image^.pINT.AddressOfData)));
  377. if Thunk <> nil then
  378. try
  379. while Thunk^.Function_ <> nil do
  380. begin
  381. if (DWORD(Thunk^.Function_) and IMAGE_ORDINAL_FLAG) = IMAGE_ORDINAL_FLAG then
  382. begin
  383. if Length(OrdinalData) = 0 then
  384. MapAndLoadModuleForReadOrdinalFuncName(ModuleName);
  385. end;
  386. ss.Add(ModuleName);
  387. Inc(Thunk);
  388. end;
  389. Inc(Image);
  390. finally
  391. SetLength(OrdinalData, 0);
  392. end;
  393. end;
  394. end;
  395. finally
  396. UnMapAndLoad(@ImageInfo);
  397. end;
  398. end;
  399. finally
  400. ss.EndUpdate;
  401. end;
  402. end;
  403. procedure GetExportTable(ss: TStrings; const PEFile: String);
  404. type
  405. PDWORDArray = ^TDWORDArray;
  406. TDWORDArray = array [0..MaxInt div SizeOf(DWORD) - 1] of DWORD;
  407. var
  408. liImageInfo: LoadedImage;
  409. pExportDirectory: PImageExportDirectory;
  410. nDirSize: Cardinal;
  411. pDummy: PImageSectionHeader;
  412. I: Integer;
  413. pNameRVAs: PDWORDArray;
  414. FuncName, FuncAddr: String;
  415. begin
  416. ss.BeginUpdate;
  417. try
  418. if MapAndLoad(PAnsiChar(AnsiString(PEFile)), nil, @liImageInfo, True, True) then
  419. begin
  420. try
  421. pExportDirectory := ImageDirectoryEntryToData(liImageInfo.MappedAddress,
  422. False, IMAGE_DIRECTORY_ENTRY_EXPORT, nDirSize);
  423. if (pExportDirectory <> nil) then
  424. begin
  425. pDummy := nil;
  426. pNameRVAs := ImageRvaToVa(liImageInfo.FileHeader,
  427. liImageInfo.MappedAddress,
  428. DWORD(pExportDirectory^.AddressOfNames), pDummy);
  429. for I := 0 to pExportDirectory^.NumberOfNames - 1 do
  430. begin
  431. pDummy := nil;
  432. FuncName := PChar(ImageRvaToVa(liImageInfo.FileHeader,
  433. liImageInfo.MappedAddress, pNameRVAs^[i], pDummy));
  434. FuncAddr := PChar('0x' + IntToHex(Integer(pNameRVAs^[I]), 8));
  435. ss.Add(FuncName);
  436. end;
  437. end;
  438. finally
  439. UnMapAndLoad(@liImageInfo);
  440. end;
  441. end;
  442. finally
  443. ss.EndUpdate;
  444. end;
  445. end;
  446. end.