feat(relinker): unused nid filter fix + cli update
This commit is contained in:
parent
febac8978e
commit
77cfe65b9c
|
|
@ -41,6 +41,7 @@ enum class ControlFlowKind : std::uint8_t {
|
|||
Return,
|
||||
IndirectJump,
|
||||
IndirectCall,
|
||||
Trap,
|
||||
};
|
||||
|
||||
struct DecodedInstructionInfo {
|
||||
|
|
|
|||
|
|
@ -440,6 +440,10 @@ DecodedInstructionInfo X64InstructionDecoder::DecodeInstruction(
|
|||
}
|
||||
}
|
||||
} else {
|
||||
if (op == 0x0B) {
|
||||
info.FlowKind = ControlFlowKind::Trap;
|
||||
return info;
|
||||
}
|
||||
if (op >= TwoByteJccRel32Min && op <= TwoByteJccRel32Max) {
|
||||
std::int32_t disp = 0;
|
||||
std::memcpy(&disp, data + pos, 4);
|
||||
|
|
|
|||
|
|
@ -26,7 +26,8 @@
|
|||
int main(const int argc, char* argv[]) {
|
||||
bool skipSyscallCheck = false;
|
||||
bool toIntel = false;
|
||||
bool skipUnusedNidFilter = false;
|
||||
std::uint32_t unusedFilterLevel = 1;
|
||||
bool unusedFilterSpecified = false;
|
||||
bool writeRegistry = false;
|
||||
bool toWindows = false;
|
||||
|
||||
|
|
@ -40,8 +41,14 @@ int main(const int argc, char* argv[]) {
|
|||
skipSyscallCheck = true;
|
||||
} else if (arg == "--to-intel") {
|
||||
toIntel = true;
|
||||
} else if (arg == "--skip-unused-nid-filter") {
|
||||
skipUnusedNidFilter = true;
|
||||
} else if (arg.rfind("unused-filter=", 0) == 0) {
|
||||
const std::string value = arg.substr(14);
|
||||
if (unusedFilterSpecified || value.size() != 1 || value[0] < '0' || value[0] > '2') {
|
||||
std::cerr << "FAIL: unused-filter must be specified once with a value of 0, 1 or 2\n";
|
||||
return 1;
|
||||
}
|
||||
unusedFilterLevel = static_cast<std::uint32_t>(value[0] - '0');
|
||||
unusedFilterSpecified = true;
|
||||
} else if (arg == "--registry") {
|
||||
writeRegistry = true;
|
||||
} else if (arg == "--rpath") {
|
||||
|
|
@ -52,6 +59,9 @@ int main(const int argc, char* argv[]) {
|
|||
runPath = argv[++i];
|
||||
} else if (arg == "--windows") {
|
||||
toWindows = true;
|
||||
} else if (arg.rfind("--", 0) == 0 || arg == "unused-filter") {
|
||||
std::cerr << "FAIL: unknown option: " << arg << "\n";
|
||||
return 1;
|
||||
} else if (inputPath.empty()) {
|
||||
inputPath = arg;
|
||||
} else if (outputPath.empty()) {
|
||||
|
|
@ -63,7 +73,7 @@ int main(const int argc, char* argv[]) {
|
|||
}
|
||||
|
||||
if (inputPath.empty() || outputPath.empty()) {
|
||||
std::cerr << "Usage: relinker [--windows] [--skip-syscall-check] [--to-intel] [--skip-unused-nid-filter] [--registry] [--rpath <path>] <input.elf> <output.elf>\n"
|
||||
std::cerr << "Usage: relinker [--windows] [--skip-syscall-check] [--to-intel] [unused-filter=0|1|2] [--registry] [--rpath <path>] <input.elf> <output.elf>\n"
|
||||
"Example: relinker input.elf output.elf\n";
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -75,6 +85,7 @@ int main(const int argc, char* argv[]) {
|
|||
auto sourceBytes = fileReader.Read(inputPath);
|
||||
|
||||
if (toIntel) {
|
||||
std::cout << "Mode: Intel instruction conversion; system unchanged; unused-filter=" << unusedFilterLevel << " (not applied)\n";
|
||||
const Relinker::ElfReader elfReader(sourceBytes);
|
||||
const auto converter = Codegen::MakeAmd64OnlyConverter();
|
||||
auto result = converter->Convert(std::move(sourceBytes), elfReader.ReadCodeSegments());
|
||||
|
|
@ -96,9 +107,10 @@ int main(const int argc, char* argv[]) {
|
|||
std::make_shared<Relinker::ValidationPolicy>(),
|
||||
std::make_shared<Relinker::SysVDynamicSectionBuilder>(),
|
||||
Relinker::MakeUnusedNidFilter(),
|
||||
!skipUnusedNidFilter
|
||||
unusedFilterLevel
|
||||
);
|
||||
|
||||
std::cout << "System: " << (toWindows ? "Windows" : "Linux") << "; unused-filter=" << unusedFilterLevel << "\n";
|
||||
auto result = pipeline->Relink(sourceBytes);
|
||||
|
||||
if (writeRegistry) {
|
||||
|
|
@ -126,6 +138,7 @@ int main(const int argc, char* argv[]) {
|
|||
}
|
||||
auto patched = patcher->Patch(sourceBytes, result.OriginalHeaders, result.DynamicSection, result.OriginalPltGotVaddr, runPath);
|
||||
fileWriter.Write(outputPath, patched);
|
||||
std::cout << "OK: " << result.RegistryEntries.size() << " NID references processed; output written\n";
|
||||
|
||||
} catch (const Domain::RelinkerException& e) {
|
||||
std::cerr << "FAIL: " << e.what();
|
||||
|
|
|
|||
|
|
@ -14,15 +14,7 @@ namespace Relinker {
|
|||
|
||||
class RelinkerPipeline : public IRelinkerPipeline {
|
||||
public:
|
||||
RelinkerPipeline(
|
||||
std::shared_ptr<IElfReader> elfReader,
|
||||
std::shared_ptr<ISyscallScanner> syscallScanner,
|
||||
std::shared_ptr<ICallSiteResolver> callSiteResolver,
|
||||
std::shared_ptr<IValidationPolicy> validationPolicy,
|
||||
std::shared_ptr<ISysVDynamicSectionBuilder> dynamicSectionBuilder,
|
||||
std::shared_ptr<IUnusedNidFilter> unusedNidFilter,
|
||||
bool filterUnusedNids
|
||||
);
|
||||
RelinkerPipeline(std::shared_ptr<IElfReader> elfReader, std::shared_ptr<ISyscallScanner> syscallScanner, std::shared_ptr<ICallSiteResolver> callSiteResolver, std::shared_ptr<IValidationPolicy> validationPolicy, std::shared_ptr<ISysVDynamicSectionBuilder> dynamicSectionBuilder, std::shared_ptr<IUnusedNidFilter> unusedNidFilter, std::uint32_t unusedFilterLevel);
|
||||
|
||||
RelinkResult Relink(const std::vector<std::uint8_t>& sourceElf) override;
|
||||
|
||||
|
|
@ -33,7 +25,7 @@ private:
|
|||
std::shared_ptr<IValidationPolicy> _validationPolicy;
|
||||
std::shared_ptr<ISysVDynamicSectionBuilder> _dynamicSectionBuilder;
|
||||
std::shared_ptr<IUnusedNidFilter> _unusedNidFilter;
|
||||
bool _filterUnusedNids;
|
||||
std::uint32_t unusedFilterLevel;
|
||||
|
||||
static constexpr std::uint32_t PT_LOAD = 1;
|
||||
static constexpr std::uint32_t PT_DYNAMIC = 2;
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@ std::unique_ptr<IControlFlowGraph> BuildControlFlowGraph(
|
|||
break;
|
||||
case Return:
|
||||
case IndirectJump:
|
||||
case Trap:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,22 +6,17 @@
|
|||
|
||||
namespace Relinker {
|
||||
|
||||
RelinkerPipeline::RelinkerPipeline(
|
||||
std::shared_ptr<IElfReader> elfReader,
|
||||
std::shared_ptr<ISyscallScanner> syscallScanner,
|
||||
std::shared_ptr<ICallSiteResolver> callSiteResolver,
|
||||
std::shared_ptr<IValidationPolicy> validationPolicy,
|
||||
std::shared_ptr<ISysVDynamicSectionBuilder> dynamicSectionBuilder,
|
||||
std::shared_ptr<IUnusedNidFilter> unusedNidFilter,
|
||||
bool filterUnusedNids)
|
||||
RelinkerPipeline::RelinkerPipeline(std::shared_ptr<IElfReader> elfReader, std::shared_ptr<ISyscallScanner> syscallScanner, std::shared_ptr<ICallSiteResolver> callSiteResolver, std::shared_ptr<IValidationPolicy> validationPolicy, std::shared_ptr<ISysVDynamicSectionBuilder> dynamicSectionBuilder, std::shared_ptr<IUnusedNidFilter> unusedNidFilter, std::uint32_t unusedFilterLevel)
|
||||
: _elfReader(std::move(elfReader))
|
||||
, _syscallScanner(std::move(syscallScanner))
|
||||
, _callSiteResolver(std::move(callSiteResolver))
|
||||
, _validationPolicy(std::move(validationPolicy))
|
||||
, _dynamicSectionBuilder(std::move(dynamicSectionBuilder))
|
||||
, _unusedNidFilter(std::move(unusedNidFilter))
|
||||
, _filterUnusedNids(filterUnusedNids)
|
||||
{}
|
||||
, unusedFilterLevel(unusedFilterLevel)
|
||||
{
|
||||
if (unusedFilterLevel > 2) throw RelinkerException("Unused NID filter level must be 0, 1 or 2");
|
||||
}
|
||||
|
||||
std::string RelinkerPipeline::_relocationTypeName(std::uint32_t type) {
|
||||
switch (type) {
|
||||
|
|
@ -201,7 +196,10 @@ RelinkResult RelinkerPipeline::Relink(const std::vector<std::uint8_t>& sourceElf
|
|||
|
||||
static constexpr std::uint32_t R_X86_64_JUMP_SLOT = 7;
|
||||
|
||||
if (_filterUnusedNids) {
|
||||
const std::size_t originalNidCount = nidRefs.size();
|
||||
std::cout << "NID input: " << originalNidCount << " references\n";
|
||||
|
||||
if (unusedFilterLevel != 0) {
|
||||
std::vector<NidReference> pltRefs;
|
||||
std::vector<NidReference> nonPltRefs;
|
||||
for (const auto& ref : nidRefs) {
|
||||
|
|
@ -211,14 +209,25 @@ RelinkResult RelinkerPipeline::Relink(const std::vector<std::uint8_t>& sourceElf
|
|||
nonPltRefs.push_back(ref);
|
||||
}
|
||||
|
||||
std::cout << "PLT preservation: " << pltRefs.size() << " -> " << pltRefs.size() << "; filtered=0\n";
|
||||
const std::size_t nonPltCount = nonPltRefs.size();
|
||||
nonPltRefs = _unusedNidFilter->Filter(nonPltRefs, raw, textSection, textVAddr);
|
||||
if (nonPltRefs.size() > nonPltCount) throw RelinkerException("Unused NID filter increased the reference count");
|
||||
std::cout << "CFG/GOT filtering: " << nonPltCount << " -> " << nonPltRefs.size() << "; filtered=" << nonPltCount - nonPltRefs.size() << "\n";
|
||||
|
||||
if (unusedFilterLevel == 2)
|
||||
std::cout << "Strict filtering: " << nonPltRefs.size() << " -> " << nonPltRefs.size() << "; filtered=0 (reserved; currently identical to level 1)\n";
|
||||
|
||||
nidRefs.clear();
|
||||
nidRefs.reserve(pltRefs.size() + nonPltRefs.size());
|
||||
for (auto& ref : pltRefs) nidRefs.push_back(std::move(ref));
|
||||
for (auto& ref : nonPltRefs) nidRefs.push_back(std::move(ref));
|
||||
} else {
|
||||
std::cout << "Unused NID filtering: disabled; filtered=0\n";
|
||||
}
|
||||
|
||||
std::cout << "NID total: " << originalNidCount << " -> " << nidRefs.size() << "; filtered=" << originalNidCount - nidRefs.size() << "\n";
|
||||
|
||||
auto dynSection = _dynamicSectionBuilder->BuildDynamicSection(
|
||||
nidRefs, neededLibraries, dynJmpRelOffset, static_cast<std::uint32_t>(dynJmpRelSize / relaEntSize));
|
||||
|
||||
|
|
@ -271,8 +280,6 @@ RelinkResult RelinkerPipeline::Relink(const std::vector<std::uint8_t>& sourceElf
|
|||
entries.push_back(std::move(entry));
|
||||
}
|
||||
|
||||
std::cout << "OK: " << entries.size() << " NID references processed\n";
|
||||
|
||||
return RelinkResult{std::move(entries), std::move(programHeaders), std::move(dynSection), gotVAddr};
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue