Coverage for /Syzygy/agent/common/hot_patcher.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
78.3%18230.C++source

Line-by-line coverage:

   1    :  // Copyright 2015 Google Inc. All Rights Reserved.
   2    :  //
   3    :  // Licensed under the Apache License, Version 2.0 (the "License");
   4    :  // you may not use this file except in compliance with the License.
   5    :  // You may obtain a copy of the License at
   6    :  //
   7    :  //     http://www.apache.org/licenses/LICENSE-2.0
   8    :  //
   9    :  // Unless required by applicable law or agreed to in writing, software
  10    :  // distributed under the License is distributed on an "AS IS" BASIS,
  11    :  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12    :  // See the License for the specific language governing permissions and
  13    :  // limitations under the License.
  14    :  
  15    :  #include "syzygy/agent/common/hot_patcher.h"
  16    :  
  17    :  #include <stdint.h>
  18    :  #include <windows.h>
  19    :  
  20    :  #include "base/logging.h"
  21    :  #include "syzygy/common/com_utils.h"
  22    :  
  23    :  namespace agent {
  24    :  namespace common {
  25    :  
  26    :  bool HotPatcher::Patch(FunctionPointer function_entry_point,
  27  E :                         FunctionPointer new_entry_point) {
  28    :    // The hot patching starts 5 bytes before the entry point of the function.
  29    :    uint8_t* hot_patch_start =
  30  E :        reinterpret_cast<uint8_t*>(function_entry_point) - 5;
  31  E :    const size_t hot_patch_length = 7U;
  32    :  
  33    :    // Change the page protection so that we can write.
  34    :    MEMORY_BASIC_INFORMATION memory_info;
  35  E :    DWORD old_page_protection = 0;
  36    :  
  37  E :    if (!::VirtualQuery(hot_patch_start, &memory_info, sizeof(memory_info))) {
  38  i :      LOG(ERROR) << "Could not execute VirtualQuery(). Error code: "
  39    :                 << ::common::LogWe();
  40  i :      return false;
  41    :    }
  42    :  
  43    :    DWORD is_executable = (PAGE_EXECUTE | PAGE_EXECUTE_READ |
  44  E :                           PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY) &
  45    :                          memory_info.Protect;
  46    :  
  47  E :    if (!::VirtualProtect(reinterpret_cast<LPVOID>(hot_patch_start),
  48    :                          hot_patch_length,
  49    :                          is_executable ? PAGE_EXECUTE_READWRITE :
  50    :                                          PAGE_READWRITE,
  51    :                          &old_page_protection)) {
  52  i :      LOG(ERROR) << "Could not grant write privileges to page. Error code: "
  53    :                 << ::common::LogWe();
  54  i :      return false;
  55    :    }
  56    :  
  57    :    // The location where we have to write the PC-relative address of the new
  58    :    // entry point.
  59    :    int32_t* new_entry_point_place =
  60  E :        reinterpret_cast<int32_t*>(hot_patch_start + 1);
  61    :  
  62    :    // The instrumenter uses 0xCC bytes for block padding. Before writing we check
  63    :    // if the target bytes contain these bytes.
  64  E :    DCHECK_EQ(*hot_patch_start, 0xCC);
  65  E :    DCHECK_EQ(*new_entry_point_place, static_cast<int>(0xCCCCCCCC));
  66    :  
  67    :    // Write the JMP instruction in the padding.
  68    :    // 0xE9 [32-bit PC-relative address]
  69  E :    *hot_patch_start = 0xE9;
  70  E :    *new_entry_point_place =
  71    :        reinterpret_cast<uint8_t*>(new_entry_point) - hot_patch_start - 5;
  72    :  
  73    :    // This is the location where the short jump overwriting the first two bytes
  74    :    // of the function should be placed.
  75    :    volatile uint16_t* jump_hook_place =
  76  E :        reinterpret_cast<uint16_t*>(hot_patch_start + 5);
  77    :  
  78    :    // Writes on x86 architecture are atomic within a cross 4-byte boundary.
  79    :    // NOTE: This can be loosened. Any two bytes starting at an address that meets
  80    :    //     the (address % 4 != 3) condition does not cross 4-byte boundary.
  81  E :    CHECK_EQ(0, reinterpret_cast<int>(jump_hook_place) % 2);
  82    :  
  83    :    // We write the instruction JMP -5 which is represented as: 0xEB 0xF9
  84    :    // We reverse the order of the bytes because of the little endian encoding
  85    :    // to get the final value 0xF9EB.
  86  E :    *jump_hook_place = 0xF9EB;
  87    :  
  88    :    // Restore the old page protection.
  89  E :    if (!::VirtualProtect(reinterpret_cast<LPVOID>(hot_patch_start),
  90    :                          hot_patch_length,
  91    :                          old_page_protection,
  92    :                          &old_page_protection)) {
  93    :      // We do not return false if this fails as the hot patching already
  94    :      // happened.
  95  i :      LOG(ERROR) << "Could not reset old privileges to page. Error code: "
  96    :                 << ::common::LogWe();
  97    :    }
  98    :  
  99  E :    return true;
 100  E :  }
 101    :  
 102    :  }  // namespace common
 103    :  }  // namespace agent

Coverage information generated Fri Jul 29 11:00:21 2016.