3 Copyright 2005, 2006, 2007, 2008, 2011 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
13 #include <sys/param.h>
22 #define rva(coerce, base, addr) (coerce) ((char *) (base) + (addr))
23 #define rvacyg(coerce, addr) rva (coerce, cygwin_hmodule, addr)
27 const char *name; // Function name, e.g. "DirectDrawCreateEx".
28 const void *hookfn; // Address of your function.
29 void *origfn; // Stored by HookAPICalls, the address of the original function.
32 /* Given an HMODULE, returns a pointer to the PE header */
33 static PIMAGE_NT_HEADERS
34 PEHeaderFromHModule (HMODULE hModule)
36 PIMAGE_NT_HEADERS pNTHeader;
38 if (PIMAGE_DOS_HEADER(hModule) ->e_magic != IMAGE_DOS_SIGNATURE)
42 pNTHeader = PIMAGE_NT_HEADERS (PBYTE (hModule)
43 + PIMAGE_DOS_HEADER (hModule) ->e_lfanew);
44 if (pNTHeader->Signature != IMAGE_NT_SIGNATURE)
52 rvadelta (PIMAGE_NT_HEADERS pnt, DWORD import_rva)
54 PIMAGE_SECTION_HEADER section = (PIMAGE_SECTION_HEADER) (pnt + 1);
55 for (int i = 0; i < pnt->FileHeader.NumberOfSections; i++)
56 if (section[i].VirtualAddress <= import_rva
57 && (section[i].VirtualAddress + section[i].Misc.VirtualSize) > import_rva)
58 // if (ascii_strncasematch ((char *) section[i].Name, ".idata", IMAGE_SIZEOF_SHORT_NAME))
59 return section[i].VirtualAddress - section[i].PointerToRawData;
64 putmem (PIMAGE_THUNK_DATA pi, const void *hookfn)
67 if (!VirtualProtect (pi, sizeof (PVOID), PAGE_READWRITE, &ofl) )
70 void *origfn = (void *) pi->u1.Function;
71 pi->u1.Function = (DWORD) hookfn;
73 VirtualProtect (pi, sizeof (PVOID), ofl, &ofl);
77 /* Builds stubs for and redirects the IAT for one DLL (pImportDesc) */
80 RedirectIAT (function_hook& fh, PIMAGE_IMPORT_DESCRIPTOR pImportDesc,
83 // If no import names table, we can't redirect this, so bail
84 if (pImportDesc->OriginalFirstThunk == 0)
87 /* import address table */
88 PIMAGE_THUNK_DATA pt = rva (PIMAGE_THUNK_DATA, hm, pImportDesc->FirstThunk);
89 /* import names table */
90 PIMAGE_THUNK_DATA pn = rva (PIMAGE_THUNK_DATA, hm, pImportDesc->OriginalFirstThunk);
92 /* Scan through the IAT, completing the stubs and redirecting the IAT
93 entries to point to the stubs. */
94 for (PIMAGE_THUNK_DATA pi = pt; pn->u1.Ordinal; pi++, pn++)
96 if (IMAGE_SNAP_BY_ORDINAL (pn->u1.Ordinal) )
100 PIMAGE_IMPORT_BY_NAME pimp = rva (PIMAGE_IMPORT_BY_NAME, hm, pn->u1.AddressOfData);
102 if (strcmp (fh.name, (char *) pimp->Name) == 0)
104 fh.origfn = putmem (pi, fh.hookfn);
108 for (hc = &cygheap->hooks; hc->next; hc = hc->next)
110 hc->next = (hook_chain *) cmalloc_abort (HEAP_1_HOOK, sizeof (hook_chain));
111 hc->next->loc = (void **) pi;
112 hc->next->func = fh.hookfn;
113 hc->next->next = NULL;
122 get_export (function_hook& fh)
124 PIMAGE_DOS_HEADER pdh = (PIMAGE_DOS_HEADER) cygwin_hmodule;
125 if (pdh->e_magic != IMAGE_DOS_SIGNATURE)
127 PIMAGE_NT_HEADERS pnt = (PIMAGE_NT_HEADERS) ((char *) pdh + pdh->e_lfanew);
128 if (pnt->Signature != IMAGE_NT_SIGNATURE || pnt->FileHeader.SizeOfOptionalHeader == 0)
130 PIMAGE_EXPORT_DIRECTORY pexp =
131 rvacyg (PIMAGE_EXPORT_DIRECTORY,
132 pnt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
136 PDWORD pfuncs = rvacyg (PDWORD, pexp->AddressOfFunctions);
137 PDWORD pnames = rvacyg (PDWORD, pexp->AddressOfNames);
138 for (DWORD i = 0; i < pexp->NumberOfNames; i++)
139 if (strcmp (fh.name, rvacyg (char *, pnames[i])) == 0)
141 fh.origfn = rvacyg (void *, pfuncs[i]);
147 makename (const char *name, char *&buf, int& i, int inc)
150 static const char *testers[] = {"NOTUSED", "64", "32"};
151 if (i < 0 || i >= (int) (sizeof (testers) / sizeof (testers[0])))
155 __small_sprintf (buf, "_%s%s", name, testers[i]);
161 /* Find first missing dll in a given executable.
162 FIXME: This is not foolproof since it doesn't look for dlls in the
163 same directory as the given executable, like Windows. Instead it
164 searches for dlls in the context of the current executable. */
166 find_first_notloaded_dll (path_conv& pc)
168 const char *res = "?";
171 OBJECT_ATTRIBUTES attr;
176 status = NtOpenFile (&h, SYNCHRONIZE | GENERIC_READ,
177 pc.get_object_attr (attr, sec_none_nih),
178 &io, FILE_SHARE_VALID_FLAGS,
179 FILE_SYNCHRONOUS_IO_NONALERT
180 | FILE_OPEN_FOR_BACKUP_INTENT
181 | FILE_NON_DIRECTORY_FILE);
182 if (!NT_SUCCESS (status))
185 hc = CreateFileMapping (h, &sec_none_nih, PAGE_READONLY, 0, 0, NULL);
189 hm = (HMODULE) MapViewOfFile(hc, FILE_MAP_READ, 0, 0, 0);
192 PIMAGE_NT_HEADERS pExeNTHdr;
193 pExeNTHdr = PEHeaderFromHModule (hm);
198 importRVA = pExeNTHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
201 long delta = rvadelta (pExeNTHdr, importRVA);
203 // Convert imports RVA to a usable pointer
204 PIMAGE_IMPORT_DESCRIPTOR pdfirst;
205 pdfirst = rva (PIMAGE_IMPORT_DESCRIPTOR, hm, importRVA - delta);
207 // Iterate through each import descriptor, and redirect if appropriate
208 for (PIMAGE_IMPORT_DESCRIPTOR pd = pdfirst; pd->FirstThunk; pd++)
210 const char *lib = rva (PSTR, hm, pd->Name - delta);
211 if (!LoadLibraryEx (lib, NULL, DONT_RESOLVE_DLL_REFERENCES
212 | LOAD_LIBRARY_AS_DATAFILE))
214 static char buf[NT_MAX_PATH];
215 res = strcpy (buf, lib);
223 UnmapViewOfFile (hm);
228 // Top level routine to find the EXE's imports and redirect them
230 hook_or_detect_cygwin (const char *name, const void *fn, WORD& subsys, HANDLE h)
232 HMODULE hm = fn ? GetModuleHandle (NULL) : (HMODULE) name;
233 PIMAGE_NT_HEADERS pExeNTHdr = PEHeaderFromHModule (hm);
238 subsys = pExeNTHdr->OptionalHeader.Subsystem;
240 DWORD importRVA = pExeNTHdr->OptionalHeader.DataDirectory
241 [IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
242 DWORD importRVASize = pExeNTHdr->OptionalHeader.DataDirectory
243 [IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
247 long delta = fn ? 0 : rvadelta (pExeNTHdr, importRVA);
252 // Convert imports RVA to a usable pointer
253 PIMAGE_IMPORT_DESCRIPTOR pdfirst;
256 if (h && importRVA + importRVASize > wincap.allocation_granularity ())
258 /* If h is not NULL, the calling function only mapped at most the first
259 64K of the image. The IAT is usually at the end of the image, so
260 what we do here is to map the IAT into our address space if it doesn't
261 reside in the first 64K anyway. The offset must be a multiple of the
262 allocation granularity, though, so we have to map a bit more. */
263 offset = rounddown (importRVA, wincap.allocation_granularity ());
264 DWORD size = importRVA - offset + importRVASize;
265 map = (char *) MapViewOfFile (h, FILE_MAP_READ, 0, offset, size);
268 pdfirst = rva (PIMAGE_IMPORT_DESCRIPTOR, map, importRVA - offset);
271 pdfirst = rva (PIMAGE_IMPORT_DESCRIPTOR, hm, importRVA);
276 char *buf = (char *) alloca (strlen (name) + sizeof ("_64"));
278 // Iterate through each import descriptor, and redirect if appropriate
279 for (PIMAGE_IMPORT_DESCRIPTOR pd = pdfirst; pd->FirstThunk; pd++)
281 if (!ascii_strcasematch (rva (PSTR, map ?: (char *) hm,
282 pd->Name - delta - offset), "cygwin1.dll"))
287 UnmapViewOfFile (map);
288 return (void *) "found it"; // just checking if executable used cygwin1.dll
291 while (!fh.origfn && (fh.name = makename (name, buf, i, 1)))
292 RedirectIAT (fh, pd, hm);
298 UnmapViewOfFile (map);
300 while (!fh.origfn && (fh.name = makename (name, buf, i, -1)))
309 char *p = getenv ("LD_PRELOAD");
312 char *s = (char *) alloca (strlen (p) + 1);
315 for (p = strtok_r (s, ":\t\n", &here); p; p = strtok_r (NULL, ":\t\n", &here))
318 WCHAR libname[lib.get_wide_win32_path_len () + 1];
319 if (!LoadLibraryW (lib.get_wide_win32_path (libname)))
322 api_fatal ("error while loading shared libraries: %s: "
323 "cannot open shared object file: %s", p,
324 strerror (get_errno ()));
330 fixup_hooks_after_fork ()
332 for (hook_chain *hc = &cygheap->hooks; (hc = hc->next); )
333 putmem ((PIMAGE_THUNK_DATA) hc->loc, hc->func);