diff --git a/patcher/CMakeLists.txt b/patcher/CMakeLists.txt index 61a04bbc..6e23debf 100644 --- a/patcher/CMakeLists.txt +++ b/patcher/CMakeLists.txt @@ -4,4 +4,5 @@ add_executable(patcher patcher.cpp) target_link_libraries(patcher PRIVATE coffi CLI11 spdlog) target_compile_options(patcher PRIVATE -DSRC_OBJECT="$") add_dependencies(patcher ref) +target_compile_features(patcher PRIVATE cxx_std_20) diff --git a/patcher/patcher.cpp b/patcher/patcher.cpp index d533fa2b..8f1726e0 100644 --- a/patcher/patcher.cpp +++ b/patcher/patcher.cpp @@ -178,6 +178,134 @@ int main(int argc, char *argv[]) { // Copy our code into the null space std::memcpy(newTextData.data() + injectionOffset, mainCode, mainSize); + // Now handle relocations - resolve imports and copy constants to .rdata + spdlog::info("Processing relocations..."); + + // Find .rdata section for constants + COFFI::section* rdataSection = nullptr; + for (auto& section : peSections) { + if (section->get_name() == ".rdata") { + rdataSection = section; + break; + } + } + + if (!rdataSection) { + spdlog::error("Could not find .rdata section in PE file"); + return 1; + } + + // Find available space in .rdata section (similar to .text) + auto rdataData = rdataSection->get_data(); + uint32_t rdataSize = rdataSection->get_data_size(); + uint32_t rdataAvailableSpace = 0; + + for (int32_t i = rdataSize - 1; i >= 0; i--) { + if (reinterpret_cast(rdataData)[i] == 0x00) { + rdataAvailableSpace++; + } else { + break; + } + } + + spdlog::info("Found {} bytes of available space in .rdata section", rdataAvailableSpace); + + // Create rdata copy for modifications + std::vector newRdataData(reinterpret_cast(rdataData), + reinterpret_cast(rdataData) + rdataSize); + uint32_t rdataInjectionOffset = rdataSize - rdataAvailableSpace; + uint32_t rdataCurrentOffset = rdataInjectionOffset; + + // Get import table information for resolving __imp_ symbols + auto& directories = peReader.get_directories(); + uint32_t importRVA = 0; + if (directories.size() > 1) { + importRVA = directories[1]->get_virtual_address(); // Import table is directory entry 1 + } + + // Process each relocation + for (auto& reloc : sectionRelocations) { + if (reloc.get_type() != 6) continue; // Only handle type 6 (IMAGE_REL_I386_DIR32) + + uint32_t relocOffset = reloc.get_virtual_address(); + std::string symbolName = reloc.get_symbol(); + uint32_t resolvedAddress = 0; + + spdlog::info("Processing relocation at offset 0x{:x} for symbol: {}", relocOffset, symbolName); + + if (symbolName.starts_with("__imp_")) { + // This is an import symbol - find it in the PE's import table + std::string functionName = symbolName.substr(6); // Remove "__imp_" prefix + + // Remove @N suffix for stdcall functions + size_t atPos = functionName.find('@'); + if (atPos != std::string::npos) { + functionName = functionName.substr(0, atPos); + } + + spdlog::info("Looking for import function: {}", functionName); + + // For now, we'll need to implement import table parsing + // This is a placeholder - you'd need to parse the import table to find the actual IAT address + spdlog::warn("Import resolution not fully implemented yet for: {}", functionName); + resolvedAddress = 0x12345678; // Placeholder + + } else if (symbolName.starts_with("??_C@")) { + // This is a string constant - find it in the object file and copy to .rdata + COFFI::symbol* constSymbol = nullptr; + for (auto& sym : symbols) { + if (sym.get_name() == symbolName) { + constSymbol = &sym; + break; + } + } + + if (constSymbol) { + // Get the string data from the object file + auto constSection = sections[constSymbol->get_section_number() - 1]; + auto constData = constSection->get_data(); + uint32_t constOffset = constSymbol->get_value(); + + // Find the string length (null-terminated) + uint32_t stringLen = 0; + while (constData[constOffset + stringLen] != 0) { + stringLen++; + } + stringLen++; // Include null terminator + + if (rdataCurrentOffset + stringLen > rdataSize) { + spdlog::error("Not enough space in .rdata for string constant"); + return 1; + } + + // Copy string to .rdata + std::memcpy(newRdataData.data() + rdataCurrentOffset, + constData + constOffset, stringLen); + + // Calculate the new address + uint32_t rdataRVA = rdataSection->get_virtual_address(); + resolvedAddress = imageBase + rdataRVA + rdataCurrentOffset; + + spdlog::info("Copied string constant '{}' to .rdata at RVA 0x{:x} (VA: 0x{:x})", + std::string(constData + constOffset), + rdataRVA + rdataCurrentOffset, resolvedAddress); + + rdataCurrentOffset += stringLen; + } + } + + // Apply the relocation to the injected code + if (resolvedAddress != 0) { + uint32_t patchOffset = injectionOffset + relocOffset; + *reinterpret_cast(newTextData.data() + patchOffset) = resolvedAddress; + spdlog::info("Applied relocation: patched offset 0x{:x} with address 0x{:x}", + patchOffset, resolvedAddress); + } + } + + // Update both sections + rdataSection->set_data(reinterpret_cast(newRdataData.data()), newRdataData.size()); + // Update the .text section with modified data (same size) textSection->set_data(reinterpret_cast(newTextData.data()), newTextData.size());