refactor(scanner): move scanner from relinker to separated module
This commit is contained in:
parent
9c7570176f
commit
88fca26a28
|
|
@ -9,6 +9,8 @@ add_executable(relinker
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/io/src/ByteWriter.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/io/src/FileReader.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/io/src/FileWriter.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/codegen/src/InstructionScanner.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/codegen/src/x86/X64InstructionDecoder.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/relinker/src/parsing/ElfReader.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/relinker/src/analysis/SyscallScanner.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/relinker/src/analysis/CallSiteResolver.cpp
|
||||
|
|
@ -21,5 +23,6 @@ target_include_directories(relinker PRIVATE
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/domain/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/elfpatcher/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/io/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/codegen/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/relinker/include
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef CODEGEN_CODEGENEXCEPTION_HPP
|
||||
#define CODEGEN_CODEGENEXCEPTION_HPP
|
||||
|
||||
#include <domain/Types.hpp>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace Codegen {
|
||||
|
||||
struct CodegenException : std::runtime_error {
|
||||
Domain::FileByteOffset FailureOffset;
|
||||
|
||||
explicit CodegenException(const std::string& message, const Domain::FileByteOffset failureOffset = 0)
|
||||
: std::runtime_error(message), FailureOffset(failureOffset) {}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
#ifndef CODEGEN_CODEGENTYPES_HPP
|
||||
#define CODEGEN_CODEGENTYPES_HPP
|
||||
|
||||
#include <domain/Types.hpp>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace Codegen {
|
||||
|
||||
struct DecodedInstruction {
|
||||
std::size_t Length;
|
||||
bool Valid;
|
||||
};
|
||||
|
||||
struct InstructionMatch {
|
||||
Domain::FileByteOffset Offset;
|
||||
std::size_t Length;
|
||||
};
|
||||
|
||||
struct RewriteRequest {
|
||||
Domain::FileByteOffset Offset;
|
||||
std::vector<std::uint8_t> NewBytes;
|
||||
};
|
||||
|
||||
struct AddressAdjustment {
|
||||
Domain::FileByteOffset OriginalOffset;
|
||||
Domain::FileByteOffset AdjustedOffset;
|
||||
std::int64_t Delta;
|
||||
};
|
||||
|
||||
struct RewriteResult {
|
||||
std::vector<std::uint8_t> Bytes;
|
||||
std::vector<AddressAdjustment> Adjustments;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef CODEGEN_IINSTRUCTIONDECODER_HPP
|
||||
#define CODEGEN_IINSTRUCTIONDECODER_HPP
|
||||
|
||||
#include <codegen/CodegenTypes.hpp>
|
||||
#include <cstdint>
|
||||
|
||||
namespace Codegen {
|
||||
|
||||
class IInstructionDecoder {
|
||||
public:
|
||||
virtual ~IInstructionDecoder() = default;
|
||||
|
||||
[[nodiscard]] virtual DecodedInstruction Decode(
|
||||
const std::uint8_t* data,
|
||||
std::size_t available
|
||||
) const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef CODEGEN_IINSTRUCTIONREWRITER_HPP
|
||||
#define CODEGEN_IINSTRUCTIONREWRITER_HPP
|
||||
|
||||
#include <codegen/CodegenTypes.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace Codegen {
|
||||
|
||||
class IInstructionRewriter {
|
||||
public:
|
||||
virtual ~IInstructionRewriter() = default;
|
||||
|
||||
[[nodiscard]] virtual RewriteResult Rewrite(
|
||||
const std::vector<std::uint8_t>& codeSection,
|
||||
const RewriteRequest& request
|
||||
) const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef CODEGEN_IINSTRUCTIONSCANNER_HPP
|
||||
#define CODEGEN_IINSTRUCTIONSCANNER_HPP
|
||||
|
||||
#include <codegen/CodegenTypes.hpp>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace Codegen {
|
||||
|
||||
class IInstructionScanner {
|
||||
public:
|
||||
virtual ~IInstructionScanner() = default;
|
||||
|
||||
[[nodiscard]] virtual std::vector<InstructionMatch> ScanCodeSection(
|
||||
const std::vector<std::uint8_t>& codeSection,
|
||||
Domain::FileByteOffset codeSectionOffset,
|
||||
Domain::FileByteOffset codeSectionSize
|
||||
) const = 0;
|
||||
};
|
||||
|
||||
std::unique_ptr<IInstructionScanner> MakeInstructionScanner();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef CODEGEN_X86_X64INSTRUCTIONDECODER_HPP
|
||||
#define CODEGEN_X86_X64INSTRUCTIONDECODER_HPP
|
||||
|
||||
#include <codegen/IInstructionDecoder.hpp>
|
||||
|
||||
namespace Codegen {
|
||||
|
||||
class X64InstructionDecoder : public IInstructionDecoder {
|
||||
public:
|
||||
[[nodiscard]] DecodedInstruction Decode(
|
||||
const std::uint8_t* data,
|
||||
std::size_t available
|
||||
) const override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef CODEGEN_X86_X64INSTRUCTIONREWRITER_HPP
|
||||
#define CODEGEN_X86_X64INSTRUCTIONREWRITER_HPP
|
||||
|
||||
#include <codegen/IInstructionRewriter.hpp>
|
||||
|
||||
namespace Codegen {
|
||||
|
||||
class X64InstructionRewriter : public IInstructionRewriter {
|
||||
public:
|
||||
[[nodiscard]] RewriteResult Rewrite(
|
||||
const std::vector<std::uint8_t>& codeSection,
|
||||
const RewriteRequest& request
|
||||
) const override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
#include <codegen/IInstructionScanner.hpp>
|
||||
#include <codegen/x86/X64InstructionDecoder.hpp>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
namespace Codegen {
|
||||
|
||||
class InstructionScanner : public IInstructionScanner {
|
||||
public:
|
||||
[[nodiscard]] std::vector<InstructionMatch> ScanCodeSection(
|
||||
const std::vector<std::uint8_t>& codeSection,
|
||||
Domain::FileByteOffset codeSectionOffset,
|
||||
Domain::FileByteOffset codeSectionSize
|
||||
) const override;
|
||||
};
|
||||
|
||||
std::vector<InstructionMatch> InstructionScanner::ScanCodeSection(
|
||||
const std::vector<std::uint8_t>& codeSection,
|
||||
const Domain::FileByteOffset codeSectionOffset,
|
||||
const Domain::FileByteOffset codeSectionSize
|
||||
) const {
|
||||
const std::size_t limit = std::min(codeSection.size(), static_cast<std::size_t>(codeSectionSize));
|
||||
|
||||
std::vector<InstructionMatch> matches;
|
||||
std::size_t i = 0;
|
||||
|
||||
while (i < limit) {
|
||||
X64InstructionDecoder decoder;
|
||||
const std::uint8_t* cursor = codeSection.data() + i;
|
||||
const std::size_t available = limit - i;
|
||||
|
||||
const auto decoded = decoder.Decode(cursor, available);
|
||||
|
||||
if (!decoded.Valid || decoded.Length == 0) {
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
matches.push_back({codeSectionOffset + i, decoded.Length});
|
||||
|
||||
i += decoded.Length;
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
std::unique_ptr<IInstructionScanner> MakeInstructionScanner() {
|
||||
return std::make_unique<InstructionScanner>();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,183 @@
|
|||
#include <codegen/x86/X64InstructionDecoder.hpp>
|
||||
|
||||
namespace Codegen {
|
||||
|
||||
DecodedInstruction X64InstructionDecoder::Decode(const std::uint8_t* data, std::size_t available) const {
|
||||
std::size_t pos = 0;
|
||||
bool rexPresent = false;
|
||||
std::uint8_t rex = 0;
|
||||
bool operandSizeOverride = false;
|
||||
|
||||
while (pos < available) {
|
||||
const std::uint8_t b = data[pos];
|
||||
|
||||
if (b == 0xF0 || b == 0xF2 || b == 0xF3 ||
|
||||
b == 0x2E || b == 0x36 || b == 0x3E || b == 0x26 ||
|
||||
b == 0x64 || b == 0x65) {
|
||||
pos += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (b == 0x66) {
|
||||
operandSizeOverride = true;
|
||||
pos += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (b == 0x67) {
|
||||
pos += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (pos < available && data[pos] >= 0x40 && data[pos] <= 0x4F) {
|
||||
rexPresent = true;
|
||||
rex = data[pos];
|
||||
pos += 1;
|
||||
}
|
||||
|
||||
if (pos >= available) {
|
||||
return {1, false};
|
||||
}
|
||||
|
||||
std::uint8_t opcode = data[pos];
|
||||
pos += 1;
|
||||
bool twoByteOpcode = false;
|
||||
|
||||
if (opcode == 0x0F) {
|
||||
if (pos >= available) {
|
||||
return {1, false};
|
||||
}
|
||||
twoByteOpcode = true;
|
||||
opcode = data[pos];
|
||||
pos += 1;
|
||||
}
|
||||
|
||||
bool hasModRm = false;
|
||||
std::size_t immediateSize = 0;
|
||||
|
||||
if (!twoByteOpcode) {
|
||||
if ((opcode >= 0x00 && opcode <= 0x03) || (opcode >= 0x08 && opcode <= 0x0B) ||
|
||||
(opcode >= 0x10 && opcode <= 0x13) || (opcode >= 0x18 && opcode <= 0x1B) ||
|
||||
(opcode >= 0x20 && opcode <= 0x23) || (opcode >= 0x28 && opcode <= 0x2B) ||
|
||||
(opcode >= 0x30 && opcode <= 0x33) || (opcode >= 0x38 && opcode <= 0x3B) ||
|
||||
opcode == 0x62 || opcode == 0x63 ||
|
||||
(opcode >= 0x84 && opcode <= 0x8F) ||
|
||||
opcode == 0xC0 || opcode == 0xC1 ||
|
||||
opcode == 0xC4 || opcode == 0xC5 || opcode == 0xC6 || opcode == 0xC7 ||
|
||||
opcode == 0xD0 || opcode == 0xD1 || opcode == 0xD2 || opcode == 0xD3 ||
|
||||
opcode == 0xF6 || opcode == 0xF7 ||
|
||||
opcode == 0xFE || opcode == 0xFF ||
|
||||
(opcode >= 0x88 && opcode <= 0x8B)) {
|
||||
hasModRm = true;
|
||||
}
|
||||
|
||||
if (opcode == 0xC6 || opcode == 0x80 ||
|
||||
opcode == 0x04 || opcode == 0x0C ||
|
||||
opcode == 0x14 || opcode == 0x1C ||
|
||||
opcode == 0x24 || opcode == 0x2C ||
|
||||
opcode == 0x34 || opcode == 0x3C ||
|
||||
(opcode >= 0xB0 && opcode <= 0xB7) ||
|
||||
opcode == 0x6A ||
|
||||
opcode == 0xA8) {
|
||||
immediateSize = 1;
|
||||
} else if (opcode == 0xC7 || opcode == 0x81 ||
|
||||
opcode == 0x05 || opcode == 0x0D ||
|
||||
opcode == 0x15 || opcode == 0x1D ||
|
||||
opcode == 0x25 || opcode == 0x2D ||
|
||||
opcode == 0x35 || opcode == 0x3D ||
|
||||
opcode == 0x68 ||
|
||||
opcode == 0xA9 ||
|
||||
(opcode >= 0xB8 && opcode <= 0xBF)) {
|
||||
if (opcode >= 0xB8 && opcode <= 0xBF) {
|
||||
immediateSize = (rexPresent && (rex & 0x08) != 0) ? 8 : (operandSizeOverride ? 2 : 4);
|
||||
} else {
|
||||
immediateSize = operandSizeOverride ? 2 : 4;
|
||||
}
|
||||
} else if (opcode == 0x83) {
|
||||
immediateSize = 1;
|
||||
}
|
||||
|
||||
if (opcode >= 0x70 && opcode <= 0x7F) {
|
||||
immediateSize = 1;
|
||||
}
|
||||
|
||||
if (opcode == 0xE8 || opcode == 0xE9) {
|
||||
immediateSize = 4;
|
||||
}
|
||||
|
||||
if (opcode == 0xEB) {
|
||||
immediateSize = 1;
|
||||
}
|
||||
} else {
|
||||
if (opcode >= 0x80 && opcode <= 0x8F) {
|
||||
immediateSize = 4;
|
||||
} else if (opcode == 0xBA) {
|
||||
hasModRm = true;
|
||||
immediateSize = 1;
|
||||
} else if (opcode == 0xA4 || opcode == 0xAC) {
|
||||
immediateSize = 1;
|
||||
} else if ((opcode >= 0x40 && opcode <= 0x4F) ||
|
||||
(opcode >= 0xA3 && opcode <= 0xAB) ||
|
||||
(opcode >= 0xB0 && opcode <= 0xB7) ||
|
||||
(opcode >= 0xBC && opcode <= 0xBF) ||
|
||||
(opcode >= 0x10 && opcode <= 0x17) ||
|
||||
(opcode >= 0x28 && opcode <= 0x2F) ||
|
||||
(opcode >= 0x38 && opcode <= 0x3A) ||
|
||||
(opcode >= 0x54 && opcode <= 0x77) ||
|
||||
(opcode >= 0xD0 && opcode <= 0xFE) ||
|
||||
opcode == 0x1F) {
|
||||
hasModRm = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasModRm) {
|
||||
if (pos + immediateSize > available) {
|
||||
return {pos + immediateSize, false};
|
||||
}
|
||||
return {pos + immediateSize, true};
|
||||
}
|
||||
|
||||
if (pos >= available) {
|
||||
return {pos, false};
|
||||
}
|
||||
|
||||
const std::uint8_t modrm = data[pos];
|
||||
pos += 1;
|
||||
|
||||
const std::uint8_t mod = static_cast<std::uint8_t>((modrm >> 6) & 0x03);
|
||||
const std::uint8_t rm = static_cast<std::uint8_t>(modrm & 0x07);
|
||||
|
||||
if (mod != 0x03 && rm == 0x04) {
|
||||
if (pos >= available) {
|
||||
return {pos, false};
|
||||
}
|
||||
const std::uint8_t sib = data[pos];
|
||||
const std::uint8_t base = static_cast<std::uint8_t>(sib & 0x07);
|
||||
pos += 1;
|
||||
|
||||
if (mod == 0x00 && base == 0x05) {
|
||||
pos += 4;
|
||||
}
|
||||
}
|
||||
|
||||
if (mod == 0x01) {
|
||||
pos += 1;
|
||||
} else if (mod == 0x02) {
|
||||
pos += 4;
|
||||
} else if (mod == 0x00 && rm == 0x05) {
|
||||
pos += 4;
|
||||
}
|
||||
|
||||
pos += immediateSize;
|
||||
|
||||
if (pos > available) {
|
||||
return {pos, false};
|
||||
}
|
||||
|
||||
return {pos, true};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
#include <relinker/analysis/SyscallScanner.hpp>
|
||||
#include <codegen/IInstructionScanner.hpp>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
||||
|
|
@ -13,192 +14,6 @@ static constexpr std::uint8_t SYSENTER_BYTE1 = 0x34;
|
|||
static constexpr std::uint8_t SYSRET_BYTE0 = 0x0F;
|
||||
static constexpr std::uint8_t SYSRET_BYTE1 = 0x07;
|
||||
|
||||
class X64InstructionLengthDecoder {
|
||||
public:
|
||||
struct DecodedInstruction {
|
||||
std::size_t Length;
|
||||
bool Valid;
|
||||
};
|
||||
|
||||
[[nodiscard]] DecodedInstruction Decode(const std::uint8_t* data, std::size_t available) const {
|
||||
std::size_t pos = 0;
|
||||
bool rexPresent = false;
|
||||
std::uint8_t rex = 0;
|
||||
bool operandSizeOverride = false;
|
||||
|
||||
while (pos < available) {
|
||||
const std::uint8_t b = data[pos];
|
||||
|
||||
if (b == 0xF0 || b == 0xF2 || b == 0xF3 ||
|
||||
b == 0x2E || b == 0x36 || b == 0x3E || b == 0x26 ||
|
||||
b == 0x64 || b == 0x65) {
|
||||
pos += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (b == 0x66) {
|
||||
operandSizeOverride = true;
|
||||
pos += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (b == 0x67) {
|
||||
pos += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (pos < available && data[pos] >= 0x40 && data[pos] <= 0x4F) {
|
||||
rexPresent = true;
|
||||
rex = data[pos];
|
||||
pos += 1;
|
||||
}
|
||||
|
||||
if (pos >= available) {
|
||||
return {1, false};
|
||||
}
|
||||
|
||||
std::uint8_t opcode = data[pos];
|
||||
pos += 1;
|
||||
bool twoByteOpcode = false;
|
||||
|
||||
if (opcode == 0x0F) {
|
||||
if (pos >= available) {
|
||||
return {1, false};
|
||||
}
|
||||
twoByteOpcode = true;
|
||||
opcode = data[pos];
|
||||
pos += 1;
|
||||
}
|
||||
|
||||
bool hasModRm = false;
|
||||
std::size_t immediateSize = 0;
|
||||
|
||||
if (!twoByteOpcode) {
|
||||
if ((opcode >= 0x00 && opcode <= 0x03) || (opcode >= 0x08 && opcode <= 0x0B) ||
|
||||
(opcode >= 0x10 && opcode <= 0x13) || (opcode >= 0x18 && opcode <= 0x1B) ||
|
||||
(opcode >= 0x20 && opcode <= 0x23) || (opcode >= 0x28 && opcode <= 0x2B) ||
|
||||
(opcode >= 0x30 && opcode <= 0x33) || (opcode >= 0x38 && opcode <= 0x3B) ||
|
||||
opcode == 0x62 || opcode == 0x63 ||
|
||||
(opcode >= 0x84 && opcode <= 0x8F) ||
|
||||
opcode == 0xC0 || opcode == 0xC1 ||
|
||||
opcode == 0xC4 || opcode == 0xC5 || opcode == 0xC6 || opcode == 0xC7 ||
|
||||
opcode == 0xD0 || opcode == 0xD1 || opcode == 0xD2 || opcode == 0xD3 ||
|
||||
opcode == 0xF6 || opcode == 0xF7 ||
|
||||
opcode == 0xFE || opcode == 0xFF ||
|
||||
(opcode >= 0x88 && opcode <= 0x8B)) {
|
||||
hasModRm = true;
|
||||
}
|
||||
|
||||
if (opcode == 0xC6 || opcode == 0x80 ||
|
||||
opcode == 0x04 || opcode == 0x0C ||
|
||||
opcode == 0x14 || opcode == 0x1C ||
|
||||
opcode == 0x24 || opcode == 0x2C ||
|
||||
opcode == 0x34 || opcode == 0x3C ||
|
||||
(opcode >= 0xB0 && opcode <= 0xB7) ||
|
||||
opcode == 0x6A ||
|
||||
opcode == 0xA8) {
|
||||
immediateSize = 1;
|
||||
} else if (opcode == 0xC7 || opcode == 0x81 ||
|
||||
opcode == 0x05 || opcode == 0x0D ||
|
||||
opcode == 0x15 || opcode == 0x1D ||
|
||||
opcode == 0x25 || opcode == 0x2D ||
|
||||
opcode == 0x35 || opcode == 0x3D ||
|
||||
opcode == 0x68 ||
|
||||
opcode == 0xA9 ||
|
||||
(opcode >= 0xB8 && opcode <= 0xBF)) {
|
||||
if (opcode >= 0xB8 && opcode <= 0xBF) {
|
||||
immediateSize = (rexPresent && (rex & 0x08) != 0) ? 8 : (operandSizeOverride ? 2 : 4);
|
||||
} else {
|
||||
immediateSize = operandSizeOverride ? 2 : 4;
|
||||
}
|
||||
} else if (opcode == 0x83) {
|
||||
immediateSize = 1;
|
||||
}
|
||||
|
||||
if (opcode >= 0x70 && opcode <= 0x7F) {
|
||||
immediateSize = 1;
|
||||
}
|
||||
|
||||
if (opcode == 0xE8 || opcode == 0xE9) {
|
||||
immediateSize = 4;
|
||||
}
|
||||
|
||||
if (opcode == 0xEB) {
|
||||
immediateSize = 1;
|
||||
}
|
||||
} else {
|
||||
if (opcode >= 0x80 && opcode <= 0x8F) {
|
||||
immediateSize = 4;
|
||||
} else if (opcode == 0xBA) {
|
||||
hasModRm = true;
|
||||
immediateSize = 1;
|
||||
} else if (opcode == 0xA4 || opcode == 0xAC) {
|
||||
immediateSize = 1;
|
||||
} else if ((opcode >= 0x40 && opcode <= 0x4F) ||
|
||||
(opcode >= 0xA3 && opcode <= 0xAB) ||
|
||||
(opcode >= 0xB0 && opcode <= 0xB7) ||
|
||||
(opcode >= 0xBC && opcode <= 0xBF) ||
|
||||
(opcode >= 0x10 && opcode <= 0x17) ||
|
||||
(opcode >= 0x28 && opcode <= 0x2F) ||
|
||||
(opcode >= 0x38 && opcode <= 0x3A) ||
|
||||
(opcode >= 0x54 && opcode <= 0x77) ||
|
||||
(opcode >= 0xD0 && opcode <= 0xFE) ||
|
||||
opcode == 0x1F) {
|
||||
hasModRm = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasModRm) {
|
||||
if (pos + immediateSize > available) {
|
||||
return {pos + immediateSize, false};
|
||||
}
|
||||
return {pos + immediateSize, true};
|
||||
}
|
||||
|
||||
if (pos >= available) {
|
||||
return {pos, false};
|
||||
}
|
||||
|
||||
const std::uint8_t modrm = data[pos];
|
||||
pos += 1;
|
||||
|
||||
const std::uint8_t mod = static_cast<std::uint8_t>((modrm >> 6) & 0x03);
|
||||
const std::uint8_t rm = static_cast<std::uint8_t>(modrm & 0x07);
|
||||
|
||||
if (mod != 0x03 && rm == 0x04) {
|
||||
if (pos >= available) {
|
||||
return {pos, false};
|
||||
}
|
||||
const std::uint8_t sib = data[pos];
|
||||
const std::uint8_t base = static_cast<std::uint8_t>(sib & 0x07);
|
||||
pos += 1;
|
||||
|
||||
if (mod == 0x00 && base == 0x05) {
|
||||
pos += 4;
|
||||
}
|
||||
}
|
||||
|
||||
if (mod == 0x01) {
|
||||
pos += 1;
|
||||
} else if (mod == 0x02) {
|
||||
pos += 4;
|
||||
} else if (mod == 0x00 && rm == 0x05) {
|
||||
pos += 4;
|
||||
}
|
||||
|
||||
pos += immediateSize;
|
||||
|
||||
if (pos > available) {
|
||||
return {pos, false};
|
||||
}
|
||||
|
||||
return {pos, true};
|
||||
}
|
||||
};
|
||||
|
||||
class SyscallScanner : public ISyscallScanner {
|
||||
public:
|
||||
void ScanCodeSectionForSyscalls(
|
||||
|
|
@ -213,16 +28,15 @@ void SyscallScanner::ScanCodeSectionForSyscalls(
|
|||
const FileByteOffset codeSectionSize) {
|
||||
const std::size_t limit = std::min(codeSection.size(), static_cast<std::size_t>(codeSectionSize));
|
||||
|
||||
std::size_t i = 0;
|
||||
const auto scanner = Codegen::MakeInstructionScanner();
|
||||
const auto matches = scanner->ScanCodeSection(codeSection, codeSectionOffset, codeSectionSize);
|
||||
|
||||
while (i < limit) {
|
||||
X64InstructionLengthDecoder decoder;
|
||||
const std::uint8_t* cursor = codeSection.data() + i;
|
||||
const std::size_t available = limit - i;
|
||||
for (const auto& [Offset, Length] : matches) {
|
||||
const std::size_t i = Offset - codeSectionOffset;
|
||||
|
||||
if (available >= 2) {
|
||||
const std::uint8_t b0 = cursor[0];
|
||||
const std::uint8_t b1 = cursor[1];
|
||||
if (i + 1 < limit) {
|
||||
const std::uint8_t b0 = codeSection[i];
|
||||
const std::uint8_t b1 = codeSection[i + 1];
|
||||
|
||||
const bool isSyscall = (b0 == SYSCALL_BYTE0 && b1 == SYSCALL_BYTE1);
|
||||
const bool isInt80 = (b0 == INT80_BYTE0 && b1 == INT80_BYTE1);
|
||||
|
|
@ -230,21 +44,12 @@ void SyscallScanner::ScanCodeSectionForSyscalls(
|
|||
const bool isSysret = (b0 == SYSRET_BYTE0 && b1 == SYSRET_BYTE1);
|
||||
|
||||
if (isSyscall || isInt80 || isSysenter || isSysret) {
|
||||
FileByteOffset instrOffset = codeSectionOffset + i;
|
||||
const FileByteOffset instrOffset = codeSectionOffset + i;
|
||||
std::ostringstream msg;
|
||||
msg << "Forbidden syscall instruction at code offset 0x" << std::hex << instrOffset;
|
||||
throw RelinkerException(msg.str(), instrOffset);
|
||||
}
|
||||
}
|
||||
|
||||
const auto decoded = decoder.Decode(cursor, available);
|
||||
|
||||
if (!decoded.Valid || decoded.Length == 0) {
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
i += decoded.Length;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue