Coverage for /Syzygy/pe/hot_patching_decomposer.h

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
0.0%0046.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    :  // The HotPatchingDecomposer decomposes a loaded module into an ImageLayout and
  16    :  // its corresponding BlockGraph. The module must have been instrumented with
  17    :  // PEHotPatchingTransform first. The module must not be unloaded from memory
  18    :  // while decomposing and while using the resulting block graph as the contents
  19    :  // of the blocks are backed by their actual memory.
  20    :  //
  21    :  // The decomposer first reads the hot patching metadata to obtain the location
  22    :  // of the blocks in memory.
  23    :  //
  24    :  // Each decomposed block will have a code label to its beginning. If the block
  25    :  // contains data, an additional data label will be inserted at the first
  26    :  // data byte.
  27    :  //
  28    :  // Inter-block PC-relative references and in-block absolute references must be
  29    :  // recovered before passing the resulting block graph to a basic block
  30    :  // decomposer. In-block PC-relative references are automatically inserted by
  31    :  // the basic block decomposer. We expect that inter-block PC-relative references
  32    :  // are used only as arguments of direct jump instructions. In-block absolute
  33    :  // references are used for referring to the jump and case tables and referencing
  34    :  // in-block code in the jump tables.
  35    :  //
  36    :  // To recover these references we apply the following algorithm:
  37    :  // - The code part of each block will be disassembled and examined:
  38    :  //   - We add all 4-byte PC-relative references from immediate arguments of
  39    :  //     branch and call instructions. We create 1-byte long dummy code blocks
  40    :  //     marked with the BUILT_BY_UNSUPPORTED_COMPILER attribute for the
  41    :  //     references that point to blocks that are not in the metadata.
  42    :  //   - We recognize jump table references in the displacement of specific
  43    :  //     indirect jump instructions. If the displacement can be interpreted as
  44    :  //     a reference to the data part of the block, we add the absolute reference
  45    :  //     and also insert a label for the jump table.
  46    :  //   - We recognize case table references in the displacement of specific
  47    :  //     MOVZX instructions. If the displacement can be interpreted as a reference
  48    :  //     to the data part of the block, we add the absolute reference and also
  49    :  //     insert a label for the case table.
  50    :  // - The data part of the block is supposed to contain only jump tables and case
  51    :  //   tables. Only jump tables contain references, and during the disassembly of
  52    :  //   the code part we already recovered the locations of these. Jump tables
  53    :  //   contain absolute references. We only recover the in-block absolute
  54    :  //   references by inspecting each 4-byte long position in the jump table and
  55    :  //   adding a reference if it can be interpreted as a pointer pointing inside
  56    :  //   the block.
  57    :  //
  58    :  // NOTE: Currently, inter-block absolute references are not recovered.
  59    :  //     Recovering (at least some of) them would allow avoiding the double
  60    :  //     indirection when hot patched blocks call each other.
  61    :  
  62    :  #ifndef SYZYGY_PE_HOT_PATCHING_DECOMPOSER_H_
  63    :  #define SYZYGY_PE_HOT_PATCHING_DECOMPOSER_H_
  64    :  
  65    :  #include <memory>
  66    :  #include <unordered_map>
  67    :  
  68    :  #include "base/win/pe_image.h"
  69    :  #include "syzygy/block_graph/hot_patching_metadata.h"
  70    :  #include "syzygy/core/disassembler_util.h"
  71    :  #include "syzygy/pe/image_layout.h"
  72    :  
  73  m :  namespace pe {
  74    :  
  75  m :  class HotPatchingDecomposer {
  76  m :   public:
  77  m :    typedef block_graph::BlockGraph BlockGraph;
  78  m :    typedef std::unordered_map<const IMAGE_SECTION_HEADER*, BlockGraph::SectionId>
  79  m :        SectionIdMap;
  80    :  
  81    :    // Constructs a hot patching decomposer for a given module.
  82    :    // @param module The handle of the module to decompose.
  83  m :    explicit HotPatchingDecomposer(HMODULE module);
  84    :  
  85  m :    ~HotPatchingDecomposer();
  86    :  
  87    :    // Decomposes the module into the image layout.
  88    :    // @param image_layout The image layout to decompose into.
  89  m :    bool Decompose(ImageLayout* image_layout);
  90    :  
  91  m :   protected:
  92  m :    typedef block_graph::BlockGraph::BlockType BlockType;
  93  m :    typedef core::RelativeAddress RelativeAddress;
  94    :  
  95    :    // Creates a new block with the given properties, and attaches the
  96    :    // data to it. This assumes that no conflicting block exists.
  97  m :    BlockGraph::Block* CreateBlock(BlockType type,
  98  m :                                   RelativeAddress address,
  99  m :                                   BlockGraph::Size size,
 100  m :                                   const base::StringPiece& name);
 101    :  
 102    :    // This function disassembles a hot patchable block and recovers inter-block
 103    :    // PC-relative references and in-block absolute references originating in the
 104    :    // code by examining the instructions. Jump table and case table labels are
 105    :    // also recovered.
 106    :    // @param block The block to disassemble.
 107    :    // @param code_size The number of bytes that should be interpreted as code.
 108  m :    bool InferCodeReferences(BlockGraph::Block* block, size_t code_size);
 109    :  
 110    :    // Recover in-block absolute references originating in jump tables.
 111    :    // @param block The block to examine.
 112    :    // @param code_size The number of bytes that should be interpreted as code.
 113  m :    bool InferJumpTableReferences(BlockGraph::Block* block, size_t code_size);
 114    :  
 115    :    // Create the blocks with the help of the hot patching metadata.
 116  m :    bool LoadHotPatchableBlocks();
 117    :  
 118    :    // Create sections in the image layout and the underlying block-graph.
 119  m :    bool LoadSectionInformation();
 120    :  
 121    :    // Parse the case table reference if the instruction is a case table read.
 122    :    //
 123    :    // We expect that case tables are used by instructions in the following
 124    :    // form: MOVZX EAX, BYTE [ECX+<case-table-address>] where
 125    :    // <case-table-address> is an address inside the block, after the code.
 126    :    // Any register can stand in place of EAX and ECX. If we encounter an
 127    :    // instruction in this form we insert an absolute reference to the block
 128    :    // itself with the proper offset. We also insert a case table label, this
 129    :    // allows us to separate jump table entries from case table entries when
 130    :    // creating jump table references.
 131    :    //
 132    :    // @param block The block containing the instruction.
 133    :    // @param offset The offset of the instruction.
 134    :    // @param inst The instruction to parse.
 135    :    // @param code_size The size of the code in the block.
 136    :    // @param parse Output parameter, true if the instruction was recognized as
 137    :    //     a case table read.
 138    :    // @returns true if no error occurred (not a case table instruction or
 139    :    //     successfully added the reference), false on failure.
 140  m :    bool ParseCaseTableRead(BlockGraph::Block* block,
 141  m :                            BlockGraph::Offset offset,
 142  m :                            const _DInst &inst,
 143  m :                            size_t code_size,
 144  m :                            bool* parsed);
 145    :  
 146    :    // Parse the in-block absolute reference to the jump table if the instruction
 147    :    // is a jump using a jump table.
 148    :    //
 149    :    // We expect that jump tables are used by instructions in the following
 150    :    // form: JMP DWORD [EAX*4+<jump-table-address>] where
 151    :    // <jump-table-address> is an address inside the block, after the code.
 152    :    // Any register can stand in place of EAX. If we encounter an
 153    :    // instruction in this form we insert an absolute reference to the
 154    :    // block itself with the proper offset. We also insert a jump table
 155    :    // label because basic block decomposer expects these labels at branch
 156    :    // reference targets.
 157    :    //
 158    :    // @param block The block containing the instruction.
 159    :    // @param offset The offset of the instruction.
 160    :    // @param inst The instruction to parse.
 161    :    // @param code_size The size of the code in the block.
 162    :    // @param parse Output parameter, true if the instruction was recognized as
 163    :    //     a jump table read.
 164    :    // @returns true if no error occurred (not a jump table instruction or
 165    :    //     successfully added the reference), false on failure.
 166  m :    bool ParseJumpTableCall(BlockGraph::Block* block,
 167  m :                            BlockGraph::Offset offset,
 168  m :                            const _DInst &inst,
 169  m :                            size_t code_size,
 170  m :                            bool* parsed);
 171    :  
 172    :    // Parse the jump and call instructions and recover PC-relative reference
 173    :    // from their immediate arguments. This also creates dummy blocks for
 174    :    // referred blocks not in the image layout. The dummy blocks will be
 175    :    // 1-byte-long code blocks backed by the actual memory at the location of
 176    :    // the target of the reference. They will also have the
 177    :    // BUILT_BY_UNSUPPORTED_COMPILER attribute set to differentiate them from
 178    :    // other blocks and to mark them that their contents should not be
 179    :    // interpreted.
 180    :    // @param block The block containing the instruction.
 181    :    // @param offset The offset of the instruction.
 182    :    // @param inst The instruction to parse.
 183    :    // @param parse Output parameter, true if the instruction was recognized as
 184    :    //     a PC-relative branch or call instruction.
 185    :    // @returns true if no error occurred (even if no reference added), false
 186    :    //     on failure.
 187  m :    bool ParsePCRelativeBranchAndCallInstuction(BlockGraph::Block* block,
 188  m :                                                BlockGraph::Offset offset,
 189  m :                                                const _DInst &inst,
 190  m :                                                bool* parsed);
 191    :  
 192    :    // This function uses the hot patching block metadata to create the
 193    :    // corresponding code block in the block graph.
 194    :    // @param block_metadata Metadata for a single code block.
 195  m :    BlockGraph::Block* ProcessHotPatchableCodeBlock(
 196  m :        const block_graph::HotPatchingBlockMetadata& block_metadata);
 197    :  
 198  m :   private:
 199    :    // The image layout that we decompose into.
 200  m :    ImageLayout* image_layout_;
 201    :  
 202    :    // The address space of the image layout.
 203  m :    BlockGraph::AddressSpace* image_;
 204    :  
 205    :    // This variable is used to generate increasing IDs for the code blocks.
 206  m :    size_t last_code_block_id_;
 207    :  
 208    :    // The handle to the module being decomposed.
 209  m :    HMODULE module_;
 210    :  
 211    :    // The PEImage object representing the module to be decomposed.
 212  m :    std::unique_ptr<base::win::PEImage> pe_image_;
 213    :  
 214    :    // Maps the section header addresses to section ids.
 215  m :    SectionIdMap section_index_;
 216    :  
 217  m :    DISALLOW_COPY_AND_ASSIGN(HotPatchingDecomposer);
 218  m :  };
 219    :  
 220  m :  }  // namespace pe
 221    :  
 222    :  #endif  // SYZYGY_PE_HOT_PATCHING_DECOMPOSER_H_

Coverage information generated Thu Jan 14 17:40:38 2016.