diff options
author | tfarina@chromium.org <tfarina@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-06-25 00:21:07 +0000 |
---|---|---|
committer | tfarina@chromium.org <tfarina@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-06-25 00:21:07 +0000 |
commit | 9cbab6520cd7684fd90982a4fe6fb84c87ba4492 (patch) | |
tree | 49fbed1c40ca3a5052fe7af8e9b3a4c994f3796b /base | |
parent | a6e9dce2f8c811744693bfdd85a585ea6d26e752 (diff) | |
download | chromium_src-9cbab6520cd7684fd90982a4fe6fb84c87ba4492.zip chromium_src-9cbab6520cd7684fd90982a4fe6fb84c87ba4492.tar.gz chromium_src-9cbab6520cd7684fd90982a4fe6fb84c87ba4492.tar.bz2 |
Move app/win/* files to base/win/, ui/base/win and chrome/common/ directories.
BUG=72317
TEST=None
R=rsesek@chromium.org,brettw@chromium.org
Review URL: http://codereview.chromium.org/7231016
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@90464 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r-- | base/base.gypi | 11 | ||||
-rw-r--r-- | base/win/iat_patch_function.cc | 278 | ||||
-rw-r--r-- | base/win/iat_patch_function.h | 72 | ||||
-rw-r--r-- | base/win/scoped_com_initializer.h | 60 |
4 files changed, 417 insertions, 4 deletions
diff --git a/base/base.gypi b/base/base.gypi index 41ea923..79bff9b 100644 --- a/base/base.gypi +++ b/base/base.gypi @@ -321,6 +321,8 @@ 'version.h', 'vlog.cc', 'vlog.h', + 'nix/xdg_util.cc', + 'nix/xdg_util.h', 'win/event_trace_consumer.h', 'win/event_trace_controller.cc', 'win/event_trace_controller.h', @@ -328,12 +330,15 @@ 'win/event_trace_provider.h', 'win/i18n.cc', 'win/i18n.h', + 'win/iat_patch_function.cc', + 'win/iat_patch_function.h', 'win/object_watcher.cc', 'win/object_watcher.h', 'win/registry.cc', 'win/registry.h', 'win/scoped_bstr.cc', 'win/scoped_bstr.h', + 'win/scoped_com_initializer.h', 'win/scoped_comptr.h', 'win/scoped_gdi_object.h', 'win/scoped_handle.h', @@ -341,14 +346,12 @@ 'win/scoped_hglobal.h', 'win/scoped_variant.cc', 'win/scoped_variant.h', - 'win/win_util.cc', - 'win/win_util.h', 'win/windows_version.cc', 'win/windows_version.h', + 'win/win_util.cc', + 'win/win_util.h', 'win/wrapped_window_proc.cc', 'win/wrapped_window_proc.h', - 'nix/xdg_util.h', - 'nix/xdg_util.cc', ], 'include_dirs': [ '..', diff --git a/base/win/iat_patch_function.cc b/base/win/iat_patch_function.cc new file mode 100644 index 0000000..a4a8902 --- /dev/null +++ b/base/win/iat_patch_function.cc @@ -0,0 +1,278 @@ +// Copyright (c) 2011 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 "base/win/iat_patch_function.h" + +#include "base/logging.h" +#include "base/win/pe_image.h" + +namespace base { +namespace win { + +namespace { + +struct InterceptFunctionInformation { + bool finished_operation; + const char* imported_from_module; + const char* function_name; + void* new_function; + void** old_function; + IMAGE_THUNK_DATA** iat_thunk; + DWORD return_code; +}; + +void* GetIATFunction(IMAGE_THUNK_DATA* iat_thunk) { + if (NULL == iat_thunk) { + NOTREACHED(); + return NULL; + } + + // Works around the 64 bit portability warning: + // The Function member inside IMAGE_THUNK_DATA is really a pointer + // to the IAT function. IMAGE_THUNK_DATA correctly maps to IMAGE_THUNK_DATA32 + // or IMAGE_THUNK_DATA64 for correct pointer size. + union FunctionThunk { + IMAGE_THUNK_DATA thunk; + void* pointer; + } iat_function; + + iat_function.thunk = *iat_thunk; + return iat_function.pointer; +} +// Change the page protection (of code pages) to writable and copy +// the data at the specified location +// +// Arguments: +// old_code Target location to copy +// new_code Source +// length Number of bytes to copy +// +// Returns: Windows error code (winerror.h). NO_ERROR if successful +DWORD ModifyCode(void* old_code, void* new_code, int length) { + if ((NULL == old_code) || (NULL == new_code) || (0 == length)) { + NOTREACHED(); + return ERROR_INVALID_PARAMETER; + } + + // Change the page protection so that we can write. + DWORD error = NO_ERROR; + DWORD old_page_protection = 0; + if (VirtualProtect(old_code, + length, + PAGE_READWRITE, + &old_page_protection)) { + + // Write the data. + CopyMemory(old_code, new_code, length); + + // Restore the old page protection. + error = ERROR_SUCCESS; + VirtualProtect(old_code, + length, + old_page_protection, + &old_page_protection); + } else { + error = GetLastError(); + NOTREACHED(); + } + + return error; +} + +bool InterceptEnumCallback(const base::win::PEImage& image, const char* module, + DWORD ordinal, const char* name, DWORD hint, + IMAGE_THUNK_DATA* iat, void* cookie) { + InterceptFunctionInformation* intercept_information = + reinterpret_cast<InterceptFunctionInformation*>(cookie); + + if (NULL == intercept_information) { + NOTREACHED(); + return false; + } + + DCHECK(module); + + if ((0 == lstrcmpiA(module, intercept_information->imported_from_module)) && + (NULL != name) && + (0 == lstrcmpiA(name, intercept_information->function_name))) { + // Save the old pointer. + if (NULL != intercept_information->old_function) { + *(intercept_information->old_function) = GetIATFunction(iat); + } + + if (NULL != intercept_information->iat_thunk) { + *(intercept_information->iat_thunk) = iat; + } + + // portability check + COMPILE_ASSERT(sizeof(iat->u1.Function) == + sizeof(intercept_information->new_function), unknown_IAT_thunk_format); + + // Patch the function. + intercept_information->return_code = + ModifyCode(&(iat->u1.Function), + &(intercept_information->new_function), + sizeof(intercept_information->new_function)); + + // Terminate further enumeration. + intercept_information->finished_operation = true; + return false; + } + + return true; +} + +// Helper to intercept a function in an import table of a specific +// module. +// +// Arguments: +// module_handle Module to be intercepted +// imported_from_module Module that exports the symbol +// function_name Name of the API to be intercepted +// new_function Interceptor function +// old_function Receives the original function pointer +// iat_thunk Receives pointer to IAT_THUNK_DATA +// for the API from the import table. +// +// Returns: Returns NO_ERROR on success or Windows error code +// as defined in winerror.h +DWORD InterceptImportedFunction(HMODULE module_handle, + const char* imported_from_module, + const char* function_name, void* new_function, + void** old_function, + IMAGE_THUNK_DATA** iat_thunk) { + if ((NULL == module_handle) || (NULL == imported_from_module) || + (NULL == function_name) || (NULL == new_function)) { + NOTREACHED(); + return ERROR_INVALID_PARAMETER; + } + + base::win::PEImage target_image(module_handle); + if (!target_image.VerifyMagic()) { + NOTREACHED(); + return ERROR_INVALID_PARAMETER; + } + + InterceptFunctionInformation intercept_information = { + false, + imported_from_module, + function_name, + new_function, + old_function, + iat_thunk, + ERROR_GEN_FAILURE}; + + // First go through the IAT. If we don't find the import we are looking + // for in IAT, search delay import table. + target_image.EnumAllImports(InterceptEnumCallback, &intercept_information); + if (!intercept_information.finished_operation) { + target_image.EnumAllDelayImports(InterceptEnumCallback, + &intercept_information); + } + + return intercept_information.return_code; +} + +// Restore intercepted IAT entry with the original function. +// +// Arguments: +// intercept_function Interceptor function +// original_function Receives the original function pointer +// +// Returns: Returns NO_ERROR on success or Windows error code +// as defined in winerror.h +DWORD RestoreImportedFunction(void* intercept_function, + void* original_function, + IMAGE_THUNK_DATA* iat_thunk) { + if ((NULL == intercept_function) || (NULL == original_function) || + (NULL == iat_thunk)) { + NOTREACHED(); + return ERROR_INVALID_PARAMETER; + } + + if (GetIATFunction(iat_thunk) != intercept_function) { + // Check if someone else has intercepted on top of us. + // We cannot unpatch in this case, just raise a red flag. + NOTREACHED(); + return ERROR_INVALID_FUNCTION; + } + + return ModifyCode(&(iat_thunk->u1.Function), + &original_function, + sizeof(original_function)); +} + +} // namespace + +IATPatchFunction::IATPatchFunction() + : module_handle_(NULL), + original_function_(NULL), + iat_thunk_(NULL), + intercept_function_(NULL) { +} + +IATPatchFunction::~IATPatchFunction() { + if (NULL != intercept_function_) { + DWORD error = Unpatch(); + DCHECK_EQ(static_cast<DWORD>(NO_ERROR), error); + } +} + +DWORD IATPatchFunction::Patch(const wchar_t* module, + const char* imported_from_module, + const char* function_name, + void* new_function) { + DCHECK_EQ(static_cast<void*>(NULL), original_function_); + DCHECK_EQ(static_cast<IMAGE_THUNK_DATA*>(NULL), iat_thunk_); + DCHECK_EQ(static_cast<void*>(NULL), intercept_function_); + + HMODULE module_handle = LoadLibraryW(module); + + if (module_handle == NULL) { + NOTREACHED(); + return GetLastError(); + } + + DWORD error = InterceptImportedFunction(module_handle, + imported_from_module, + function_name, + new_function, + &original_function_, + &iat_thunk_); + + if (NO_ERROR == error) { + DCHECK_NE(original_function_, intercept_function_); + module_handle_ = module_handle; + intercept_function_ = new_function; + } else { + FreeLibrary(module_handle); + } + + return error; +} + +DWORD IATPatchFunction::Unpatch() { + DWORD error = RestoreImportedFunction(intercept_function_, + original_function_, + iat_thunk_); + DCHECK_EQ(static_cast<DWORD>(NO_ERROR), error); + + // Hands off the intercept if we fail to unpatch. + // If IATPatchFunction::Unpatch fails during RestoreImportedFunction + // it means that we cannot safely unpatch the import address table + // patch. In this case its better to be hands off the intercept as + // trying to unpatch again in the destructor of IATPatchFunction is + // not going to be any safer + if (module_handle_) + FreeLibrary(module_handle_); + module_handle_ = NULL; + intercept_function_ = NULL; + original_function_ = NULL; + iat_thunk_ = NULL; + + return error; +} + +} // namespace win +} // namespace base diff --git a/base/win/iat_patch_function.h b/base/win/iat_patch_function.h new file mode 100644 index 0000000..16e7bb0 --- /dev/null +++ b/base/win/iat_patch_function.h @@ -0,0 +1,72 @@ +// Copyright (c) 2011 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. + +#ifndef BASE_WIN_IAT_PATCH_FUNCTION_H_ +#define BASE_WIN_IAT_PATCH_FUNCTION_H_ +#pragma once + +#include <windows.h> + +#include "base/basictypes.h" + +namespace base { +namespace win { + +// A class that encapsulates Import Address Table patching helpers and restores +// the original function in the destructor. +// +// It will intercept functions for a specific DLL imported from another DLL. +// This is the case when, for example, we want to intercept +// CertDuplicateCertificateContext function (exported from crypt32.dll) called +// by wininet.dll. +class IATPatchFunction { + public: + IATPatchFunction(); + ~IATPatchFunction(); + + // Intercept a function in an import table of a specific + // module. Save the original function and the import + // table address. These values will be used later + // during Unpatch + // + // Arguments: + // module Module to be intercepted + // imported_from_module Module that exports the 'function_name' + // function_name Name of the API to be intercepted + // + // Returns: Windows error code (winerror.h). NO_ERROR if successful + // + // Note: Patching a function will make the IAT patch take some "ownership" on + // |module|. It will LoadLibrary(module) to keep the DLL alive until a call + // to Unpatch(), which will call FreeLibrary() and allow the module to be + // unloaded. The idea is to help prevent the DLL from going away while a + // patch is still active. + DWORD Patch(const wchar_t* module, + const char* imported_from_module, + const char* function_name, + void* new_function); + + // Unpatch the IAT entry using internally saved original + // function. + // + // Returns: Windows error code (winerror.h). NO_ERROR if successful + DWORD Unpatch(); + + bool is_patched() const { + return (NULL != intercept_function_); + } + + private: + HMODULE module_handle_; + void* intercept_function_; + void* original_function_; + IMAGE_THUNK_DATA* iat_thunk_; + + DISALLOW_COPY_AND_ASSIGN(IATPatchFunction); +}; + +} // namespace win +} // namespace base + +#endif // BASE_WIN_IAT_PATCH_FUNCTION_H_ diff --git a/base/win/scoped_com_initializer.h b/base/win/scoped_com_initializer.h new file mode 100644 index 0000000..e7e3b4ac --- /dev/null +++ b/base/win/scoped_com_initializer.h @@ -0,0 +1,60 @@ +// Copyright (c) 2011 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. + +#ifndef BASE_WIN_SCOPED_COM_INITIALIZER_H_ +#define BASE_WIN_SCOPED_COM_INITIALIZER_H_ +#pragma once + +#include "base/basictypes.h" +#include "build/build_config.h" + +#if defined(OS_WIN) + +#include <objbase.h> + +namespace base { +namespace win { + +// Initializes COM in the constructor (STA), and uninitializes COM in the +// destructor. +class ScopedCOMInitializer { + public: + ScopedCOMInitializer() : hr_(CoInitialize(NULL)) { + } + + ScopedCOMInitializer::~ScopedCOMInitializer() { + if (SUCCEEDED(hr_)) + CoUninitialize(); + } + + private: + HRESULT hr_; + + DISALLOW_COPY_AND_ASSIGN(ScopedCOMInitializer); +}; + +} // namespace win +} // namespace base + +#else + +namespace base { +namespace win { + +// Do-nothing class for other platforms. +class ScopedCOMInitializer { + public: + ScopedCOMInitializer() {} + ~ScopedCOMInitializer() {} + + private: + DISALLOW_COPY_AND_ASSIGN(ScopedCOMInitializer); +}; + +} // namespace win +} // namespace base + +#endif + +#endif // BASE_WIN_SCOPED_COM_INITIALIZER_H_ |