Index: chrome/app/close_handle_hook_win.cc |
diff --git a/chrome/app/close_handle_hook_win.cc b/chrome/app/close_handle_hook_win.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..ca0b01e76c331c38192e97e3eba0e380147a2dfe |
--- /dev/null |
+++ b/chrome/app/close_handle_hook_win.cc |
@@ -0,0 +1,118 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chrome/app/close_handle_hook_win.h" |
+ |
+#include <Windows.h> |
+ |
+#include <vector> |
+ |
+#include "base/files/file_path.h" |
+#include "base/lazy_instance.h" |
+#include "base/strings/string16.h" |
+#include "base/win/iat_patch_function.h" |
+#include "base/win/scoped_handle.h" |
+#include "chrome/common/chrome_version_info.h" |
+ |
+namespace { |
+ |
+typedef BOOL (WINAPI* CloseHandleType) (HANDLE handle); |
+CloseHandleType g_close_function = NULL; |
+ |
+// The entry point for CloseHandle interception. This function notifies the |
+// verifier about the handle that is being closed, and calls the original |
+// function. |
+BOOL WINAPI CloseHandleHook(HANDLE handle) { |
+ base::win::OnHandleBeingClosed(handle); |
+ return g_close_function(handle); |
+} |
+ |
+// Keeps track of all the hooks needed to intercept CloseHandle. |
+class CloseHandleHooks { |
+ public: |
+ CloseHandleHooks() {} |
+ ~CloseHandleHooks() {} |
+ |
+ void AddIATPatch(const base::string16& module); |
+ void Unpatch(); |
+ |
+ private: |
+ std::vector<base::win::IATPatchFunction*> hooks_; |
+ DISALLOW_COPY_AND_ASSIGN(CloseHandleHooks); |
+}; |
+base::LazyInstance<CloseHandleHooks> g_hooks = LAZY_INSTANCE_INITIALIZER; |
+ |
+void CloseHandleHooks::AddIATPatch(const base::string16& module) { |
+ if (module.empty()) |
+ return; |
+ |
+ base::win::IATPatchFunction* patch = new base::win::IATPatchFunction; |
+ patch->Patch(module.c_str(), "kernel32.dll", "CloseHandle", CloseHandleHook); |
+ hooks_.push_back(patch); |
+ if (!g_close_function) { |
+ // Things are probably messed up if each intercepted function points to |
+ // a different place, but we need only one function to call. |
+ g_close_function = |
+ reinterpret_cast<CloseHandleType>(patch->original_function()); |
+ } |
+} |
+ |
+void CloseHandleHooks::Unpatch() { |
+ for (std::vector<base::win::IATPatchFunction*>::iterator it = hooks_.begin(); |
+ it != hooks_.end(); ++it) { |
+ (*it)->Unpatch(); |
+ } |
+} |
+ |
+bool UseHooks() { |
+ chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel(); |
+ if (channel == chrome::VersionInfo::CHANNEL_CANARY || |
+ channel == chrome::VersionInfo::CHANNEL_DEV) { |
+ return true; |
+ } |
+ |
+ return false; |
+} |
+ |
+base::string16 GetModuleName(HMODULE module) { |
+ base::string16 name; |
+ if (!module) |
+ return name; |
+ wchar_t buffer[MAX_PATH]; |
+ int rv = GetModuleFileName(module, buffer, MAX_PATH); |
+ if (rv == MAX_PATH) |
+ return name; |
+ |
+ buffer[MAX_PATH - 1] = L'\0'; |
+ name.assign(buffer); |
+ base::FilePath path(name); |
+ return path.BaseName().AsUTF16Unsafe(); |
+} |
+ |
+HMODULE GetChromeDLLModule() { |
+ HMODULE module; |
+ if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | |
+ GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, |
+ reinterpret_cast<wchar_t*>(&GetChromeDLLModule), |
+ &module)) { |
+ return NULL; |
+ } |
+ return module; |
+} |
+ |
+} // namespace |
+ |
+void InstallCloseHandleHooks() { |
+ if (!UseHooks()) |
+ return; |
+ |
+ base::win::EnableHandleVerifier(); |
+ CloseHandleHooks* hooks = g_hooks.Pointer(); |
+ hooks->AddIATPatch(L"chrome.exe"); |
+ hooks->AddIATPatch(GetModuleName(GetChromeDLLModule())); |
+} |
+ |
+void RemoveCloseHandleHooks() { |
+ g_hooks.Get().Unpatch(); |
+} |