1 : // Copyright 2013 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/pehacker/operations/add_imports_operation.h"
16 :
17 : #include "syzygy/block_graph/transform.h"
18 :
19 : namespace pehacker {
20 : namespace operations {
21 :
22 : namespace {
23 :
24 : using pe::transforms::ImportedModule;
25 :
26 : static const char kFunctionName[] = "function_name";
27 : static const char kMustNotExist[] = "must_not_exist";
28 : static const char kOrdinal[] = "ordinal";
29 :
30 : // A simple struct for representing content parsed from an 'add_import'
31 : // operation.
32 : struct ImportInfo {
33 : static const int kUnusedOrdinal = -1;
34 : std::string function_name; // Empty if ordinal is being used.
35 : int ordinal; // -1 if name is being used.
36 : bool must_not_exist;
37 : };
38 :
39 : // Parses a dictionary describing an import.
40 E : bool ParseImport(const base::DictionaryValue* import, ImportInfo* import_info) {
41 E : DCHECK_NE(reinterpret_cast<const base::DictionaryValue*>(NULL), import);
42 E : DCHECK_NE(reinterpret_cast<ImportInfo*>(NULL), import_info);
43 :
44 E : bool have_function_name = import->HasKey(kFunctionName);
45 E : bool have_ordinal = import->HasKey(kOrdinal);
46 E : if (have_function_name && have_ordinal) {
47 i : LOG(ERROR) << "Only one of \"" << kFunctionName << "\" or \""
48 : << kOrdinal << "\" may be defined in an import.";
49 i : return false;
50 : }
51 :
52 E : std::string function_name;
53 E : if (have_function_name && !import->GetString(kFunctionName, &function_name)) {
54 i : LOG(ERROR) << "\"" << kFunctionName << "\" must be a string.";
55 i : return false;
56 : }
57 :
58 E : int ordinal = -1;
59 E : if (have_ordinal && !import->GetInteger(kOrdinal, &ordinal)) {
60 i : LOG(ERROR) << "\"" << kOrdinal << "\" must be an integer.";
61 i : return false;
62 : }
63 :
64 E : bool must_not_exist = false;
65 : if (import->HasKey(kMustNotExist) &&
66 E : !import->GetBoolean(kMustNotExist, &must_not_exist)) {
67 i : LOG(ERROR) << "\"" << kMustNotExist << "\" must be a boolean.";
68 i : return false;
69 : }
70 :
71 E : import_info->function_name = function_name;
72 E : import_info->ordinal = ordinal;
73 E : import_info->must_not_exist = must_not_exist;
74 :
75 E : return true;
76 E : }
77 :
78 : } // namespace
79 :
80 : const char AddImportsOperation::kName[] = "AddImportsOperation";
81 :
82 E : const char* AddImportsOperation::name() const {
83 E : return kName;
84 E : }
85 :
86 : bool AddImportsOperation::Init(const TransformPolicyInterface* policy,
87 E : const base::DictionaryValue* operation) {
88 E : DCHECK_NE(reinterpret_cast<TransformPolicyInterface*>(NULL), policy);
89 E : DCHECK_NE(reinterpret_cast<base::DictionaryValue*>(NULL), operation);
90 :
91 E : const base::ListValue* modules = NULL;
92 E : if (!operation->GetList("modules", &modules)) {
93 i : LOG(ERROR) << "Operation \"add_imports\" must contain a list of "
94 : << "\"modules\".";
95 i : return false;
96 : }
97 :
98 : // Iterate over the modules to be imported.
99 E : for (size_t i = 0; i < modules->GetSize(); ++i) {
100 E : const base::DictionaryValue* module = NULL;
101 E : if (!modules->GetDictionary(i, &module)) {
102 i : LOG(ERROR) << "Each module must be a dictionary.";
103 i : return false;
104 : }
105 :
106 E : std::string module_name;
107 : if (!module->GetString("module_name", &module_name) ||
108 E : module_name.empty()) {
109 i : LOG(ERROR) << "Each module must contain a \"module_name\".";
110 i : return false;
111 : }
112 :
113 E : const base::ListValue* imports = NULL;
114 E : if (!module->GetList("imports", &imports) || imports->empty()) {
115 i : LOG(ERROR) << "Each module must contain a list of \"imports\".";
116 i : return false;
117 : }
118 :
119 E : bool must_not_exist = false;
120 : if (module->HasKey(kMustNotExist) &&
121 E : !module->GetBoolean(kMustNotExist, &must_not_exist)) {
122 i : LOG(ERROR) << "\"" << kMustNotExist << "\" must be a boolean.";
123 i : return false;
124 : }
125 :
126 : // Get the imported module with this name. ImportModule objects aren't
127 : // copyable so we have to go out of our way to build a map of them.
128 : ImportedModuleMap::iterator mod_it =
129 E : imported_module_map_.find(module_name);
130 E : if (mod_it == imported_module_map_.end()) {
131 E : ImportedModule* imported_module = new ImportedModule(module_name);
132 E : imported_modules_.push_back(imported_module);
133 : mod_it = imported_module_map_.insert(std::make_pair(
134 E : module_name, imported_module)).first;
135 : }
136 :
137 : // Iterate over the imports to be added from this module.
138 E : for (size_t j = 0; j < imports->GetSize(); ++j) {
139 E : const base::DictionaryValue* import = NULL;
140 E : if (!imports->GetDictionary(j, &import)) {
141 i : LOG(ERROR) << "Each import must be a dictionary.";
142 i : return false;
143 : }
144 :
145 E : ImportInfo import_info = {};
146 E : if (!ParseImport(import, &import_info))
147 i : return false;
148 :
149 E : if (import_info.ordinal != ImportInfo::kUnusedOrdinal) {
150 : // TODO(chrisha): Add support for imports by ordinal.
151 i : LOG(ERROR) << "Imports by ordinal are not currently supported.";
152 i : return false;
153 : }
154 :
155 : // TODO(chrisha): Add support for a kMustImport mode.
156 E : if (must_not_exist) {
157 i : LOG(WARNING) << "The directive \"" << kMustNotExist << "\" is not yet "
158 : << "supported.";
159 : }
160 :
161 : // Configure the import.
162 E : VLOG(1) << "Parsed import \"" << module_name << ":"
163 : << import_info.function_name << "\".";
164 : mod_it->second->AddSymbol(
165 E : import_info.function_name, ImportedModule::kAlwaysImport);
166 E : }
167 E : }
168 :
169 : // Configure the transform itself.
170 E : ImportedModuleMap::iterator it = imported_module_map_.begin();
171 E : for (; it != imported_module_map_.end(); ++it)
172 E : add_imports_tx_.AddModule(it->second);
173 :
174 E : return true;
175 E : }
176 :
177 : bool AddImportsOperation::Apply(const TransformPolicyInterface* policy,
178 : BlockGraph* block_graph,
179 E : BlockGraph::Block* header_block) {
180 E : DCHECK_NE(reinterpret_cast<TransformPolicyInterface*>(NULL), policy);
181 E : DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
182 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), header_block);
183 :
184 : // We pass our call through the unittesting seam so that we don't have to
185 : // actually run the transform on a decomposed image in our tests.
186 E : VLOG(1) << "Applying \"" << add_imports_tx_.name() << "\" transform.";
187 : if (!ApplyTransform(&add_imports_tx_,
188 : policy,
189 : block_graph,
190 E : header_block)) {
191 E : return false;
192 : }
193 E : return true;
194 E : }
195 :
196 : bool AddImportsOperation::ApplyTransform(
197 : block_graph::BlockGraphTransformInterface* tx,
198 : const TransformPolicyInterface* policy,
199 : BlockGraph* block_graph,
200 i : BlockGraph::Block* header_block) {
201 : DCHECK_NE(reinterpret_cast<block_graph::BlockGraphTransformInterface*>(NULL),
202 i : tx);
203 i : DCHECK_NE(reinterpret_cast<TransformPolicyInterface*>(NULL), policy);
204 i : DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
205 i : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), header_block);
206 :
207 : if (!block_graph::ApplyBlockGraphTransform(tx,
208 : policy,
209 : block_graph,
210 i : header_block)) {
211 i : return false;
212 : }
213 i : return true;
214 i : }
215 :
216 : } // namespace operations
217 : } // namespace pehacker
|