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/pe/transforms/add_debug_directory_entry_transform.h"
16 :
17 : #include "syzygy/block_graph/typed_block.h"
18 : #include "syzygy/pe/pe_utils.h"
19 :
20 : namespace pe {
21 : namespace transforms {
22 :
23 : using block_graph::TypedBlock;
24 :
25 : typedef TypedBlock<IMAGE_DOS_HEADER> DosHeader;
26 : typedef TypedBlock<IMAGE_NT_HEADERS> NtHeaders;
27 : typedef TypedBlock<IMAGE_DEBUG_DIRECTORY> ImageDebugDirectory;
28 :
29 : const char AddDebugDirectoryEntryTransform::kTransformName[] =
30 : "AddDebugDirectoryEntryTransform";
31 :
32 : bool AddDebugDirectoryEntryTransform::TransformBlockGraph(
33 : const TransformPolicyInterface* policy,
34 : BlockGraph* block_graph,
35 E : BlockGraph::Block* dos_header_block) {
36 E : DCHECK_NE(reinterpret_cast<TransformPolicyInterface*>(NULL), policy);
37 E : DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
38 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), dos_header_block);
39 E : DCHECK_EQ(BlockGraph::PE_IMAGE, block_graph->image_format());
40 :
41 E : added_ = false;
42 E : block_ = NULL;
43 E : offset_ = -1;
44 :
45 E : DosHeader dos_header;
46 E : NtHeaders nt_headers;
47 : if (!dos_header.Init(0, dos_header_block) ||
48 E : !dos_header.Dereference(dos_header->e_lfanew, &nt_headers)) {
49 i : LOG(ERROR) << "Unable to dereference PE image headers.";
50 i : return false;
51 : }
52 :
53 : // Don't have a debug directory? Then make one with a single entry.
54 : // In general, keeping around a reference to data inside a TypedBlock is not
55 : // safe, as if the data is resized the reference will no longer be valid.
56 : // However, I do not modify the underlying block for the lifetime of this
57 : // function, hence reusing this reference is safe.
58 : IMAGE_DATA_DIRECTORY& debug_dir_info =
59 E : nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
60 E : if (!nt_headers.HasReference(debug_dir_info.VirtualAddress)) {
61 E : debug_dir_info.Size = sizeof(IMAGE_DEBUG_DIRECTORY);
62 :
63 : BlockGraph::Section* section = block_graph->FindOrAddSection(
64 E : kReadOnlyDataSectionName, kReadOnlyDataCharacteristics);
65 E : DCHECK(section != NULL);
66 :
67 : BlockGraph::Block* debug_dir_block = block_graph->AddBlock(
68 E : BlockGraph::DATA_BLOCK, debug_dir_info.Size, "Debug Directory");
69 E : DCHECK(debug_dir_block != NULL);
70 E : debug_dir_block->set_section(section->id());
71 E : debug_dir_block->AllocateData(debug_dir_info.Size);
72 :
73 : nt_headers.SetReference(BlockGraph::RELATIVE_REF,
74 : debug_dir_info.VirtualAddress,
75 : debug_dir_block,
76 E : 0, 0);
77 :
78 E : added_ = true;
79 : }
80 :
81 : // Get the debug directory, and remember it for post-transform.
82 E : ImageDebugDirectory debug_dir;
83 E : if (!nt_headers.Dereference(debug_dir_info.VirtualAddress, &debug_dir)) {
84 i : LOG(ERROR) << "Unable to dereference ImageDebugDirectory.";
85 i : return false;
86 : }
87 E : block_ = debug_dir.block();
88 :
89 : // Did we already add an entry? Initialize it and be done with it. This can
90 : // happen if there was no debug directory to begin with.
91 E : if (added_) {
92 E : offset_ = 0;
93 E : debug_dir->Type = type_;
94 E : return true;
95 : }
96 :
97 : // If we get here we've got a non-empty debug data directory with entries
98 : // that we did not make. We either have to find an existing entry or create
99 : // a new one.
100 :
101 : // If we're not explicitly adding another entry, look for an existing one
102 : // with the matching type.
103 E : if (!always_add_) {
104 E : for (size_t i = 0; i < debug_dir.ElementCount(); ++i) {
105 E : if (debug_dir[i].Type == type_) {
106 E : offset_ = debug_dir.OffsetOf(debug_dir[i]);
107 E : break;
108 : }
109 i : }
110 : }
111 :
112 : // If we found an existing entry we're done.
113 E : if (offset_ != -1)
114 E : return true;
115 :
116 : // Make the new entry and initialize it. We only set the type as the rest of
117 : // it is already going to be initialized with zeros.
118 i : added_ = true;
119 i : size_t entry_index = debug_dir.ElementCount();
120 i : size_t entry_size = sizeof(IMAGE_DEBUG_DIRECTORY);
121 : offset_ = debug_dir.offset() +
122 i : entry_index * entry_size;
123 i : debug_dir.block()->InsertData(offset_, entry_size, true);
124 i : DCHECK_EQ(entry_index + 1, debug_dir.ElementCount());
125 i : debug_dir[entry_index].Type = type_;
126 :
127 : // Update the debug directory info struct.
128 i : debug_dir_info.Size += entry_size;
129 :
130 i : return true;
131 E : }
132 :
133 : } // namespace transforms
134 : } // namespace pe
|