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/orderers/pe_orderer.h"
16 :
17 : #include <windows.h>
18 :
19 : #include "base/strings/string_piece.h"
20 : #include "syzygy/block_graph/typed_block.h"
21 : #include "syzygy/pe/pe_utils.h"
22 :
23 : namespace pe {
24 : namespace orderers {
25 :
26 : namespace {
27 :
28 : using base::StringPiece;
29 : using block_graph::OrderedBlockGraph;
30 : using block_graph::BlockGraph;
31 : using block_graph::TypedBlock;
32 :
33 : // Ensures that the provided header blocks represent valid PE headers and
34 : // lays them out in the image as the first two blocks (DOS followed by NT)
35 : // outside of any defined sections.
36 : bool ValidateAndLayoutHeaders(OrderedBlockGraph* ordered_block_graph,
37 : BlockGraph::Block* dos_header_block,
38 : TypedBlock<IMAGE_DOS_HEADER>* dos_header,
39 E : TypedBlock<IMAGE_NT_HEADERS>* nt_headers) {
40 E : DCHECK(ordered_block_graph != NULL);
41 E : DCHECK(dos_header_block != NULL);
42 E : DCHECK(dos_header != NULL);
43 E : DCHECK(nt_headers != NULL);
44 :
45 : // Validate the headers.
46 E : if (!dos_header->Init(0, dos_header_block)) {
47 E : LOG(ERROR) << "Unable to cast IMAGE_DOS_HEADER.";
48 E : return false;
49 : }
50 :
51 E : if (!IsValidDosHeaderBlock(dos_header_block)) {
52 i : LOG(ERROR) << "Invalid DOS header block.";
53 i : return false;
54 : }
55 :
56 E : if (!dos_header->Dereference((*dos_header)->e_lfanew, nt_headers)) {
57 i : LOG(ERROR) << "Unable to cast IMAGE_NT_HEADERS.";
58 i : return false;
59 : }
60 :
61 E : if (nt_headers->offset() != 0) {
62 i : LOG(ERROR) << "NT headers must start at offset 0.";
63 i : return false;
64 : }
65 :
66 E : if (!IsValidNtHeadersBlock(nt_headers->block())) {
67 i : LOG(ERROR) << "Invalid NT headers block.";
68 i : return false;
69 : }
70 :
71 : // Move the headers out of any sections, placing them as the first two
72 : // blocks.
73 E : ordered_block_graph->PlaceAtHead(NULL, nt_headers->block());
74 E : ordered_block_graph->PlaceAtHead(NULL, dos_header->block());
75 :
76 E : return true;
77 E : }
78 :
79 : // Finds the section, and the number of times a section with the given name was
80 : // seen. The returned section will be one of the sections with matching name if
81 : // there are any, NULL otherwise.
82 : size_t FindSection(const StringPiece& section_name,
83 : BlockGraph* block_graph,
84 E : BlockGraph::Section** section) {
85 E : DCHECK(block_graph != NULL);
86 E : DCHECK(section != NULL);
87 :
88 E : *section = NULL;
89 :
90 E : size_t count = 0;
91 : BlockGraph::SectionMap::iterator section_it =
92 E : block_graph->sections_mutable().begin();
93 E : for (; section_it != block_graph->sections_mutable().end(); ++section_it) {
94 E : BlockGraph::Section* s = §ion_it->second;
95 E : if (s->name() == section_name) {
96 E : *section = s;
97 E : ++count;
98 : }
99 E : }
100 :
101 E : return count;
102 E : }
103 :
104 : // Looks for the given section by name, returning it via @p section if there
105 : // exists exactly one section with that name. Returns true if no or exactly one
106 : // section with that name was found. Returns false if 2 or more sections with
107 : // the name @p section_name were found.
108 : bool FindZeroOrOneSection(const StringPiece& section_name,
109 : BlockGraph* block_graph,
110 E : BlockGraph::Section** section) {
111 E : DCHECK(block_graph != NULL);
112 E : DCHECK(section != NULL);
113 :
114 E : *section = NULL;
115 E : size_t section_count = FindSection(section_name, block_graph, section);
116 E : if (section_count > 1) {
117 E : *section = NULL;
118 E : LOG(ERROR) << "Multiple \"" << section_name << "\" sections exist.";
119 E : return false;
120 : }
121 :
122 E : return true;
123 E : }
124 :
125 : // The data referred to by some data directories is expected to lay in a
126 : // specific section set aside just for that purpose. This function accomplishes
127 : // the following:
128 : //
129 : // 1. Looks for the section by name. If more than one section with name
130 : // @p section_name exists, returns false. If exactly one section exists
131 : // sets the characteristics, places it at the end of the image and continues.
132 : // If no section is found, continues.
133 : // 2. Looks for the data directory with index @p data_dir_index. If it is not
134 : // present returns true.
135 : // 3. If no section was found in step 1, returns false.
136 : // 4. Dereferences the data pointed to by the data directory as an instance of
137 : // @p DataDirEntryType. If this is not possible, returns false.
138 : // 5. Ensures that the block referred to by the data directory lies within the
139 : // section found in step 1.
140 : template<typename DataDirEntryType>
141 : bool LayoutSectionAndDataDirEntry(
142 : const StringPiece& section_name,
143 : uint32 section_characteristics,
144 : size_t data_dir_index,
145 : const TypedBlock<IMAGE_NT_HEADERS>& nt_headers,
146 E : OrderedBlockGraph* ordered_block_graph) {
147 E : DCHECK(ordered_block_graph != NULL);
148 :
149 : // If we find more than one section with this name return in error.
150 E : BlockGraph::Section* section = NULL;
151 : if (!FindZeroOrOneSection(section_name,
152 : ordered_block_graph->block_graph(),
153 E : §ion)) {
154 E : return false;
155 : }
156 :
157 E : if (section != NULL) {
158 : // Set the section characteristics and move it to the end of the image.
159 E : section->set_characteristics(section_characteristics);
160 E : ordered_block_graph->PlaceAtTail(section);
161 : }
162 :
163 : // Do we have an entry in the |data_dir_index|th data directory?
164 : if (nt_headers.HasReference(nt_headers->OptionalHeader.DataDirectory[
165 E : data_dir_index].VirtualAddress)) {
166 : // If so, we expect to have found a matching section earlier.
167 E : if (section == NULL) {
168 E : LOG(ERROR) << "Image has data directory " << data_dir_index << " but no "
169 : << "\"" << section_name << "\" section.";
170 E : return false;
171 : }
172 :
173 : // Dereference the data as an instance of DataDirEntryType and ensure that
174 : // it lies in the appropriate section.
175 E : TypedBlock<DataDirEntryType> data_dir;
176 : if (!nt_headers.Dereference(nt_headers->OptionalHeader.DataDirectory[
177 : data_dir_index].VirtualAddress,
178 E : &data_dir)) {
179 i : LOG(ERROR) << "Unable to dereference data directory "
180 : << data_dir_index << ".";
181 i : return false;
182 : }
183 :
184 : // If it lies in another section we put it at the head of the appropriate
185 : // section.
186 E : if (data_dir.block()->section() != section->id())
187 E : ordered_block_graph->PlaceAtHead(section, data_dir.block());
188 : }
189 :
190 E : return true;
191 E : }
192 :
193 : } // namespace
194 :
195 : const char PEOrderer::kOrdererName[] = "PEOrderer";
196 :
197 : bool PEOrderer::OrderBlockGraph(OrderedBlockGraph* ordered_block_graph,
198 E : BlockGraph::Block* dos_header_block) {
199 E : DCHECK(ordered_block_graph != NULL);
200 E : DCHECK(dos_header_block != NULL);
201 :
202 E : TypedBlock<IMAGE_DOS_HEADER> dos_header;
203 E : TypedBlock<IMAGE_NT_HEADERS> nt_headers;
204 : if (!ValidateAndLayoutHeaders(ordered_block_graph, dos_header_block,
205 E : &dos_header, &nt_headers)) {
206 E : return false;
207 : }
208 :
209 : if (!LayoutSectionAndDataDirEntry<IMAGE_RESOURCE_DIRECTORY>(
210 : kResourceSectionName,
211 : kReadOnlyDataCharacteristics,
212 : IMAGE_DIRECTORY_ENTRY_RESOURCE,
213 : nt_headers,
214 E : ordered_block_graph)) {
215 E : return false;
216 : }
217 :
218 : if (!LayoutSectionAndDataDirEntry<IMAGE_BASE_RELOCATION>(
219 : kRelocSectionName,
220 : kRelocCharacteristics,
221 : IMAGE_DIRECTORY_ENTRY_BASERELOC,
222 : nt_headers,
223 E : ordered_block_graph)) {
224 E : return false;
225 : }
226 :
227 E : return true;
228 E : }
229 :
230 : } // namespace orderers
231 : } // namespace pe
|