aboutsummaryrefslogtreecommitdiff
path: root/lib/interception
diff options
context:
space:
mode:
Diffstat (limited to 'lib/interception')
-rw-r--r--lib/interception/.clang-format1
-rw-r--r--lib/interception/interception_linux.h10
-rw-r--r--lib/interception/interception_win.cc60
-rw-r--r--lib/interception/interception_win.h4
4 files changed, 66 insertions, 9 deletions
diff --git a/lib/interception/.clang-format b/lib/interception/.clang-format
new file mode 100644
index 000000000000..f6cb8ad931f5
--- /dev/null
+++ b/lib/interception/.clang-format
@@ -0,0 +1 @@
+BasedOnStyle: Google
diff --git a/lib/interception/interception_linux.h b/lib/interception/interception_linux.h
index d3f774bede9f..27a66c882041 100644
--- a/lib/interception/interception_linux.h
+++ b/lib/interception/interception_linux.h
@@ -35,12 +35,12 @@ void *GetFuncAddrVer(const char *func_name, const char *ver);
(::__interception::uptr) & WRAP(func))
#if !defined(__ANDROID__) // android does not have dlvsym
-# define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \
- ::__interception::real_##func = (func##_f)(unsigned long) \
- ::__interception::GetFuncAddrVer(#func, symver)
+#define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \
+ (::__interception::real_##func = (func##_f)( \
+ unsigned long)::__interception::GetFuncAddrVer(#func, symver))
#else
-# define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \
- INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func)
+#define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \
+ INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func)
#endif // !defined(__ANDROID__)
#endif // INTERCEPTION_LINUX_H
diff --git a/lib/interception/interception_win.cc b/lib/interception/interception_win.cc
index 19cf184948b9..4c04c83b982b 100644
--- a/lib/interception/interception_win.cc
+++ b/lib/interception/interception_win.cc
@@ -15,6 +15,7 @@
#ifdef _WIN32
#include "interception.h"
+#define WIN32_LEAN_AND_MEAN
#include <windows.h>
namespace __interception {
@@ -182,7 +183,7 @@ bool OverrideFunction(uptr old_func, uptr new_func, uptr *orig_old_func) {
return true;
}
-static const void **InterestingDLLsAvailable() {
+static void **InterestingDLLsAvailable() {
const char *InterestingDLLs[] = {
"kernel32.dll",
"msvcr110.dll", // VS2012
@@ -198,14 +199,65 @@ static const void **InterestingDLLsAvailable() {
result[j++] = (void *)h;
}
}
- return (const void **)&result[0];
+ return &result[0];
+}
+
+namespace {
+// Utility for reading loaded PE images.
+template <typename T> class RVAPtr {
+ public:
+ RVAPtr(void *module, uptr rva)
+ : ptr_(reinterpret_cast<T *>(reinterpret_cast<char *>(module) + rva)) {}
+ operator T *() { return ptr_; }
+ T *operator->() { return ptr_; }
+ T *operator++() { return ++ptr_; }
+
+ private:
+ T *ptr_;
+};
+} // namespace
+
+// Internal implementation of GetProcAddress. At least since Windows 8,
+// GetProcAddress appears to initialize DLLs before returning function pointers
+// into them. This is problematic for the sanitizers, because they typically
+// want to intercept malloc *before* MSVCRT initializes. Our internal
+// implementation walks the export list manually without doing initialization.
+uptr InternalGetProcAddress(void *module, const char *func_name) {
+ // Check that the module header is full and present.
+ RVAPtr<IMAGE_DOS_HEADER> dos_stub(module, 0);
+ RVAPtr<IMAGE_NT_HEADERS> headers(module, dos_stub->e_lfanew);
+ if (!module || dos_stub->e_magic != IMAGE_DOS_SIGNATURE || // "MZ"
+ headers->Signature != IMAGE_NT_SIGNATURE || // "PE\0\0"
+ headers->FileHeader.SizeOfOptionalHeader <
+ sizeof(IMAGE_OPTIONAL_HEADER)) {
+ return 0;
+ }
+
+ IMAGE_DATA_DIRECTORY *export_directory =
+ &headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
+ RVAPtr<IMAGE_EXPORT_DIRECTORY> exports(module,
+ export_directory->VirtualAddress);
+ RVAPtr<DWORD> functions(module, exports->AddressOfFunctions);
+ RVAPtr<DWORD> names(module, exports->AddressOfNames);
+ RVAPtr<WORD> ordinals(module, exports->AddressOfNameOrdinals);
+
+ for (DWORD i = 0; i < exports->NumberOfNames; i++) {
+ RVAPtr<char> name(module, names[i]);
+ if (!strcmp(func_name, name)) {
+ DWORD index = ordinals[i];
+ RVAPtr<char> func(module, functions[index]);
+ return (uptr)(char *)func;
+ }
+ }
+
+ return 0;
}
static bool GetFunctionAddressInDLLs(const char *func_name, uptr *func_addr) {
*func_addr = 0;
- const void **DLLs = InterestingDLLsAvailable();
+ void **DLLs = InterestingDLLsAvailable();
for (size_t i = 0; *func_addr == 0 && DLLs[i]; ++i)
- *func_addr = (uptr)GetProcAddress((HMODULE)DLLs[i], func_name);
+ *func_addr = InternalGetProcAddress(DLLs[i], func_name);
return (*func_addr != 0);
}
diff --git a/lib/interception/interception_win.h b/lib/interception/interception_win.h
index ba768a7233f9..96c4a0c0f5a3 100644
--- a/lib/interception/interception_win.h
+++ b/lib/interception/interception_win.h
@@ -30,6 +30,10 @@ bool OverrideFunction(uptr old_func, uptr new_func, uptr *orig_old_func = 0);
// Overrides a function in a system DLL or DLL CRT by its exported name.
bool OverrideFunction(const char *name, uptr new_func, uptr *orig_old_func = 0);
+
+// Windows-only replacement for GetProcAddress. Useful for some sanitizers.
+uptr InternalGetProcAddress(void *module, const char *func_name);
+
} // namespace __interception
#if defined(INTERCEPTION_DYNAMIC_CRT)