+/* hookapi.cc
+
+ Copyright 2005, 2006, 2007, 2008, 2011 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
#include "winsup.h"
+#include <stdlib.h>
+#include <sys/param.h>
+#include "ntdll.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)
return pNTHeader;
}
-long
+static long
rvadelta (PIMAGE_NT_HEADERS pnt, DWORD import_rva)
{
PIMAGE_SECTION_HEADER section = (PIMAGE_SECTION_HEADER) (pnt + 1);
for (int i = 0; i < pnt->FileHeader.NumberOfSections; i++)
if (section[i].VirtualAddress <= import_rva
- && (section[i].VirtualAddress + section[i].Misc.VirtualSize) >= import_rva)
- // if (strncasematch ((char *) section[i].Name, ".idata", IMAGE_SIZEOF_SHORT_NAME))
+ && (section[i].VirtualAddress + section[i].Misc.VirtualSize) > import_rva)
+ // if (ascii_strncasematch ((char *) section[i].Name, ".idata", IMAGE_SIZEOF_SHORT_NAME))
return section[i].VirtualAddress - section[i].PointerToRawData;
return -1;
}
-void *
+static void *
putmem (PIMAGE_THUNK_DATA pi, const void *hookfn)
{
DWORD ofl;
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 = (hook_chain *) cmalloc_abort (HEAP_1_HOOK, sizeof (hook_chain));
hc->next->loc = (void **) pi;
hc->next->func = fh.hookfn;
hc->next->next = NULL;
return true;
}
-void
+static 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;
return name;
}
-// Top level routine to find the EXE's imports, and redirect them
+/* Find first missing dll in a given executable.
+ FIXME: This is not foolproof since it doesn't look for dlls in the
+ same directory as the given executable, like Windows. Instead it
+ searches for dlls in the context of the current executable. */
+const char *
+find_first_notloaded_dll (path_conv& pc)
+{
+ const char *res = "?";
+ HANDLE hc = NULL;
+ HMODULE hm = NULL;
+ OBJECT_ATTRIBUTES attr;
+ IO_STATUS_BLOCK io;
+ HANDLE h;
+ NTSTATUS status;
+
+ status = NtOpenFile (&h, SYNCHRONIZE | GENERIC_READ,
+ pc.get_object_attr (attr, sec_none_nih),
+ &io, FILE_SHARE_VALID_FLAGS,
+ FILE_SYNCHRONOUS_IO_NONALERT
+ | FILE_OPEN_FOR_BACKUP_INTENT
+ | FILE_NON_DIRECTORY_FILE);
+ if (!NT_SUCCESS (status))
+ goto out;
+
+ hc = CreateFileMapping (h, &sec_none_nih, PAGE_READONLY, 0, 0, NULL);
+ NtClose (h);
+ if (!hc)
+ goto out;
+ hm = (HMODULE) MapViewOfFile(hc, FILE_MAP_READ, 0, 0, 0);
+ CloseHandle (hc);
+
+ PIMAGE_NT_HEADERS pExeNTHdr;
+ pExeNTHdr = PEHeaderFromHModule (hm);
+
+ if (pExeNTHdr)
+ {
+ DWORD importRVA;
+ importRVA = pExeNTHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
+ if (importRVA)
+ {
+ long delta = rvadelta (pExeNTHdr, importRVA);
+
+ // Convert imports RVA to a usable pointer
+ PIMAGE_IMPORT_DESCRIPTOR pdfirst;
+ pdfirst = rva (PIMAGE_IMPORT_DESCRIPTOR, hm, importRVA - delta);
+
+ // Iterate through each import descriptor, and redirect if appropriate
+ for (PIMAGE_IMPORT_DESCRIPTOR pd = pdfirst; pd->FirstThunk; pd++)
+ {
+ const char *lib = rva (PSTR, hm, pd->Name - delta);
+ if (!LoadLibraryEx (lib, NULL, DONT_RESOLVE_DLL_REFERENCES
+ | LOAD_LIBRARY_AS_DATAFILE))
+ {
+ static char buf[NT_MAX_PATH];
+ res = strcpy (buf, lib);
+ }
+ }
+ }
+ }
+
+out:
+ if (hm)
+ UnmapViewOfFile (hm);
+
+ return res;
+}
+
+// Top level routine to find the EXE's imports and redirect them
void *
-hook_or_detect_cygwin (const char *name, const void *fn)
+hook_or_detect_cygwin (const char *name, const void *fn, WORD& subsys, HANDLE h)
{
HMODULE hm = fn ? GetModuleHandle (NULL) : (HMODULE) name;
PIMAGE_NT_HEADERS pExeNTHdr = PEHeaderFromHModule (hm);
if (!pExeNTHdr)
return false;
+ subsys = pExeNTHdr->OptionalHeader.Subsystem;
+
DWORD importRVA = pExeNTHdr->OptionalHeader.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
+ DWORD importRVASize = pExeNTHdr->OptionalHeader.DataDirectory
+ [IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
if (!importRVA)
return false;
long delta = fn ? 0 : rvadelta (pExeNTHdr, importRVA);
if (delta < 0)
return false;
+ importRVA -= delta;
// Convert imports RVA to a usable pointer
- PIMAGE_IMPORT_DESCRIPTOR pdfirst = rva (PIMAGE_IMPORT_DESCRIPTOR, hm, importRVA - delta);
+ PIMAGE_IMPORT_DESCRIPTOR pdfirst;
+ char *map = NULL;
+ DWORD offset = 0;
+ if (h && importRVA + importRVASize > wincap.allocation_granularity ())
+ {
+ /* If h is not NULL, the calling function only mapped at most the first
+ 64K of the image. The IAT is usually at the end of the image, so
+ what we do here is to map the IAT into our address space if it doesn't
+ reside in the first 64K anyway. The offset must be a multiple of the
+ allocation granularity, though, so we have to map a bit more. */
+ offset = rounddown (importRVA, wincap.allocation_granularity ());
+ DWORD size = importRVA - offset + importRVASize;
+ map = (char *) MapViewOfFile (h, FILE_MAP_READ, 0, offset, size);
+ if (!map)
+ return false;
+ pdfirst = rva (PIMAGE_IMPORT_DESCRIPTOR, map, importRVA - offset);
+ }
+ else
+ pdfirst = rva (PIMAGE_IMPORT_DESCRIPTOR, hm, importRVA);
function_hook fh;
fh.origfn = NULL;
fh.hookfn = fn;
char *buf = (char *) alloca (strlen (name) + sizeof ("_64"));
- int i;
+ int i = 0;
// Iterate through each import descriptor, and redirect if appropriate
for (PIMAGE_IMPORT_DESCRIPTOR pd = pdfirst; pd->FirstThunk; pd++)
{
- if (!strcasematch (rva (PSTR, hm, pd->Name - delta), "cygwin1.dll"))
+ if (!ascii_strcasematch (rva (PSTR, map ?: (char *) hm,
+ pd->Name - delta - offset), "cygwin1.dll"))
continue;
if (!fn)
- return (void *) "found it"; // just checking if executable used cygwin1.dll
+ {
+ if (map)
+ UnmapViewOfFile (map);
+ return (void *) "found it"; // just checking if executable used cygwin1.dll
+ }
i = -1;
while (!fh.origfn && (fh.name = makename (name, buf, i, 1)))
RedirectIAT (fh, pd, hm);
break;
}
+ if (map)
+ UnmapViewOfFile (map);
+
while (!fh.origfn && (fh.name = makename (name, buf, i, -1)))
get_export (fh);
for (p = strtok_r (s, ":\t\n", &here); p; p = strtok_r (NULL, ":\t\n", &here))
{
path_conv lib (p);
- if (!LoadLibrary (lib))
+ WCHAR libname[lib.get_wide_win32_path_len () + 1];
+ if (!LoadLibraryW (lib.get_wide_win32_path (libname)))
{
__seterrno ();
api_fatal ("error while loading shared libraries: %s: "