Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Faylor <me@cgf.cx>2005-03-22 22:00:31 +0300
committerChristopher Faylor <me@cgf.cx>2005-03-22 22:00:31 +0300
commitb1d9a0bd41fbd1b8bb1424ae79d3be26fb3a4dcd (patch)
treec98214c49d0cbf3978df204493f9f59441596ee2 /winsup/cygwin/hookapi.cc
parent7e3fd32b1cfee93aa4d73570940e3781ad2d5680 (diff)
* Makefile.in (DLL_OFILES): Add hookapi.o. Eliminate some cruft.
* cygheap.h (cygheap_types): Add new enum: HEAP_1_HOOK. (hook_chain): New struct. (init_cygheap::hooks): Define new element. * cygheap.cc (cygheap_fixup_in_child): Zero hook chain on exec. * dcrt0.cc (dll_crt0_1): Call ld_preload just before calling main function. * external.cc (cygwin_internal): Implement CW_HOOK. * fork.cc (fork_child): Call fixup_hooks_after_fork. * init.cc (cygwin_hmodule): Reinstate after a long absence. * include/sys/cygwin.h: Define CW_HOOK. * hookapi.cc: New file. * select.cc (start_thread_socket): Add debugging output. * fhandler_disk_file.cc (fhandler_disk_file::fchmod): gcc 4.x accommodation. * fhandler_socket.cc (fhandler_socket::connect): Make sure that err is initialized.
Diffstat (limited to 'winsup/cygwin/hookapi.cc')
-rw-r--r--winsup/cygwin/hookapi.cc218
1 files changed, 218 insertions, 0 deletions
diff --git a/winsup/cygwin/hookapi.cc b/winsup/cygwin/hookapi.cc
new file mode 100644
index 000000000..09c70c24b
--- /dev/null
+++ b/winsup/cygwin/hookapi.cc
@@ -0,0 +1,218 @@
+#include "winsup.h"
+#include "cygerrno.h"
+#include "security.h"
+#include "path.h"
+#include "fhandler.h"
+#include "dtable.h"
+#include "cygheap.h"
+#include <stdlib.h>
+#include <imagehlp.h>
+#include <alloca.h>
+
+#define rva(coerce, base, addr) (coerce) ((char *) (base) + (addr))
+#define rvacyg(coerce, addr) rva (coerce, cygwin_hmodule, addr)
+
+struct function_hook
+{
+ const char *name; // Function name, e.g. "DirectDrawCreateEx".
+ const void *hookfn; // Address of your function.
+ void *origfn; // Stored by HookAPICalls, the address of the original function.
+};
+
+/* Given an HMODULE, returns a pointer to the PE header */
+static PIMAGE_NT_HEADERS
+PEHeaderFromHModule (HMODULE hModule)
+{
+ PIMAGE_NT_HEADERS pNTHeader = NULL;
+
+ if (PIMAGE_DOS_HEADER(hModule) ->e_magic != IMAGE_DOS_SIGNATURE)
+ /* nothing */;
+ else
+ {
+ pNTHeader = PIMAGE_NT_HEADERS (PBYTE (hModule)
+ + PIMAGE_DOS_HEADER (hModule) ->e_lfanew);
+ if (pNTHeader->Signature != IMAGE_NT_SIGNATURE)
+ pNTHeader = NULL;
+ }
+
+ return pNTHeader;
+}
+
+void *
+putmem (PIMAGE_THUNK_DATA pi, const void *hookfn)
+{
+
+ DWORD flOldProtect, flNewProtect, flDontCare;
+ MEMORY_BASIC_INFORMATION mbi;
+
+ /* Get the current protection attributes */
+ VirtualQuery (pi, &mbi, sizeof (mbi));
+
+ /* Remove ReadOnly and ExecuteRead attributes, add on ReadWrite flag */
+ flNewProtect = mbi.Protect;
+ flNewProtect &= ~(PAGE_READONLY | PAGE_EXECUTE_READ);
+ flNewProtect |= PAGE_READWRITE;
+
+ if (!VirtualProtect (pi, sizeof (PVOID), flNewProtect, &flOldProtect) )
+ return NULL;
+
+ void *origfn = (void *) pi->u1.Function;
+ pi->u1.Function = (DWORD) hookfn;
+
+ (void) VirtualProtect (pi, sizeof (PVOID), flOldProtect, &flDontCare);
+ return origfn;
+}
+
+/* Builds stubs for and redirects the IAT for one DLL (pImportDesc) */
+
+static bool
+RedirectIAT (function_hook& fh, PIMAGE_IMPORT_DESCRIPTOR pImportDesc,
+ HMODULE hm)
+{
+ // If no import names table, we can't redirect this, so bail
+ if (pImportDesc->OriginalFirstThunk == 0)
+ return false;
+
+ /* import address table */
+ PIMAGE_THUNK_DATA pt = rva (PIMAGE_THUNK_DATA, hm, pImportDesc->FirstThunk);
+ /* import names table */
+ PIMAGE_THUNK_DATA pn = rva (PIMAGE_THUNK_DATA, hm, pImportDesc->OriginalFirstThunk);
+
+ /* Scan through the IAT, completing the stubs and redirecting the IAT
+ entries to point to the stubs. */
+ for (PIMAGE_THUNK_DATA pi = pt; pn->u1.Ordinal; pi++, pn++)
+ {
+ if (IMAGE_SNAP_BY_ORDINAL (pn->u1.Ordinal) )
+ continue;
+
+ /* import by name */
+ PIMAGE_IMPORT_BY_NAME pimp = rva (PIMAGE_IMPORT_BY_NAME, hm, pn->u1.AddressOfData);
+
+ if (strcmp (fh.name, (char *) pimp->Name) == 0)
+ {
+ fh.origfn = putmem (pi, fh.hookfn);
+ if (!fh.origfn)
+ return false;
+ hook_chain *hc;
+ for (hc = &cygheap->hooks; hc->next; hc = hc->next)
+ continue;
+ hc->next = (hook_chain *) cmalloc (HEAP_1_HOOK, sizeof (hook_chain));
+ hc->next->loc = (void **) pi;
+ hc->next->func = fh.hookfn;
+ hc->next->next = NULL;
+ break;
+ }
+ }
+
+ return true;
+}
+
+void
+get_export (function_hook& fh)
+{
+ extern HMODULE cygwin_hmodule;
+ PIMAGE_DOS_HEADER pdh = (PIMAGE_DOS_HEADER) cygwin_hmodule;
+ if (pdh->e_magic != IMAGE_DOS_SIGNATURE)
+ return;
+ PIMAGE_NT_HEADERS pnt = (PIMAGE_NT_HEADERS) ((char *) pdh + pdh->e_lfanew);
+ if (pnt->Signature != IMAGE_NT_SIGNATURE || pnt->FileHeader.SizeOfOptionalHeader == 0)
+ return;
+ PIMAGE_EXPORT_DIRECTORY pexp =
+ rvacyg (PIMAGE_EXPORT_DIRECTORY,
+ pnt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
+ if (!pexp)
+ return;
+
+ PDWORD pfuncs = rvacyg (PDWORD, pexp->AddressOfFunctions);
+ PDWORD pnames = rvacyg (PDWORD, pexp->AddressOfNames);
+ for (DWORD i = 0; i < pexp->NumberOfNames; i++)
+ if (strcmp (fh.name, rvacyg (char *, pnames[i])) == 0)
+ {
+ fh.origfn = rvacyg (void *, pfuncs[i]);
+ break;
+ }
+}
+
+static const char *
+makename (const char *name, char *&buf, int& i, int inc)
+{
+ i += inc;
+ static const char *testers[] = {"NOTUSED", "64", "32"};
+ if (i < 0 || i >= (int) (sizeof (testers) / sizeof (testers[0])))
+ return NULL;
+ if (i)
+ {
+ __small_sprintf (buf, "_%s%s", name, testers[i]);
+ name = buf;
+ }
+ return name;
+}
+
+// Top level routine to find the EXE's imports, and redirect them
+void *
+hook_cygwin (const char *name, const void *fn)
+{
+ HMODULE hm = GetModuleHandle (NULL);
+ PIMAGE_NT_HEADERS pExeNTHdr = PEHeaderFromHModule (hm);
+
+ if (!pExeNTHdr)
+ return false;
+
+ DWORD importRVA = pExeNTHdr->OptionalHeader.DataDirectory
+ [IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
+ if (!importRVA)
+ return false;
+
+ // Convert imports RVA to a usable pointer
+ PIMAGE_IMPORT_DESCRIPTOR pdfirst = rva (PIMAGE_IMPORT_DESCRIPTOR, hm, importRVA);
+
+ function_hook fh;
+ fh.origfn = NULL;
+ fh.hookfn = fn;
+ char *buf = (char *) alloca (strlen (name) + strlen ("64") + sizeof ("_"));
+ int i = -1;
+ while (!fh.origfn && (fh.name = makename (name, buf, i, 1)))
+ {
+ // Iterate through each import descriptor, and redirect if appropriate
+ for (PIMAGE_IMPORT_DESCRIPTOR pd = pdfirst; pd->FirstThunk; pd++)
+ {
+ PSTR modname = rva (PSTR, hm, pd->Name);
+ if (strcasematch (modname, "cygwin1.dll"))
+ RedirectIAT (fh, pd, hm);
+ }
+ }
+
+ while (!fh.origfn && (fh.name = makename (name, buf, i, -1)))
+ get_export (fh);
+
+ return fh.origfn;
+}
+
+void
+ld_preload ()
+{
+ char *p = getenv ("LD_PRELOAD");
+ if (!p)
+ return;
+ char *s = (char *) alloca (strlen (p) + 1);
+ strcpy (s, p);
+ char *here = NULL;
+ for (p = strtok_r (s, " \t\n", &here); p; p = strtok_r (NULL, " \t\n", &here))
+ {
+ path_conv lib (p);
+ if (!LoadLibrary (lib))
+ {
+ __seterrno ();
+ api_fatal ("error while loading shared libraries: %s: "
+ "cannot open shared object file: %s", p,
+ strerror (get_errno ()));
+ }
+ }
+}
+
+void
+fixup_hooks_after_fork ()
+{
+ for (hook_chain *hc = &cygheap->hooks; (hc = hc->next); )
+ putmem ((PIMAGE_THUNK_DATA) hc->loc, hc->func);
+}