1 : // Copyright 2012 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 : // Defines a PE-specific block-graph transform that finds or adds imports to a
16 : // given module. Multiple libraries may be specified, and multiple functions per
17 : // library. If an import is not found and the mode is kFindOnly, then the
18 : // import will be added. This may also cause an entire imported module to
19 : // be added.
20 : //
21 : // Use is as follows:
22 : //
23 : // ImportedModule foo_dll("foo.dll");
24 : // size_t foo_foo_index = foo_dll.AddSymbol("foo");
25 : // size_t foo_bar_index = foo_dll.AddSymbol("bar");
26 : //
27 : // AddImportsTransform add_imports_transform;
28 : // add_imports_transform.AddModule(&foo_dll);
29 : // add_imports_transform.TransformBlockGraph(block_graph, dos_header_block);
30 : //
31 : // // Create a reference to function 'bar' in 'foo.dll'.
32 : // BlockGraph::Reference foo_bar_ref;
33 : // CHECK(foo_dll.GetSymbolReference(foo_bar_index, &foo_bar_ref));
34 : // some_block->SetReference(some_offset, foo_bar_ref);
35 : //
36 : // NOTE: The references provided by GetSymbolReference are only valid
37 : // immediately after they are constructed. If the import directory entries
38 : // are changed between creating the reference and adding it to a block,
39 : // than it may have been invalidated.
40 :
41 : #ifndef SYZYGY_PE_TRANSFORMS_ADD_IMPORTS_TRANSFORM_H_
42 : #define SYZYGY_PE_TRANSFORMS_ADD_IMPORTS_TRANSFORM_H_
43 :
44 : #include <windows.h>
45 :
46 : #include "syzygy/block_graph/typed_block.h"
47 : #include "syzygy/block_graph/transforms/named_transform.h"
48 :
49 : namespace pe {
50 : namespace transforms {
51 :
52 : using block_graph::transforms::NamedBlockGraphTransformImpl;
53 :
54 : // A transform for adding imported modules/symbols to a given block-graph.
55 : class AddImportsTransform
56 : : public NamedBlockGraphTransformImpl<AddImportsTransform> {
57 : public:
58 : typedef block_graph::BlockGraph BlockGraph;
59 :
60 : // Some forward declares.
61 : struct ImportedModule;
62 :
63 : AddImportsTransform();
64 :
65 : // Adds the given module and symbols to the list of modules and symbols to
66 : // import.
67 E : void AddModule(ImportedModule* imported_module) {
68 E : DCHECK(imported_module != NULL);
69 E : imported_modules_.push_back(imported_module);
70 E : }
71 :
72 : // Performs the transform. Adds entries for any missing modules and symbols,
73 : // returning references to their entries via the ImportedModule structures.
74 : //
75 : // @param block_graph the BlockGraph to populate.
76 : // @param dos_header_block the block containing the module's DOS header.
77 : // @returns true on success, false otherwise.
78 : virtual bool TransformBlockGraph(
79 : BlockGraph* block_graph, BlockGraph::Block* dos_header_block) OVERRIDE;
80 :
81 : // @returns the number of imported modules that were added to the image.
82 E : size_t modules_added() const { return modules_added_; }
83 :
84 : // @returns the number of imported symbols that were added to the image.
85 E : size_t symbols_added() const { return symbols_added_; }
86 :
87 : // @returns a pointer to the Block containing the Image Import Descriptor.
88 : BlockGraph::Block* image_import_descriptor_block() {
89 : return image_import_descriptor_block_;
90 : }
91 :
92 : // @returns a pointer to the Block containing the Import Address Table.
93 : BlockGraph::Block* import_address_table_block() {
94 : return import_address_table_block_;
95 : }
96 :
97 : // The name of this transform.
98 : static const char kTransformName[];
99 :
100 : protected:
101 : // A collection of modules (and symbols from them) to be imported. This
102 : // must be populated prior to calling the transform.
103 : std::vector<ImportedModule*> imported_modules_;
104 :
105 : // Statistics regarding the completed transform.
106 : size_t modules_added_;
107 : size_t symbols_added_;
108 :
109 : // We cache the blocks containing the IDT and IAT.
110 : BlockGraph::Block* image_import_descriptor_block_;
111 : BlockGraph::Block* import_address_table_block_;
112 : };
113 :
114 : // Describes a list of symbols to be imported from a module.
115 : struct AddImportsTransform::ImportedModule {
116 : ImportedModule() { }
117 :
118 : typedef block_graph::TypedBlock<IMAGE_IMPORT_DESCRIPTOR>
119 : ImageImportDescriptor;
120 :
121 : // Used to indicate that a symbol has not been imported.
122 : static const size_t kInvalidIatIndex;
123 :
124 : // The various modes in which the transform will treat a symbol.
125 : enum TransformMode {
126 : // Will search for the imported symbol and explicitly add an import entry
127 : // for it if it doesn't already exist.
128 : kAlwaysImport,
129 : // Will search for the imported symbol, ignoring it if not found.
130 : kFindOnly,
131 : };
132 :
133 : // @param module_name the name of the module to import.
134 : explicit ImportedModule(const base::StringPiece& module_name)
135 : : name_(module_name.begin(), module_name.end()), mode_(kFindOnly),
136 E : added_(false) {
137 E : }
138 :
139 : // Accesses the name of the module.
140 : // @returns the name of the module to import.
141 E : const std::string& name() const { return name_; }
142 :
143 : // @returns the mode of the transform.
144 E : TransformMode mode() const { return mode_; }
145 :
146 : // Determines if this module has been imported.
147 : // @returns true if there is an import entry for this module, false otherwise.
148 : // @note this is only meaningful after this transform has been applied.
149 E : bool ModuleIsImported() const { return import_descriptor_.block() != NULL; }
150 :
151 : // Determines if this module was added to the import table by the transform.
152 : // @returns true if the module was added, false otherwise.
153 : // @note this is only meaningful after this transform has been applied.
154 E : bool ModuleWasAdded() const { return added_; }
155 :
156 : // @returns the import descriptor for this module.
157 : // @note this is only meaningful after this transform has been applied, and
158 : // is only valid immediately after the transform. All bets are off if
159 : // another transform is applied.
160 : const ImageImportDescriptor& import_descriptor() const {
161 : return import_descriptor_;
162 : }
163 E : ImageImportDescriptor& import_descriptor() {
164 E : return import_descriptor_;
165 E : }
166 :
167 : // Adds a symbol to be imported, returning its index.
168 : // @param symbol_name the symbol to be added.
169 : // @param mode the transform mode.
170 : // @returns the index of the symbol in this module, to be used for querying
171 : // information about the symbol post-transform.
172 : size_t AddSymbol(const base::StringPiece& symbol_name,
173 : TransformMode mode);
174 :
175 : // Returns the number of symbols that are to be imported from this module.
176 E : size_t size() const { return symbols_.size(); }
177 :
178 : // Accesses the name of the index'th symbol.
179 : //
180 : // @param index the index of the symbol to fetch.
181 : // @returns the name of the index'th symbol.
182 E : const std::string& GetSymbolName(size_t index) const {
183 E : DCHECK_LT(index, symbols_.size());
184 E : return symbols_[index].name;
185 E : }
186 :
187 : // @param index the index of the symbol to query.
188 : // @returns true if the @p index'th symbol is find only.
189 E : TransformMode GetSymbolMode(size_t index) const {
190 E : DCHECK_LT(index, symbols_.size());
191 E : return symbols_[index].mode;
192 E : }
193 :
194 : // @param index the index of the symbol to query.
195 : // @returns true if the @p index symbol has an import entry.
196 : // @note this is only meaningful after the transformation has been applied.
197 E : bool SymbolIsImported(size_t index) const {
198 E : DCHECK_LT(index, symbols_.size());
199 E : return symbols_[index].iat_index != kInvalidIatIndex;
200 E : }
201 :
202 : // @param index the index of the symbol to fetch.
203 : // @returns true if the symbol was added, false otherwise.
204 : // @note this is only meaningful after the transformation has been applied.
205 E : bool SymbolWasAdded(size_t index) const {
206 E : DCHECK_LT(index, symbols_.size());
207 E : return symbols_[index].added;
208 E : }
209 :
210 : // @param index the index of the symbol to query.
211 : // @returns the index of the symbol in the IAT and the HNA/INT. This can be
212 : // used for directly navigating the IID returned by 'import_descriptor'.
213 : // Returns kInvalidIatIndex if the symbol was not imported.
214 : // @note this is only meaningful after the transformation has been applied.
215 E : size_t GetSymbolIatIndex(size_t index) const {
216 E : DCHECK_LT(index, symbols_.size());
217 E : return symbols_[index].iat_index;
218 E : }
219 :
220 : // Gets an absolute reference to the IAT entry of the ith symbol. Returns
221 : // true on success, false if this was not possible. This will fail if the
222 : // AddImportsTransform has not successfully run on this ImportedModule
223 : // object, or if this symbol is in kFindOnly mode and no import exists for
224 : // the symbol. See SymbolIsImported.
225 : //
226 : // The returned reference is only valid while the import data directory is
227 : // not modified. Once added to a block, the imports may be further modified
228 : // and reference tracking will ensure things are kept up to date; until this
229 : // time @p abs_reference is left dangling.
230 : //
231 : // @param index the index of the symbol to fetch.
232 : // @param abs_reference the reference to populate.
233 : // @returns true on success, false otherwise.
234 : bool GetSymbolReference(size_t index,
235 : BlockGraph::Reference* abs_reference) const;
236 :
237 : private:
238 : // The AddImportsTransform is a friend so that it may directly set certain
239 : // output structures.
240 : friend AddImportsTransform;
241 :
242 : // Represents a symbol imported from this library. Currently this only
243 : // supports importing by name, but we could always extend this to handle
244 : // ordinals.
245 : struct Symbol {
246 : // The name of the symbol to import.
247 : std::string name;
248 : // The index of the imported symbol in the module's Import Name Table. This
249 : // is left as kInvalidIatIndex if this symbol's mode is kFindOnly and the
250 : // import does not exist.
251 : size_t iat_index;
252 : // The transform mode for this symbol.
253 : TransformMode mode;
254 : // If this is true then the symbol was added by the transform.
255 : bool added;
256 : };
257 :
258 : // The name of the module to be imported.
259 : std::string name_;
260 :
261 : // The image import descriptor associated with this module. This will refer
262 : // to a block in the block-graph provided to the AddImportsTransform, assuming
263 : // successful completion.
264 : ImageImportDescriptor import_descriptor_;
265 :
266 : // The list of symbols to be imported from this module.
267 : std::vector<Symbol> symbols_;
268 :
269 : // Transform mode for the whole module. Is kFindOnly if all symbols in this
270 : // module are kFindOnly, otherwise is kAlwaysImport.
271 : TransformMode mode_;
272 :
273 : // Set to true if this module was added to image by the transform.
274 : bool added_;
275 :
276 : DISALLOW_COPY_AND_ASSIGN(ImportedModule);
277 : };
278 :
279 : } // namespace transforms
280 : } // namespace pe
281 :
282 : #endif // SYZYGY_PE_TRANSFORMS_ADD_IMPORTS_TRANSFORM_H_
|