summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormaruel@chromium.org <maruel@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-06-25 01:59:21 +0000
committermaruel@chromium.org <maruel@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-06-25 01:59:21 +0000
commit1bbb107508df005ce6da1577e1a7026ab932f3be (patch)
tree3122cfed5ec0e379bdc65488f6191efd9c42e7f7
parent541434c24710c131b697cf461fc3a21ddb74ed39 (diff)
downloadchromium_src-1bbb107508df005ce6da1577e1a7026ab932f3be.zip
chromium_src-1bbb107508df005ce6da1577e1a7026ab932f3be.tar.gz
chromium_src-1bbb107508df005ce6da1577e1a7026ab932f3be.tar.bz2
Complete revert of r90464. It was partially done in r90471.
The revert didn't apply cleanly but verified that this commands: git diff $(git svn find-rev r90463) -- $(git diff origin/trunk --name-only) returns nothing. BUG= TEST= Review URL: http://codereview.chromium.org/7261013 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@90472 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--app/win/iat_patch_function.cc278
-rw-r--r--app/win/iat_patch_function.h72
-rw-r--r--app/win/scoped_co_mem.h49
-rw-r--r--app/win/scoped_com_initializer.h60
-rw-r--r--app/win/shell.cc112
-rw-r--r--app/win/shell.h41
6 files changed, 612 insertions, 0 deletions
diff --git a/app/win/iat_patch_function.cc b/app/win/iat_patch_function.cc
new file mode 100644
index 0000000..9abd6f2
--- /dev/null
+++ b/app/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 "app/win/iat_patch_function.h"
+
+#include "base/logging.h"
+#include "base/win/pe_image.h"
+
+namespace app {
+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 app
diff --git a/app/win/iat_patch_function.h b/app/win/iat_patch_function.h
new file mode 100644
index 0000000..4a2aa0c
--- /dev/null
+++ b/app/win/iat_patch_function.h
@@ -0,0 +1,72 @@
+// Copyright (c) 2010 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 APP_WIN_IAT_PATCH_FUNCTION_H_
+#define APP_WIN_IAT_PATCH_FUNCTION_H_
+#pragma once
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+
+namespace app {
+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 app
+
+#endif // APP_WIN_IAT_PATCH_FUNCTION_H_
diff --git a/app/win/scoped_co_mem.h b/app/win/scoped_co_mem.h
new file mode 100644
index 0000000..a6017fa
--- /dev/null
+++ b/app/win/scoped_co_mem.h
@@ -0,0 +1,49 @@
+// Copyright (c) 2010 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 APP_WIN_SCOPED_CO_MEM_H_
+#define APP_WIN_SCOPED_CO_MEM_H_
+#pragma once
+
+#include <objbase.h>
+
+#include "base/basictypes.h"
+
+namespace app {
+namespace win {
+
+// Simple scoped memory releaser class for COM allocated memory.
+// Example:
+// app::win::ScopedCoMem<ITEMIDLIST> file_item;
+// SHGetSomeInfo(&file_item, ...);
+// ...
+// return; <-- memory released
+template<typename T>
+class ScopedCoMem {
+ public:
+ explicit ScopedCoMem() : mem_ptr_(NULL) {}
+
+ ~ScopedCoMem() {
+ if (mem_ptr_)
+ CoTaskMemFree(mem_ptr_);
+ }
+
+ T** operator&() { // NOLINT
+ return &mem_ptr_;
+ }
+
+ operator T*() {
+ return mem_ptr_;
+ }
+
+ private:
+ T* mem_ptr_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedCoMem);
+};
+
+} // namespace win
+} // namespace app
+
+#endif // APP_WIN_SCOPED_CO_MEM_H_
diff --git a/app/win/scoped_com_initializer.h b/app/win/scoped_com_initializer.h
new file mode 100644
index 0000000..3a2cf55
--- /dev/null
+++ b/app/win/scoped_com_initializer.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2010 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 APP_WIN_SCOPED_COM_INITIALIZER_H_
+#define APP_WIN_SCOPED_COM_INITIALIZER_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+
+#include <objbase.h>
+
+namespace app {
+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 app
+
+#else
+
+namespace app {
+namespace win {
+
+// Do-nothing class for other platforms.
+class ScopedCOMInitializer {
+ public:
+ ScopedCOMInitializer() {}
+ ~ScopedCOMInitializer() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ScopedCOMInitializer);
+};
+
+} // namespace win
+} // namespace app
+
+#endif
+
+#endif // APP_WIN_SCOPED_COM_INITIALIZER_H_
diff --git a/app/win/shell.cc b/app/win/shell.cc
new file mode 100644
index 0000000..cf47387
--- /dev/null
+++ b/app/win/shell.cc
@@ -0,0 +1,112 @@
+// 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 "app/win/shell.h"
+
+#include <shellapi.h>
+#include <shlobj.h>
+
+#include "base/file_path.h"
+#include "base/native_library.h"
+#include "base/string_util.h"
+#include "base/win/scoped_comptr.h"
+#include "base/win/win_util.h"
+#include "base/win/windows_version.h"
+
+namespace app {
+namespace win {
+
+namespace {
+
+const wchar_t kShell32[] = L"shell32.dll";
+const char kSHGetPropertyStoreForWindow[] = "SHGetPropertyStoreForWindow";
+
+// Define the type of SHGetPropertyStoreForWindow is SHGPSFW.
+typedef DECLSPEC_IMPORT HRESULT (STDAPICALLTYPE *SHGPSFW)(HWND hwnd,
+ REFIID riid,
+ void** ppv);
+
+} // namespace
+
+// Open an item via a shell execute command. Error code checking and casting
+// explanation: http://msdn2.microsoft.com/en-us/library/ms647732.aspx
+bool OpenItemViaShell(const FilePath& full_path) {
+ HINSTANCE h = ::ShellExecuteW(
+ NULL, NULL, full_path.value().c_str(), NULL,
+ full_path.DirName().value().c_str(), SW_SHOWNORMAL);
+
+ LONG_PTR error = reinterpret_cast<LONG_PTR>(h);
+ if (error > 32)
+ return true;
+
+ if ((error == SE_ERR_NOASSOC))
+ return OpenItemWithExternalApp(full_path.value());
+
+ return false;
+}
+
+bool OpenItemViaShellNoZoneCheck(const FilePath& full_path) {
+ SHELLEXECUTEINFO sei = { sizeof(sei) };
+ sei.fMask = SEE_MASK_NOZONECHECKS | SEE_MASK_FLAG_DDEWAIT;
+ sei.nShow = SW_SHOWNORMAL;
+ sei.lpVerb = NULL;
+ sei.lpFile = full_path.value().c_str();
+ if (::ShellExecuteExW(&sei))
+ return true;
+ LONG_PTR error = reinterpret_cast<LONG_PTR>(sei.hInstApp);
+ if ((error == SE_ERR_NOASSOC))
+ return OpenItemWithExternalApp(full_path.value());
+ return false;
+}
+
+// Show the Windows "Open With" dialog box to ask the user to pick an app to
+// open the file with.
+bool OpenItemWithExternalApp(const string16& full_path) {
+ SHELLEXECUTEINFO sei = { sizeof(sei) };
+ sei.fMask = SEE_MASK_FLAG_DDEWAIT;
+ sei.nShow = SW_SHOWNORMAL;
+ sei.lpVerb = L"openas";
+ sei.lpFile = full_path.c_str();
+ return (TRUE == ::ShellExecuteExW(&sei));
+}
+
+void SetAppIdForWindow(const string16& app_id, HWND hwnd) {
+ // This functionality is only available on Win7+.
+ if (base::win::GetVersion() < base::win::VERSION_WIN7)
+ return;
+
+ // Load Shell32.dll into memory.
+ // TODO(brg): Remove this mechanism when the Win7 SDK is available in trunk.
+ std::wstring shell32_filename(kShell32);
+ FilePath shell32_filepath(shell32_filename);
+ base::NativeLibrary shell32_library = base::LoadNativeLibrary(
+ shell32_filepath, NULL);
+
+ if (!shell32_library)
+ return;
+
+ // Get the function pointer for SHGetPropertyStoreForWindow.
+ void* function = base::GetFunctionPointerFromNativeLibrary(
+ shell32_library,
+ kSHGetPropertyStoreForWindow);
+
+ if (!function) {
+ base::UnloadNativeLibrary(shell32_library);
+ return;
+ }
+
+ // Set the application's name.
+ base::win::ScopedComPtr<IPropertyStore> pps;
+ SHGPSFW SHGetPropertyStoreForWindow = static_cast<SHGPSFW>(function);
+ HRESULT result = SHGetPropertyStoreForWindow(
+ hwnd, __uuidof(*pps), reinterpret_cast<void**>(pps.Receive()));
+ if (S_OK == result)
+ base::win::SetAppIdForPropertyStore(pps, app_id.c_str());
+
+ // Cleanup.
+ base::UnloadNativeLibrary(shell32_library);
+}
+
+} // namespace win
+} // namespace app
diff --git a/app/win/shell.h b/app/win/shell.h
new file mode 100644
index 0000000..44ee3ba7
--- /dev/null
+++ b/app/win/shell.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2010 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 APP_WIN_SHELL_H_
+#define APP_WIN_SHELL_H_
+
+#include <windows.h>
+
+#include "base/string16.h"
+
+class FilePath;
+
+namespace app {
+namespace win {
+
+// Open or run a file via the Windows shell. In the event that there is no
+// default application registered for the file specified by 'full_path',
+// ask the user, via the Windows "Open With" dialog.
+// Returns 'true' on successful open, 'false' otherwise.
+bool OpenItemViaShell(const FilePath& full_path);
+
+// The download manager now writes the alternate data stream with the
+// zone on all downloads. This function is equivalent to OpenItemViaShell
+// without showing the zone warning dialog.
+bool OpenItemViaShellNoZoneCheck(const FilePath& full_path);
+
+// Ask the user, via the Windows "Open With" dialog, for an application to use
+// to open the file specified by 'full_path'.
+// Returns 'true' on successful open, 'false' otherwise.
+bool OpenItemWithExternalApp(const string16& full_path);
+
+// Sets the application id given as the Application Model ID for the window
+// specified. This method is used to insure that different web applications
+// do not group together on the Win7 task bar.
+void SetAppIdForWindow(const string16& app_id, HWND hwnd);
+
+} // namespace win
+} // namespace app
+
+#endif // APP_WIN_SHELL_H_