summaryrefslogtreecommitdiffstats
path: root/toolkit/xre/test/win/TestDllInterceptor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/xre/test/win/TestDllInterceptor.cpp')
-rw-r--r--toolkit/xre/test/win/TestDllInterceptor.cpp237
1 files changed, 237 insertions, 0 deletions
diff --git a/toolkit/xre/test/win/TestDllInterceptor.cpp b/toolkit/xre/test/win/TestDllInterceptor.cpp
new file mode 100644
index 000000000..dff71817f
--- /dev/null
+++ b/toolkit/xre/test/win/TestDllInterceptor.cpp
@@ -0,0 +1,237 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#if _WIN32_WINNT < 0x0600
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x0600
+#endif
+
+#include <shlobj.h>
+#include <stdio.h>
+
+#include "mozilla/WindowsVersion.h"
+#include "nsWindowsDllInterceptor.h"
+#include "nsWindowsHelpers.h"
+
+using namespace mozilla;
+
+struct payload {
+ UINT64 a;
+ UINT64 b;
+ UINT64 c;
+
+ bool operator==(const payload &other) const {
+ return (a == other.a &&
+ b == other.b &&
+ c == other.c);
+ }
+};
+
+extern "C" __declspec(dllexport) __declspec(noinline) payload rotatePayload(payload p) {
+ UINT64 tmp = p.a;
+ p.a = p.b;
+ p.b = p.c;
+ p.c = tmp;
+ return p;
+}
+
+static bool patched_func_called = false;
+
+static payload (*orig_rotatePayload)(payload);
+
+static payload
+patched_rotatePayload(payload p)
+{
+ patched_func_called = true;
+ return orig_rotatePayload(p);
+}
+
+bool TestHook(const char *dll, const char *func)
+{
+ void *orig_func;
+ bool successful = false;
+ {
+ WindowsDllInterceptor TestIntercept;
+ TestIntercept.Init(dll);
+ successful = TestIntercept.AddHook(func, 0, &orig_func);
+ }
+
+ if (successful) {
+ printf("TEST-PASS | WindowsDllInterceptor | Could hook %s from %s\n", func, dll);
+ return true;
+ } else {
+ printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Failed to hook %s from %s\n", func, dll);
+ return false;
+ }
+}
+
+bool TestDetour(const char *dll, const char *func)
+{
+ void *orig_func;
+ bool successful = false;
+ {
+ WindowsDllInterceptor TestIntercept;
+ TestIntercept.Init(dll);
+ successful = TestIntercept.AddDetour(func, 0, &orig_func);
+ }
+
+ if (successful) {
+ printf("TEST-PASS | WindowsDllInterceptor | Could detour %s from %s\n", func, dll);
+ return true;
+ } else {
+ printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Failed to detour %s from %s\n", func, dll);
+ return false;
+ }
+}
+
+bool MaybeTestHook(const bool cond, const char* dll, const char* func)
+{
+ if (!cond) {
+ return true;
+ }
+
+ return TestHook(dll, func);
+}
+
+bool ShouldTestTipTsf()
+{
+#if defined(_M_X64)
+ return false;
+#else
+ if (!IsWin8OrLater()) {
+ return false;
+ }
+
+ nsModuleHandle shell32(LoadLibraryW(L"shell32.dll"));
+ if (!shell32) {
+ return true;
+ }
+
+ auto pSHGetKnownFolderPath = reinterpret_cast<decltype(&SHGetKnownFolderPath)>(GetProcAddress(shell32, "SHGetKnownFolderPath"));
+ if (!pSHGetKnownFolderPath) {
+ return true;
+ }
+
+ PWSTR commonFilesPath = nullptr;
+ if (FAILED(pSHGetKnownFolderPath(FOLDERID_ProgramFilesCommon, 0, nullptr,
+ &commonFilesPath))) {
+ return true;
+ }
+
+ wchar_t fullPath[MAX_PATH + 1] = {};
+ wcscpy(fullPath, commonFilesPath);
+ wcscat(fullPath, L"\\Microsoft Shared\\Ink\\tiptsf.dll");
+ CoTaskMemFree(commonFilesPath);
+
+ if (!LoadLibraryW(fullPath)) {
+ return false;
+ }
+
+ // Leak the module so that it's loaded for the interceptor test
+ return true;
+#endif
+}
+
+int main()
+{
+ payload initial = { 0x12345678, 0xfc4e9d31, 0x87654321 };
+ payload p0, p1;
+ ZeroMemory(&p0, sizeof(p0));
+ ZeroMemory(&p1, sizeof(p1));
+
+ p0 = rotatePayload(initial);
+
+ {
+ WindowsDllInterceptor ExeIntercept;
+ ExeIntercept.Init("TestDllInterceptor.exe");
+ if (ExeIntercept.AddHook("rotatePayload", reinterpret_cast<intptr_t>(patched_rotatePayload), (void**) &orig_rotatePayload)) {
+ printf("TEST-PASS | WindowsDllInterceptor | Hook added\n");
+ } else {
+ printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Failed to add hook\n");
+ return 1;
+ }
+
+ p1 = rotatePayload(initial);
+
+ if (patched_func_called) {
+ printf("TEST-PASS | WindowsDllInterceptor | Hook called\n");
+ } else {
+ printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Hook was not called\n");
+ return 1;
+ }
+
+ if (p0 == p1) {
+ printf("TEST-PASS | WindowsDllInterceptor | Hook works properly\n");
+ } else {
+ printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Hook didn't return the right information\n");
+ return 1;
+ }
+ }
+
+ patched_func_called = false;
+ ZeroMemory(&p1, sizeof(p1));
+
+ p1 = rotatePayload(initial);
+
+ if (!patched_func_called) {
+ printf("TEST-PASS | WindowsDllInterceptor | Hook was not called after unregistration\n");
+ } else {
+ printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Hook was still called after unregistration\n");
+ return 1;
+ }
+
+ if (p0 == p1) {
+ printf("TEST-PASS | WindowsDllInterceptor | Original function worked properly\n");
+ } else {
+ printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Original function didn't return the right information\n");
+ return 1;
+ }
+
+ if (TestHook("user32.dll", "GetWindowInfo") &&
+#ifdef _WIN64
+ TestHook("user32.dll", "SetWindowLongPtrA") &&
+ TestHook("user32.dll", "SetWindowLongPtrW") &&
+#else
+ TestHook("user32.dll", "SetWindowLongA") &&
+ TestHook("user32.dll", "SetWindowLongW") &&
+#endif
+ TestHook("user32.dll", "TrackPopupMenu") &&
+#ifdef _M_IX86
+ // We keep this test to hook complex code on x86. (Bug 850957)
+ TestHook("ntdll.dll", "NtFlushBuffersFile") &&
+#endif
+ TestHook("ntdll.dll", "NtCreateFile") &&
+ TestHook("ntdll.dll", "NtReadFile") &&
+ TestHook("ntdll.dll", "NtReadFileScatter") &&
+ TestHook("ntdll.dll", "NtWriteFile") &&
+ TestHook("ntdll.dll", "NtWriteFileGather") &&
+ TestHook("ntdll.dll", "NtQueryFullAttributesFile") &&
+ // Bug 733892: toolkit/crashreporter/nsExceptionHandler.cpp
+ TestHook("kernel32.dll", "SetUnhandledExceptionFilter") &&
+#ifdef _M_IX86
+ // Bug 670967: xpcom/base/AvailableMemoryTracker.cpp
+ TestHook("kernel32.dll", "VirtualAlloc") &&
+ TestHook("kernel32.dll", "MapViewOfFile") &&
+ TestHook("gdi32.dll", "CreateDIBSection") &&
+ TestHook("kernel32.dll", "CreateFileW") &&
+#endif
+ TestDetour("user32.dll", "CreateWindowExW") &&
+ TestHook("user32.dll", "InSendMessageEx") &&
+ TestHook("imm32.dll", "ImmGetContext") &&
+ TestHook("imm32.dll", "ImmGetCompositionStringW") &&
+ TestHook("imm32.dll", "ImmSetCandidateWindow") &&
+#ifdef _M_X64
+ TestHook("user32.dll", "GetKeyState") &&
+#endif
+ MaybeTestHook(ShouldTestTipTsf(), "tiptsf.dll", "ProcessCaretEvents") &&
+#ifdef _M_IX86
+ TestHook("user32.dll", "SendMessageTimeoutW") &&
+#endif
+ TestDetour("ntdll.dll", "LdrLoadDll")) {
+ printf("TEST-PASS | WindowsDllInterceptor | all checks passed\n");
+ return 0;
+ }
+
+ return 1;
+}