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