#include "PELibrary.hpp" using namespace pepp; // Explicit templates. template class RelocationDirectory<32>; template class RelocationDirectory<64>; template int RelocationDirectory::getNumBlocks() const { auto base = m_base; int count = 0; while (base->VirtualAddress) { count++; base = decltype(base)((char*)base + base->SizeOfBlock); } return count; } template int RelocationDirectory::getNumEntries(detail::Image_t<>::RelocationBase_t* reloc) const { // MSDN: The Block Size field is then followed by any number of Type or Offset field entries. // Each entry is a WORD (2 bytes) return (reloc->SizeOfBlock - sizeof(decltype(*reloc))) / sizeof(std::uint16_t); } template std::uint32_t RelocationDirectory::getRemainingFreeBytes() const { auto base = m_base; std::uint32_t count = 0; while (base->VirtualAddress) { count += base->SizeOfBlock; base = decltype(base)((char*)base + base->SizeOfBlock); } return std::max(m_section->getVirtualSize() - count, 0); } template bool pepp::RelocationDirectory::changeRelocationType(std::uint32_t rva, RelocationType type) { auto base = m_base; std::vector entries; while (base->VirtualAddress) { int numEntries = getNumEntries(base); std::uint16_t* entry = (std::uint16_t*)(base + 1); for (int i = 0; i != numEntries; i++, entry++) { BlockEntry block(base->VirtualAddress, *entry); if (block.getRva() == rva) { *entry = craftRelocationBlockEntry(type, block.getOffset()); return true; } } base = decltype(base)((char*)base + base->SizeOfBlock); } return false; } template std::vector RelocationDirectory::getBlockEntries(int blockIdx) { auto base = m_base; int count = 0; std::vector entries; while (base->VirtualAddress) { if (count == blockIdx) { int numEntries = getNumEntries(base); std::uint16_t* entry = (std::uint16_t*)(base + 1); for (int i = 0; i != numEntries; i++, entry++) { entries.emplace_back(base->VirtualAddress, *entry); } } base = decltype(base)((char*)base + base->SizeOfBlock); count++; } return entries; } template BlockStream RelocationDirectory::createBlock(std::uint32_t rva, std::uint32_t num_entries) { std::uint32_t size = sizeof(detail::Image_t<>::RelocationBase_t) + (num_entries * sizeof(std::uint16_t)); std::uint32_t rsize = m_section->getVirtualSize(); //std::uint32_t remainingBytesLeft = getRemainingFreeBytes(); // Extend .reloc section if needed //if (remainingBytesLeft < size) //{ // if (!m_image->extendSection(m_section->getName(), size - remainingBytesLeft)) // return BlockStream(); //} auto base = m_base; // Traverse to last block while (base->VirtualAddress) { if (base->VirtualAddress == rva) { return BlockStream(base); } base = decltype(base)((char*)base + base->SizeOfBlock); } std::uint16_t* entryPtr = (std::uint16_t*)(base + 1); for (int i = 0; i <= num_entries; ++i) entryPtr[i] = 0x0; //printf("block va: 0x%x\n", base->VirtualAddress); //printf("block sz: 0x%x\n", base->SizeOfBlock); //printf("new block va: 0x%x\n", rva); //printf("new block sz: 0x%x\n", size); // Set the new block's descriptor base->VirtualAddress = rva; base->SizeOfBlock = size; return BlockStream(base); } template BlockStream pepp::RelocationDirectory::getBlockStream(std::uint32_t rva) { auto base = m_base; // Traverse to last block while (base->VirtualAddress) { if (base->VirtualAddress == rva) return BlockStream(base); base = decltype(base)((char*)base + base->SizeOfBlock); } return BlockStream(); } template void pepp::RelocationDirectory::extend(std::uint32_t num_entries) { std::uint32_t size = sizeof(detail::Image_t<>::RelocationBase_t) + num_entries * sizeof(std::uint16_t); std::uint32_t remaining_bytes = getRemainingFreeBytes(); if (remaining_bytes < size) { m_image->extendSection(m_section->getName(), size); //__debugbreak(); } } template void pepp::RelocationDirectory::forEachEntry(std::function Callback) { auto base = m_base; std::vector entries; while (base->VirtualAddress) { int numEntries = getNumEntries(base); std::uint16_t* entry = (std::uint16_t*)(base + 1); for (int i = 0; i != numEntries; i++, entry++) { BlockEntry block(base->VirtualAddress, *entry); Callback(block); } base = decltype(base)((char*)base + base->SizeOfBlock); } } template bool pepp::RelocationDirectory::isRelocationPresent(std::uint32_t rva) const { auto base = m_base; std::vector entries; while (base->VirtualAddress) { int numEntries = getNumEntries(base); std::uint16_t* entry = (std::uint16_t*)(base + 1); for (int i = 0; i != numEntries; i++, entry++) { BlockEntry block(base->VirtualAddress, *entry); if (block.getRva() == rva) return true; } base = decltype(base)((char*)base + base->SizeOfBlock); } return false; } template std::uint32_t pepp::RelocationDirectory::getTotalBlockSize() { auto base = m_base; std::uint32_t count = 0; // Traverse to last block while (base->SizeOfBlock) { if (base->SizeOfBlock >= 0x1000) break; count += base->SizeOfBlock; base = decltype(base)((char*)base + base->SizeOfBlock); } return count; } template void pepp::RelocationDirectory::increaseBlockSize(std::uint32_t rva, std::uint32_t num_entries) { auto base = m_base; while (base->VirtualAddress) { if (base->VirtualAddress == rva) { base->SizeOfBlock += (num_entries * sizeof(uint16_t)); base->SizeOfBlock = (base->SizeOfBlock + 0x3) & ~0x3; break; } base = decltype(base)((char*)base + base->SizeOfBlock); } } template void pepp::RelocationDirectory::adjustBlockToFit(uint32_t delta) { auto base = m_base; std::uint32_t count = 0; // Traverse to last block while (true) { auto next = decltype(base)((char*)base + base->SizeOfBlock); if (next->SizeOfBlock == 0 || next->SizeOfBlock >= 0x1000) break; base = next; } base->SizeOfBlock += delta; }