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