3 Copyright 2005, 2006, 2007, 2008 Red Hat, Inc.
5 This file is part of Cygwin.
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
21 #define rva(coerce, base, addr) (coerce) ((char *) (base) + (addr))
22 #define rvacyg(coerce, addr) rva (coerce, cygwin_hmodule, addr)
26 const char *name; // Function name, e.g. "DirectDrawCreateEx".
27 const void *hookfn; // Address of your function.
28 void *origfn; // Stored by HookAPICalls, the address of the original function.
31 /* Given an HMODULE, returns a pointer to the PE header */
32 static PIMAGE_NT_HEADERS
33 PEHeaderFromHModule (HMODULE hModule)
35 PIMAGE_NT_HEADERS pNTHeader;
37 if (PIMAGE_DOS_HEADER(hModule) ->e_magic != IMAGE_DOS_SIGNATURE)
41 pNTHeader = PIMAGE_NT_HEADERS (PBYTE (hModule)
42 + PIMAGE_DOS_HEADER (hModule) ->e_lfanew);
43 if (pNTHeader->Signature != IMAGE_NT_SIGNATURE)
51 rvadelta (PIMAGE_NT_HEADERS pnt, DWORD import_rva)
53 PIMAGE_SECTION_HEADER section = (PIMAGE_SECTION_HEADER) (pnt + 1);
54 for (int i = 0; i < pnt->FileHeader.NumberOfSections; i++)
55 if (section[i].VirtualAddress <= import_rva
56 && (section[i].VirtualAddress + section[i].Misc.VirtualSize) > import_rva)
57 // if (ascii_strncasematch ((char *) section[i].Name, ".idata", IMAGE_SIZEOF_SHORT_NAME))
58 return section[i].VirtualAddress - section[i].PointerToRawData;
63 putmem (PIMAGE_THUNK_DATA pi, const void *hookfn)
66 if (!VirtualProtect (pi, sizeof (PVOID), PAGE_READWRITE, &ofl) )
69 void *origfn = (void *) pi->u1.Function;
70 pi->u1.Function = (DWORD) hookfn;
72 VirtualProtect (pi, sizeof (PVOID), ofl, &ofl);
76 /* Builds stubs for and redirects the IAT for one DLL (pImportDesc) */
79 RedirectIAT (function_hook& fh, PIMAGE_IMPORT_DESCRIPTOR pImportDesc,
82 // If no import names table, we can't redirect this, so bail
83 if (pImportDesc->OriginalFirstThunk == 0)
86 /* import address table */
87 PIMAGE_THUNK_DATA pt = rva (PIMAGE_THUNK_DATA, hm, pImportDesc->FirstThunk);
88 /* import names table */
89 PIMAGE_THUNK_DATA pn = rva (PIMAGE_THUNK_DATA, hm, pImportDesc->OriginalFirstThunk);
91 /* Scan through the IAT, completing the stubs and redirecting the IAT
92 entries to point to the stubs. */
93 for (PIMAGE_THUNK_DATA pi = pt; pn->u1.Ordinal; pi++, pn++)
95 if (IMAGE_SNAP_BY_ORDINAL (pn->u1.Ordinal) )
99 PIMAGE_IMPORT_BY_NAME pimp = rva (PIMAGE_IMPORT_BY_NAME, hm, pn->u1.AddressOfData);
101 if (strcmp (fh.name, (char *) pimp->Name) == 0)
103 fh.origfn = putmem (pi, fh.hookfn);
107 for (hc = &cygheap->hooks; hc->next; hc = hc->next)
109 hc->next = (hook_chain *) cmalloc_abort (HEAP_1_HOOK, sizeof (hook_chain));
110 hc->next->loc = (void **) pi;
111 hc->next->func = fh.hookfn;
112 hc->next->next = NULL;
121 get_export (function_hook& fh)
123 PIMAGE_DOS_HEADER pdh = (PIMAGE_DOS_HEADER) cygwin_hmodule;
124 if (pdh->e_magic != IMAGE_DOS_SIGNATURE)
126 PIMAGE_NT_HEADERS pnt = (PIMAGE_NT_HEADERS) ((char *) pdh + pdh->e_lfanew);
127 if (pnt->Signature != IMAGE_NT_SIGNATURE || pnt->FileHeader.SizeOfOptionalHeader == 0)
129 PIMAGE_EXPORT_DIRECTORY pexp =
130 rvacyg (PIMAGE_EXPORT_DIRECTORY,
131 pnt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
135 PDWORD pfuncs = rvacyg (PDWORD, pexp->AddressOfFunctions);
136 PDWORD pnames = rvacyg (PDWORD, pexp->AddressOfNames);
137 for (DWORD i = 0; i < pexp->NumberOfNames; i++)
138 if (strcmp (fh.name, rvacyg (char *, pnames[i])) == 0)
140 fh.origfn = rvacyg (void *, pfuncs[i]);
146 makename (const char *name, char *&buf, int& i, int inc)
149 static const char *testers[] = {"NOTUSED", "64", "32"};
150 if (i < 0 || i >= (int) (sizeof (testers) / sizeof (testers[0])))
154 __small_sprintf (buf, "_%s%s", name, testers[i]);
160 /* Find first missing dll in a given executable.
161 FIXME: This is not foolproof since it doesn't look for dlls in the
162 same directory as the given executable, like Windows. Instead it
163 searches for dlls in the context of the current executable. */
165 find_first_notloaded_dll (path_conv& pc)
167 const char *res = "?";
170 OBJECT_ATTRIBUTES attr;
175 status = NtOpenFile (&h, SYNCHRONIZE | GENERIC_READ,
176 pc.get_object_attr (attr, sec_none_nih),
177 &io, FILE_SHARE_READ | FILE_SHARE_WRITE,
178 FILE_SYNCHRONOUS_IO_NONALERT
179 | FILE_OPEN_FOR_BACKUP_INTENT
180 | FILE_NON_DIRECTORY_FILE);
181 if (!NT_SUCCESS (status))
184 hc = CreateFileMapping (h, &sec_none_nih, PAGE_READONLY, 0, 0, NULL);
188 hm = (HMODULE) MapViewOfFile(hc, FILE_MAP_READ, 0, 0, 0);
191 PIMAGE_NT_HEADERS pExeNTHdr;
192 pExeNTHdr = PEHeaderFromHModule (hm);
198 importRVA = pExeNTHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
202 long delta = rvadelta (pExeNTHdr, importRVA);
204 // Convert imports RVA to a usable pointer
205 PIMAGE_IMPORT_DESCRIPTOR pdfirst;
206 pdfirst = rva (PIMAGE_IMPORT_DESCRIPTOR, hm, importRVA - delta);
208 // Iterate through each import descriptor, and redirect if appropriate
209 for (PIMAGE_IMPORT_DESCRIPTOR pd = pdfirst; pd->FirstThunk; pd++)
211 const char *lib = rva (PSTR, hm, pd->Name - delta);
212 if (!LoadLibraryEx (lib, NULL, DONT_RESOLVE_DLL_REFERENCES
213 | LOAD_LIBRARY_AS_DATAFILE))
215 static char buf[NT_MAX_PATH];
216 res = strcpy (buf, lib);
222 UnmapViewOfFile (hm);
227 // Top level routine to find the EXE's imports and redirect them
229 hook_or_detect_cygwin (const char *name, const void *fn, WORD& subsys)
231 HMODULE hm = fn ? GetModuleHandle (NULL) : (HMODULE) name;
232 PIMAGE_NT_HEADERS pExeNTHdr = PEHeaderFromHModule (hm);
237 subsys = pExeNTHdr->OptionalHeader.Subsystem;
239 DWORD importRVA = pExeNTHdr->OptionalHeader.DataDirectory
240 [IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
244 long delta = fn ? 0 : rvadelta (pExeNTHdr, importRVA);
248 // Convert imports RVA to a usable pointer
249 PIMAGE_IMPORT_DESCRIPTOR pdfirst = rva (PIMAGE_IMPORT_DESCRIPTOR, hm, importRVA - delta);
254 char *buf = (char *) alloca (strlen (name) + sizeof ("_64"));
256 // Iterate through each import descriptor, and redirect if appropriate
257 for (PIMAGE_IMPORT_DESCRIPTOR pd = pdfirst; pd->FirstThunk; pd++)
259 if (!ascii_strcasematch (rva (PSTR, hm, pd->Name - delta), "cygwin1.dll"))
262 return (void *) "found it"; // just checking if executable used cygwin1.dll
264 while (!fh.origfn && (fh.name = makename (name, buf, i, 1)))
265 RedirectIAT (fh, pd, hm);
270 while (!fh.origfn && (fh.name = makename (name, buf, i, -1)))
279 char *p = getenv ("LD_PRELOAD");
282 char *s = (char *) alloca (strlen (p) + 1);
285 for (p = strtok_r (s, ":\t\n", &here); p; p = strtok_r (NULL, ":\t\n", &here))
288 WCHAR libname[lib.get_wide_win32_path_len () + 1];
289 if (!LoadLibraryW (lib.get_wide_win32_path (libname)))
292 api_fatal ("error while loading shared libraries: %s: "
293 "cannot open shared object file: %s", p,
294 strerror (get_errno ()));
300 fixup_hooks_after_fork ()
302 for (hook_chain *hc = &cygheap->hooks; (hc = hc->next); )
303 putmem ((PIMAGE_THUNK_DATA) hc->loc, hc->func);