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/pe/image_filter.h"
16 :
17 : #include <errno.h>
18 :
19 : #include "base/file_util.h"
20 : #include "base/stringprintf.h"
21 : #include "base/json/json_reader.h"
22 :
23 : namespace pe {
24 :
25 : namespace {
26 :
27 : // Keys used by the JSON serialization.
28 : const char kBaseAddress[] = "base_address";
29 : const char kChecksum[] = "checksum";
30 : const char kFilter[] = "filter";
31 : const char kPath[] = "path";
32 : const char kSignature[] = "signature";
33 : const char kSize[] = "size";
34 : const char kTimeDateStamp[] = "time_date_stamp";
35 :
36 : // Outputs |value| as a hex-coded string. Returns true on succes, false on
37 : // failure.
38 E : bool OutputHexUint32(uint32 value, core::JSONFileWriter* json) {
39 E : DCHECK(json != NULL);
40 :
41 E : std::string s;
42 E : if (json->pretty_print()) {
43 E : s = base::StringPrintf("0x%08X", value);
44 E : } else {
45 E : s = base::StringPrintf("%X", value);
46 : }
47 :
48 E : if (!json->OutputString(s))
49 i : return false;
50 :
51 E : return true;
52 E : }
53 :
54 : // Parses a hex-coded value from |string|, placing it in |value|. Returns true
55 : // on success, false if anything went wront. Logs an error message on failure.
56 E : bool ParseHexUint32(const std::string& string, uint32* value) {
57 E : DCHECK(value != NULL);
58 :
59 E : char* end_ptr = NULL;
60 E : errno = 0;
61 E : *value = ::strtoul(string.c_str(), &end_ptr, 16);
62 E : if (errno != 0 || end_ptr != string.c_str() + string.size()) {
63 i : LOG(ERROR) << "String does not contain a 32-bit hex value: " << string;
64 i : return false;
65 : }
66 :
67 E : return true;
68 E : }
69 :
70 : // Gets a uint32 value from the |dict| entry under |key|. Expects the value to
71 : // be stored as a hex-encoded string, which will be decoded. Returns true on
72 : // success, false otherwise. Logs an error message on failure.
73 : bool GetHexUint32(const DictionaryValue& dict,
74 : const char* key,
75 E : uint32* value) {
76 E : DCHECK(key != NULL);
77 E : DCHECK(value != NULL);
78 :
79 E : std::string s;
80 : if (!dict.GetString(key, &s) ||
81 E : !ParseHexUint32(s, value)) {
82 i : LOG(ERROR) << "Dictionary does not contain a valid hex-formatted "
83 : << "string under key \"" << key << "\".";
84 i : return false;
85 : }
86 :
87 E : return true;
88 E : }
89 :
90 : // Gets an integer value from the |dict| entry under |key|. Expects the value
91 : // to be stored as an integer. Returns true on success, false otherwise. Logs
92 : // and error message on failure.
93 E : bool GetInteger(const DictionaryValue& dict, const char* key, int* value) {
94 E : DCHECK(key != NULL);
95 E : DCHECK(value != NULL);
96 E : if (!dict.GetInteger(key, value)) {
97 i : LOG(ERROR) << "Dictionary does not contain integer under key \""
98 : << key << "\".";
99 i : return false;
100 : }
101 E : return true;
102 E : }
103 :
104 : // Loads a module signature from the given |dict|, populating the signature
105 : // member of |filter|. Returns true on success, false otherwise. Logs an error
106 : // message on failure.
107 E : bool LoadSignatureFromJSON(const DictionaryValue& dict, ImageFilter* filter) {
108 E : DCHECK(filter != NULL);
109 :
110 E : uint32 base_address = 0;
111 E : int size = 0;
112 E : PEFile::Signature& s = filter->signature;
113 : if (!GetHexUint32(dict, kBaseAddress, &base_address) ||
114 : !GetHexUint32(dict, kChecksum, &s.module_checksum) ||
115 : !GetInteger(dict, kSize, &size) ||
116 : size <= 0 ||
117 : !GetHexUint32(dict, kTimeDateStamp, &s.module_time_date_stamp) ||
118 E : !dict.GetString(kPath, &s.path)) {
119 i : LOG(ERROR) << "Invalid signature dictionary.";
120 i : return false;
121 : }
122 E : s.base_address.set_value(base_address);
123 E : s.module_size = size;
124 :
125 E : return true;
126 E : }
127 :
128 : // Loads a relative address range from the given list. The list is expected to
129 : // be of length 2, with the first entry being a string containing a hex-encoded
130 : // RVA, and the second being an integer length. Adds the range to the address
131 : // filter in |filter|. Returns true on success, false otherwise. Logs an error
132 : // message on failure.
133 E : bool LoadRangeFromJSON(const ListValue& range, ImageFilter* filter) {
134 E : DCHECK(filter != NULL);
135 :
136 E : if (range.GetSize() != 2)
137 i : return false;
138 :
139 E : ListValue::const_iterator it = range.begin();
140 E : Value* address_value = *(it++);
141 E : Value* length_value = *it;
142 E : DCHECK(address_value != NULL);
143 E : DCHECK(length_value != NULL);
144 :
145 E : std::string address_string;
146 E : uint32 address = 0;
147 : if (!address_value->GetAsString(&address_string) ||
148 E : !ParseHexUint32(address_string, &address)) {
149 i : return false;
150 : }
151 :
152 E : int length = 0;
153 E : if (!length_value->GetAsInteger(&length) || length <= 0)
154 i : return false;
155 :
156 : // Mark the range we just parsed.
157 : filter->filter.Mark(ImageFilter::Range(
158 E : ImageFilter::RelativeAddress(address), length));
159 :
160 E : return true;
161 E : }
162 :
163 : // Loads a relative address filter from the given |list|, populating the
164 : // address filter in |filter|. Expects that the signature member of |filter|
165 : // has already been appropriately initialized. Returns true on success, false
166 : // otherwise. Logs an error message on failure.
167 E : bool LoadFilterFromJSON(const ListValue& list, ImageFilter* filter) {
168 E : DCHECK(filter != NULL);
169 :
170 : // Initialize the filter. This assumes that the signature has already been
171 : // loaded.
172 : filter->filter = ImageFilter::RelativeAddressFilter(
173 : ImageFilter::Range(ImageFilter::RelativeAddress(0),
174 E : filter->signature.module_size));
175 :
176 E : ListValue::const_iterator it = list.begin();
177 E : for (; it != list.end(); ++it) {
178 E : Value* value = *it;
179 E : DCHECK(value != NULL);
180 :
181 : // LoadRangeFromJSON takes care of logging on failure, and adding the range
182 : // to the filter on success.
183 E : ListValue* range = NULL;
184 : if (!value->GetAsList(&range) ||
185 E : !LoadRangeFromJSON(*range, filter)) {
186 i : LOG(ERROR) << "Encountered invalid range in filter list.";
187 i : return false;
188 : }
189 E : }
190 :
191 E : return true;
192 E : }
193 :
194 : } // namespace
195 :
196 E : void ImageFilter::Init(const PEFile::Signature& pe_signature) {
197 E : signature = pe_signature;
198 : filter = RelativeAddressFilter(
199 E : Range(RelativeAddress(0), signature.module_size));
200 E : }
201 :
202 E : void ImageFilter::Init(const PEFile& pe_file) {
203 E : pe_file.GetSignature(&signature);
204 : filter = RelativeAddressFilter(
205 E : Range(RelativeAddress(0), signature.module_size));
206 E : }
207 :
208 E : bool ImageFilter::Init(const base::FilePath& path) {
209 E : PEFile pe_file;
210 E : if (!pe_file.Init(path))
211 E : return false;
212 E : Init(pe_file);
213 E : return true;
214 E : }
215 :
216 E : bool ImageFilter::IsForModule(const PEFile::Signature& pe_signature) const {
217 E : if (!pe_signature.IsConsistent(signature))
218 E : return false;
219 E : return true;
220 E : }
221 :
222 E : bool ImageFilter::IsForModule(const PEFile& pe_file) const {
223 E : PEFile::Signature pe_signature;
224 E : pe_file.GetSignature(&pe_signature);
225 E : if (!IsForModule(pe_signature))
226 E : return false;
227 E : return true;
228 E : }
229 :
230 E : bool ImageFilter::IsForModule(const base::FilePath& path) const {
231 E : PEFile pe_file;
232 E : if (!pe_file.Init(path))
233 E : return false;
234 E : if (!IsForModule(pe_file))
235 E : return false;
236 E : return true;
237 E : }
238 :
239 E : bool ImageFilter::SaveToJSON(core::JSONFileWriter* json) const {
240 E : DCHECK(json != NULL);
241 :
242 E : core::JSONFileWriter& j = *json;
243 :
244 : if (!j.OutputComment("This is a serialized ImageFilter.") ||
245 E : !j.OpenDict()) {
246 i : return false;
247 : }
248 :
249 : // Write the module signature.
250 : if (!j.OutputComment("This is the signature of the module to which this") ||
251 : !j.OutputComment("filter applies.") ||
252 : !j.OutputKey(kSignature) ||
253 : !j.OpenDict() ||
254 : !j.OutputKey(kPath) ||
255 : !j.OutputString(signature.path) ||
256 : !j.OutputKey(kBaseAddress) ||
257 : !OutputHexUint32(signature.base_address.value(), json) ||
258 : !j.OutputKey(kChecksum) ||
259 : !OutputHexUint32(signature.module_checksum, json) ||
260 : !j.OutputKey(kSize) ||
261 : !j.OutputInteger(signature.module_size) ||
262 : !j.OutputKey(kTimeDateStamp) ||
263 : !OutputHexUint32(signature.module_time_date_stamp, json) ||
264 E : !j.CloseDict()) {
265 i : return false;
266 : }
267 :
268 : if (!j.OutputComment("This is the filtered address space, consisting of") ||
269 : !j.OutputComment("a list of [rva, length] tuples.") ||
270 : !j.OutputKey(kFilter) ||
271 E : !j.OpenList()) {
272 i : return false;
273 : }
274 :
275 : // Write the ranges in the filter.
276 : RelativeAddressFilter::RangeSet::const_iterator it =
277 E : filter.marked_ranges().begin();
278 E : for (; it != filter.marked_ranges().end(); ++it) {
279 : if (!j.OpenList() ||
280 : !OutputHexUint32(it->start().value(), json) ||
281 : !j.OutputInteger(it->size()) ||
282 E : !j.CloseList()) {
283 i : return false;
284 : }
285 E : }
286 :
287 E : if (!j.CloseList() || !j.CloseDict())
288 i : return false;
289 :
290 E : return true;
291 E : }
292 :
293 E : bool ImageFilter::SaveToJSON(bool pretty_print, FILE* file) const {
294 E : DCHECK(file != NULL);
295 :
296 E : core::JSONFileWriter json_writer(file, pretty_print);
297 E : if (!SaveToJSON(&json_writer))
298 i : return false;
299 :
300 E : return true;
301 E : }
302 :
303 : bool ImageFilter::SaveToJSON(bool pretty_print,
304 E : const base::FilePath& path) const {
305 E : file_util::ScopedFILE file(file_util::OpenFile(path, "wb"));
306 E : if (file.get() == NULL) {
307 i : LOG(ERROR) << "Unable to open file for writing: " << path.value();
308 i : return false;
309 : }
310 :
311 E : if (!SaveToJSON(pretty_print, file.get()))
312 i : return false;
313 :
314 E : return true;
315 E : }
316 :
317 E : bool ImageFilter::LoadFromJSON(const DictionaryValue& dict) {
318 : // Get the signature dictionary.
319 : const DictionaryValue* signature_dict;
320 E : if (!dict.GetDictionary(kSignature, &signature_dict)) {
321 i : LOG(ERROR) << "Dictionary does not contain a dictionary under key \""
322 : << kSignature << "\".";
323 i : return false;
324 : }
325 E : if (!LoadSignatureFromJSON(*signature_dict, this))
326 i : return false;
327 :
328 : // Get the filter list and parse it.
329 : const ListValue* filter;
330 E : if (!dict.GetList(kFilter, &filter)) {
331 i : LOG(ERROR) << "Dictionary does not contain a list under key \""
332 : << kFilter << "\".";
333 i : return false;
334 : }
335 E : if (!LoadFilterFromJSON(*filter, this))
336 i : return false;
337 :
338 E : return true;
339 E : }
340 :
341 E : bool ImageFilter::LoadFromJSON(FILE* file) {
342 E : DCHECK(file != NULL);
343 :
344 : // Read the file into one big array.
345 E : char buffer[4096] = {};
346 E : std::vector<char> json;
347 E : while (!::feof(file)) {
348 E : size_t bytes = ::fread(buffer, sizeof(buffer[0]), arraysize(buffer), file);
349 E : if (::ferror(file)) {
350 i : LOG(ERROR) << "Error reading from file.";
351 i : return false;
352 : }
353 E : DCHECK_LT(0u, bytes);
354 E : size_t offset = json.size();
355 E : json.resize(offset + bytes);
356 E : ::memcpy(json.data() + offset, buffer, bytes);
357 E : }
358 :
359 E : if (json.empty()) {
360 i : LOG(ERROR) << "File is empty.";
361 i : return false;
362 : }
363 :
364 E : base::JSONReader json_reader;
365 : scoped_ptr<base::Value> value(
366 E : json_reader.Read(base::StringPiece(json.data(), json.size())));
367 E : if (value.get() == NULL) {
368 i : LOG(ERROR) << "Failed to parse JSON from file.";
369 i : return false;
370 : }
371 :
372 : base::DictionaryValue* dict;
373 E : if (!value->GetAsDictionary(&dict) || dict == NULL) {
374 i : LOG(ERROR) << "JSON does not contain dictionary at top level.";
375 i : return false;
376 : }
377 :
378 E : if (!LoadFromJSON(*dict))
379 i : return false;
380 :
381 E : return true;
382 E : }
383 :
384 E : bool ImageFilter::LoadFromJSON(const base::FilePath& path) {
385 E : file_util::ScopedFILE file(file_util::OpenFile(path, "rb"));
386 E : if (file.get() == NULL) {
387 E : LOG(ERROR) << "Unable to open file for reading: " << path.value();
388 E : return false;
389 : }
390 :
391 E : if (!LoadFromJSON(file.get()))
392 i : return false;
393 :
394 E : return true;
395 E : }
396 :
397 : } // namespace pe
|