1 : // Copyright 2013 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/coff_relinker.h"
16 :
17 : #include "base/files/file_util.h"
18 : #include "syzygy/pe/coff_decomposer.h"
19 : #include "syzygy/pe/coff_file_writer.h"
20 : #include "syzygy/pe/coff_image_layout_builder.h"
21 : #include "syzygy/pe/pe_utils.h"
22 : #include "syzygy/pe/transforms/coff_convert_legacy_code_references_transform.h"
23 : #include "syzygy/pe/transforms/coff_prepare_headers_transform.h"
24 :
25 : namespace pe {
26 :
27 : namespace {
28 :
29 : using block_graph::ApplyBlockGraphTransform;
30 : using block_graph::BlockGraph;
31 : using block_graph::OrderedBlockGraph;
32 : using core::RelativeAddress;
33 :
34 : typedef block_graph::BlockGraphOrdererInterface Orderer;
35 : typedef block_graph::BlockGraphTransformInterface Transform;
36 :
37 : // Decompose @p image_file into @p image_layout.
38 : //
39 : // @param image_file the COFF file to decompose.
40 : // @param image_layout the layout to fill with the results.
41 : // @param headers_block where to place the headers block pointer.
42 : // @returns true on success, or false on failure.
43 : bool Decompose(const CoffFile& image_file,
44 : ImageLayout* image_layout,
45 E : BlockGraph::Block** headers_block) {
46 E : DCHECK(image_layout != NULL);
47 E : DCHECK(headers_block != NULL);
48 :
49 E : LOG(INFO) << "Decomposing module: " << image_file.path().value() << ".";
50 :
51 : // Decompose the input image.
52 E : CoffDecomposer decomposer(image_file);
53 E : if (!decomposer.Decompose(image_layout)) {
54 i : LOG(ERROR) << "Unable to decompose module: "
55 : << image_file.path().value() << ".";
56 i : return false;
57 : }
58 :
59 : // Get the headers block.
60 E : *headers_block = image_layout->blocks.GetBlockByAddress(RelativeAddress(0));
61 E : if (*headers_block == NULL) {
62 i : LOG(ERROR) << "Unable to find the headers block.";
63 i : return false;
64 : }
65 :
66 E : return true;
67 E : }
68 :
69 : // Build an image layout from an ordered block graph.
70 : //
71 : // @param ordered_graph the ordered block graph to lay out.
72 : // @param headers_block the headers block in @p ordered_graph.
73 : // @param image_layout the image layout to fill with the results.
74 : // @returns true on success, or false on failure.
75 : bool BuildImageLayout(const OrderedBlockGraph& ordered_graph,
76 : BlockGraph::Block* headers_block,
77 E : ImageLayout* image_layout) {
78 E : DCHECK(headers_block != NULL);
79 E : DCHECK(image_layout != NULL);
80 :
81 E : LOG(INFO) << "Building image layout.";
82 :
83 E : CoffImageLayoutBuilder builder(image_layout);
84 E : if (!builder.LayoutImage(ordered_graph)) {
85 i : LOG(ERROR) << "Image layout failed.";
86 i : return false;
87 : }
88 :
89 E : return true;
90 E : }
91 :
92 : // Write an image layout to disk.
93 : //
94 : // @param image_layout the image layout.
95 : // @param output_path the path to which the result is written.
96 : // @returns true on success, or false on failure.
97 : bool WriteImage(const ImageLayout& image_layout,
98 E : const base::FilePath& output_path) {
99 E : CoffFileWriter writer(&image_layout);
100 :
101 E : LOG(INFO) << "Writing image to file: " << output_path.value() << ".";
102 E : if (!writer.WriteImage(output_path)) {
103 i : LOG(ERROR) << "Failed to write image: " << output_path.value() << ".";
104 i : return false;
105 : }
106 :
107 E : return true;
108 E : }
109 :
110 : } // namespace
111 :
112 : CoffRelinker::CoffRelinker(const CoffTransformPolicy* transform_policy)
113 E : : PECoffRelinker(transform_policy) {
114 E : }
115 :
116 E : bool CoffRelinker::Init() {
117 E : DCHECK(inited_ == false);
118 :
119 : // Initialize the paths.
120 E : if (!CheckPaths())
121 E : return false;
122 :
123 E : LOG(INFO) << "Input module: " << input_path_.value() << ".";
124 E : LOG(INFO) << "Output module: " << output_path_.value() << ".";
125 :
126 : // Open the input PE file.
127 E : if (!input_image_file_.Init(input_path_)) {
128 i : LOG(ERROR) << "Unable to load input image: " << input_path_.value() << ".";
129 i : return false;
130 : }
131 :
132 : // Decompose the image.
133 E : if (!Decompose(input_image_file_, &input_image_layout_, &headers_block_))
134 i : return false;
135 :
136 E : inited_ = true;
137 :
138 E : return true;
139 E : }
140 :
141 E : bool CoffRelinker::Relink() {
142 E : if (!inited_) {
143 i : LOG(ERROR) << "Init() has not been successfully called.";
144 i : return false;
145 : }
146 :
147 E : if (!ApplyUserTransforms())
148 E : return false;
149 :
150 : // We apply the extra prepare headers transform. This ensures that the
151 : // header block is properly sized to receive layout information
152 : // post-ordering.
153 : //
154 : // TODO(chrisha): Remove CoffConvertLegacyCodeReferencesTransform when the
155 : // basic block assembler is made fully COFF-compatible.
156 E : pe::transforms::CoffConvertLegacyCodeReferencesTransform fix_refs_tx;
157 E : pe::transforms::CoffPrepareHeadersTransform prep_headers_tx;
158 E : std::vector<Transform*> post_transforms;
159 E : post_transforms.push_back(&fix_refs_tx);
160 E : post_transforms.push_back(&prep_headers_tx);
161 : if (!block_graph::ApplyBlockGraphTransforms(
162 E : post_transforms, transform_policy_, &block_graph_, headers_block_)) {
163 i : return false;
164 : }
165 :
166 E : OrderedBlockGraph ordered_graph(&block_graph_);
167 E : if (!ApplyUserOrderers(&ordered_graph))
168 E : return false;
169 :
170 : // Lay it out.
171 E : ImageLayout output_image_layout(&block_graph_);
172 : if (!BuildImageLayout(ordered_graph, headers_block_,
173 E : &output_image_layout)) {
174 i : return false;
175 : }
176 :
177 : // Write the image.
178 E : if (!WriteImage(output_image_layout, output_path_))
179 i : return false;
180 :
181 E : return true;
182 E : }
183 :
184 E : bool CoffRelinker::CheckPaths() {
185 : // At a very minimum we have to specify input and output.
186 E : if (input_path_.empty() || output_path_.empty()) {
187 E : LOG(ERROR) << "Input path and output path must be set and non-empty.";
188 E : return false;
189 : }
190 :
191 E : if (!base::PathExists(input_path_)) {
192 E : LOG(ERROR) << "Input file not found: " << input_path_.value() << ".";
193 E : return false;
194 : }
195 :
196 : // Ensure we aren't about to overwrite anything we don't want to. We do this
197 : // early on so that we abort before decomposition, transformation, etc.
198 E : if (!allow_overwrite_) {
199 E : if (base::PathExists(output_path_)) {
200 E : LOG(ERROR) << "Output file already exists: "
201 : << output_path_.value() << ".";
202 E : return false;
203 : }
204 : }
205 :
206 E : return true;
207 E : }
208 :
209 : } // namespace pe
|