void
InitTlsAllocationTracker()
{
  if (sInitialized) {
    return;
  }

  sRecentTlsAllocationStacks = new stacks_t();

  // Windows DLL interceptor
  static WindowsDllInterceptor sKernel32DllInterceptor{};

  // Initialize dll interceptor and add hook.
  sKernel32DllInterceptor.Init("kernel32.dll");
  bool succeeded = sKernel32DllInterceptor.AddHook(
    "TlsAlloc",
    reinterpret_cast<intptr_t>(InterposedTlsAlloc),
    reinterpret_cast<void**>(&gOriginalTlsAlloc));

  if (!succeeded) {
    return;
  }

  succeeded = sKernel32DllInterceptor.AddHook(
    "TlsFree",
    reinterpret_cast<intptr_t>(InterposedTlsFree),
    reinterpret_cast<void**>(&gOriginalTlsFree));

  if (!succeeded) {
    return;
  }

  sInitialized = true;
}
void
XRE_SetupDllBlocklist()
{
  NtDllIntercept.Init("ntdll.dll");

  bool ok = NtDllIntercept.AddHook("LdrLoadDll", reinterpret_cast<intptr_t>(patched_LdrLoadDll), (void**) &stub_LdrLoadDll);

#ifdef DEBUG
  if (!ok)
    printf_stderr ("LdrLoadDll hook failed, no dll blocklisting active\n");
#endif
}
bool TestHook(const char *dll, const char *func)
{
  void *orig_func;
  WindowsDllInterceptor TestIntercept;
  TestIntercept.Init(dll);
  if (TestIntercept.AddHook(func, 0, &orig_func)) {
    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;
  }
}
void PoisonWrite() {
  // Quick sanity check that we don't poison twice.
  static bool WritesArePoisoned = false;
  MOZ_ASSERT(!WritesArePoisoned);
  if (WritesArePoisoned)
    return;
  WritesArePoisoned = true;

  if (!PoisonWriteEnabled())
    return;

  sNtDllInterceptor.Init("ntdll.dll");
  sNtDllInterceptor.AddHook("NtWriteFile", reinterpret_cast<intptr_t>(patched_WriteFile), reinterpret_cast<void**>(&gOriginalWriteFile));
  sNtDllInterceptor.AddHook("NtWriteFileGather", reinterpret_cast<intptr_t>(patched_WriteFileGather), reinterpret_cast<void**>(&gOriginalWriteFileGather));
}
Example #5
0
static void InstallHooks()
{
    gNtdllIntercept.Init("ntdll.dll");
    bool ok = gNtdllIntercept.AddHook("RtlAllocateHeap", reinterpret_cast<intptr_t>(RtlAllocateHeapHook), (void**) &gRtlAllocateHeapOrig);
    if (ok)
        lf("memtrace.dll: Hooked RtlAllocateHeap");
    else
        lf("memtrace.dll: failed to hook RtlAllocateHeap");

    ok = gNtdllIntercept.AddHook("RtlFreeHeap", reinterpret_cast<intptr_t>(RtlFreeHeapHook), (void**) &gRtlFreeHeapOrig);
    if (ok)
        lf("memtrace.dll: Hooked RtlFreeHeap");
    else
        lf("memtrace.dll: failed to hook RtlFreeHeap");
}
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 TestHook(HookTestFunc funcTester, 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 CheckHook(funcTester, orig_func, dll, func);
  } else {
    printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Failed to hook %s from %s\n", func, dll);
    return false;
  }
}
Example #8
0
static void
InitializeHooks()
{
  static bool initialized = false;
  if (initialized) {
    return;
  }
  initialized = true;
  sDeviceNames = new std::unordered_map<std::wstring, std::wstring>();
  for (const std::wstring& name : GetDosDeviceNames()) {
    sDeviceNames->emplace(name, GetDeviceMapping(name));
  }

  sKernel32Intercept.Init("kernelbase.dll");
  sOriginalQueryDosDeviceWFnPtr.Set(sKernel32Intercept, "QueryDosDeviceW",
                                    &QueryDosDeviceWHook);
}
Example #9
0
void Compatibility::Init() {
  // Note we collect some AT statistics/telemetry here for convenience.
  InitConsumers();

  CrashReporter::AnnotateCrashReport(
      CrashReporter::Annotation::AccessibilityInProcClient,
      nsPrintfCString("0x%X", sConsumers));

  // Gather telemetry
  uint32_t temp = sConsumers;
  for (int i = 0; temp; i++) {
    if (temp & 0x1) statistics::A11yConsumers(i);

    temp >>= 1;
  }

  // Turn off new tab switching for Jaws and WE.
  if (sConsumers & (JAWS | OLDJAWS | WE)) {
    // Check to see if the pref for disallowing CtrlTab is already set. If so,
    // bail out (respect the user settings). If not, set it.
    if (!Preferences::HasUserValue("browser.ctrlTab.disallowForScreenReaders"))
      Preferences::SetBool("browser.ctrlTab.disallowForScreenReaders", true);
  }

  // If we have a consumer who is not NVDA, we enable detection for the
  // InSendMessageEx compatibility hack. NVDA does not require this.
  // We also skip UIA, as we see crashes there.
  if ((sConsumers & (~(UIAUTOMATION | NVDA))) && BrowserTabsRemoteAutostart()) {
    sUser32Interceptor.Init("user32.dll");
    sInSendMessageExStub.Set(sUser32Interceptor, "InSendMessageEx",
                             &InSendMessageExHook);

    // The vectored exception handler allows us to catch exceptions ahead of any
    // SEH handlers.
    if (!sVectoredExceptionHandler) {
      // We need to let ASan's ShadowExceptionHandler remain in the firstHandler
      // position, otherwise we'll get infinite recursion when our handler
      // faults on shadow memory.
      const ULONG firstHandler = FALSE;
      sVectoredExceptionHandler = AddVectoredExceptionHandler(
          firstHandler, &DetectInSendMessageExCompat);
    }
  }
}
namespace mozilla {

intptr_t FileDescriptorToID(int aFd) {
  return _get_osfhandle(aFd);
}

static WindowsDllInterceptor sNtDllInterceptor;

void AbortOnBadWrite(HANDLE);
bool ValidWriteAssert(bool ok);

typedef NTSTATUS (WINAPI* WriteFile_fn)(HANDLE, HANDLE, PIO_APC_ROUTINE,
                                        void*, PIO_STATUS_BLOCK,
                                        const void*, ULONG, PLARGE_INTEGER,
                                        PULONG);
WriteFile_fn gOriginalWriteFile;

static NTSTATUS WINAPI
patched_WriteFile(HANDLE aFile, HANDLE aEvent, PIO_APC_ROUTINE aApc,
                  void* aApcUser, PIO_STATUS_BLOCK aIoStatus,
                  const void* aBuffer, ULONG aLength,
                  PLARGE_INTEGER aOffset, PULONG aKey)
{
  AbortOnBadWrite(aFile);
  return gOriginalWriteFile(aFile, aEvent, aApc, aApcUser, aIoStatus,
                            aBuffer, aLength, aOffset, aKey);
}


typedef NTSTATUS (WINAPI* WriteFileGather_fn)(HANDLE, HANDLE, PIO_APC_ROUTINE,
                                              void*, PIO_STATUS_BLOCK,
                                              FILE_SEGMENT_ELEMENT*,
                                              ULONG, PLARGE_INTEGER, PULONG);
WriteFileGather_fn gOriginalWriteFileGather;

static NTSTATUS WINAPI
patched_WriteFileGather(HANDLE aFile, HANDLE aEvent, PIO_APC_ROUTINE aApc,
                        void* aApcUser, PIO_STATUS_BLOCK aIoStatus,
                        FILE_SEGMENT_ELEMENT* aSegments, ULONG aLength,
                        PLARGE_INTEGER aOffset, PULONG aKey)
{
  AbortOnBadWrite(aFile);
  return gOriginalWriteFileGather(aFile, aEvent, aApc, aApcUser, aIoStatus,
                                  aSegments, aLength, aOffset, aKey);
}

void AbortOnBadWrite(HANDLE aFile)
{
  if (!PoisonWriteEnabled())
    return;

  // Debugging files are OK.
  if (IsDebugFile(reinterpret_cast<intptr_t>(aFile)))
    return;

  ValidWriteAssert(false);
}

void PoisonWrite() {
  // Quick sanity check that we don't poison twice.
  static bool WritesArePoisoned = false;
  MOZ_ASSERT(!WritesArePoisoned);
  if (WritesArePoisoned)
    return;
  WritesArePoisoned = true;

  if (!PoisonWriteEnabled())
    return;

  sNtDllInterceptor.Init("ntdll.dll");
  sNtDllInterceptor.AddHook("NtWriteFile", reinterpret_cast<intptr_t>(patched_WriteFile), reinterpret_cast<void**>(&gOriginalWriteFile));
  sNtDllInterceptor.AddHook("NtWriteFileGather", reinterpret_cast<intptr_t>(patched_WriteFileGather), reinterpret_cast<void**>(&gOriginalWriteFileGather));
}
}
Example #11
0
namespace mozilla {

#ifdef XP_WIN
static void
InitializeHooks();
#endif

ChromiumCDMAdapter::ChromiumCDMAdapter(nsTArray<Pair<nsCString, nsCString>>&& aHostPathPairs)
{
#ifdef XP_WIN
  InitializeHooks();
#endif
  PopulateHostFiles(std::move(aHostPathPairs));
}

void
ChromiumCDMAdapter::SetAdaptee(PRLibrary* aLib)
{
  mLib = aLib;
}

void*
ChromiumCdmHost(int aHostInterfaceVersion, void* aUserData)
{
  GMP_LOG("ChromiumCdmHostFunc(%d, %p)", aHostInterfaceVersion, aUserData);
  if (aHostInterfaceVersion != cdm::Host_8::kVersion &&
      aHostInterfaceVersion != cdm::Host_9::kVersion) {
    return nullptr;
  }
  return aUserData;
}

#define STRINGIFY(s) _STRINGIFY(s)
#define _STRINGIFY(s) #s

#ifdef MOZILLA_OFFICIAL
static cdm::HostFile
TakeToCDMHostFile(HostFileData& aHostFileData)
{
  return cdm::HostFile(aHostFileData.mBinary.Path().get(),
                       aHostFileData.mBinary.TakePlatformFile(),
                       aHostFileData.mSig.TakePlatformFile());
}
#endif

GMPErr
ChromiumCDMAdapter::GMPInit(const GMPPlatformAPI* aPlatformAPI)
{
  GMP_LOG("ChromiumCDMAdapter::GMPInit");
  sPlatform = aPlatformAPI;
  if (!mLib) {
    return GMPGenericErr;
  }

#ifdef MOZILLA_OFFICIAL
  // Note: we must call the VerifyCdmHost_0 function if it's present before
  // we call the initialize function.
  auto verify = reinterpret_cast<decltype(::VerifyCdmHost_0)*>(
    PR_FindFunctionSymbol(mLib, STRINGIFY(VerifyCdmHost_0)));
  if (verify) {
    nsTArray<cdm::HostFile> files;
    for (HostFileData& hostFile : mHostFiles) {
      files.AppendElement(TakeToCDMHostFile(hostFile));
    }
    bool result = verify(files.Elements(), files.Length());
    GMP_LOG("%s VerifyCdmHost_0 returned %d", __func__, result);
  }
#endif

  auto init = reinterpret_cast<decltype(::INITIALIZE_CDM_MODULE)*>(
    PR_FindFunctionSymbol(mLib, STRINGIFY(INITIALIZE_CDM_MODULE)));
  if (!init) {
    return GMPGenericErr;
  }

  GMP_LOG(STRINGIFY(INITIALIZE_CDM_MODULE) "()");
  init();

  return GMPNoErr;
}

GMPErr
ChromiumCDMAdapter::GMPGetAPI(const char* aAPIName,
                              void* aHostAPI,
                              void** aPluginAPI,
                              uint32_t aDecryptorId)
{
  GMP_LOG("ChromiumCDMAdapter::GMPGetAPI(%s, 0x%p, 0x%p, %u) this=0x%p",
          aAPIName,
          aHostAPI,
          aPluginAPI,
          aDecryptorId,
          this);
  bool isCDM9 = !strcmp(aAPIName, CHROMIUM_CDM_API);
  bool isCDM8 = !strcmp(aAPIName, CHROMIUM_CDM_API_BACKWARD_COMPAT);
  if (isCDM8 || isCDM9) {
    auto create = reinterpret_cast<decltype(::CreateCdmInstance)*>(
      PR_FindFunctionSymbol(mLib, "CreateCdmInstance"));
    if (!create) {
      GMP_LOG("ChromiumCDMAdapter::GMPGetAPI(%s, 0x%p, 0x%p, %u) this=0x%p "
              "FAILED to find CreateCdmInstance",
              aAPIName,
              aHostAPI,
              aPluginAPI,
              aDecryptorId,
              this);
      return GMPGenericErr;
    }

    int version = isCDM8 ? cdm::ContentDecryptionModule_8::kVersion :
                           cdm::ContentDecryptionModule_9::kVersion;
    void* cdm =
      create(version,
             kEMEKeySystemWidevine.get(),
             kEMEKeySystemWidevine.Length(),
             &ChromiumCdmHost,
             aHostAPI);
    if (!cdm) {
      GMP_LOG("ChromiumCDMAdapter::GMPGetAPI(%s, 0x%p, 0x%p, %u) this=0x%p "
              "FAILED to create cdm version %d",
              aAPIName,
              aHostAPI,
              aPluginAPI,
              aDecryptorId,
              this,
              version);
      return GMPGenericErr;
    }
    GMP_LOG("cdm: 0x%p, version: %d", cdm, version);
    *aPluginAPI = cdm;
  }
  return *aPluginAPI ? GMPNoErr : GMPNotImplementedErr;
}

void
ChromiumCDMAdapter::GMPShutdown()
{
  GMP_LOG("ChromiumCDMAdapter::GMPShutdown()");

  decltype(::DeinitializeCdmModule)* deinit;
  deinit = (decltype(deinit))(PR_FindFunctionSymbol(mLib, "DeinitializeCdmModule"));
  if (deinit) {
    GMP_LOG("DeinitializeCdmModule()");
    deinit();
  }
}

/* static */
bool
ChromiumCDMAdapter::Supports(int32_t aModuleVersion,
                             int32_t aInterfaceVersion,
                             int32_t aHostVersion)
{
  return aModuleVersion == CDM_MODULE_VERSION &&
         (aInterfaceVersion == cdm::ContentDecryptionModule_8::kVersion ||
         aInterfaceVersion == cdm::ContentDecryptionModule_9::kVersion) &&
         (aHostVersion == cdm::Host_8::kVersion ||
         aHostVersion == cdm::Host_9::kVersion);
}

#ifdef XP_WIN

static WindowsDllInterceptor sKernel32Intercept;

typedef DWORD(WINAPI* QueryDosDeviceWFnPtr)(_In_opt_ LPCWSTR lpDeviceName,
                                            _Out_ LPWSTR lpTargetPath,
                                            _In_ DWORD ucchMax);

static WindowsDllInterceptor::FuncHookType<QueryDosDeviceWFnPtr>
  sOriginalQueryDosDeviceWFnPtr;

static std::unordered_map<std::wstring, std::wstring>* sDeviceNames = nullptr;

DWORD WINAPI
QueryDosDeviceWHook(LPCWSTR lpDeviceName, LPWSTR lpTargetPath, DWORD ucchMax)
{
  if (!sDeviceNames) {
    return 0;
  }
  std::wstring name = std::wstring(lpDeviceName);
  auto iter = sDeviceNames->find(name);
  if (iter == sDeviceNames->end()) {
    return 0;
  }
  const std::wstring& device = iter->second;
  if (device.size() + 1 > ucchMax) {
    return 0;
  }
  PodCopy(lpTargetPath, device.c_str(), device.size());
  lpTargetPath[device.size()] = 0;
  GMP_LOG("QueryDosDeviceWHook %S -> %S", lpDeviceName, lpTargetPath);
  return name.size();
}

static std::vector<std::wstring>
GetDosDeviceNames()
{
  std::vector<std::wstring> v;
  std::vector<wchar_t> buf;
  buf.resize(1024);
  DWORD rv = GetLogicalDriveStringsW(buf.size(), buf.data());
  if (rv == 0 || rv > buf.size()) {
    return v;
  }

  // buf will be a list of null terminated strings, with the last string
  // being 0 length.
  const wchar_t* p = buf.data();
  const wchar_t* end = &buf.back();
  size_t l;
  while (p < end && (l = wcsnlen_s(p, end - p)) > 0) {
    // The string is of the form "C:\". We need to strip off the trailing
    // backslash.
    std::wstring drive = std::wstring(p, p + l);
    if (drive.back() == '\\') {
      drive.erase(drive.end() - 1);
    }
    v.push_back(move(drive));
    p += l + 1;
  }
  return v;
}

static std::wstring
GetDeviceMapping(const std::wstring& aDosDeviceName)
{
  wchar_t buf[MAX_PATH] = { 0 };
  DWORD rv = QueryDosDeviceW(aDosDeviceName.c_str(), buf, MAX_PATH);
  if (rv == 0) {
    return std::wstring(L"");
  }
  return std::wstring(buf, buf + rv);
}

static void
InitializeHooks()
{
  static bool initialized = false;
  if (initialized) {
    return;
  }
  initialized = true;
  sDeviceNames = new std::unordered_map<std::wstring, std::wstring>();
  for (const std::wstring& name : GetDosDeviceNames()) {
    sDeviceNames->emplace(name, GetDeviceMapping(name));
  }

  sKernel32Intercept.Init("kernelbase.dll");
  sOriginalQueryDosDeviceWFnPtr.Set(sKernel32Intercept, "QueryDosDeviceW",
                                    &QueryDosDeviceWHook);
}
#endif

HostFile::HostFile(HostFile&& aOther)
  : mPath(aOther.mPath)
  , mFile(aOther.TakePlatformFile())
{
}

HostFile::~HostFile()
{
  if (mFile != cdm::kInvalidPlatformFile) {
#ifdef XP_WIN
    CloseHandle(mFile);
#else
    close(mFile);
#endif
    mFile = cdm::kInvalidPlatformFile;
  }
}

#ifdef XP_WIN
HostFile::HostFile(const nsCString& aPath)
  : mPath(NS_ConvertUTF8toUTF16(aPath))
{
  HANDLE handle = CreateFileW(mPath.get(),
                              GENERIC_READ,
                              FILE_SHARE_READ | FILE_SHARE_WRITE,
                              NULL,
                              OPEN_EXISTING,
                              0,
                              NULL);
  mFile = (handle == INVALID_HANDLE_VALUE) ? cdm::kInvalidPlatformFile : handle;
}
#endif

#ifndef XP_WIN
HostFile::HostFile(const nsCString& aPath)
  : mPath(aPath)
{
  // Note: open() returns -1 on failure; i.e. kInvalidPlatformFile.
  mFile = open(aPath.get(), O_RDONLY);
}
#endif

cdm::PlatformFile
HostFile::TakePlatformFile()
{
  cdm::PlatformFile f = mFile;
  mFile = cdm::kInvalidPlatformFile;
  return f;
}

void
ChromiumCDMAdapter::PopulateHostFiles(nsTArray<Pair<nsCString, nsCString>>&& aHostPathPairs)
{
  for (const auto& pair : aHostPathPairs) {
    mHostFiles.AppendElement(
      HostFileData(mozilla::HostFile(pair.first()),
                   mozilla::HostFile(pair.second())));
  }
}

} // namespace mozilla
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") &&
      TestHook("ntdll.dll", "NtFlushBuffersFile") &&
      TestHook("ntdll.dll", "LdrLoadDll")) {
    printf("TEST-PASS | WindowsDllInterceptor | all checks passed\n");
    return 0;
  }

  return 1;
}
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", "NtWriteFile") &&
      TestHook("ntdll.dll", "NtWriteFileGather") &&
      // 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") &&
#endif
      TestHook("ntdll.dll", "LdrLoadDll")) {
    printf("TEST-PASS | WindowsDllInterceptor | all checks passed\n");
    return 0;
  }

  return 1;
}
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(TestGetWindowInfo, "user32.dll", "GetWindowInfo") &&
#ifdef _WIN64
      TestHook(TestSetWindowLongPtr, "user32.dll", "SetWindowLongPtrA") &&
      TestHook(TestSetWindowLongPtr, "user32.dll", "SetWindowLongPtrW") &&
#else
      TestHook(TestSetWindowLong, "user32.dll", "SetWindowLongA") &&
      TestHook(TestSetWindowLong, "user32.dll", "SetWindowLongW") &&
#endif
      TestHook(TestTrackPopupMenu, "user32.dll", "TrackPopupMenu") &&
#ifdef _M_IX86
      // We keep this test to hook complex code on x86. (Bug 850957)
      TestHook(TestNtFlushBuffersFile, "ntdll.dll", "NtFlushBuffersFile") &&
#endif
      TestHook(TestNtCreateFile, "ntdll.dll", "NtCreateFile") &&
      TestHook(TestNtReadFile, "ntdll.dll", "NtReadFile") &&
      TestHook(TestNtReadFileScatter, "ntdll.dll", "NtReadFileScatter") &&
      TestHook(TestNtWriteFile, "ntdll.dll", "NtWriteFile") &&
      TestHook(TestNtWriteFileGather, "ntdll.dll", "NtWriteFileGather") &&
      TestHook(TestNtQueryFullAttributesFile, "ntdll.dll", "NtQueryFullAttributesFile") &&
      // Bug 733892: toolkit/crashreporter/nsExceptionHandler.cpp
      TestHook(TestSetUnhandledExceptionFilter, "kernel32.dll", "SetUnhandledExceptionFilter") &&
#ifdef _M_IX86
      // Bug 670967: xpcom/base/AvailableMemoryTracker.cpp
      TestHook(TestVirtualAlloc, "kernel32.dll", "VirtualAlloc") &&
      TestHook(TestMapViewOfFile, "kernel32.dll", "MapViewOfFile") &&
      TestHook(TestCreateDIBSection, "gdi32.dll", "CreateDIBSection") &&
      TestHook(TestCreateFileW, "kernel32.dll", "CreateFileW") &&    // see Bug 1316415
#endif
      TestHook(TestCreateFileA, "kernel32.dll", "CreateFileA") &&
      TestDetour("user32.dll", "CreateWindowExW") &&
      TestHook(TestInSendMessageEx, "user32.dll", "InSendMessageEx") &&
      TestHook(TestImmGetContext, "imm32.dll", "ImmGetContext") &&
      // TestHook("imm32.dll", "ImmReleaseContext") &&    // see Bug 1316415
      TestHook(TestImmGetCompositionStringW, "imm32.dll", "ImmGetCompositionStringW") &&
      TestHook(TestImmSetCandidateWindow, "imm32.dll", "ImmSetCandidateWindow") &&
      TestHook(TestImmNotifyIME, "imm32.dll", "ImmNotifyIME") &&
      TestHook(TestGetSaveFileNameW, "comdlg32.dll", "GetSaveFileNameW") &&
      TestHook(TestGetOpenFileNameW, "comdlg32.dll", "GetOpenFileNameW") &&
#ifdef _M_X64
      TestHook(TestGetKeyState, "user32.dll", "GetKeyState") &&    // see Bug 1316415
      TestHook(TestLdrUnloadDll, "ntdll.dll", "LdrUnloadDll") &&
      MaybeTestHook(IsWin8OrLater(), TestLdrResolveDelayLoadedAPI, "ntdll.dll", "LdrResolveDelayLoadedAPI") &&
      MaybeTestHook(!IsWin8OrLater(), TestRtlInstallFunctionTableCallback, "kernel32.dll", "RtlInstallFunctionTableCallback") &&
#endif
      MaybeTestHook(ShouldTestTipTsf(), TestProcessCaretEvents, "tiptsf.dll", "ProcessCaretEvents") &&
#ifdef _M_IX86
      TestHook(TestSendMessageTimeoutW, "user32.dll", "SendMessageTimeoutW") &&
#endif
      TestHook(TestTlsAlloc, "kernel32.dll", "TlsAlloc") &&
      TestHook(TestTlsFree, "kernel32.dll", "TlsFree") &&
      TestDetour("ntdll.dll", "LdrLoadDll")) {
    printf("TEST-PASS | WindowsDllInterceptor | all checks passed\n");
    return 0;
  }

  return 1;
}