12 #define rva(coerce, base, addr) (coerce) ((char *) (base) + (addr))
13 #define rvacyg(coerce, addr) rva (coerce, cygwin_hmodule, addr)
17 const char *name; // Function name, e.g. "DirectDrawCreateEx".
18 const void *hookfn; // Address of your function.
19 void *origfn; // Stored by HookAPICalls, the address of the original function.
22 /* Given an HMODULE, returns a pointer to the PE header */
23 static PIMAGE_NT_HEADERS
24 PEHeaderFromHModule (HMODULE hModule)
26 PIMAGE_NT_HEADERS pNTHeader;
28 if (PIMAGE_DOS_HEADER(hModule) ->e_magic != IMAGE_DOS_SIGNATURE)
32 pNTHeader = PIMAGE_NT_HEADERS (PBYTE (hModule)
33 + PIMAGE_DOS_HEADER (hModule) ->e_lfanew);
34 if (pNTHeader->Signature != IMAGE_NT_SIGNATURE)
42 rvadelta (PIMAGE_NT_HEADERS pnt, long import_rva)
44 PIMAGE_SECTION_HEADER section = (PIMAGE_SECTION_HEADER) (pnt + 1);
45 for (int i = 0; i < pnt->FileHeader.NumberOfSections; i++)
46 if (section[i].VirtualAddress <= import_rva
47 && (section[i].VirtualAddress + section[i].Misc.VirtualSize) >= import_rva)
48 // if (strncasematch ((char *) section[i].Name, ".idata", IMAGE_SIZEOF_SHORT_NAME))
49 return section[i].VirtualAddress - section[i].PointerToRawData;
54 putmem (PIMAGE_THUNK_DATA pi, const void *hookfn)
57 DWORD flOldProtect, flNewProtect, flDontCare;
58 MEMORY_BASIC_INFORMATION mbi;
60 /* Get the current protection attributes */
61 VirtualQuery (pi, &mbi, sizeof (mbi));
63 /* Remove ReadOnly and ExecuteRead attributes, add on ReadWrite flag */
64 flNewProtect = mbi.Protect;
65 flNewProtect &= ~(PAGE_READONLY | PAGE_EXECUTE_READ);
66 flNewProtect |= PAGE_READWRITE;
68 if (!VirtualProtect (pi, sizeof (PVOID), flNewProtect, &flOldProtect) )
71 void *origfn = (void *) pi->u1.Function;
72 pi->u1.Function = (DWORD) hookfn;
74 VirtualProtect (pi, sizeof (PVOID), flOldProtect, &flDontCare);
78 /* Builds stubs for and redirects the IAT for one DLL (pImportDesc) */
81 RedirectIAT (function_hook& fh, PIMAGE_IMPORT_DESCRIPTOR pImportDesc,
84 // If no import names table, we can't redirect this, so bail
85 if (pImportDesc->OriginalFirstThunk == 0)
88 /* import address table */
89 PIMAGE_THUNK_DATA pt = rva (PIMAGE_THUNK_DATA, hm, pImportDesc->FirstThunk);
90 /* import names table */
91 PIMAGE_THUNK_DATA pn = rva (PIMAGE_THUNK_DATA, hm, pImportDesc->OriginalFirstThunk);
93 /* Scan through the IAT, completing the stubs and redirecting the IAT
94 entries to point to the stubs. */
95 for (PIMAGE_THUNK_DATA pi = pt; pn->u1.Ordinal; pi++, pn++)
97 if (IMAGE_SNAP_BY_ORDINAL (pn->u1.Ordinal) )
101 PIMAGE_IMPORT_BY_NAME pimp = rva (PIMAGE_IMPORT_BY_NAME, hm, pn->u1.AddressOfData);
103 if (strcmp (fh.name, (char *) pimp->Name) == 0)
105 fh.origfn = putmem (pi, fh.hookfn);
109 for (hc = &cygheap->hooks; hc->next; hc = hc->next)
111 hc->next = (hook_chain *) cmalloc (HEAP_1_HOOK, sizeof (hook_chain));
112 hc->next->loc = (void **) pi;
113 hc->next->func = fh.hookfn;
114 hc->next->next = NULL;
123 get_export (function_hook& fh)
125 extern HMODULE cygwin_hmodule;
126 PIMAGE_DOS_HEADER pdh = (PIMAGE_DOS_HEADER) cygwin_hmodule;
127 if (pdh->e_magic != IMAGE_DOS_SIGNATURE)
129 PIMAGE_NT_HEADERS pnt = (PIMAGE_NT_HEADERS) ((char *) pdh + pdh->e_lfanew);
130 if (pnt->Signature != IMAGE_NT_SIGNATURE || pnt->FileHeader.SizeOfOptionalHeader == 0)
132 PIMAGE_EXPORT_DIRECTORY pexp =
133 rvacyg (PIMAGE_EXPORT_DIRECTORY,
134 pnt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
138 PDWORD pfuncs = rvacyg (PDWORD, pexp->AddressOfFunctions);
139 PDWORD pnames = rvacyg (PDWORD, pexp->AddressOfNames);
140 for (DWORD i = 0; i < pexp->NumberOfNames; i++)
141 if (strcmp (fh.name, rvacyg (char *, pnames[i])) == 0)
143 fh.origfn = rvacyg (void *, pfuncs[i]);
149 makename (const char *name, char *&buf, int& i, int inc)
152 static const char *testers[] = {"NOTUSED", "64", "32"};
153 if (i < 0 || i >= (int) (sizeof (testers) / sizeof (testers[0])))
157 __small_sprintf (buf, "_%s%s", name, testers[i]);
163 // Top level routine to find the EXE's imports, and redirect them
165 hook_or_detect_cygwin (const char *name, const void *fn)
167 HMODULE hm = fn ? GetModuleHandle (NULL) : (HMODULE) name;
168 PIMAGE_NT_HEADERS pExeNTHdr = PEHeaderFromHModule (hm);
173 DWORD importRVA = pExeNTHdr->OptionalHeader.DataDirectory
174 [IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
178 long delta = fn ? 0 : rvadelta (pExeNTHdr, importRVA);
182 // Convert imports RVA to a usable pointer
183 PIMAGE_IMPORT_DESCRIPTOR pdfirst = rva (PIMAGE_IMPORT_DESCRIPTOR, hm, importRVA - delta);
188 char *buf = fn ? NULL : (char *) alloca (strlen (name) + strlen ("64") + sizeof ("_"));
190 // Iterate through each import descriptor, and redirect if appropriate
191 for (PIMAGE_IMPORT_DESCRIPTOR pd = pdfirst; pd->FirstThunk; pd++)
193 if (!strcasematch (rva (PSTR, hm, pd->Name - delta), "cygwin1.dll"))
196 return (void *) "found it"; // just checking if executable used cygwin1.dll
198 while (!fh.origfn && (fh.name = makename (name, buf, i, 1)))
199 RedirectIAT (fh, pd, hm);
204 while (!fh.origfn && (fh.name = makename (name, buf, i, -1)))
213 char *p = getenv ("LD_PRELOAD");
216 char *s = (char *) alloca (strlen (p) + 1);
219 for (p = strtok_r (s, ":\t\n", &here); p; p = strtok_r (NULL, ":\t\n", &here))
222 if (!LoadLibrary (lib))
225 api_fatal ("error while loading shared libraries: %s: "
226 "cannot open shared object file: %s", p,
227 strerror (get_errno ()));
233 fixup_hooks_after_fork ()
235 for (hook_chain *hc = &cygheap->hooks; (hc = hc->next); )
236 putmem ((PIMAGE_THUNK_DATA) hc->loc, hc->func);