Index: syzygy/pe/pe_utils.cc |
diff --git a/syzygy/pe/pe_utils.cc b/syzygy/pe/pe_utils.cc |
index 808f0665e2e6c4c051f6e11fc5dd6592963b199b..8b0ec9b95bb1a2d01b4078359b985ce0c5d7fc93 100644 |
--- a/syzygy/pe/pe_utils.cc |
+++ b/syzygy/pe/pe_utils.cc |
@@ -547,4 +547,169 @@ void RedirectReferences(const ReferenceMap& redirects) { |
} |
} |
+size_t GetSectionOffset(const ImageLayout& image_layout, |
+ const RelativeAddress rel_addr, |
+ size_t section_index) { |
+ if (section_index == BlockGraph::kInvalidSectionId) |
+ return rel_addr.value(); |
+ |
+ DCHECK_GT(image_layout.sections.size(), section_index); |
+ const ImageLayout::SectionInfo& section_info = |
+ image_layout.sections[section_index]; |
+ |
+ DCHECK_GE(rel_addr, section_info.addr); |
+ return rel_addr - section_info.addr; |
+} |
+ |
+template <class Type> |
+bool UpdateReference(size_t start, Type new_value, std::vector<uint8_t>* data) { |
+ common::BinaryBufferParser parser(&data->at(0), data->size()); |
+ |
+ Type* ref_ptr = NULL; |
+ if (!parser.GetAtIgnoreAlignment(start, |
+ const_cast<const Type**>(&ref_ptr))) { |
+ LOG(ERROR) << "Reference data not in block"; |
+ return false; |
+ } |
+ * ref_ptr = new_value; |
+ |
+ return true; |
+} |
+ |
+bool ResolveReferences2(core::AbsoluteAddress image_base, |
+ core::RelativeAddress addr, |
+ BlockGraph::Block::ReferenceMap::const_iterator ref_it, |
+ const ImageLayout& image_layout) { |
+ BlockGraph::Offset start = ref_it->first; |
+ const BlockGraph::Reference& ref = ref_it->second; |
+ BlockGraph::Block* dst = ref.referenced(); |
+ |
+ RelativeAddress src_addr(addr + start); |
+ RelativeAddress dst_addr; |
+ if (!image_layout.blocks.GetAddressOf(dst, &dst_addr)) { |
+ LOG(ERROR) << "All blocks must have an address."; |
+ return false; |
+ } |
+ dst_addr += ref.offset(); |
+ |
+ // Compute the new value of the reference. |
+ uint32_t value = 0; |
+ switch (ref.type()) { |
+ case BlockGraph::ABSOLUTE_REF: |
+ value = image_base.value() + dst_addr.value(); |
+ break; |
+ |
+ case BlockGraph::PC_RELATIVE_REF: |
+ value = dst_addr - (src_addr + ref.size()); |
+ break; |
+ |
+ case BlockGraph::RELATIVE_REF: |
+ value = dst_addr.value(); |
+ break; |
+ } |
+ |
+ return true; |
+} |
+ |
+bool ResolveReferences(core::AbsoluteAddress image_base, |
+ const block_graph::BlockGraph::Block* block, |
+ core::RelativeAddress addr, |
+ const core::FileOffsetAddress file_offs, |
+ SectionIndexFileRangeMap section_file_range_map, |
+ SectionIndexSpace section_index_space, |
+ bool write_references_in_place, |
+ std::vector<uint8_t>* buffer, |
+ const ImageLayout& image_layout) { |
+ BlockGraph::Block::ReferenceMap::const_iterator ref_it( |
+ block->references().begin()); |
+ BlockGraph::Block::ReferenceMap::const_iterator ref_end( |
+ block->references().end()); |
+ for (; ref_it != ref_end; ++ref_it) { |
+ BlockGraph::Offset start = ref_it->first; |
+ const BlockGraph::Reference& ref = ref_it->second; |
+ BlockGraph::Block* dst = ref.referenced(); |
+ |
+ RelativeAddress src_addr(addr + start); |
+ RelativeAddress dst_addr; |
+ if (!image_layout.blocks.GetAddressOf(dst, &dst_addr)) { |
+ LOG(ERROR) << "All blocks must have an address."; |
+ return false; |
+ } |
+ dst_addr += ref.offset(); |
+ |
+ // Compute the new value of the reference. |
+ uint32_t value = 0; |
+ switch (ref.type()) { |
+ case BlockGraph::ABSOLUTE_REF: |
+ value = image_base.value() + dst_addr.value(); |
+ break; |
+ |
+ case BlockGraph::PC_RELATIVE_REF: |
+ value = dst_addr - (src_addr + ref.size()); |
+ break; |
+ |
+ case BlockGraph::RELATIVE_REF: |
+ value = dst_addr.value(); |
+ break; |
+ |
+ case BlockGraph::FILE_OFFSET_REF: { |
+ // Get the index of the section containing the destination block. |
+ SectionIndexSpace::const_iterator section_index_space_it = |
+ section_index_space.FindContaining( |
+ SectionIndexSpace::Range(dst_addr, 1)); |
+ DCHECK(section_index_space_it != section_index_space.end()); |
+ size_t dst_section_index = section_index_space_it->second; |
+ |
+ // Get the offset of the block in its section, as well as the range of |
+ // the section on disk. Validate that the referred location is |
+ // actually directly represented on disk (not in implicit virtual data). |
+ const FileRange& file_range = |
+ section_file_range_map[dst_section_index]; |
+ size_t section_offset = GetSectionOffset(image_layout, |
+ dst_addr, |
+ dst_section_index); |
+ if (section_offset >= file_range.size()) { |
+ LOG(ERROR) << "Encountered file offset reference that refers to " |
+ << "a location outside of the explicit section data."; |
+ return false; |
+ } |
+ |
+ // Finally, calculate the value of the file offset. |
+ value = file_range.start().value() + section_offset; |
+ break; |
+ } |
+ |
+ default: |
+ LOG(ERROR) << "Impossible reference type"; |
+ return false; |
+ } |
+ |
+ if (!write_references_in_place) |
+ return true; |
+ |
+ // Now store the new value. |
+ BlockGraph::Offset ref_offset = file_offs.value() + start; |
+ switch (ref.size()) { |
+ case sizeof(uint8_t) : |
+ if (!UpdateReference(ref_offset, static_cast<uint8_t>(value), buffer)) |
+ return false; |
+ break; |
+ |
+ case sizeof(uint16_t) : |
+ if (!UpdateReference(ref_offset, static_cast<uint16_t>(value), buffer)) |
+ return false; |
+ break; |
+ |
+ case sizeof(uint32_t) : |
+ if (!UpdateReference(ref_offset, static_cast<uint32_t>(value), buffer)) |
+ return false; |
+ break; |
+ |
+ default: |
+ LOG(ERROR) << "Unsupported reference size."; |
+ return false; |
+ } |
+ } |
+ return true; |
+} |
} // namespace pe |