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_file_writer.h"
16 :
17 : #include <cstdio>
18 :
19 : #include "base/files/file_util.h"
20 : #include "base/win/scoped_handle.h"
21 : #include "syzygy/block_graph/block_graph.h"
22 :
23 : namespace pe {
24 :
25 : using block_graph::BlockGraph;
26 : using core::RelativeAddress;
27 :
28 : CoffFileWriter::CoffFileWriter(const ImageLayout* image_layout)
29 E : : image_layout_(image_layout) {
30 E : }
31 :
32 E : bool CoffFileWriter::WriteImage(const base::FilePath& path) {
33 E : DCHECK(image_layout_ != NULL);
34 :
35 : // Overwrite the destination file.
36 E : base::ScopedFILE file(base::OpenFile(path, "wb"));
37 E : if (file.get() == NULL) {
38 i : LOG(ERROR) << "Unable to open file " << path.value() << ".";
39 i : return false;
40 : }
41 :
42 : // Write every range in order. In a COFF file, block graph relative
43 : // addresses match file offsets, so writing out the file can simply be
44 : // done in address order, with appropriate padding.
45 E : std::vector<uint8> padding;
46 E : RelativeAddress cursor(0);
47 : BlockGraph::AddressSpace::RangeMapConstIter it =
48 E : image_layout_->blocks.begin();
49 E : for (; it != image_layout_->blocks.end(); ++it) {
50 : // Pad up to the address of the next block.
51 E : DCHECK_LE(cursor, it->first.start());
52 E : size_t pad_size = it->first.start() - cursor;
53 E : if (pad_size > 0) {
54 E : if (pad_size > padding.size())
55 E : padding.resize(pad_size, 0);
56 : if (std::fwrite(&padding[0], sizeof(padding[0]), pad_size,
57 E : file.get()) != pad_size) {
58 i : LOG(ERROR) << "Unable to write padding (" << pad_size
59 : << " bytes) to file.";
60 i : return false;
61 : }
62 E : cursor += pad_size;
63 : }
64 :
65 E : const BlockGraph::Block* block = it->second;
66 :
67 : // Ignore BSS blocks.
68 E : if ((block->attributes() & BlockGraph::COFF_BSS) != 0)
69 E : continue;
70 :
71 : // Write the contents of the block.
72 E : DCHECK(block != NULL);
73 E : const uint8* data = block->data();
74 E : size_t data_size = block->data_size();
75 E : if (std::fwrite(data, sizeof(*data), data_size, file.get()) != data_size) {
76 i : LOG(ERROR) << "Unable to write contents of block \""
77 : << block->name() << "\" ("
78 : << data_size << " bytes) to file.";
79 i : return false;
80 : }
81 :
82 : // Advance cursor.
83 E : cursor += block->data_size();
84 E : DCHECK_EQ(it->first.end(), cursor);
85 E : }
86 :
87 E : return true;
88 E : }
89 :
90 : } // namespace pe
|