15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/iat_patch_function.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/pe_image.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace base {
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace win {
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct InterceptFunctionInformation {
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool finished_operation;
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* imported_from_module;
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* function_name;
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void* new_function;
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void** old_function;
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IMAGE_THUNK_DATA** iat_thunk;
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD return_code;
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void* GetIATFunction(IMAGE_THUNK_DATA* iat_thunk) {
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (NULL == iat_thunk) {
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Works around the 64 bit portability warning:
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The Function member inside IMAGE_THUNK_DATA is really a pointer
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to the IAT function. IMAGE_THUNK_DATA correctly maps to IMAGE_THUNK_DATA32
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // or IMAGE_THUNK_DATA64 for correct pointer size.
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  union FunctionThunk {
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IMAGE_THUNK_DATA thunk;
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void* pointer;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } iat_function;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  iat_function.thunk = *iat_thunk;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return iat_function.pointer;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool InterceptEnumCallback(const base::win::PEImage& image, const char* module,
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           DWORD ordinal, const char* name, DWORD hint,
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           IMAGE_THUNK_DATA* iat, void* cookie) {
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  InterceptFunctionInformation* intercept_information =
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    reinterpret_cast<InterceptFunctionInformation*>(cookie);
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (NULL == intercept_information) {
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(module);
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((0 == lstrcmpiA(module, intercept_information->imported_from_module)) &&
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     (NULL != name) &&
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     (0 == lstrcmpiA(name, intercept_information->function_name))) {
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Save the old pointer.
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (NULL != intercept_information->old_function) {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *(intercept_information->old_function) = GetIATFunction(iat);
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (NULL != intercept_information->iat_thunk) {
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *(intercept_information->iat_thunk) = iat;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // portability check
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    COMPILE_ASSERT(sizeof(iat->u1.Function) ==
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sizeof(intercept_information->new_function), unknown_IAT_thunk_format);
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Patch the function.
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    intercept_information->return_code =
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ModifyCode(&(iat->u1.Function),
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 &(intercept_information->new_function),
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 sizeof(intercept_information->new_function));
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Terminate further enumeration.
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    intercept_information->finished_operation = true;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Helper to intercept a function in an import table of a specific
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// module.
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Arguments:
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// module_handle          Module to be intercepted
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// imported_from_module   Module that exports the symbol
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// function_name          Name of the API to be intercepted
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// new_function           Interceptor function
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// old_function           Receives the original function pointer
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// iat_thunk              Receives pointer to IAT_THUNK_DATA
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//                        for the API from the import table.
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns: Returns NO_ERROR on success or Windows error code
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//          as defined in winerror.h
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DWORD InterceptImportedFunction(HMODULE module_handle,
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const char* imported_from_module,
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const char* function_name, void* new_function,
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                void** old_function,
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                IMAGE_THUNK_DATA** iat_thunk) {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((NULL == module_handle) || (NULL == imported_from_module) ||
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     (NULL == function_name) || (NULL == new_function)) {
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ERROR_INVALID_PARAMETER;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::PEImage target_image(module_handle);
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!target_image.VerifyMagic()) {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ERROR_INVALID_PARAMETER;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  InterceptFunctionInformation intercept_information = {
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    false,
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    imported_from_module,
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    function_name,
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_function,
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    old_function,
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    iat_thunk,
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ERROR_GEN_FAILURE};
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First go through the IAT. If we don't find the import we are looking
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // for in IAT, search delay import table.
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  target_image.EnumAllImports(InterceptEnumCallback, &intercept_information);
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!intercept_information.finished_operation) {
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    target_image.EnumAllDelayImports(InterceptEnumCallback,
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     &intercept_information);
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return intercept_information.return_code;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Restore intercepted IAT entry with the original function.
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Arguments:
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// intercept_function     Interceptor function
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// original_function      Receives the original function pointer
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns: Returns NO_ERROR on success or Windows error code
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//          as defined in winerror.h
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DWORD RestoreImportedFunction(void* intercept_function,
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              void* original_function,
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              IMAGE_THUNK_DATA* iat_thunk) {
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((NULL == intercept_function) || (NULL == original_function) ||
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (NULL == iat_thunk)) {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ERROR_INVALID_PARAMETER;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (GetIATFunction(iat_thunk) != intercept_function) {
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Check if someone else has intercepted on top of us.
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We cannot unpatch in this case, just raise a red flag.
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ERROR_INVALID_FUNCTION;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ModifyCode(&(iat_thunk->u1.Function),
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    &original_function,
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    sizeof(original_function));
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Change the page protection (of code pages) to writable and copy
1705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// the data at the specified location
1715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)//
1725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Arguments:
1735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// old_code               Target location to copy
1745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// new_code               Source
1755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// length                 Number of bytes to copy
1765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)//
1775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Returns: Windows error code (winerror.h). NO_ERROR if successful
1785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)DWORD ModifyCode(void* old_code, void* new_code, int length) {
1795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if ((NULL == old_code) || (NULL == new_code) || (0 == length)) {
1805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    NOTREACHED();
1815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return ERROR_INVALID_PARAMETER;
1825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
1835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Change the page protection so that we can write.
1855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  MEMORY_BASIC_INFORMATION memory_info;
1865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DWORD error = NO_ERROR;
1875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DWORD old_page_protection = 0;
1885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!VirtualQuery(old_code, &memory_info, sizeof(memory_info))) {
1905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    error = GetLastError();
1915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return error;
1925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
1935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DWORD is_executable = (PAGE_EXECUTE | PAGE_EXECUTE_READ |
1955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                        PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY) &
1965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                        memory_info.Protect;
1975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (VirtualProtect(old_code,
1995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                     length,
2005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                     is_executable ? PAGE_EXECUTE_READWRITE :
2015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                     PAGE_READWRITE,
2025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                     &old_page_protection)) {
2035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // Write the data.
2055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    CopyMemory(old_code, new_code, length);
2065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // Restore the old page protection.
2085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    error = ERROR_SUCCESS;
2095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    VirtualProtect(old_code,
2105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                  length,
2115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                  old_page_protection,
2125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                  &old_page_protection);
2135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  } else {
2145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    error = GetLastError();
2155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
2165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return error;
2185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
2195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IATPatchFunction::IATPatchFunction()
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : module_handle_(NULL),
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      original_function_(NULL),
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      iat_thunk_(NULL),
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      intercept_function_(NULL) {
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IATPatchFunction::~IATPatchFunction() {
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (NULL != intercept_function_) {
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DWORD error = Unpatch();
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_EQ(static_cast<DWORD>(NO_ERROR), error);
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DWORD IATPatchFunction::Patch(const wchar_t* module,
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              const char* imported_from_module,
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              const char* function_name,
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              void* new_function) {
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(static_cast<void*>(NULL), original_function_);
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(static_cast<IMAGE_THUNK_DATA*>(NULL), iat_thunk_);
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(static_cast<void*>(NULL), intercept_function_);
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HMODULE module_handle = LoadLibraryW(module);
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (module_handle == NULL) {
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return GetLastError();
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD error = InterceptImportedFunction(module_handle,
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          imported_from_module,
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          function_name,
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          new_function,
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          &original_function_,
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          &iat_thunk_);
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (NO_ERROR == error) {
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_NE(original_function_, intercept_function_);
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    module_handle_ = module_handle;
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    intercept_function_ = new_function;
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FreeLibrary(module_handle);
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return error;
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DWORD IATPatchFunction::Unpatch() {
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD error = RestoreImportedFunction(intercept_function_,
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        original_function_,
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        iat_thunk_);
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(static_cast<DWORD>(NO_ERROR), error);
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Hands off the intercept if we fail to unpatch.
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If IATPatchFunction::Unpatch fails during RestoreImportedFunction
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // it means that we cannot safely unpatch the import address table
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // patch. In this case its better to be hands off the intercept as
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // trying to unpatch again in the destructor of IATPatchFunction is
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // not going to be any safer
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (module_handle_)
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FreeLibrary(module_handle_);
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  module_handle_ = NULL;
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  intercept_function_ = NULL;
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  original_function_ = NULL;
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  iat_thunk_ = NULL;
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return error;
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
289effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid* IATPatchFunction::original_function() const {
290effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK(is_patched());
291effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return original_function_;
292effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
293effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace win
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace base
296