1 : // Copyright 2014 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_utils.h"
16 :
17 : #include "base/bind.h"
18 : #include "syzygy/block_graph/typed_block.h"
19 :
20 : namespace pe {
21 :
22 : namespace {
23 :
24 : using block_graph::BlockGraph;
25 : using block_graph::TypedBlock;
26 :
27 : // This is used by FindCoffSymbol as a callback function with VisitCoffSymbols.
28 : bool VisitCoffSymbol(const base::StringPiece& symbol_name,
29 : CoffSymbolOffsets* symbol_offsets,
30 : BlockGraph::Block* symbols_block,
31 : BlockGraph::Block* strings_block,
32 E : BlockGraph::Offset symbol_offset) {
33 E : DCHECK_NE(reinterpret_cast<CoffSymbolOffsets*>(NULL), symbol_offsets);
34 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), symbols_block);
35 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), strings_block);
36 :
37 : // Record the offset for matching names.
38 E : base::StringPiece name;
39 E : if (!GetCoffSymbolName(symbols_block, strings_block, symbol_offset, &name))
40 i : return false;
41 E : if (name != symbol_name)
42 E : return true;
43 E : symbol_offsets->insert(symbol_offset);
44 E : return true;
45 E : }
46 :
47 : bool AddSymbolToNameOffsetMap(CoffSymbolNameOffsetMap* map,
48 : BlockGraph::Block* symbols_block,
49 : BlockGraph::Block* strings_block,
50 E : BlockGraph::Offset symbol_offset) {
51 E : DCHECK_NE(reinterpret_cast<CoffSymbolNameOffsetMap*>(NULL), map);
52 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), symbols_block);
53 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), strings_block);
54 :
55 E : base::StringPiece name;
56 E : if (!GetCoffSymbolName(symbols_block, strings_block, symbol_offset, &name))
57 i : return false;
58 :
59 E : std::string name2 = name.as_string();
60 : CoffSymbolNameOffsetMap::iterator it = map->insert(
61 E : std::make_pair(name2, CoffSymbolOffsets())).first;
62 E : DCHECK(it != map->end());
63 E : it->second.insert(symbol_offset);
64 E : return true;
65 E : }
66 :
67 : } // namespace
68 :
69 : bool FindCoffSpecialBlocks(BlockGraph* block_graph,
70 : BlockGraph::Block** headers_block,
71 : BlockGraph::Block** symbols_block,
72 E : BlockGraph::Block** strings_block) {
73 E : DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
74 :
75 E : bool headers_block_found = false;
76 E : bool symbols_block_found = false;
77 E : bool strings_block_found = false;
78 :
79 : // Walk through all the blocks once to find all the special blocks.
80 E : BlockGraph::BlockMap& blocks = block_graph->blocks_mutable();
81 E : BlockGraph::BlockMap::iterator it = blocks.begin();
82 E : for (; it != blocks.end(); ++it) {
83 E : if ((it->second.attributes() & BlockGraph::COFF_HEADERS) != 0) {
84 E : if (headers_block != NULL)
85 E : *headers_block = &it->second;
86 E : headers_block_found = true;
87 E : } else if ((it->second.attributes() & BlockGraph::COFF_SYMBOL_TABLE) != 0) {
88 E : if (symbols_block != NULL)
89 E : *symbols_block = &it->second;
90 E : symbols_block_found = true;
91 E : } else if ((it->second.attributes() & BlockGraph::COFF_STRING_TABLE) != 0) {
92 E : if (strings_block != NULL)
93 E : *strings_block = &it->second;
94 E : strings_block_found = true;
95 : }
96 E : }
97 :
98 E : if (!headers_block_found || !symbols_block_found || !strings_block_found)
99 E : return false;
100 E : return true;
101 E : }
102 :
103 : bool GetCoffSymbolName(const BlockGraph::Block* symbols_block,
104 : const BlockGraph::Block* strings_block,
105 : BlockGraph::Offset symbol_offset,
106 E : base::StringPiece* name) {
107 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), symbols_block);
108 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), strings_block);
109 E : DCHECK_LE(0, symbol_offset);
110 E : DCHECK_GE(symbols_block->data_size(), symbol_offset + sizeof(IMAGE_SYMBOL));
111 E : DCHECK_NE(reinterpret_cast<base::StringPiece*>(NULL), name);
112 :
113 : // Cast to a raw symbol.
114 : const IMAGE_SYMBOL* symbol = reinterpret_cast<const IMAGE_SYMBOL*>(
115 E : symbols_block->data() + symbol_offset);
116 :
117 : // If the symbol name is short enough it's stored directly in the symbol
118 : // record.
119 E : if (symbol->N.Name.Short != 0) {
120 : // The string isn't necessarily zero terminated if it uses the whole
121 : // length, so we determine it's length using a cap.
122 E : const char* s = reinterpret_cast<const char*>(&symbol->N.ShortName);
123 :
124 E : size_t length = ::strnlen(s, sizeof(symbol->N.ShortName));
125 E : *name = base::StringPiece(s, length);
126 E : return true;
127 : }
128 :
129 : // Otherwise the name is stored in the string table, and is zero
130 : // terminated.
131 E : size_t i = symbol->N.Name.Long;
132 E : if (i >= strings_block->size()) {
133 i : LOG(ERROR) << "COFF symbol name outside of strings block.";
134 i : return false;
135 : }
136 :
137 : // If the string is outside of the data portion of the block then it is
138 : // implicitly zero length.
139 E : if (i >= strings_block->data_size()) {
140 i : *name = base::StringPiece(NULL, 0);
141 i : return true;
142 : }
143 :
144 : // Determine the length of the symbol name.
145 : const char* s = reinterpret_cast<const char*>(
146 E : strings_block->data() + symbol->N.Name.Long);
147 E : size_t max_length = strings_block->data_size() - symbol->N.Name.Long;
148 E : size_t length = ::strnlen(s, max_length);
149 :
150 : // Ensure the terminating zero is actually in the strings block.
151 : if (length == max_length &&
152 E : strings_block->data_size() == strings_block->size()) {
153 i : LOG(ERROR) << "COFF symbol name has no terminating NUL.";
154 i : return false;
155 : }
156 :
157 E : *name = base::StringPiece(s, length);
158 E : return true;
159 E : }
160 :
161 : bool VisitCoffSymbols(const VisitCoffSymbolCallback& callback,
162 : BlockGraph::Block* symbols_block,
163 E : BlockGraph::Block* strings_block) {
164 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), symbols_block);
165 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), strings_block);
166 :
167 E : TypedBlock<IMAGE_SYMBOL> symbols;
168 E : if (!symbols.Init(0, symbols_block)) {
169 i : LOG(ERROR) << "Unable to cast symbol table.";
170 i : return false;
171 : }
172 :
173 E : size_t num_symbols = symbols.ElementCount();
174 E : for (size_t i = 0; i < num_symbols; i += 1 + symbols[i].NumberOfAuxSymbols) {
175 E : size_t symbol_offset = i * sizeof(IMAGE_SYMBOL);
176 E : if (!callback.Run(symbols_block, strings_block, symbol_offset))
177 E : return false;
178 E : }
179 :
180 E : return true;
181 E : }
182 :
183 : bool VisitCoffSymbols(const VisitCoffSymbolCallback& callback,
184 E : BlockGraph* block_graph) {
185 E : DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
186 :
187 E : BlockGraph::Block* symbols_block = NULL;
188 E : BlockGraph::Block* strings_block = NULL;
189 : if (!FindCoffSpecialBlocks(block_graph, NULL, &symbols_block,
190 E : &strings_block)) {
191 i : return false;
192 : }
193 :
194 E : if (!VisitCoffSymbols(callback, symbols_block, strings_block))
195 E : return false;
196 :
197 E : return true;
198 E : }
199 :
200 : bool FindCoffSymbol(const base::StringPiece& symbol_name,
201 : BlockGraph::Block* symbols_block,
202 : BlockGraph::Block* strings_block,
203 E : CoffSymbolOffsets* symbol_offsets) {
204 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), symbols_block);
205 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), strings_block);
206 E : DCHECK_NE(reinterpret_cast<CoffSymbolOffsets*>(NULL), symbol_offsets);
207 :
208 E : symbol_offsets->clear();
209 : VisitCoffSymbolCallback callback = base::Bind(
210 E : &VisitCoffSymbol, symbol_name, symbol_offsets);
211 E : if (!VisitCoffSymbols(callback, symbols_block, strings_block))
212 i : return false;
213 E : return true;
214 E : }
215 :
216 : bool FindCoffSymbol(const base::StringPiece& symbol_name,
217 : BlockGraph* block_graph,
218 E : CoffSymbolOffsets* symbol_offsets) {
219 E : DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
220 E : DCHECK_NE(reinterpret_cast<CoffSymbolOffsets*>(NULL), symbol_offsets);
221 :
222 E : BlockGraph::Block* symbols_block = NULL;
223 E : BlockGraph::Block* strings_block = NULL;
224 : if (!FindCoffSpecialBlocks(block_graph, NULL, &symbols_block,
225 E : &strings_block)) {
226 i : return false;
227 : }
228 :
229 : if (!FindCoffSymbol(symbol_name, symbols_block, strings_block,
230 E : symbol_offsets)) {
231 i : return false;
232 : }
233 :
234 E : return true;
235 E : }
236 :
237 : bool BuildCoffSymbolNameOffsetMap(BlockGraph::Block* symbols_block,
238 : BlockGraph::Block* strings_block,
239 E : CoffSymbolNameOffsetMap* map) {
240 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), symbols_block);
241 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), strings_block);
242 E : DCHECK_NE(reinterpret_cast<CoffSymbolNameOffsetMap*>(NULL), map);
243 :
244 E : map->clear();
245 : VisitCoffSymbolCallback callback = base::Bind(
246 E : &AddSymbolToNameOffsetMap, base::Unretained(map));
247 E : if (!VisitCoffSymbols(callback, symbols_block, strings_block))
248 i : return false;
249 E : return true;
250 E : }
251 :
252 : bool BuildCoffSymbolNameOffsetMap(BlockGraph* block_graph,
253 E : CoffSymbolNameOffsetMap* map) {
254 E : DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
255 E : DCHECK_NE(reinterpret_cast<CoffSymbolNameOffsetMap*>(NULL), map);
256 :
257 E : BlockGraph::Block* symbols_block = NULL;
258 E : BlockGraph::Block* strings_block = NULL;
259 : if (!FindCoffSpecialBlocks(block_graph, NULL, &symbols_block,
260 E : &strings_block)) {
261 i : return false;
262 : }
263 :
264 E : if (!BuildCoffSymbolNameOffsetMap(symbols_block, strings_block, map))
265 i : return false;
266 :
267 E : return true;
268 E : }
269 :
270 : } // namespace pe
|