peloader.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586
  1. /****************************************************************************
  2. *
  3. * SciTech MGL Graphics Library
  4. *
  5. * ========================================================================
  6. *
  7. * The contents of this file are subject to the SciTech MGL Public
  8. * License Version 1.0 (the "License"); you may not use this file
  9. * except in compliance with the License. You may obtain a copy of
  10. * the License at http://www.scitechsoft.com/mgl-license.txt
  11. *
  12. * Software distributed under the License is distributed on an
  13. * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  14. * implied. See the License for the specific language governing
  15. * rights and limitations under the License.
  16. *
  17. * The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
  18. *
  19. * The Initial Developer of the Original Code is SciTech Software, Inc.
  20. * All Rights Reserved.
  21. *
  22. * ========================================================================
  23. *
  24. * Language: ANSI C
  25. * Environment: Any
  26. *
  27. * Description: Module to implement a simple Portable Binary DLL loader
  28. * library. This library can be used to load PE DLL's under
  29. * any Intel based OS, provided the DLL's do not have any
  30. * imports in the import table.
  31. *
  32. * NOTE: This loader module expects the DLL's to be built with
  33. * Watcom C++ and may produce unexpected results with
  34. * DLL's linked by another compiler.
  35. *
  36. ****************************************************************************/
  37. #include "drvlib/peloader.h"
  38. #include "pmapi.h"
  39. #include "drvlib/os/os.h"
  40. #include "drvlib/libc/init.h"
  41. #if (defined(__WINDOWS32__) || defined(__DRIVER__)) && defined(CHECKED)
  42. #define WIN32_LEAN_AND_MEAN
  43. #define STRICT
  44. #include <windows.h>
  45. #endif
  46. #include "drvlib/pe.h"
  47. /*--------------------------- Global variables ----------------------------*/
  48. static int result = PE_ok;
  49. /*------------------------- Implementation --------------------------------*/
  50. /****************************************************************************
  51. PARAMETERS:
  52. f - Handle to open file to read driver from
  53. startOffset - Offset to the start of the driver within the file
  54. RETURNS:
  55. Handle to loaded PE DLL, or NULL on failure.
  56. REMARKS:
  57. This function loads a Portable Binary DLL library from disk, relocates
  58. the code and returns a handle to the loaded library. This function is the
  59. same as the regular PE_loadLibrary except that it take a handle to an
  60. open file and an offset within that file for the DLL to load.
  61. ****************************************************************************/
  62. static int PE_readHeader(
  63. FILE *f,
  64. long startOffset,
  65. FILE_HDR *filehdr,
  66. OPTIONAL_HDR *opthdr)
  67. {
  68. EXE_HDR exehdr;
  69. ulong offset,signature;
  70. /* Read the EXE header and check for valid header signature */
  71. result = PE_invalidDLLImage;
  72. fseek(f, startOffset, SEEK_SET);
  73. if (fread(&exehdr, 1, sizeof(exehdr), f) != sizeof(exehdr))
  74. return false;
  75. if (exehdr.signature != 0x5A4D)
  76. return false;
  77. /* Now seek to the start of the PE header defined at offset 0x3C
  78. * in the MS-DOS EXE header, and read the signature and check it.
  79. */
  80. fseek(f, startOffset+0x3C, SEEK_SET);
  81. if (fread(&offset, 1, sizeof(offset), f) != sizeof(offset))
  82. return false;
  83. fseek(f, startOffset+offset, SEEK_SET);
  84. if (fread(&signature, 1, sizeof(signature), f) != sizeof(signature))
  85. return false;
  86. if (signature != 0x00004550)
  87. return false;
  88. /* Now read the PE file header and check that it is correct */
  89. if (fread(filehdr, 1, sizeof(*filehdr), f) != sizeof(*filehdr))
  90. return false;
  91. if (filehdr->Machine != IMAGE_FILE_MACHINE_I386)
  92. return false;
  93. if (!(filehdr->Characteristics & IMAGE_FILE_32BIT_MACHINE))
  94. return false;
  95. if (!(filehdr->Characteristics & IMAGE_FILE_DLL))
  96. return false;
  97. if (fread(opthdr, 1, sizeof(*opthdr), f) != sizeof(*opthdr))
  98. return false;
  99. if (opthdr->Magic != 0x10B)
  100. return false;
  101. /* Success, so return true! */
  102. return true;
  103. }
  104. /****************************************************************************
  105. PARAMETERS:
  106. f - Handle to open file to read driver from
  107. startOffset - Offset to the start of the driver within the file
  108. RETURNS:
  109. Size of the DLL file on disk, or -1 on error
  110. REMARKS:
  111. This function scans the headers for a Portable Binary DLL to determine the
  112. length of the DLL file on disk.
  113. {secret}
  114. ****************************************************************************/
  115. ulong PEAPI PE_getFileSize(
  116. FILE *f,
  117. ulong startOffset)
  118. {
  119. FILE_HDR filehdr;
  120. OPTIONAL_HDR opthdr;
  121. SECTION_HDR secthdr;
  122. ulong size;
  123. int i;
  124. /* Read the PE file headers from disk */
  125. if (!PE_readHeader(f,startOffset,&filehdr,&opthdr))
  126. return 0xFFFFFFFF;
  127. /* Scan all the section headers summing up the total size */
  128. size = opthdr.SizeOfHeaders;
  129. for (i = 0; i < filehdr.NumberOfSections; i++) {
  130. if (fread(&secthdr, 1, sizeof(secthdr), f) != sizeof(secthdr))
  131. return 0xFFFFFFFF;
  132. size += secthdr.SizeOfRawData;
  133. }
  134. return size;
  135. }
  136. /****************************************************************************
  137. DESCRIPTION:
  138. Loads a Portable Binary DLL into memory from an open file
  139. HEADER:
  140. peloader.h
  141. PARAMETERS:
  142. f - Handle to open file to read driver from
  143. startOffset - Offset to the start of the driver within the file
  144. size - Place to store the size of the driver loaded
  145. shared - True to load module into shared memory
  146. RETURNS:
  147. Handle to loaded PE DLL, or NULL on failure.
  148. REMARKS:
  149. This function loads a Portable Binary DLL library from disk, relocates
  150. the code and returns a handle to the loaded library. This function is the
  151. same as the regular PE_loadLibrary except that it take a handle to an
  152. open file and an offset within that file for the DLL to load.
  153. SEE ALSO:
  154. PE_loadLibrary, PE_getProcAddress, PE_freeLibrary
  155. ****************************************************************************/
  156. PE_MODULE * PEAPI PE_loadLibraryExt(
  157. FILE *f,
  158. ulong startOffset,
  159. ulong *size,
  160. ibool shared)
  161. {
  162. FILE_HDR filehdr;
  163. OPTIONAL_HDR opthdr;
  164. SECTION_HDR secthdr;
  165. ulong offset,pageOffset;
  166. ulong text_off,text_addr,text_size;
  167. ulong data_off,data_addr,data_size,data_end;
  168. ulong export_off,export_addr,export_size,export_end;
  169. ulong reloc_off,reloc_size;
  170. ulong image_size;
  171. int i,delta,numFixups;
  172. ushort relocType,*fixup;
  173. PE_MODULE *hMod = NULL;
  174. void *reloc = NULL;
  175. BASE_RELOCATION *baseReloc;
  176. InitLibC_t InitLibC;
  177. /* Read the PE file headers from disk */
  178. if (!PE_readHeader(f,startOffset,&filehdr,&opthdr))
  179. return NULL;
  180. /* Scan all the section headers and find the necessary sections */
  181. text_off = data_off = reloc_off = export_off = 0;
  182. text_addr = text_size = 0;
  183. data_addr = data_size = data_end = 0;
  184. export_addr = export_size = export_end = 0;
  185. reloc_size = 0;
  186. for (i = 0; i < filehdr.NumberOfSections; i++) {
  187. if (fread(&secthdr, 1, sizeof(secthdr), f) != sizeof(secthdr))
  188. goto Error;
  189. if (strcmp(secthdr.Name, ".edata") == 0 || strcmp(secthdr.Name, ".rdata") == 0) {
  190. /* Exports section */
  191. export_off = secthdr.PointerToRawData;
  192. export_addr = secthdr.VirtualAddress;
  193. export_size = secthdr.SizeOfRawData;
  194. export_end = export_addr + export_size;
  195. }
  196. else if (strcmp(secthdr.Name, ".idata") == 0) {
  197. /* Imports section, ignore */
  198. }
  199. else if (strcmp(secthdr.Name, ".reloc") == 0) {
  200. /* Relocations section */
  201. reloc_off = secthdr.PointerToRawData;
  202. reloc_size = secthdr.SizeOfRawData;
  203. }
  204. else if (!text_off && secthdr.Characteristics & IMAGE_SCN_CNT_CODE) {
  205. /* Code section */
  206. text_off = secthdr.PointerToRawData;
  207. text_addr = secthdr.VirtualAddress;
  208. text_size = secthdr.SizeOfRawData;
  209. }
  210. else if (!data_off && secthdr.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) {
  211. /* Data section */
  212. data_off = secthdr.PointerToRawData;
  213. data_addr = secthdr.VirtualAddress;
  214. data_size = secthdr.SizeOfRawData;
  215. data_end = data_addr + data_size;
  216. }
  217. }
  218. /* Check to make sure that we have all the sections we need */
  219. if (!text_off || !data_off || !export_off || !reloc_off) {
  220. result = PE_invalidDLLImage;
  221. goto Error;
  222. }
  223. /* Find the size of the image to load allocate memory for it */
  224. image_size = MAX(export_end,data_end) - text_addr;
  225. *size = sizeof(PE_MODULE) + image_size + 4096;
  226. if (shared)
  227. hMod = PM_mallocShared(*size);
  228. else
  229. hMod = PM_malloc(*size);
  230. reloc = PM_malloc(reloc_size);
  231. if (!hMod || !reloc) {
  232. result = PE_outOfMemory;
  233. goto Error;
  234. }
  235. hMod->text = (uchar*)ROUND_4K((ulong)hMod + sizeof(PE_MODULE));
  236. hMod->data = (uchar*)((ulong)hMod->text + (data_addr - text_addr));
  237. hMod->export = (uchar*)((ulong)hMod->text + (export_addr - text_addr));
  238. hMod->textBase = text_addr;
  239. hMod->dataBase = data_addr;
  240. hMod->exportBase = export_addr;
  241. hMod->exportDir = opthdr.DataDirectory[0].RelVirtualAddress - export_addr;
  242. hMod->shared = shared;
  243. /* Now read the section images from disk */
  244. result = PE_invalidDLLImage;
  245. fseek(f, startOffset+text_off, SEEK_SET);
  246. if (fread(hMod->text, 1, text_size, f) != text_size)
  247. goto Error;
  248. fseek(f, startOffset+data_off, SEEK_SET);
  249. if (fread(hMod->data, 1, data_size, f) != data_size)
  250. goto Error;
  251. fseek(f, startOffset+export_off, SEEK_SET);
  252. if (fread(hMod->export, 1, export_size, f) != export_size)
  253. goto Error;
  254. fseek(f, startOffset+reloc_off, SEEK_SET);
  255. if (fread(reloc, 1, reloc_size, f) != reloc_size)
  256. goto Error;
  257. /* Now perform relocations on all sections in the image */
  258. delta = (ulong)hMod->text - opthdr.ImageBase - text_addr;
  259. baseReloc = (BASE_RELOCATION*)reloc;
  260. for (;;) {
  261. /* Check for termination condition */
  262. if (!baseReloc->PageRVA || !baseReloc->BlockSize)
  263. break;
  264. /* Do fixups */
  265. pageOffset = baseReloc->PageRVA - hMod->textBase;
  266. numFixups = (baseReloc->BlockSize - sizeof(BASE_RELOCATION)) / sizeof(ushort);
  267. fixup = (ushort*)(baseReloc + 1);
  268. for (i = 0; i < numFixups; i++) {
  269. relocType = *fixup >> 12;
  270. if (relocType) {
  271. offset = pageOffset + (*fixup & 0x0FFF);
  272. *(ulong*)(hMod->text + offset) += delta;
  273. }
  274. fixup++;
  275. }
  276. /* Move to next relocation block */
  277. baseReloc = (BASE_RELOCATION*)((ulong)baseReloc + baseReloc->BlockSize);
  278. }
  279. /* Initialise the C runtime library for the loaded DLL */
  280. result = PE_unableToInitLibC;
  281. if ((InitLibC = (InitLibC_t)PE_getProcAddress(hMod,"_InitLibC")) == NULL)
  282. goto Error;
  283. if (!InitLibC(&___imports,PM_getOSType()))
  284. goto Error;
  285. /* Clean up, close the file and return the loaded module handle */
  286. PM_free(reloc);
  287. result = PE_ok;
  288. return hMod;
  289. Error:
  290. if (shared)
  291. PM_freeShared(hMod);
  292. else
  293. PM_free(hMod);
  294. PM_free(reloc);
  295. return NULL;
  296. }
  297. /****************************************************************************
  298. DESCRIPTION:
  299. Loads a Portable Binary DLL into memory
  300. HEADER:
  301. peloader.h
  302. PARAMETERS:
  303. szDLLName - Name of the PE DLL library to load
  304. shared - True to load module into shared memory
  305. RETURNS:
  306. Handle to loaded PE DLL, or NULL on failure.
  307. REMARKS:
  308. This function loads a Portable Binary DLL library from disk, relocates
  309. the code and returns a handle to the loaded library. This function
  310. will only work on DLL's that do not have any imports, since we don't
  311. resolve import dependencies in this function.
  312. SEE ALSO:
  313. PE_getProcAddress, PE_freeLibrary
  314. ****************************************************************************/
  315. PE_MODULE * PEAPI PE_loadLibrary(
  316. const char *szDLLName,
  317. ibool shared)
  318. {
  319. PE_MODULE *hMod;
  320. #if (defined(__WINDOWS32__) || defined(__DRIVER__)) && defined(CHECKED)
  321. if (!shared) {
  322. PM_MODULE hInst;
  323. InitLibC_t InitLibC;
  324. /* For Win32 if are building checked libraries for debugging, we use
  325. * the real Win32 DLL functions so that we can debug the resulting DLL
  326. * files with the Win32 debuggers. Note that we can't do this if
  327. * we need to load the files into a shared memory context.
  328. */
  329. if ((hInst = PM_loadLibrary(szDLLName)) == NULL) {
  330. result = PE_fileNotFound;
  331. return NULL;
  332. }
  333. /* Initialise the C runtime library for the loaded DLL */
  334. result = PE_unableToInitLibC;
  335. if ((InitLibC = (void*)PM_getProcAddress(hInst,"_InitLibC")) == NULL)
  336. return NULL;
  337. if (!InitLibC(&___imports,PM_getOSType()))
  338. return NULL;
  339. /* Allocate the PE_MODULE structure */
  340. if ((hMod = PM_malloc(sizeof(*hMod))) == NULL)
  341. return NULL;
  342. hMod->text = (void*)hInst;
  343. hMod->shared = -1;
  344. /* DLL loaded successfully so return module handle */
  345. result = PE_ok;
  346. return hMod;
  347. }
  348. else
  349. #endif
  350. {
  351. FILE *f;
  352. ulong size;
  353. /* Attempt to open the file on disk */
  354. if (shared < 0)
  355. shared = 0;
  356. if ((f = fopen(szDLLName,"rb")) == NULL) {
  357. result = PE_fileNotFound;
  358. return NULL;
  359. }
  360. hMod = PE_loadLibraryExt(f,0,&size,shared);
  361. fclose(f);
  362. return hMod;
  363. }
  364. }
  365. /****************************************************************************
  366. DESCRIPTION:
  367. Loads a Portable Binary DLL into memory
  368. HEADER:
  369. peloader.h
  370. PARAMETERS:
  371. szDLLName - Name of the PE DLL library to load
  372. shared - True to load module into shared memory
  373. RETURNS:
  374. Handle to loaded PE DLL, or NULL on failure.
  375. REMARKS:
  376. This function is the same as the regular PE_loadLibrary function, except
  377. that it looks for the drivers in the MGL_ROOT/drivers directory or a
  378. /drivers directory relative to the current directory.
  379. SEE ALSO:
  380. PE_loadLibraryMGL, PE_getProcAddress, PE_freeLibrary
  381. ****************************************************************************/
  382. PE_MODULE * PEAPI PE_loadLibraryMGL(
  383. const char *szDLLName,
  384. ibool shared)
  385. {
  386. #if !defined(__WIN32_VXD__) && !defined(__NT_DRIVER__)
  387. PE_MODULE *hMod;
  388. #endif
  389. char path[256] = "";
  390. /* We look in the 'drivers' directory, optionally under the MGL_ROOT
  391. * environment variable directory.
  392. */
  393. #if !defined(__WIN32_VXD__) && !defined(__NT_DRIVER__)
  394. if (getenv("MGL_ROOT")) {
  395. strcpy(path,getenv("MGL_ROOT"));
  396. PM_backslash(path);
  397. }
  398. strcat(path,"drivers");
  399. PM_backslash(path);
  400. strcat(path,szDLLName);
  401. if ((hMod = PE_loadLibrary(path,shared)) != NULL)
  402. return hMod;
  403. #endif
  404. strcpy(path,"drivers");
  405. PM_backslash(path);
  406. strcat(path,szDLLName);
  407. return PE_loadLibrary(path,shared);
  408. }
  409. /****************************************************************************
  410. DESCRIPTION:
  411. Gets a function address from a Portable Binary DLL
  412. HEADER:
  413. peloader.h
  414. PARAMETERS:
  415. hModule - Handle to a loaded PE DLL library
  416. szProcName - Name of the function to get the address of
  417. RETURNS:
  418. Pointer to the function, or NULL on failure.
  419. REMARKS:
  420. This function searches for the named, exported function in a loaded PE
  421. DLL library, and returns the address of the function. If the function is
  422. not found in the library, this function return NULL.
  423. SEE ALSO:
  424. PE_loadLibrary, PE_freeLibrary
  425. ****************************************************************************/
  426. void * PEAPI PE_getProcAddress(
  427. PE_MODULE *hModule,
  428. const char *szProcName)
  429. {
  430. #if (defined(__WINDOWS32__) || defined(__DRIVER__)) && defined(CHECKED)
  431. if (hModule->shared == -1)
  432. return (void*)PM_getProcAddress(hModule->text,szProcName);
  433. else
  434. #endif
  435. {
  436. uint i;
  437. EXPORT_DIRECTORY *exports;
  438. ulong funcOffset;
  439. ulong *AddressTable;
  440. ulong *NameTable;
  441. ushort *OrdinalTable;
  442. char *name;
  443. /* Find the address of the export tables from the export section */
  444. if (!hModule)
  445. return NULL;
  446. exports = (EXPORT_DIRECTORY*)(hModule->export + hModule->exportDir);
  447. AddressTable = (ulong*)(hModule->export + exports->AddressTableRVA - hModule->exportBase);
  448. NameTable = (ulong*)(hModule->export + exports->NameTableRVA - hModule->exportBase);
  449. OrdinalTable = (ushort*)(hModule->export + exports->OrdinalTableRVA - hModule->exportBase);
  450. /* Search the export name table to find the function name */
  451. for (i = 0; i < exports->NumberOfNamePointers; i++) {
  452. name = (char*)(hModule->export + NameTable[i] - hModule->exportBase);
  453. if (strcmp(name,szProcName) == 0)
  454. break;
  455. }
  456. if (i == exports->NumberOfNamePointers)
  457. return NULL;
  458. funcOffset = AddressTable[OrdinalTable[i]];
  459. if (!funcOffset)
  460. return NULL;
  461. return (void*)(hModule->text + funcOffset - hModule->textBase);
  462. }
  463. }
  464. /****************************************************************************
  465. DESCRIPTION:
  466. Frees a loaded Portable Binary DLL
  467. HEADER:
  468. peloader.h
  469. PARAMETERS:
  470. hModule - Handle to a loaded PE DLL library to free
  471. REMARKS:
  472. This function frees a loaded PE DLL library from memory.
  473. SEE ALSO:
  474. PE_getProcAddress, PE_loadLibrary
  475. ****************************************************************************/
  476. void PEAPI PE_freeLibrary(
  477. PE_MODULE *hModule)
  478. {
  479. TerminateLibC_t TerminateLibC;
  480. #if (defined(__WINDOWS32__) || defined(__DRIVER__)) && defined(CHECKED)
  481. if (hModule->shared == -1) {
  482. /* Run the C runtime library exit code on module unload */
  483. if ((TerminateLibC = (TerminateLibC_t)PM_getProcAddress(hModule->text,"_TerminateLibC")) != NULL)
  484. TerminateLibC();
  485. PM_freeLibrary(hModule->text);
  486. PM_free(hModule);
  487. }
  488. else
  489. #endif
  490. {
  491. if (hModule) {
  492. /* Run the C runtime library exit code on module unload */
  493. if ((TerminateLibC = (TerminateLibC_t)PE_getProcAddress(hModule,"_TerminateLibC")) != NULL)
  494. TerminateLibC();
  495. if (hModule->shared)
  496. PM_freeShared(hModule);
  497. else
  498. PM_free(hModule);
  499. }
  500. }
  501. }
  502. /****************************************************************************
  503. DESCRIPTION:
  504. Returns the error code for the last operation
  505. HEADER:
  506. peloader.h
  507. RETURNS:
  508. Error code for the last operation.
  509. SEE ALSO:
  510. PE_getProcAddress, PE_loadLibrary
  511. ****************************************************************************/
  512. int PEAPI PE_getError(void)
  513. {
  514. return result;
  515. }