| Index: chrome_elf/hook_util/hook_util.cc
|
| diff --git a/chrome_elf/hook_util/hook_util.cc b/chrome_elf/hook_util/hook_util.cc
|
| deleted file mode 100644
|
| index e16330d9975e54f34242f9d0cacd8d4127edbb07..0000000000000000000000000000000000000000
|
| --- a/chrome_elf/hook_util/hook_util.cc
|
| +++ /dev/null
|
| @@ -1,334 +0,0 @@
|
| -// 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 "hook_util.h"
|
| -
|
| -#include <versionhelpers.h> // windows.h must be before
|
| -
|
| -#include "base/win/pe_image.h"
|
| -#include "sandbox/win/src/interception_internal.h"
|
| -#include "sandbox/win/src/internal_types.h"
|
| -#include "sandbox/win/src/sandbox_utils.h"
|
| -#include "sandbox/win/src/service_resolver.h"
|
| -
|
| -namespace {
|
| -
|
| -//------------------------------------------------------------------------------
|
| -// Common hooking utility functions - LOCAL
|
| -//------------------------------------------------------------------------------
|
| -
|
| -#if !defined(_WIN64)
|
| -// Whether a process is running under WOW64 (the wrapper that allows 32-bit
|
| -// processes to run on 64-bit versions of Windows). This will return
|
| -// WOW64_DISABLED for both "32-bit Chrome on 32-bit Windows" and "64-bit
|
| -// Chrome on 64-bit Windows". WOW64_UNKNOWN means "an error occurred", e.g.
|
| -// the process does not have sufficient access rights to determine this.
|
| -enum WOW64Status {
|
| - WOW64_DISABLED,
|
| - WOW64_ENABLED,
|
| - WOW64_UNKNOWN,
|
| -};
|
| -
|
| -WOW64Status GetWOW64StatusForCurrentProcess() {
|
| - typedef BOOL(WINAPI * IsWow64ProcessFunc)(HANDLE, PBOOL);
|
| - IsWow64ProcessFunc is_wow64_process = reinterpret_cast<IsWow64ProcessFunc>(
|
| - GetProcAddress(GetModuleHandle(L"kernel32.dll"), "IsWow64Process"));
|
| - if (!is_wow64_process)
|
| - return WOW64_DISABLED;
|
| - BOOL is_wow64 = FALSE;
|
| - if (!is_wow64_process(GetCurrentProcess(), &is_wow64))
|
| - return WOW64_UNKNOWN;
|
| - return is_wow64 ? WOW64_ENABLED : WOW64_DISABLED;
|
| -}
|
| -#endif // !defined(_WIN64)
|
| -
|
| -// Change the page protections to writable, copy the data,
|
| -// restore protections. Returns a winerror code.
|
| -DWORD PatchMem(void* target, void* new_bytes, size_t length) {
|
| - if (target == nullptr || new_bytes == nullptr || length == 0)
|
| - return ERROR_INVALID_PARAMETER;
|
| -
|
| - // Preserve executable state.
|
| - MEMORY_BASIC_INFORMATION memory_info = {};
|
| - if (!::VirtualQuery(target, &memory_info, sizeof(memory_info))) {
|
| - return GetLastError();
|
| - }
|
| -
|
| - DWORD is_executable = (PAGE_EXECUTE | PAGE_EXECUTE_READ |
|
| - PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY) &
|
| - memory_info.Protect;
|
| -
|
| - // Make target writeable.
|
| - DWORD old_page_protection = 0;
|
| - if (!::VirtualProtect(target, length,
|
| - is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE,
|
| - &old_page_protection)) {
|
| - return GetLastError();
|
| - }
|
| -
|
| - // Write the data.
|
| - ::memcpy(target, new_bytes, length);
|
| -
|
| - // Restore old page protection.
|
| - if (!::VirtualProtect(target, length, old_page_protection,
|
| - &old_page_protection)) {
|
| -// Yes, this could fail. However, memory was already patched.
|
| -#ifdef _DEBUG
|
| - assert(false);
|
| -#endif // _DEBUG
|
| - }
|
| -
|
| - return NO_ERROR;
|
| -}
|
| -
|
| -//------------------------------------------------------------------------------
|
| -// Import Address Table hooking support - LOCAL
|
| -//------------------------------------------------------------------------------
|
| -
|
| -void* GetIATFunctionPtr(IMAGE_THUNK_DATA* iat_thunk) {
|
| - if (iat_thunk == nullptr)
|
| - return nullptr;
|
| -
|
| - // 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;
|
| -}
|
| -
|
| -// Used to pass target function information during pe_image enumeration.
|
| -struct IATHookFunctionInfo {
|
| - 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;
|
| -};
|
| -
|
| -// Callback function for pe_image enumeration. This function is called from
|
| -// within PEImage::EnumOneImportChunk().
|
| -// NOTE: Returning true means continue enumerating. False means stop.
|
| -bool IATFindHookFuncCallback(const base::win::PEImage& image,
|
| - const char* module,
|
| - DWORD ordinal,
|
| - const char* import_name,
|
| - DWORD hint,
|
| - IMAGE_THUNK_DATA* iat,
|
| - void* cookie) {
|
| - IATHookFunctionInfo* hook_func_info =
|
| - reinterpret_cast<IATHookFunctionInfo*>(cookie);
|
| - if (hook_func_info == nullptr)
|
| - return false;
|
| -
|
| - // Check for the right module.
|
| - if (module == nullptr ||
|
| - ::strnicmp(module, hook_func_info->imported_from_module,
|
| - ::strlen(module)) != 0)
|
| - return true;
|
| -
|
| - // Check for the right function.
|
| - if (import_name == nullptr ||
|
| - ::strnicmp(import_name, hook_func_info->function_name,
|
| - ::strlen(import_name)) != 0)
|
| - return true;
|
| -
|
| - // At this point, the target function was found. Even if something fails now,
|
| - // don't do any further enumerating.
|
| - hook_func_info->finished_operation = true;
|
| -
|
| - // This is it. Do the hook!
|
| - // 1) Save the old function pointer.
|
| - *(hook_func_info->old_function) = GetIATFunctionPtr(iat);
|
| -
|
| - // 2) Save the IAT thunk.
|
| - *(hook_func_info->iat_thunk) = iat;
|
| -
|
| - // 3) Sanity check the pointer sizes (architectures).
|
| - if (sizeof(iat->u1.Function) != sizeof(hook_func_info->new_function)) {
|
| - hook_func_info->return_code = ERROR_BAD_ENVIRONMENT;
|
| -#ifdef _DEBUG
|
| - assert(false);
|
| -#endif // _DEBUG
|
| - return false;
|
| - }
|
| -
|
| - // 4) Sanity check that the new hook function is not actually the
|
| - // same as the existing function for this import!
|
| - if (*(hook_func_info->old_function) == hook_func_info->new_function) {
|
| - hook_func_info->return_code = ERROR_INVALID_FUNCTION;
|
| -#ifdef _DEBUG
|
| - assert(false);
|
| -#endif // _DEBUG
|
| - return false;
|
| - }
|
| -
|
| - // 5) Patch the function pointer.
|
| - hook_func_info->return_code =
|
| - PatchMem(&(iat->u1.Function), &(hook_func_info->new_function),
|
| - sizeof(hook_func_info->new_function));
|
| -
|
| - return false;
|
| -}
|
| -
|
| -// Applies an import-address-table hook. Returns a system winerror.h code.
|
| -// Call RemoveIATHook() with |new_function|, |old_function| and |iat_thunk|
|
| -// to remove the hook.
|
| -DWORD ApplyIATHook(HMODULE module_handle,
|
| - const char* imported_from_module,
|
| - const char* function_name,
|
| - void* new_function,
|
| - void** old_function,
|
| - IMAGE_THUNK_DATA** iat_thunk) {
|
| - base::win::PEImage target_image(module_handle);
|
| - if (!target_image.VerifyMagic())
|
| - return ERROR_INVALID_PARAMETER;
|
| -
|
| - IATHookFunctionInfo hook_info = {false,
|
| - imported_from_module,
|
| - function_name,
|
| - new_function,
|
| - old_function,
|
| - iat_thunk,
|
| - ERROR_PROC_NOT_FOUND};
|
| -
|
| - // 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(IATFindHookFuncCallback, &hook_info);
|
| - if (!hook_info.finished_operation) {
|
| - target_image.EnumAllDelayImports(IATFindHookFuncCallback, &hook_info);
|
| - }
|
| -
|
| - return hook_info.return_code;
|
| -}
|
| -
|
| -// Removes an import-address-table hook. Returns a system winerror.h code.
|
| -DWORD RemoveIATHook(void* intercept_function,
|
| - void* original_function,
|
| - IMAGE_THUNK_DATA* iat_thunk) {
|
| - if (GetIATFunctionPtr(iat_thunk) != intercept_function) {
|
| -#ifdef _DEBUG
|
| - assert(false);
|
| -#endif // _DEBUG
|
| - // Someone else has messed with the same target. Cannot unpatch.
|
| - return ERROR_INVALID_FUNCTION;
|
| - }
|
| -
|
| - return PatchMem(&(iat_thunk->u1.Function), &original_function,
|
| - sizeof(original_function));
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -namespace elf_hook {
|
| -
|
| -//------------------------------------------------------------------------------
|
| -// System Service hooking support
|
| -//------------------------------------------------------------------------------
|
| -
|
| -sandbox::ServiceResolverThunk* HookSystemService(bool relaxed) {
|
| - // Create a thunk via the appropriate ServiceResolver instance.
|
| - sandbox::ServiceResolverThunk* thunk = nullptr;
|
| -
|
| - // No hooking on unsupported OS versions.
|
| - if (!::IsWindows7OrGreater())
|
| - return thunk;
|
| -
|
| - // Pseudo-handle, no need to close.
|
| - HANDLE current_process = ::GetCurrentProcess();
|
| -
|
| -#if defined(_WIN64)
|
| - // ServiceResolverThunk can handle all the formats in 64-bit (instead only
|
| - // handling one like it does in 32-bit versions).
|
| - thunk = new sandbox::ServiceResolverThunk(current_process, relaxed);
|
| -#else
|
| - if (GetWOW64StatusForCurrentProcess() == WOW64_ENABLED) {
|
| - if (::IsWindows10OrGreater())
|
| - thunk = new sandbox::Wow64W10ResolverThunk(current_process, relaxed);
|
| - else if (::IsWindows8OrGreater())
|
| - thunk = new sandbox::Wow64W8ResolverThunk(current_process, relaxed);
|
| - else
|
| - thunk = new sandbox::Wow64ResolverThunk(current_process, relaxed);
|
| - } else if (::IsWindows8OrGreater()) {
|
| - thunk = new sandbox::Win8ResolverThunk(current_process, relaxed);
|
| - } else {
|
| - thunk = new sandbox::ServiceResolverThunk(current_process, relaxed);
|
| - }
|
| -#endif
|
| -
|
| - return thunk;
|
| -}
|
| -
|
| -//------------------------------------------------------------------------------
|
| -// Import Address Table hooking support
|
| -//------------------------------------------------------------------------------
|
| -
|
| -IATHook::IATHook()
|
| - : intercept_function_(nullptr),
|
| - original_function_(nullptr),
|
| - iat_thunk_(nullptr) {}
|
| -
|
| -IATHook::~IATHook() {
|
| - if (intercept_function_ != nullptr) {
|
| - if (Unhook() != NO_ERROR) {
|
| -#ifdef _DEBUG
|
| - assert(false);
|
| -#endif // _DEBUG
|
| - }
|
| - }
|
| -}
|
| -
|
| -DWORD IATHook::Hook(HMODULE module,
|
| - const char* imported_from_module,
|
| - const char* function_name,
|
| - void* new_function) {
|
| - if ((module == 0 || module == INVALID_HANDLE_VALUE) ||
|
| - imported_from_module == nullptr || function_name == nullptr ||
|
| - new_function == nullptr)
|
| - return ERROR_INVALID_PARAMETER;
|
| -
|
| - // Only hook once per object, to ensure unhook.
|
| - if (intercept_function_ != nullptr || original_function_ != nullptr ||
|
| - iat_thunk_ != nullptr) {
|
| -#ifdef _DEBUG
|
| - assert(false);
|
| -#endif //_DEBUG
|
| - return ERROR_SHARING_VIOLATION;
|
| - }
|
| -
|
| - DWORD winerror = ApplyIATHook(module, imported_from_module, function_name,
|
| - new_function, &original_function_, &iat_thunk_);
|
| - if (winerror == NO_ERROR)
|
| - intercept_function_ = new_function;
|
| -
|
| - return winerror;
|
| -}
|
| -
|
| -DWORD IATHook::Unhook() {
|
| - if (intercept_function_ == nullptr || original_function_ == nullptr ||
|
| - iat_thunk_ == nullptr)
|
| - return ERROR_INVALID_PARAMETER;
|
| -
|
| - DWORD winerror =
|
| - RemoveIATHook(intercept_function_, original_function_, iat_thunk_);
|
| -#ifdef _DEBUG
|
| - if (winerror != NO_ERROR)
|
| - assert(false);
|
| -#endif //_DEBUG
|
| -
|
| - intercept_function_ = nullptr;
|
| - original_function_ = nullptr;
|
| - iat_thunk_ = nullptr;
|
| -
|
| - return winerror;
|
| -}
|
| -
|
| -} // namespace elf_hook
|
|
|