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_
|