diff --git a/core/elfpatcher/src/windows/WindowsPeFormat.hpp b/core/elfpatcher/src/windows/WindowsPeFormat.hpp new file mode 100644 index 000000000..d1728f541 --- /dev/null +++ b/core/elfpatcher/src/windows/WindowsPeFormat.hpp @@ -0,0 +1,61 @@ +#ifndef CORE_ELFPATCHER_SRC_WINDOWS_WINDOWSPEFORMAT_HPP +#define CORE_ELFPATCHER_SRC_WINDOWS_WINDOWSPEFORMAT_HPP + +constexpr std::uint16_t kMzMagic = 0x5A4D; +constexpr std::uint32_t kPeSignature = 0x00004550; +constexpr std::uint16_t kMachinAmd64 = 0x8664; +constexpr std::uint16_t kOptMagicPe32Plus = 0x020B; +constexpr std::uint16_t kCharsDll = 0x2000; +constexpr std::uint16_t kCharsExe = 0x0002; +constexpr std::uint16_t kCharsLargeAddressAware = 0x0020; +constexpr std::uint32_t kSectionAlignment = 0x1000; +constexpr std::uint32_t kFileAlignment = 0x200; +constexpr std::uint32_t kOsVersion = 6; +constexpr std::uint32_t kOsVersionMinor = 0; +constexpr std::uint32_t kSubsystemConsole = 3; +constexpr std::uint32_t kNumberOfRvaAndSizes = 16; +constexpr std::uint32_t kSizeOfPeHeaders = 0x400; + +constexpr std::uint32_t kRelTypeDir64 = 10; +constexpr std::uint32_t kRelTypeAbsolute = 0; +constexpr std::uint32_t kRelocBlockHeaderSize = 8; +constexpr std::uint32_t kRelocEntrySize = 2; + +struct MzHeader { + std::uint8_t data[0x40]; +}; + +struct PeSection { + char name[8]; + std::uint32_t virtualSize; + std::uint32_t virtualAddress; + std::uint32_t rawSize; + std::uint32_t rawOffset; + std::uint32_t characteristics; + std::vector data; +}; + +struct DataDirectory { + std::uint32_t rva; + std::uint32_t size; +}; + +struct LoadSegment { + std::uint64_t vaddr; + std::uint64_t memSize; + std::uint64_t fileOffset; + std::uint64_t fileSize; + std::uint32_t flags; +}; + +struct ImportThunkEntry { + std::string symbolName; + std::uint32_t gotRva; +}; + +struct ImportDllBlock { + std::string dllName; + std::vector thunks; +}; + +#endif \ No newline at end of file diff --git a/core/elfpatcher/src/windows/WindowsPePatcher.cpp b/core/elfpatcher/src/windows/WindowsPePatcher.cpp index 61efee0d8..e80f3a440 100644 --- a/core/elfpatcher/src/windows/WindowsPePatcher.cpp +++ b/core/elfpatcher/src/windows/WindowsPePatcher.cpp @@ -1,14 +1,206 @@ #include +#include #include +#include +#include +#include +#include +#include +#include +#include "WindowsPeFormat.hpp" +#include "io/ByteWriter.hpp" namespace Elfpatcher::Windows { +namespace { + +MzHeader buildMzStub(std::uint32_t peOffset) { + MzHeader h{}; + h.data[0] = 'M'; + h.data[1] = 'Z'; + std::memcpy(h.data + 0x3c, &peOffset, 4); + return h; +} + +void writeSectionHeader(std::vector& buf, std::size_t off, const PeSection& sec) { + std::memcpy(buf.data() + off, sec.name, 8); + WriteU32(buf, off + 8, sec.virtualSize); + WriteU32(buf, off + 12, sec.virtualAddress); + WriteU32(buf, off + 16, sec.rawSize); + WriteU32(buf, off + 20, sec.rawOffset); + WriteU32(buf, off + 24, 0); + WriteU32(buf, off + 28, 0); + WriteU16(buf, off + 32, 0); + WriteU16(buf, off + 34, 0); + WriteU32(buf, off + 36, sec.characteristics); +} + +std::vector buildRelocSection( + const std::vector& relaData, + const std::uint64_t imageBase) +{ + constexpr std::size_t kRelaEntSize = 24; + if (relaData.size() % kRelaEntSize != 0) + throw Domain::RelinkerException("RELA data size is not a multiple of 24"); + + std::map> pageToOffsets; + + for (std::size_t i = 0; i + kRelaEntSize <= relaData.size(); i += kRelaEntSize) { + std::uint64_t rOffset, rInfo; + std::int64_t rAddend; + std::memcpy(&rOffset, relaData.data() + i, 8); + std::memcpy(&rInfo, relaData.data() + i + 8, 8); + std::memcpy(&rAddend, relaData.data() + i + 16, 8); + + const auto relType = static_cast(rInfo & 0xffffffff); + const auto symIdx = static_cast(rInfo >> 32); + + constexpr std::uint32_t kRelativeType = 8; + if (relType != kRelativeType) + continue; + if (symIdx != 0) + throw Domain::RelinkerException("R_X86_64_RELATIVE with non-zero symbol index"); + + if (rOffset < imageBase) + throw Domain::RelinkerException("RELATIVE relocation target vaddr below imageBase", rOffset); + + const std::uint64_t rva = rOffset - imageBase; + if (rva > 0xFFFFFFFFull) + throw Domain::RelinkerException("RELATIVE relocation RVA exceeds 32-bit range", rOffset); + + const auto rva32 = static_cast(rva); + const std::uint32_t page = rva32 & ~0xFFFu; + const std::uint32_t pageOff = rva32 & 0xFFFu; + pageToOffsets[page].push_back(pageOff); + } + + std::vector buf; + for (auto& [page, offsets] : pageToOffsets) { + std::sort(offsets.begin(), offsets.end()); + auto entryCount = static_cast(offsets.size()); + if (entryCount % 2 != 0) { + offsets.push_back(0); + entryCount++; + } + const std::uint32_t blockSize = kRelocBlockHeaderSize + entryCount * kRelocEntrySize; + appendU32(buf, page); + appendU32(buf, blockSize); + for (const std::uint32_t off : offsets) { + const auto entry = static_cast((kRelTypeDir64 << 12) | (off & 0xFFF)); + appendU16(buf, entry); + } + } + return buf; +} + + +std::vector buildImportSection( + const std::vector& dlls, + const std::uint32_t sectionRva, + std::vector>& outGotPatches) +{ + if (dlls.empty()) + return {}; + + const auto descriptorTableSize = static_cast((dlls.size() + 1) * 20); + + std::vector descriptorBuf; + std::vector dataBuf; + + const std::uint32_t dataBase = sectionRva + descriptorTableSize; + + for (const auto& dll : dlls) { + const std::uint32_t dllNameRva = dataBase + static_cast(dataBuf.size()); + appendStr(dataBuf, dll.dllName); + alignBuf(dataBuf, 2); + + const std::uint32_t iltRva = dataBase + static_cast(dataBuf.size()); + for (const auto& thunk : dll.thunks) { + const std::uint32_t hintNameRva = dataBase + static_cast(dataBuf.size()) + + static_cast((dll.thunks.size() + 1) * 8); + appendU64(dataBuf, hintNameRva); + } + appendU64(dataBuf, 0); + + for (const auto& thunk : dll.thunks) { + appendU16(dataBuf, 0); + appendStr(dataBuf, thunk.symbolName); + alignBuf(dataBuf, 2); + } + + const std::uint32_t iatRva = dataBase + static_cast(dataBuf.size()); + for (std::size_t i = 0; i < dll.thunks.size(); ++i) { + const std::uint32_t iatEntryRva = iatRva + static_cast(i * 8); + outGotPatches.emplace_back(dll.thunks[i].gotRva, iatEntryRva); + appendU64(dataBuf, 0); + } + appendU64(dataBuf, 0); + + appendU32(descriptorBuf, iltRva); + appendU32(descriptorBuf, 0); + appendU32(descriptorBuf, 0); + appendU32(descriptorBuf, dllNameRva); + appendU32(descriptorBuf, iatRva); + } + + appendU32(descriptorBuf, 0); + appendU32(descriptorBuf, 0); + appendU32(descriptorBuf, 0); + appendU32(descriptorBuf, 0); + appendU32(descriptorBuf, 0); + + std::vector result; + result.insert(result.end(), descriptorBuf.begin(), descriptorBuf.end()); + result.insert(result.end(), dataBuf.begin(), dataBuf.end()); + return result; +} + +std::vector buildEntryStub(std::uint64_t realEntryVaddr, std::uint64_t stubVaddr) { + std::vector s; + const std::uint64_t callInsnVaddr = stubVaddr + s.size() + 5; + const std::int64_t rel = static_cast(realEntryVaddr) - static_cast(callInsnVaddr); + if (rel < std::int64_t(-0x80000000) || rel > std::int64_t(0x7FFFFFFF)) + throw Domain::RelinkerException("Entry stub: rel32 call target out of range"); + const auto rel32 = static_cast(rel); + s.push_back(0xE8); + s.push_back(static_cast(rel32 & 0xFF)); + s.push_back(static_cast((rel32 >> 8) & 0xFF)); + s.push_back(static_cast((rel32 >> 16) & 0xFF)); + s.push_back(static_cast((rel32 >> 24) & 0xFF)); + s.push_back(0xC3); + return s; +} + +std::uint64_t readElfU64(const std::vector& buf, std::size_t off) { + if (off + 8 > buf.size()) + throw Domain::RelinkerException("ELF read out of bounds", off); + std::uint64_t v; + std::memcpy(&v, buf.data() + off, 8); + return v; +} + +std::uint32_t readElfU32(const std::vector& buf, std::size_t off) { + if (off + 4 > buf.size()) + throw Domain::RelinkerException("ELF read out of bounds", off); + std::uint32_t v; + std::memcpy(&v, buf.data() + off, 4); + return v; +} + +std::string readCStr(const std::vector& buf, std::size_t off) { + std::string s; + while (off < buf.size() && buf[off] != 0) + s.push_back(static_cast(buf[off++])); + return s; +} + +} + WindowsPePatcher::WindowsPePatcher( std::shared_ptr entryStubBuilder, std::shared_ptr programHeaderLayoutBuilder, std::shared_ptr sectionHeaderTableBuilder, - std::shared_ptr byteWriter -) + std::shared_ptr byteWriter) : _entryStubBuilder(std::move(entryStubBuilder)) , _programHeaderLayoutBuilder(std::move(programHeaderLayoutBuilder)) , _sectionHeaderTableBuilder(std::move(sectionHeaderTableBuilder)) @@ -23,7 +215,347 @@ std::vector WindowsPePatcher::Patch( std::uint64_t originalPltGotVaddr, const std::string& runPath) { - throw Domain::RelinkerException("Not implemented"); + if (sourceElf.size() < 64) + throw Domain::RelinkerException("Source ELF too small"); + if (sourceElf[0] != 0x7f || sourceElf[1] != 'E' || sourceElf[2] != 'L' || sourceElf[3] != 'F') + throw Domain::RelinkerException("Source is not an ELF file"); + + const std::uint64_t elfEntryVaddr = readElfU64(sourceElf, 0x18); + + std::vector loadSegs; + auto imageBase = std::uint64_t(-1); + std::uint64_t imageTop = 0; + + for (const auto& ph : originalHeaders) { + if (ph.Type != PT_LOAD) continue; + if (ph.MemorySize == 0) continue; + LoadSegment seg{}; + seg.vaddr = ph.MappedAddress; + seg.memSize = ph.MemorySize; + seg.fileOffset = ph.Offset; + seg.fileSize = ph.FileSize; + seg.flags = ph.Flags; + loadSegs.push_back(seg); + if (seg.vaddr < imageBase) imageBase = seg.vaddr; + const std::uint64_t top = alignUp64(seg.vaddr + seg.memSize, kSectionAlignment); + if (top > imageTop) imageTop = top; + } + + if (loadSegs.empty()) + throw Domain::RelinkerException("No PT_LOAD segments found"); + if (imageBase == std::uint64_t(-1)) + throw Domain::RelinkerException("Could not determine image base"); + if (imageBase % kSectionAlignment != 0) + throw Domain::RelinkerException("Image base is not section-aligned"); + + std::uint32_t gotRva = 0; + bool gotFound = false; + if (originalPltGotVaddr != 0) { + if (originalPltGotVaddr < imageBase) + throw Domain::RelinkerException("GOT vaddr below image base"); + const std::uint64_t gotRva64 = originalPltGotVaddr - imageBase; + if (gotRva64 > 0xFFFFFFFFull) + throw Domain::RelinkerException("GOT RVA exceeds 32-bit range"); + gotRva = static_cast(gotRva64); + gotFound = true; + } + + std::vector imageBuf(static_cast(imageTop - imageBase), 0); + + for (const auto& seg : loadSegs) { + const std::uint64_t destOff = seg.vaddr - imageBase; + if (destOff + seg.fileSize > imageBuf.size()) + throw Domain::RelinkerException("PT_LOAD segment exceeds image buffer", seg.vaddr); + if (seg.fileOffset + seg.fileSize > sourceElf.size()) + throw Domain::RelinkerException("PT_LOAD segment file data out of bounds", seg.fileOffset); + std::memcpy(imageBuf.data() + destOff, sourceElf.data() + seg.fileOffset, static_cast(seg.fileSize)); + } + + const auto loadImageRva = static_cast(kSizeOfPeHeaders); + if (imageBase < loadImageRva) + throw Domain::RelinkerException("Image base too small to accommodate PE headers"); + + const std::uint64_t adjustedBase = imageBase - loadImageRva; + if (adjustedBase % kSectionAlignment != 0) + throw Domain::RelinkerException("Adjusted image base is not section-aligned"); + + std::vector importDlls; + std::vector> gotPatches; + + { + const std::vector& relaPlt = dynamicSection.RelaPltData; + const std::vector& dynStr = dynamicSection.DynStrData; + const std::vector& dynSym = dynamicSection.DynSymData; + + constexpr std::size_t kRelaEnt = 24; + constexpr std::size_t kSymEnt = 24; + + if (relaPlt.size() % kRelaEnt != 0) + throw Domain::RelinkerException("RelaPlt size not multiple of 24"); + + std::map dllMap; + + for (std::size_t i = 0; i + kRelaEnt <= relaPlt.size(); i += kRelaEnt) { + std::uint64_t rOffset, rInfo; + std::memcpy(&rOffset, relaPlt.data() + i, 8); + std::memcpy(&rInfo, relaPlt.data() + i + 8, 8); + + const auto symIdx = static_cast(rInfo >> 32); + const auto relType = static_cast(rInfo & 0xffffffff); + + constexpr std::uint32_t kJumpSlot = 7; + if (relType != kJumpSlot) + throw Domain::RelinkerException("Unexpected relocation type in RelaPlt"); + if (symIdx == 0) + throw Domain::RelinkerException("JUMP_SLOT relocation with zero symbol index"); + + const std::size_t symOff = static_cast(symIdx) * kSymEnt; + if (symOff + 4 > dynSym.size()) + throw Domain::RelinkerException("Symbol index out of dynSym bounds"); + + std::uint32_t nameOff; + std::memcpy(&nameOff, dynSym.data() + symOff, 4); + if (nameOff >= dynStr.size()) + throw Domain::RelinkerException("Symbol name offset out of dynStr bounds"); + + const std::string symName = readCStr(dynStr, nameOff); + if (symName.empty()) + throw Domain::RelinkerException("Empty symbol name in JUMP_SLOT relocation"); + + if (rOffset < imageBase) + throw Domain::RelinkerException("JUMP_SLOT target vaddr below image base", rOffset); + const std::uint64_t rva64 = rOffset - imageBase; + if (rva64 > 0xFFFFFFFFull) + throw Domain::RelinkerException("JUMP_SLOT target RVA exceeds 32-bit range"); + const auto targetGotRva = static_cast(rva64); + + const std::string dllName = symName + ".dll"; + if (dllMap.find(dllName) == dllMap.end()) { + importDlls.push_back({dllName, {}}); + dllMap[dllName] = &importDlls.back(); + } + dllMap[dllName]->thunks.push_back({symName, targetGotRva}); + } + + const std::vector& relaData = dynamicSection.RelaData; + if (relaData.size() % kRelaEnt != 0) + throw Domain::RelinkerException("RelaData size not multiple of 24"); + + constexpr std::uint32_t kGlobDat = 6; + constexpr std::uint32_t kAbs64 = 1; + + for (std::size_t i = 0; i + kRelaEnt <= relaData.size(); i += kRelaEnt) { + std::uint64_t rOffset, rInfo; + std::memcpy(&rOffset, relaData.data() + i, 8); + std::memcpy(&rInfo, relaData.data() + i + 8, 8); + + const auto symIdx = static_cast(rInfo >> 32); + const auto relType = static_cast(rInfo & 0xffffffff); + + constexpr std::uint32_t kRelativeType = 8; + if (relType == kRelativeType) continue; + + if (relType != kGlobDat && relType != kAbs64) + throw Domain::RelinkerException("Unexpected relocation type in RelaData"); + if (symIdx == 0) + throw Domain::RelinkerException("GLOB_DAT/ABS64 relocation with zero symbol index"); + + const std::size_t symOff = static_cast(symIdx) * kSymEnt; + if (symOff + 4 > dynSym.size()) + throw Domain::RelinkerException("Symbol index out of dynSym bounds"); + + std::uint32_t nameOff; + std::memcpy(&nameOff, dynSym.data() + symOff, 4); + if (nameOff >= dynStr.size()) + throw Domain::RelinkerException("Symbol name offset out of dynStr bounds"); + + const std::string symName = readCStr(dynStr, nameOff); + if (symName.empty()) + throw Domain::RelinkerException("Empty symbol name in GLOB_DAT/ABS64 relocation"); + + if (rOffset < imageBase) + throw Domain::RelinkerException("GLOB_DAT target vaddr below image base", rOffset); + const std::uint64_t rva64 = rOffset - imageBase; + if (rva64 > 0xFFFFFFFFull) + throw Domain::RelinkerException("GLOB_DAT target RVA exceeds 32-bit range"); + const auto targetGotRva = static_cast(rva64); + + const std::string dllName = symName + ".dll"; + if (dllMap.find(dllName) == dllMap.end()) { + importDlls.push_back({dllName, {}}); + dllMap[dllName] = &importDlls.back(); + } + dllMap[dllName]->thunks.push_back({symName, targetGotRva}); + } + } + + const auto loadImageSize = static_cast(imageBuf.size()); + const std::uint32_t importSectionRva = alignUp(loadImageRva + loadImageSize, kSectionAlignment); + + std::vector importSectionData = buildImportSection(importDlls, importSectionRva, gotPatches); + alignBuf(importSectionData, kFileAlignment); + + for (const auto& [gotRva_, iatRva] : gotPatches) { + const auto destInImage = static_cast(gotRva_); + if (destInImage + 8 > imageBuf.size()) + throw Domain::RelinkerException("GOT patch target outside image buffer"); + const std::uint64_t iatVa = adjustedBase + iatRva; + std::memcpy(imageBuf.data() + destInImage, &iatVa, 8); + } + + const std::uint32_t relocSectionRva = alignUp(importSectionRva + static_cast(importSectionData.size()), kSectionAlignment); + std::vector relocSectionData = buildRelocSection(dynamicSection.RelaData, imageBase); + alignBuf(relocSectionData, kFileAlignment); + + const std::uint32_t stubSectionRva = alignUp(relocSectionRva + static_cast(relocSectionData.size()), kSectionAlignment); + const std::uint64_t stubVaddr = adjustedBase + stubSectionRva; + std::vector stubData = buildEntryStub(elfEntryVaddr, stubVaddr); + alignBuf(stubData, kFileAlignment); + + const std::uint32_t entryPointRva = stubSectionRva; + + std::uint16_t numSections = 1; + if (!importSectionData.empty()) numSections++; + if (!relocSectionData.empty()) numSections++; + numSections++; + + const std::uint32_t sizeOfHeaders = alignUp( + 0x40 + 4 + 20 + 240 + static_cast(numSections) * 40, + kFileAlignment); + + if (sizeOfHeaders > kSizeOfPeHeaders) + throw Domain::RelinkerException("PE headers exceed reserved header block size"); + + const std::uint32_t sizeOfImage = alignUp(stubSectionRva + static_cast(stubData.size()), kSectionAlignment); + + const std::uint32_t mzPeOffset = 0x40; + std::vector result(kSizeOfPeHeaders, 0); + + WriteU16(result, 0, kMzMagic); + WriteU32(result, 0x3c, mzPeOffset); + + std::size_t off = mzPeOffset; + WriteU32(result, off, kPeSignature); off += 4; + + WriteU16(result, off, kMachinAmd64); off += 2; + WriteU16(result, off, numSections); off += 2; + WriteU32(result, off, 0); off += 4; + WriteU32(result, off, 0); off += 4; + WriteU32(result, off, 0); off += 4; + WriteU16(result, off, 240); off += 2; + WriteU16(result, off, kCharsExe | kCharsLargeAddressAware); off += 2; + + WriteU16(result, off, kOptMagicPe32Plus); off += 2; + writeU8(result, off, 0); off += 1; + writeU8(result, off, 0); off += 1; + WriteU32(result, off, 0); off += 4; + WriteU32(result, off, 0); off += 4; + WriteU32(result, off, 0); off += 4; + WriteU32(result, off, entryPointRva); off += 4; + WriteU32(result, off, loadImageRva); off += 4; + + writeU64(result, off, adjustedBase); off += 8; + WriteU32(result, off, kSectionAlignment); off += 4; + WriteU32(result, off, kFileAlignment); off += 4; + WriteU16(result, off, static_cast(kOsVersion)); off += 2; + WriteU16(result, off, static_cast(kOsVersionMinor)); off += 2; + WriteU16(result, off, 0); off += 2; + WriteU16(result, off, 0); off += 2; + WriteU16(result, off, static_cast(kOsVersion)); off += 2; + WriteU16(result, off, static_cast(kOsVersionMinor)); off += 2; + WriteU32(result, off, 0); off += 4; + WriteU32(result, off, sizeOfImage); off += 4; + WriteU32(result, off, kSizeOfPeHeaders); off += 4; + WriteU32(result, off, 0); off += 4; + WriteU16(result, off, static_cast(kSubsystemConsole)); off += 2; + WriteU16(result, off, 0); off += 2; + writeU64(result, off, 0); off += 8; + writeU64(result, off, 0); off += 8; + writeU64(result, off, 0); off += 8; + writeU64(result, off, 0); off += 8; + WriteU32(result, off, 0); off += 4; + WriteU32(result, off, kNumberOfRvaAndSizes); off += 4; + + for (std::uint32_t i = 0; i < kNumberOfRvaAndSizes; ++i) { + WriteU32(result, off, 0); off += 4; + WriteU32(result, off, 0); off += 4; + } + + if (!importSectionData.empty()) { + WriteU32(result, mzPeOffset + 4 + 20 + 104, importSectionRva); + WriteU32(result, mzPeOffset + 4 + 20 + 108, static_cast(importDlls.size() * 20)); + } + if (!relocSectionData.empty()) { + WriteU32(result, mzPeOffset + 4 + 20 + 168, relocSectionRva); + WriteU32(result, mzPeOffset + 4 + 20 + 172, static_cast(relocSectionData.size())); + } + + std::size_t shdrsOff = mzPeOffset + 4 + 20 + 240; + + auto writeSec = [&](const char* name, std::uint32_t virtualSize, std::uint32_t rva, std::uint32_t rawSize, std::uint32_t rawOff, std::uint32_t chars) { + char n[8]{}; + std::memcpy(n, name, std::min(std::strlen(name), std::size_t(8))); + std::memcpy(result.data() + shdrsOff, n, 8); + WriteU32(result, shdrsOff + 8, virtualSize); + WriteU32(result, shdrsOff + 12, rva); + WriteU32(result, shdrsOff + 16, rawSize); + WriteU32(result, shdrsOff + 20, rawOff); + WriteU32(result, shdrsOff + 24, 0); + WriteU32(result, shdrsOff + 28, 0); + WriteU16(result, shdrsOff + 32, 0); + WriteU16(result, shdrsOff + 34, 0); + WriteU32(result, shdrsOff + 36, chars); + shdrsOff += 40; + }; + + constexpr std::uint32_t kSecExec = 0x60000020; + constexpr std::uint32_t kSecRW = 0xC0000040; + constexpr std::uint32_t kSecRO = 0x40000040; + constexpr std::uint32_t kSecDiscard = 0x02000000; + + const std::uint32_t loadRawSize = alignUp(loadImageSize, kFileAlignment); + std::uint32_t curRawOff = kSizeOfPeHeaders; + + writeSec(".load", loadImageSize, loadImageRva, loadRawSize, curRawOff, kSecExec | kSecRW); + curRawOff += loadRawSize; + + std::uint32_t importRawOff = 0; + if (!importSectionData.empty()) { + importRawOff = curRawOff; + writeSec(".idata", static_cast(importSectionData.size()), importSectionRva, + static_cast(importSectionData.size()), curRawOff, kSecRW); + curRawOff += static_cast(importSectionData.size()); + } + + std::uint32_t relocRawOff = 0; + if (!relocSectionData.empty()) { + relocRawOff = curRawOff; + writeSec(".reloc", static_cast(relocSectionData.size()), relocSectionRva, + static_cast(relocSectionData.size()), curRawOff, kSecDiscard | kSecRO); + curRawOff += static_cast(relocSectionData.size()); + } + + const std::uint32_t stubRawOff = curRawOff; + writeSec(".entry", static_cast(stubData.size()), stubSectionRva, + static_cast(stubData.size()), stubRawOff, kSecExec); + + alignBuf(result, kFileAlignment); + + { + std::vector loadRaw(imageBuf.begin(), imageBuf.end()); + loadRaw.resize(loadRawSize, 0); + result.insert(result.end(), loadRaw.begin(), loadRaw.end()); + } + + if (!importSectionData.empty()) + result.insert(result.end(), importSectionData.begin(), importSectionData.end()); + + if (!relocSectionData.empty()) + result.insert(result.end(), relocSectionData.begin(), relocSectionData.end()); + + result.insert(result.end(), stubData.begin(), stubData.end()); + + return result; } } diff --git a/core/main.cpp b/core/main.cpp index ac8416809..424b6b2d2 100644 --- a/core/main.cpp +++ b/core/main.cpp @@ -21,12 +21,15 @@ #include #include #include +#include int main(const int argc, char* argv[]) { bool skipSyscallCheck = false; bool toIntel = false; bool skipUnusedNidFilter = false; bool writeRegistry = false; + bool toWindows = false; + std::string inputPath; std::string outputPath; std::string runPath = "$ORIGIN/libs"; @@ -47,6 +50,8 @@ int main(const int argc, char* argv[]) { return 1; } runPath = argv[++i]; + } else if (arg == "--windows") { + toWindows = true; } else if (inputPath.empty()) { inputPath = arg; } else if (outputPath.empty()) { @@ -58,7 +63,7 @@ int main(const int argc, char* argv[]) { } if (inputPath.empty() || outputPath.empty()) { - std::cerr << "Usage: relinker [--skip-syscall-check] [--to-intel] [--skip-unused-nid-filter] [--registry] [--rpath ] \n" + std::cerr << "Usage: relinker [--windows] [--skip-syscall-check] [--to-intel] [--skip-unused-nid-filter] [--registry] [--rpath ] \n" "Example: relinker input.elf output.elf\n"; return 1; } @@ -104,17 +109,31 @@ int main(const int argc, char* argv[]) { } auto byteWriter = std::make_shared(); - Elfpatcher::Linux::LinuxElfPatcher elfPatcher( - std::make_shared(), - std::make_shared( - std::make_shared(), + + std::shared_ptr patcher; + if (toWindows) { + patcher = std::make_shared( + std::make_shared(), + std::make_shared( + std::make_shared(), + byteWriter + ), + std::make_shared(byteWriter), byteWriter - ), - std::make_shared(byteWriter), - byteWriter - ); - auto patchedElf = elfPatcher.Patch(sourceBytes, result.OriginalHeaders, result.DynamicSection, result.OriginalPltGotVaddr, runPath); - fileWriter.Write(outputPath, patchedElf); + ); + } else { + patcher = std::make_shared( + std::make_shared(), + std::make_shared( + std::make_shared(), + byteWriter + ), + std::make_shared(byteWriter), + byteWriter + ); + } + auto patched = patcher->Patch(sourceBytes, result.OriginalHeaders, result.DynamicSection, result.OriginalPltGotVaddr, runPath); + fileWriter.Write(outputPath, patched); } catch (const Domain::RelinkerException& e) { std::cerr << "FAIL: " << e.what();