1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/app/close_handle_hook_win.h"
6
7#include <Windows.h>
8
9#include <vector>
10
11#include "base/files/file_path.h"
12#include "base/lazy_instance.h"
13#include "base/strings/string16.h"
14#include "base/win/iat_patch_function.h"
15#include "base/win/scoped_handle.h"
16#include "chrome/common/chrome_version_info.h"
17
18namespace {
19
20typedef BOOL (WINAPI* CloseHandleType) (HANDLE handle);
21CloseHandleType g_close_function = NULL;
22
23// The entry point for CloseHandle interception. This function notifies the
24// verifier about the handle that is being closed, and calls the original
25// function.
26BOOL WINAPI CloseHandleHook(HANDLE handle) {
27  base::win::OnHandleBeingClosed(handle);
28  return g_close_function(handle);
29}
30
31// Keeps track of all the hooks needed to intercept CloseHandle.
32class CloseHandleHooks {
33 public:
34  CloseHandleHooks() {}
35  ~CloseHandleHooks() {}
36
37  void AddIATPatch(const base::string16& module);
38  void Unpatch();
39
40 private:
41  std::vector<base::win::IATPatchFunction*> hooks_;
42  DISALLOW_COPY_AND_ASSIGN(CloseHandleHooks);
43};
44base::LazyInstance<CloseHandleHooks> g_hooks = LAZY_INSTANCE_INITIALIZER;
45
46void CloseHandleHooks::AddIATPatch(const base::string16& module) {
47  if (module.empty())
48    return;
49
50  base::win::IATPatchFunction* patch = new base::win::IATPatchFunction;
51  patch->Patch(module.c_str(), "kernel32.dll", "CloseHandle", CloseHandleHook);
52  hooks_.push_back(patch);
53  if (!g_close_function) {
54    // Things are probably messed up if each intercepted function points to
55    // a different place, but we need only one function to call.
56    g_close_function =
57      reinterpret_cast<CloseHandleType>(patch->original_function());
58  }
59}
60
61void CloseHandleHooks::Unpatch() {
62  for (std::vector<base::win::IATPatchFunction*>::iterator it = hooks_.begin();
63       it != hooks_.end(); ++it) {
64    (*it)->Unpatch();
65  }
66}
67
68bool UseHooks() {
69  return false;
70}
71
72base::string16 GetModuleName(HMODULE module) {
73  base::string16 name;
74  if (!module)
75    return name;
76  wchar_t buffer[MAX_PATH];
77  int rv = GetModuleFileName(module, buffer, MAX_PATH);
78  if (rv == MAX_PATH)
79    return name;
80
81  buffer[MAX_PATH - 1] = L'\0';
82  name.assign(buffer);
83  base::FilePath path(name);
84  return path.BaseName().AsUTF16Unsafe();
85}
86
87HMODULE GetChromeDLLModule() {
88  HMODULE module;
89  if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
90                             GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
91                         reinterpret_cast<wchar_t*>(&GetChromeDLLModule),
92                         &module)) {
93    return NULL;
94  }
95  return module;
96}
97
98}  // namespace
99
100void InstallCloseHandleHooks() {
101  if (UseHooks()) {
102    CloseHandleHooks* hooks = g_hooks.Pointer();
103    hooks->AddIATPatch(L"chrome.exe");
104    hooks->AddIATPatch(GetModuleName(GetChromeDLLModule()));
105  } else {
106    base::win::DisableHandleVerifier();
107  }
108}
109
110void RemoveCloseHandleHooks() {
111  g_hooks.Get().Unpatch();
112}
113