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 : #include "syzygy/instrument/transforms/thunk_import_references_transform.h"
16 :
17 : // The Win8 SDK defines this in winerror.h, and it is subsequently redefined by
18 : // delayimp.h
19 : #undef FACILITY_VISUALCPP
20 : #include <delayimp.h>
21 : #include <limits>
22 :
23 : #include "base/logging.h"
24 : #include "base/strings/string_util.h"
25 : #include "base/strings/stringprintf.h"
26 : #include "syzygy/block_graph/basic_block_assembler.h"
27 : #include "syzygy/block_graph/block_builder.h"
28 : #include "syzygy/block_graph/typed_block.h"
29 : #include "syzygy/common/defs.h"
30 : #include "syzygy/pe/pe_utils.h"
31 :
32 : namespace instrument {
33 : namespace transforms {
34 :
35 : namespace {
36 :
37 : using block_graph::BlockGraph;
38 : using block_graph::TypedBlock;
39 : using block_graph::ConstTypedBlock;
40 :
41 : // A simple struct that can be used to let us access strings using TypedBlock.
42 : struct StringStruct {
43 : const char string[1];
44 : };
45 :
46 : typedef BlockGraph::Offset Offset;
47 : typedef TypedBlock<IMAGE_DOS_HEADER> DosHeader;
48 : typedef TypedBlock<IMAGE_IMPORT_BY_NAME> ImageImportByName;
49 : typedef TypedBlock<IMAGE_IMPORT_DESCRIPTOR> ImageImportDescriptor;
50 : typedef TypedBlock<IMAGE_NT_HEADERS> NtHeaders;
51 : typedef TypedBlock<StringStruct> StringBlock;
52 : typedef TypedBlock<ImgDelayDescr> ImageDelayImportDescriptor;
53 :
54 : // We add this suffix to the destination
55 : const char kThunkSuffix[] = "_ImportThunk";
56 : const char kDelayThunkSuffix[] = "_DelayImportThunk";
57 :
58 : } // namespace
59 :
60 : using pe::transforms::PEAddImportsTransform;
61 : using pe::transforms::ImportedModule;
62 :
63 : const char ThunkImportReferencesTransform::kTransformName[] =
64 : "ThunkImportReferencesTransform";
65 :
66 : const char ThunkImportReferencesTransform::kEntryHookName[] =
67 : "_indirect_penter";
68 : const char ThunkImportReferencesTransform::kDefaultInstrumentDll[] =
69 : "call_trace.dll";
70 :
71 : ThunkImportReferencesTransform::ThunkImportReferencesTransform()
72 : : thunk_section_(NULL),
73 E : instrument_dll_name_(kDefaultInstrumentDll) {
74 E : }
75 :
76 : bool ThunkImportReferencesTransform::TransformBlockGraph(
77 : const TransformPolicyInterface* policy,
78 : BlockGraph* block_graph,
79 E : BlockGraph::Block* header_block) {
80 E : DCHECK_NE(reinterpret_cast<TransformPolicyInterface*>(NULL), policy);
81 E : DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
82 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), header_block);
83 E : DCHECK_EQ(BlockGraph::PE_IMAGE, block_graph->image_format());
84 E : DCHECK_EQ(reinterpret_cast<BlockGraph::Section*>(NULL), thunk_section_);
85 :
86 : // We always exclude our own agent DLL from instrumentation.
87 E : modules_to_exclude_.insert(instrument_dll_name_);
88 :
89 : // Start by finding or adding import entries for our instrumentation hook.
90 E : ImportedModule import_module(instrument_dll_name_);
91 : size_t hook_index = import_module.AddSymbol(
92 E : kEntryHookName, ImportedModule::kAlwaysImport);
93 :
94 E : add_imports_transform_.AddModule(&import_module);
95 :
96 : if (!add_imports_transform_.TransformBlockGraph(
97 E : policy, block_graph, header_block)) {
98 i : LOG(ERROR) << "Unable to add imports for instrumentation DLL.";
99 i : return false;
100 : }
101 :
102 E : if (!import_module.GetSymbolReference(hook_index, &hook_ref_)) {
103 i : LOG(ERROR) << "Unable to get import reference for hook.";
104 i : return false;
105 : }
106 :
107 E : ImportAddressLocationNameMap import_locations;
108 : if (!LookupImportLocations(modules_to_exclude_,
109 : header_block,
110 E : &import_locations)) {
111 i : LOG(ERROR) << "Unable to resolve import names and locations.";
112 i : return false;
113 : }
114 : if (!LookupDelayImportLocations(modules_to_exclude_,
115 : header_block,
116 E : &import_locations)) {
117 i : LOG(ERROR) << "Unable to resolve delay import names and locations.";
118 i : return false;
119 : }
120 :
121 : // Now instrument all the import locations we located.
122 E : if (!InstrumentImportReferences(block_graph, import_locations)) {
123 i : LOG(ERROR) << "Unable to instrument import references.";
124 i : return false;
125 : }
126 :
127 E : return true;
128 E : }
129 :
130 : void ThunkImportReferencesTransform::ExcludeModule(
131 E : const base::StringPiece& module_name) {
132 E : modules_to_exclude_.insert(module_name.as_string());
133 E : }
134 :
135 : bool ThunkImportReferencesTransform::ModuleNameLess::operator()(
136 E : const std::string& lhs, const std::string& rhs) const {
137 E : size_t len = std::min(lhs.size(), rhs.size());
138 E : for (size_t i = 0; i < len; ++i) {
139 E : char lhc = base::ToLowerASCII(lhs[i]);
140 E : char rhc = base::ToLowerASCII(rhs[i]);
141 E : if (lhc < rhc)
142 E : return true;
143 E : else if (lhc > rhc)
144 E : return false;
145 E : }
146 :
147 : // The strings are equal the end of the shorter string,
148 : // if the lhs is shorter it's smaller.
149 E : return lhs.size() < rhs.size();
150 E : }
151 :
152 : // This method builds up a set of thunk blocks as well as a thunk table
153 : // containing pointers to these blocks. Existing import references are then
154 : // replaced by references to the thunk table. Since imports are invoked via
155 : // an indirect call or jump instruction, changing the address of the call
156 : // statement from an address into the IAT to an address into the thunk table
157 : // gets the thunk called properly.
158 : bool ThunkImportReferencesTransform::InstrumentImportReferences(
159 : BlockGraph* block_graph,
160 E : const ImportAddressLocationNameMap& import_locations) {
161 : // Find or create the section we put our thunks in.
162 : thunk_section_ = block_graph->FindOrAddSection(common::kThunkSectionName,
163 E : pe::kCodeCharacteristics);
164 E : if (thunk_section_ == NULL) {
165 i : LOG(ERROR) << "Unable to find or create .thunks section.";
166 i : return false;
167 : }
168 :
169 : // Find the set of blocks referred by import_locations.
170 E : BlockSet import_blocks;
171 E : if (!GetImportBlocks(import_locations, &import_blocks)) {
172 i : LOG(ERROR) << "Unable to get import blocks.";
173 i : return false;
174 : }
175 :
176 : // Typedef for the thunk block map. The key is the <iat block, offset> the
177 : // (since all callers can use the same thunk) and the value is the offset into
178 : // the thunk table that points to the thunk block for that IAT entry.
179 : typedef std::pair<const BlockGraph::Block*, BlockGraph::Offset>
180 : ThunkBlockKey;
181 : typedef std::map<ThunkBlockKey, BlockGraph::Offset> ThunkBlockMap;
182 E : ThunkBlockMap thunk_block_map;
183 :
184 : // Create the thunk table - we'll grow it as we go.
185 : BlockGraph::Block* thunk_table_block =
186 E : block_graph->AddBlock(BlockGraph::DATA_BLOCK, 0, "ImportsThunkTable");
187 E : thunk_table_block->set_section(thunk_section_->id());
188 E : BlockGraph::Offset thunk_table_offset = 0;
189 :
190 : // Now iterate through the import blocks and instrument the references.
191 E : BlockSet::const_iterator it = import_blocks.begin();
192 E : for (; it != import_blocks.end(); ++it) {
193 E : BlockGraph::Block* iat_block = *it;
194 :
195 : // Next, list all referrers to get all references into the IAT. For each
196 : // eligible reference, create a thunk (in its own block) and add a pointer
197 : // to it to the thunk table.
198 E : BlockGraph::Block::ReferrerSet iat_referrers(iat_block->referrers());
199 : BlockGraph::Block::ReferrerSet::const_iterator iat_referrer_iter(
200 E : iat_referrers.begin());
201 E : for (; iat_referrer_iter != iat_referrers.end(); ++iat_referrer_iter) {
202 E : BlockGraph::Block* referrer = iat_referrer_iter->first;
203 :
204 E : if (referrer == iat_block) {
205 i : LOG(WARNING) << "Unexpected self-reference in IAT.";
206 i : continue;
207 : }
208 :
209 E : if (referrer->type() != BlockGraph::CODE_BLOCK) {
210 : // We shouldn't see data referring to import table entries, outside
211 : // the PE structures.
212 E : DCHECK(referrer->attributes() & BlockGraph::PE_PARSED);
213 :
214 E : LOG(INFO) << "Skipping non-code block reference from block: '"
215 : << referrer->name() << "'";
216 E : continue;
217 : }
218 :
219 E : if (referrer->attributes() & BlockGraph::THUNK) {
220 E : LOG(INFO) << "Skipping thunk block reference from block: '"
221 : << referrer->name() << "'";
222 E : continue;
223 : }
224 :
225 : // Now that we know the referring block, we need to find out where in the
226 : // IAT it refers to.
227 E : BlockGraph::Reference ref;
228 E : if (!referrer->GetReference(iat_referrer_iter->second, &ref)) {
229 i : LOG(ERROR) << "Unable to get reference from referrer.";
230 i : return false;
231 : }
232 :
233 : // See whether this is an eligible import.
234 : ImportAddressLocationNameMap::const_iterator it(
235 : import_locations.find(
236 E : std::make_pair(ref.referenced(), ref.offset())));
237 E : if (it == import_locations.end()) {
238 : // It's not an eligible location, skip it.
239 E : continue;
240 : }
241 :
242 : // For now, let's not try and thunk thunks. This means that we can't
243 : // e.g. double-instrument, which is a potentially legitimate use case,
244 : // but it should only be supported if there's adequate testing for it.
245 E : if (referrer->section() == thunk_section_->id()) {
246 i : LOG(ERROR) << "Thunking a reference from the thunk section, "
247 : << "in block: '" << referrer->name() << "'";
248 i : return false;
249 : }
250 :
251 : // Look for the reference in the thunk block map, and only create a
252 : // new one if it does not already exist.
253 E : BlockGraph::Block* thunk_block = NULL;
254 E : BlockGraph::Offset new_ref_offset = 0;
255 :
256 E : ThunkBlockKey key(std::make_pair(iat_block, ref.offset()));
257 E : ThunkBlockMap::const_iterator thunk_it = thunk_block_map.find(key);
258 E : if (thunk_it == thunk_block_map.end()) {
259 : // Create the thunk block for this offset into the IAT.
260 E : thunk_block = CreateOneThunk(block_graph, ref, it->second);
261 E : if (thunk_block == NULL) {
262 i : LOG(DFATAL) << "Unable to create thunk block.";
263 i : return false;
264 : }
265 :
266 : // Now add a reference to the thunk in the thunk table.
267 : BlockGraph::Reference thunk_ref(BlockGraph::ABSOLUTE_REF,
268 : sizeof(core::AbsoluteAddress),
269 E : thunk_block, 0, 0);
270 : thunk_table_block->set_size(
271 E : thunk_table_offset + sizeof(core::AbsoluteAddress));
272 E : thunk_table_block->SetReference(thunk_table_offset, thunk_ref);
273 :
274 : // Remember this thunk in case we need to use it again.
275 E : thunk_block_map[key] = thunk_table_offset;
276 E : new_ref_offset = thunk_table_offset;
277 :
278 : // Move to the next empty entry in the thunk table.
279 E : thunk_table_offset += sizeof(core::AbsoluteAddress);
280 : DCHECK_EQ(static_cast<BlockGraph::Size>(thunk_table_offset),
281 E : thunk_table_block->size());
282 E : } else {
283 E : new_ref_offset = thunk_it->second;
284 : }
285 :
286 : // Update the referrer to point to the new location in the thunk table.
287 : BlockGraph::Reference new_ref(ref.type(),
288 : ref.size(),
289 : thunk_table_block,
290 : new_ref_offset,
291 E : 0);
292 E : referrer->SetReference(iat_referrer_iter->second, new_ref);
293 E : }
294 E : }
295 :
296 E : return true;
297 E : }
298 :
299 : BlockGraph::Block* ThunkImportReferencesTransform::CreateOneThunk(
300 : BlockGraph* block_graph,
301 : const BlockGraph::Reference& destination,
302 E : const base::StringPiece& name) {
303 : using block_graph::BasicBlockSubGraph;
304 : using block_graph::BasicBlockAssembler;
305 : using block_graph::BasicCodeBlock;
306 : using block_graph::BlockBuilder;
307 : using block_graph::Operand;
308 : using block_graph::Displacement;
309 :
310 : // Construct the name for the new thunk.
311 E : std::string thunk_name(name.as_string());
312 E : thunk_name.append(kThunkSuffix);
313 :
314 : // Set up a basic block subgraph containing a single block description, with
315 : // that block description containing a single empty basic block, and get an
316 : // assembler writing into that basic block.
317 E : BasicBlockSubGraph bbsg;
318 : BasicBlockSubGraph::BlockDescription* block_desc = bbsg.AddBlockDescription(
319 : thunk_name,
320 : NULL,
321 : BlockGraph::CODE_BLOCK,
322 : thunk_section_->id(),
323 : 1,
324 E : 0);
325 E : BasicCodeBlock* bb = bbsg.AddBasicCodeBlock(name);
326 E : block_desc->basic_block_order.push_back(bb);
327 E : BasicBlockAssembler assm(bb->instructions().begin(), &bb->instructions());
328 :
329 : // The thunk contains this.
330 : // push dword ptr [<import>]
331 : // jmp dword ptr [<entry_hook>]
332 : assm.push(
333 E : Operand(Displacement(destination.referenced(), destination.offset())));
334 E : assm.jmp(Operand(Displacement(hook_ref_.referenced(), hook_ref_.offset())));
335 :
336 : // Condense into a block.
337 E : BlockBuilder block_builder(block_graph);
338 E : if (!block_builder.Merge(&bbsg)) {
339 i : LOG(ERROR) << "Failed to build thunk block.";
340 i : return NULL;
341 : }
342 :
343 : // Exactly one new block should have been created.
344 E : DCHECK_EQ(1u, block_builder.new_blocks().size());
345 E : BlockGraph::Block* thunk = block_builder.new_blocks().front();
346 :
347 E : return thunk;
348 E : }
349 :
350 : bool ThunkImportReferencesTransform::GetImportBlocks(
351 : const ImportAddressLocationNameMap& import_locations,
352 E : BlockSet* import_blocks) {
353 E : DCHECK(import_blocks != NULL);
354 :
355 E : ImportAddressLocationNameMap::const_iterator it;
356 E : BlockGraph::Block* last_block = NULL;
357 E : while (true) {
358 : it = import_locations.upper_bound(
359 E : std::make_pair(last_block, std::numeric_limits<Offset>::max()));
360 :
361 E : if (it == import_locations.end())
362 E : break;
363 :
364 E : last_block = it->first.first;
365 E : import_blocks->insert(last_block);
366 E : }
367 :
368 E : return true;
369 E : }
370 :
371 : bool ThunkImportReferencesTransform::LookupImportLocations(
372 : const ModuleNameSet& exclusions,
373 : BlockGraph::Block* header_block,
374 E : ImportAddressLocationNameMap* import_locations) {
375 E : DCHECK(header_block != NULL);
376 E : DCHECK(import_locations != NULL);
377 :
378 : // Start by retrieving the NT headers.
379 E : DosHeader dos_header;
380 E : NtHeaders nt_headers;
381 : if (!dos_header.Init(0, header_block) ||
382 E : !dos_header.Dereference(dos_header->e_lfanew, &nt_headers)) {
383 i : LOG(ERROR) << "Unable to cast image headers.";
384 i : return false;
385 : }
386 :
387 : // Get to the import directory.
388 : const IMAGE_DATA_DIRECTORY* import_directory =
389 E : &nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
390 :
391 E : ImageImportDescriptor iida;
392 E : if (!nt_headers.Dereference(import_directory->VirtualAddress, &iida)) {
393 i : LOG(ERROR) << "Failed to dereference Image Import Descriptor Array.";
394 i : return false;
395 : }
396 :
397 : // The array is NULL terminated with a potentially incomplete descriptor so
398 : // we can't use ElementCount - 1.
399 : size_t descriptor_count =
400 : (common::AlignUp(iida.block()->size(), sizeof(IMAGE_IMPORT_DESCRIPTOR)) /
401 E : sizeof(IMAGE_IMPORT_DESCRIPTOR)) - 1;
402 :
403 E : for (size_t iida_index = 0; iida_index < descriptor_count; ++iida_index) {
404 E : StringBlock dll_name_block;
405 E : if (!iida.Dereference(iida[iida_index].Name, &dll_name_block)) {
406 i : LOG(ERROR) << "Unable to dereference DLL name.";
407 i : return false;
408 : }
409 :
410 E : size_t len = strnlen(dll_name_block->string, dll_name_block.ElementCount());
411 E : std::string dll_name(dll_name_block->string, dll_name_block->string + len);
412 :
413 : // Move to the next one if this is an excluded module.
414 E : if (exclusions.find(dll_name) != exclusions.end())
415 E : continue;
416 :
417 : // Walk the IAT and the INT(also know as hna) for this module concurrently
418 : // until we come to a zero terminator for one or the other and mark their
419 : // offsets and names in the location names map.
420 E : TypedBlock<IMAGE_IMPORT_BY_NAME*> hna, iat;
421 : if (!iida.Dereference(iida[iida_index].OriginalFirstThunk, &hna) ||
422 E : !iida.Dereference(iida[iida_index].FirstThunk, &iat)) {
423 i : LOG(ERROR) << "Unable to dereference OriginalFirstThunk/FirstThunk.";
424 i : return false;
425 : }
426 :
427 : // Loop through the imports, tag and bag them.
428 E : size_t i = 0;
429 E : for (; i < hna.ElementCount() && i < iat.ElementCount(); ++i) {
430 E : ConstTypedBlock<IMAGE_THUNK_DATA32> thunk;
431 E : if (!thunk.Init(hna.OffsetOf(hna[i]), hna.block())) {
432 i : LOG(ERROR) << "Unable to dereference IMAGE_THUNK_DATA32.";
433 i : return false;
434 : }
435 :
436 : // Construct the location for this entry.
437 : ImportAddressLocation key(
438 E : std::make_pair(iat.block(), iat.OffsetOf(iat[i])));
439 E : std::string import_name = dll_name;
440 :
441 : // Is this an ordinal import?
442 E : if (IMAGE_SNAP_BY_ORDINAL(thunk->u1.Ordinal)) {
443 : // Ordinal imports are named <dll>:#<ordinal>.
444 : base::StringAppendF(&import_name,
445 : ":#%d",
446 E : IMAGE_ORDINAL(thunk->u1.Ordinal));
447 E : } else if (!thunk.HasReference(thunk->u1.AddressOfData)) {
448 : // Have no reference? Then terminate the iteration.
449 : // We sanity check that the actual data is null.
450 E : DCHECK_EQ(0u, thunk->u1.AddressOfData);
451 E : break;
452 i : } else {
453 : // Otherwise this should point to an IMAGE_IMPORT_BY_NAME structure.
454 E : ImageImportByName iibn;
455 E : if (!hna.Dereference(hna[i], &iibn)) {
456 i : LOG(ERROR) << "Unable to dereference IMAGE_IMPORT_BY_NAME.";
457 i : return false;
458 : }
459 : size_t len =
460 : strnlen(iibn->Name,
461 E : iibn.block()->size() - iibn.OffsetOf(iibn->Name));
462 E : std::string function_name(iibn->Name, iibn->Name + len);
463 :
464 E : base::StringAppendF(&import_name, ":%s", function_name.c_str());
465 E : }
466 :
467 : // Tag and name it.
468 : bool inserted =
469 E : import_locations->insert(std::make_pair(key, import_name)).second;
470 :
471 E : DCHECK(inserted);
472 E : }
473 E : }
474 :
475 E : return true;
476 E : }
477 :
478 : bool ThunkImportReferencesTransform::LookupDelayImportLocations(
479 : const ModuleNameSet& exclusions,
480 : BlockGraph::Block* header_block,
481 E : ImportAddressLocationNameMap* import_locations) {
482 E : DCHECK(header_block != NULL);
483 E : DCHECK(import_locations != NULL);
484 :
485 : // Start by retrieving the NT headers.
486 E : DosHeader dos_header;
487 E : NtHeaders nt_headers;
488 : if (!dos_header.Init(0, header_block) ||
489 E : !dos_header.Dereference(dos_header->e_lfanew, &nt_headers)) {
490 i : LOG(ERROR) << "Unable to cast image headers.";
491 i : return false;
492 : }
493 :
494 : // Get to the delay import directory.
495 : const IMAGE_DATA_DIRECTORY* delay_import_directory =
496 : &nt_headers->OptionalHeader
497 E : .DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT];
498 :
499 E : ImageDelayImportDescriptor idida;
500 E : if (!nt_headers.Dereference(delay_import_directory->VirtualAddress, &idida)) {
501 : // Unable to dereference, this is only an error if there are delay imports.
502 E : if (!nt_headers.HasReference(delay_import_directory->VirtualAddress)) {
503 E : DCHECK_EQ(0U, delay_import_directory->VirtualAddress);
504 E : return true;
505 : }
506 :
507 i : LOG(ERROR) << "Failed to dereference delay Image Import Descriptor Array.";
508 i : return false;
509 : }
510 :
511 E : for (size_t idida_idx = 0; idida_idx < idida.ElementCount(); ++idida_idx) {
512 : // The last descriptor is a sentinel.
513 E : if (idida[idida_idx].grAttrs == 0)
514 E : break;
515 :
516 E : StringBlock dll_name_block;
517 E : if (!idida.Dereference(idida[idida_idx].rvaDLLName, &dll_name_block)) {
518 i : LOG(ERROR) << "Unable to dereference DLL name.";
519 i : return false;
520 : }
521 :
522 E : size_t len = strnlen(dll_name_block->string, dll_name_block.ElementCount());
523 E : std::string dll_name(dll_name_block->string, dll_name_block->string + len);
524 :
525 : // Move to the next one if this is an excluded module.
526 E : if (exclusions.find(dll_name) != exclusions.end())
527 i : continue;
528 :
529 : // Walk the IAT and the INT(also know as hna) for this module concurrently
530 : // until we come to a zero terminator for one or the other and mark their
531 : // offsets and names in the location names map.
532 E : TypedBlock<IMAGE_IMPORT_BY_NAME*> hna, iat;
533 : if (!idida.Dereference(idida[idida_idx].rvaINT, &hna) ||
534 E : !idida.Dereference(idida[idida_idx].rvaIAT, &iat)) {
535 i : LOG(ERROR) << "Unable to dereference OriginalFirstThunk/FirstThunk.";
536 i : return false;
537 : }
538 :
539 : // Loop through the imports, tag and bag them.
540 E : size_t i = 0;
541 E : for (; i < hna.ElementCount() && i < iat.ElementCount(); ++i) {
542 E : ConstTypedBlock<IMAGE_THUNK_DATA32> thunk;
543 E : if (!thunk.Init(hna.OffsetOf(hna[i]), hna.block())) {
544 i : LOG(ERROR) << "Unable to dereference IMAGE_THUNK_DATA32.";
545 i : return false;
546 : }
547 :
548 : // Construct the location for this entry.
549 : ImportAddressLocation key(
550 E : std::make_pair(iat.block(), iat.OffsetOf(iat[i])));
551 E : std::string import_name = dll_name;
552 :
553 : // Is this an ordinal import?
554 E : if (IMAGE_SNAP_BY_ORDINAL(thunk->u1.Ordinal)) {
555 : // Ordinal imports are named <dll>:#<ordinal>.
556 : base::StringAppendF(&import_name,
557 : ":#%d",
558 i : IMAGE_ORDINAL(thunk->u1.Ordinal));
559 E : } else if (!thunk.HasReference(thunk->u1.AddressOfData)) {
560 : // Have no reference? Then terminate the iteration.
561 : // We sanity check that the actual data is null.
562 E : DCHECK_EQ(0u, thunk->u1.AddressOfData);
563 E : break;
564 i : } else {
565 : // Otherwise this should point to an IMAGE_IMPORT_BY_NAME structure.
566 E : ImageImportByName iibn;
567 E : if (!hna.Dereference(hna[i], &iibn)) {
568 i : LOG(ERROR) << "Unable to dereference IMAGE_IMPORT_BY_NAME.";
569 i : return false;
570 : }
571 : size_t len =
572 : strnlen(iibn->Name,
573 E : iibn.block()->size() - iibn.OffsetOf(iibn->Name));
574 E : std::string function_name(iibn->Name, iibn->Name + len);
575 :
576 E : base::StringAppendF(&import_name, ":%s", function_name.c_str());
577 E : }
578 :
579 : // Tag and name it.
580 : bool inserted =
581 E : import_locations->insert(std::make_pair(key, import_name)).second;
582 :
583 E : DCHECK(inserted);
584 E : }
585 E : }
586 :
587 E : return true;
588 E : }
589 :
590 : } // namespace transforms
591 : } // namespace instrument
|