| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome_frame/module_utils.h" | 5 #include "chrome_frame/module_utils.h" |
| 6 | 6 |
| 7 #include <atlbase.h> | 7 #include <atlbase.h> |
| 8 #include <TlHelp32.h> | 8 #include "base/logging.h" |
| 9 | 9 |
| 10 #include "base/scoped_ptr.h" | 10 const wchar_t kBeaconWindowClassName[] = |
| 11 #include "base/file_version_info.h" | 11 L"ChromeFrameBeaconWindowClass826C5D01-E355-4b23-8AC2-40650E0B7843"; |
| 12 #include "base/logging.h" | |
| 13 #include "base/scoped_handle.h" | |
| 14 #include "base/string_util.h" | |
| 15 #include "base/version.h" | |
| 16 #include "chrome_frame/exception_barrier.h" | |
| 17 | 12 |
| 18 DllRedirector::DllRedirector() : dcgo_ptr_(NULL), initialized_(false), | 13 // static |
| 19 module_handle_(NULL) {} | 14 ATOM DllRedirector::atom_ = 0; |
| 20 | 15 |
| 21 DllRedirector::~DllRedirector() { | 16 bool DllRedirector::RegisterAsFirstCFModule() { |
| 22 if (module_handle_) { | 17 // This would imply that this module had already registered a window class |
| 23 FreeLibrary(module_handle_); | 18 // which should never happen. |
| 24 module_handle_ = NULL; | 19 if (atom_) { |
| 25 } | 20 NOTREACHED(); |
| 26 } | 21 return true; |
| 27 | |
| 28 void DllRedirector::EnsureInitialized(const wchar_t* module_name, | |
| 29 REFCLSID clsid) { | |
| 30 if (!initialized_) { | |
| 31 initialized_ = true; | |
| 32 // Also sets module_handle_. | |
| 33 dcgo_ptr_ = GetDllGetClassObjectFromModuleName(module_name, clsid); | |
| 34 } | |
| 35 } | |
| 36 | |
| 37 LPFNGETCLASSOBJECT DllRedirector::get_dll_get_class_object_ptr() const { | |
| 38 DCHECK(initialized_); | |
| 39 return dcgo_ptr_; | |
| 40 } | |
| 41 | |
| 42 LPFNGETCLASSOBJECT DllRedirector::GetDllGetClassObjectFromModuleName( | |
| 43 const wchar_t* module_name, REFCLSID clsid) { | |
| 44 module_handle_ = NULL; | |
| 45 LPFNGETCLASSOBJECT proc_ptr = NULL; | |
| 46 HMODULE module_handle; | |
| 47 if (GetOldestNamedModuleHandle(module_name, clsid, &module_handle)) { | |
| 48 HMODULE this_module = reinterpret_cast<HMODULE>(&__ImageBase); | |
| 49 if (module_handle != this_module) { | |
| 50 proc_ptr = GetDllGetClassObjectPtr(module_handle); | |
| 51 if (proc_ptr) { | |
| 52 // Stash away the module handle in module_handle_ so that it will be | |
| 53 // automatically closed when we get destroyed. GetDllGetClassObjectPtr | |
| 54 // above will have incremented the module's ref count. | |
| 55 module_handle_ = module_handle; | |
| 56 } | |
| 57 } else { | |
| 58 LOG(INFO) << "Module Scan: DllGetClassObject found in current module."; | |
| 59 } | |
| 60 } | 22 } |
| 61 | 23 |
| 62 return proc_ptr; | 24 WNDCLASSEX wnd_class = {0}; |
| 63 } | 25 wnd_class.cbSize = sizeof(WNDCLASSEX); |
| 26 wnd_class.style = CS_GLOBALCLASS; |
| 27 wnd_class.lpfnWndProc = &DefWindowProc; |
| 28 wnd_class.cbClsExtra = sizeof(HMODULE); |
| 29 wnd_class.cbWndExtra = 0; |
| 30 wnd_class.hInstance = NULL; |
| 31 wnd_class.hIcon = NULL; |
| 64 | 32 |
| 65 bool DllRedirector::GetOldestNamedModuleHandle(const std::wstring& module_name, | 33 wnd_class.hCursor = LoadCursor(NULL, IDC_ARROW); |
| 66 REFCLSID clsid, | 34 wnd_class.hbrBackground = NULL; |
| 67 HMODULE* oldest_module_handle) { | 35 wnd_class.lpszMenuName = NULL; |
| 68 DCHECK(oldest_module_handle); | 36 wnd_class.lpszClassName = kBeaconWindowClassName; |
| 37 wnd_class.hIconSm = wnd_class.hIcon; |
| 69 | 38 |
| 70 ScopedHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 0)); | 39 ATOM atom = RegisterClassEx(&wnd_class); |
| 71 if (snapshot == INVALID_HANDLE_VALUE) { | |
| 72 LOG(ERROR) << "Could not create module snapshot!"; | |
| 73 return false; | |
| 74 } | |
| 75 | |
| 76 | 40 |
| 77 bool success = false; | 41 bool success = false; |
| 78 PathToHModuleMap map; | 42 if (atom != 0) { |
| 79 | 43 HWND hwnd = CreateWindow(MAKEINTATOM(atom), L"temp_window", WS_POPUP, |
| 80 { | 44 0, 0, 0, 0, NULL, NULL, NULL, NULL); |
| 81 // Here we add an SEH to the chain to prevent our VEH from picking up on any | 45 DCHECK(IsWindow(hwnd)); |
| 82 // exceptions thrown in DLLs who hook some of the below api calls. We will | 46 if (hwnd) { |
| 83 // still report the exceptions if they make our way back to us, the hope is | 47 HMODULE this_module = reinterpret_cast<HMODULE>(&__ImageBase); |
| 84 // that they will not. | 48 LONG_PTR lp = reinterpret_cast<LONG_PTR>(this_module); |
| 85 ExceptionBarrier exception_barrier; | 49 SetClassLongPtr(hwnd, 0, lp); |
| 86 | 50 // We need to check the GLE value since SetClassLongPtr returns 0 on |
| 87 // First get the list of module paths, and save the full path to base | 51 // failure as well as on the first call. |
| 88 // address mapping. | 52 if (GetLastError() == ERROR_SUCCESS) { |
| 89 MODULEENTRY32W module_entry = {0}; | 53 atom_ = atom; |
| 90 module_entry.dwSize = sizeof(module_entry); | 54 success = true; |
| 91 BOOL cont = Module32FirstW(snapshot, &module_entry); | |
| 92 while (cont) { | |
| 93 if (!lstrcmpi(module_entry.szModule, module_name.c_str())) { | |
| 94 std::wstring full_path(module_entry.szExePath); | |
| 95 map[full_path] = module_entry.hModule; | |
| 96 } | 55 } |
| 97 SecureZeroMemory(&module_entry, sizeof(MODULEENTRY32W)); | 56 DestroyWindow(hwnd); |
| 98 module_entry.dwSize = sizeof(module_entry); | |
| 99 cont = Module32NextW(snapshot, &module_entry); | |
| 100 } | 57 } |
| 101 } | 58 } |
| 102 | 59 |
| 103 // Next, enumerate the map and find the oldest version of the module. | |
| 104 // (check if the map is of size 1 first) | |
| 105 if (!map.empty()) { | |
| 106 if (map.size() == 1) { | |
| 107 *oldest_module_handle = map.begin()->second; | |
| 108 } else { | |
| 109 *oldest_module_handle = GetHandleOfOldestModule(map, clsid); | |
| 110 } | |
| 111 | |
| 112 if (*oldest_module_handle != NULL) { | |
| 113 success = true; | |
| 114 } | |
| 115 } else { | |
| 116 LOG(INFO) << "Module Scan: No modules named " << module_name | |
| 117 << " were found."; | |
| 118 } | |
| 119 | |
| 120 return success; | 60 return success; |
| 121 } | 61 } |
| 122 | 62 |
| 123 HMODULE DllRedirector::GetHandleOfOldestModule(const PathToHModuleMap& map, | 63 void DllRedirector::UnregisterAsFirstCFModule() { |
| 124 REFCLSID clsid) { | 64 if (atom_) { |
| 65 UnregisterClass(MAKEINTATOM(atom_), NULL); |
| 66 } |
| 67 } |
| 68 |
| 69 HMODULE DllRedirector::GetFirstCFModule() { |
| 70 WNDCLASSEX wnd_class = {0}; |
| 125 HMODULE oldest_module = NULL; | 71 HMODULE oldest_module = NULL; |
| 126 scoped_ptr<Version> min_version( | 72 HWND hwnd = CreateWindow(kBeaconWindowClassName, L"temp_window", WS_POPUP, 0, |
| 127 Version::GetVersionFromString("999.999.999.999")); | 73 0, 0, 0, NULL, NULL, NULL, NULL); |
| 128 | 74 DCHECK(IsWindow(hwnd)); |
| 129 PathToHModuleMap::const_iterator map_iter(map.begin()); | 75 if (hwnd) { |
| 130 for (; map_iter != map.end(); ++map_iter) { | 76 oldest_module = reinterpret_cast<HMODULE>(GetClassLongPtr(hwnd, 0)); |
| 131 // First check that either we are in the current module or that the DLL | 77 DestroyWindow(hwnd); |
| 132 // returns a class factory for our clsid. | |
| 133 bool current_module = | |
| 134 (map_iter->second == reinterpret_cast<HMODULE>(&__ImageBase)); | |
| 135 bool gco_succeeded = false; | |
| 136 if (!current_module) { | |
| 137 LPFNGETCLASSOBJECT dgco_ptr = GetDllGetClassObjectPtr(map_iter->second); | |
| 138 if (dgco_ptr) { | |
| 139 { | |
| 140 CComPtr<IClassFactory> class_factory; | |
| 141 HRESULT hr = dgco_ptr(clsid, IID_IClassFactory, | |
| 142 reinterpret_cast<void**>(&class_factory)); | |
| 143 gco_succeeded = SUCCEEDED(hr) && class_factory != NULL; | |
| 144 } | |
| 145 // Release the module ref count we picked up in GetDllGetClassObjectPtr. | |
| 146 FreeLibrary(map_iter->second); | |
| 147 } | |
| 148 } | |
| 149 | |
| 150 if (current_module || gco_succeeded) { | |
| 151 // Then check that the version is less than we've already found: | |
| 152 scoped_ptr<FileVersionInfo> version_info( | |
| 153 FileVersionInfo::CreateFileVersionInfo(map_iter->first)); | |
| 154 scoped_ptr<Version> version( | |
| 155 Version::GetVersionFromString(version_info->file_version())); | |
| 156 if (version->CompareTo(*min_version.get()) < 0) { | |
| 157 oldest_module = map_iter->second; | |
| 158 min_version.reset(version.release()); | |
| 159 } | |
| 160 } | |
| 161 } | 78 } |
| 162 | |
| 163 return oldest_module; | 79 return oldest_module; |
| 164 } | 80 } |
| 165 | 81 |
| 166 LPFNGETCLASSOBJECT DllRedirector::GetDllGetClassObjectPtr(HMODULE module) { | 82 LPFNGETCLASSOBJECT DllRedirector::GetDllGetClassObjectPtr(HMODULE module) { |
| 167 LPFNGETCLASSOBJECT proc_ptr = NULL; | 83 LPFNGETCLASSOBJECT proc_ptr = NULL; |
| 168 HMODULE temp_handle = 0; | 84 HMODULE temp_handle = 0; |
| 169 // Increment the module ref count while we have an pointer to its | 85 // Increment the module ref count while we have an pointer to its |
| 170 // DllGetClassObject function. | 86 // DllGetClassObject function. |
| 171 if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, | 87 if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, |
| 172 reinterpret_cast<LPCTSTR>(module), | 88 reinterpret_cast<LPCTSTR>(module), |
| 173 &temp_handle)) { | 89 &temp_handle)) { |
| 174 proc_ptr = reinterpret_cast<LPFNGETCLASSOBJECT>( | 90 proc_ptr = reinterpret_cast<LPFNGETCLASSOBJECT>( |
| 175 GetProcAddress(temp_handle, "DllGetClassObject")); | 91 GetProcAddress(temp_handle, "DllGetClassObject")); |
| 176 if (!proc_ptr) { | 92 if (!proc_ptr) { |
| 177 FreeLibrary(temp_handle); | 93 FreeLibrary(temp_handle); |
| 178 LOG(ERROR) << "Module Scan: Couldn't get address of " | 94 LOG(ERROR) << "Module Scan: Couldn't get address of " |
| 179 << "DllGetClassObject: " | 95 << "DllGetClassObject: " |
| 180 << GetLastError(); | 96 << GetLastError(); |
| 181 } | 97 } |
| 182 } else { | 98 } else { |
| 183 LOG(ERROR) << "Module Scan: Could not increment module count: " | 99 LOG(ERROR) << "Module Scan: Could not increment module count: " |
| 184 << GetLastError(); | 100 << GetLastError(); |
| 185 } | 101 } |
| 186 return proc_ptr; | 102 return proc_ptr; |
| 187 } | 103 } |
| OLD | NEW |