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/pe_relinker.h"
16 :
17 : #include "base/files/file_util.h"
18 : #include "syzygy/pdb/pdb_byte_stream.h"
19 : #include "syzygy/pdb/pdb_file.h"
20 : #include "syzygy/pdb/pdb_reader.h"
21 : #include "syzygy/pdb/pdb_util.h"
22 : #include "syzygy/pdb/pdb_writer.h"
23 : #include "syzygy/pe/decomposer.h"
24 : #include "syzygy/pe/metadata.h"
25 : #include "syzygy/pe/pdb_info.h"
26 : #include "syzygy/pe/pe_file_writer.h"
27 : #include "syzygy/pe/pe_relinker_util.h"
28 : #include "syzygy/pe/serialization.h"
29 :
30 : namespace pe {
31 :
32 : namespace {
33 :
34 : typedef block_graph::BlockGraphTransformInterface Transform;
35 : typedef block_graph::BlockGraphOrdererInterface Orderer;
36 :
37 : using block_graph::ApplyBlockGraphTransform;
38 : using block_graph::BlockGraph;
39 : using block_graph::OrderedBlockGraph;
40 : using core::RelativeAddress;
41 : using pdb::NameStreamMap;
42 : using pdb::PdbByteStream;
43 : using pdb::PdbFile;
44 : using pdb::PdbInfoHeader70;
45 : using pdb::PdbMutatorInterface;
46 : using pdb::PdbStream;
47 : using pdb::WritablePdbStream;
48 :
49 : // Decomposes the module enclosed by the given PE file.
50 : bool Decompose(const PEFile& pe_file,
51 : const base::FilePath& pdb_path,
52 : ImageLayout* image_layout,
53 E : BlockGraph::Block** dos_header_block) {
54 E : DCHECK(image_layout != NULL);
55 E : DCHECK(dos_header_block != NULL);
56 :
57 E : LOG(INFO) << "Decomposing module: " << pe_file.path().value();
58 :
59 E : BlockGraph* block_graph = image_layout->blocks.graph();
60 E : ImageLayout orig_image_layout(block_graph);
61 :
62 : // Decompose the input image.
63 E : Decomposer decomposer(pe_file);
64 E : decomposer.set_pdb_path(pdb_path);
65 E : if (!decomposer.Decompose(&orig_image_layout)) {
66 i : LOG(ERROR) << "Unable to decompose module: " << pe_file.path().value();
67 i : return false;
68 : }
69 :
70 : // Make a copy of the image layout without padding. We don't want to carry
71 : // the padding through the toolchain.
72 E : LOG(INFO) << "Removing padding blocks.";
73 E : if (!pe::CopyImageLayoutWithoutPadding(orig_image_layout, image_layout)) {
74 i : LOG(ERROR) << "Failed to remove padding blocks.";
75 i : return false;
76 : }
77 :
78 : // Get the DOS header block.
79 : *dos_header_block =
80 : image_layout->blocks.GetBlockByAddress(
81 E : BlockGraph::RelativeAddress(0));
82 E : if (*dos_header_block == NULL) {
83 i : LOG(ERROR) << "Unable to find the DOS header block.";
84 i : return false;
85 : }
86 :
87 E : return true;
88 E : }
89 :
90 : // Writes the image.
91 : bool WriteImage(const ImageLayout& image_layout,
92 E : const base::FilePath& output_path) {
93 E : PEFileWriter writer(image_layout);
94 :
95 E : LOG(INFO) << "Writing image: " << output_path.value();
96 E : if (!writer.WriteImage(output_path)) {
97 i : LOG(ERROR) << "Failed to write image \"" << output_path.value() << "\".";
98 i : return false;
99 : }
100 :
101 E : return true;
102 E : }
103 :
104 : } // namespace
105 :
106 : PERelinker::PERelinker(const PETransformPolicy* pe_transform_policy)
107 : : PECoffRelinker(pe_transform_policy),
108 : pe_transform_policy_(pe_transform_policy),
109 : add_metadata_(true), augment_pdb_(true),
110 : compress_pdb_(false), strip_strings_(false),
111 E : padding_(0), code_alignment_(1), output_guid_(GUID_NULL) {
112 E : DCHECK(pe_transform_policy != NULL);
113 E : }
114 :
115 E : bool PERelinker::AppendPdbMutator(PdbMutatorInterface* pdb_mutator) {
116 E : DCHECK(pdb_mutator != NULL);
117 E : pdb_mutators_.push_back(pdb_mutator);
118 E : return true;
119 E : }
120 :
121 : bool PERelinker::AppendPdbMutators(
122 E : const std::vector<PdbMutatorInterface*>& pdb_mutators) {
123 : pdb_mutators_.insert(pdb_mutators_.end(),
124 : pdb_mutators.begin(),
125 E : pdb_mutators.end());
126 E : return true;
127 E : }
128 :
129 E : bool PERelinker::Init() {
130 E : DCHECK(!inited_);
131 :
132 : // Initialize the paths.
133 : if (!ValidateAndInferPaths(input_path_, output_path_, allow_overwrite_,
134 E : &input_pdb_path_, &output_pdb_path_)) {
135 E : return false;
136 : }
137 :
138 E : LOG(INFO) << "Input module : " << input_path_.value();
139 E : LOG(INFO) << "Input PDB : " << input_pdb_path_.value();
140 E : LOG(INFO) << "Output module: " << output_path_.value();
141 E : LOG(INFO) << "Output PDB : " << output_pdb_path_.value();
142 :
143 : // Open the input PE file.
144 E : if (!input_pe_file_.Init(input_path_)) {
145 i : LOG(ERROR) << "Unable to load \"" << input_path_.value() << "\".";
146 i : return false;
147 : }
148 :
149 : // Generate a GUID for the relinked image's PDB file.
150 E : if (FAILED(::CoCreateGuid(&output_guid_))) {
151 i : LOG(ERROR) << "Failed to create new PDB GUID.";
152 i : return false;
153 : }
154 :
155 : // Decompose the image.
156 : if (!Decompose(input_pe_file_, input_pdb_path_, &input_image_layout_,
157 E : &headers_block_)) {
158 i : return false;
159 : }
160 :
161 E : inited_ = true;
162 :
163 E : return true;
164 E : }
165 :
166 E : bool PERelinker::Relink() {
167 E : if (!inited_) {
168 i : LOG(ERROR) << "Init has not been successfully called.";
169 i : return false;
170 : }
171 :
172 : // Apply the user supplied transforms.
173 E : if (!ApplyUserTransforms())
174 E : return false;
175 :
176 : // Finalize the block-graph. This applies PE and Syzygy specific transforms.
177 : if (!FinalizeBlockGraph(input_path_, output_pdb_path_, output_guid_,
178 : add_metadata_, pe_transform_policy_, &block_graph_,
179 E : headers_block_)) {
180 i : return false;
181 : }
182 :
183 : // Apply the user supplied orderers.
184 E : OrderedBlockGraph ordered_block_graph(&block_graph_);
185 E : if (!ApplyUserOrderers(&ordered_block_graph))
186 E : return false;
187 :
188 : // Finalize the ordered block graph. This applies PE specific orderers.
189 E : if (!FinalizeOrderedBlockGraph(&ordered_block_graph, headers_block_))
190 i : return false;
191 :
192 : // Lay it out.
193 E : ImageLayout output_image_layout(&block_graph_);
194 : if (!BuildImageLayout(padding_, code_alignment_,
195 : ordered_block_graph, headers_block_,
196 E : &output_image_layout)) {
197 i : return false;
198 : }
199 :
200 : // Write the image.
201 E : if (!WriteImage(output_image_layout, output_path_))
202 i : return false;
203 :
204 : // From here on down we are processing the PDB file.
205 :
206 : // Read the PDB file.
207 E : LOG(INFO) << "Reading PDB file: " << input_pdb_path_.value();
208 E : pdb::PdbReader pdb_reader;
209 E : PdbFile pdb_file;
210 E : if (!pdb_reader.Read(input_pdb_path_, &pdb_file)) {
211 i : LOG(ERROR) << "Unable to read PDB file: " << input_pdb_path_.value();
212 i : return false;
213 : }
214 :
215 : // Apply any user specified mutators to the PDB file.
216 E : if (!pdb::ApplyPdbMutators(pdb_mutators_, &pdb_file))
217 E : return false;
218 :
219 : // Finalize the PDB file.
220 E : RelativeAddressRange input_range;
221 E : GetOmapRange(input_image_layout_.sections, &input_range);
222 : if (!FinalizePdbFile(input_path_, output_path_, input_range,
223 : output_image_layout, output_guid_, augment_pdb_,
224 E : strip_strings_, compress_pdb_, &pdb_file)) {
225 i : return false;
226 : }
227 :
228 : // Write the PDB file.
229 E : LOG(INFO) << "Writing the PDB.";
230 E : pdb::PdbWriter pdb_writer;
231 E : if (!pdb_writer.Write(output_pdb_path_, pdb_file)) {
232 i : LOG(ERROR) << "Failed to write PDB file \"" << output_pdb_path_.value()
233 : << "\".";
234 i : return false;
235 : }
236 :
237 E : LOG(INFO) << "PE relinker finished.";
238 :
239 E : return true;
240 E : }
241 :
242 : } // namespace pe
|