mirror of
https://github.com/orange-cpp/omath.git
synced 2026-04-18 18:43:27 +00:00
added stuff
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
#include <array>
|
||||
#include <fstream>
|
||||
#include <omath/utility/elf_pattern_scan.hpp>
|
||||
#include <span>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
@@ -140,6 +141,87 @@ namespace
|
||||
std::uintptr_t raw_base_addr{};
|
||||
std::vector<std::byte> data;
|
||||
};
|
||||
template<FileArch arch>
|
||||
std::optional<ExtractedSection> get_elf_section_from_memory_impl(const std::span<const std::byte> data,
|
||||
const std::string_view& section_name)
|
||||
{
|
||||
using FH = typename ElfHeaders<arch>::FileHeader;
|
||||
using SH = typename ElfHeaders<arch>::SectionHeader;
|
||||
|
||||
if (data.size() < sizeof(FH))
|
||||
return std::nullopt;
|
||||
|
||||
const auto* file_header = reinterpret_cast<const FH*>(data.data());
|
||||
|
||||
const auto shoff = static_cast<std::size_t>(file_header->e_shoff);
|
||||
const auto shnum = static_cast<std::size_t>(file_header->e_shnum);
|
||||
const auto shstrndx = static_cast<std::size_t>(file_header->e_shstrndx);
|
||||
|
||||
const auto shstrtab_hdr_off = shoff + shstrndx * sizeof(SH);
|
||||
if (shstrtab_hdr_off + sizeof(SH) > data.size())
|
||||
return std::nullopt;
|
||||
|
||||
const auto* shstrtab_hdr = reinterpret_cast<const SH*>(data.data() + shstrtab_hdr_off);
|
||||
const auto shstrtab_off = static_cast<std::size_t>(shstrtab_hdr->sh_offset);
|
||||
const auto shstrtab_size = static_cast<std::size_t>(shstrtab_hdr->sh_size);
|
||||
|
||||
if (shstrtab_off + shstrtab_size > data.size())
|
||||
return std::nullopt;
|
||||
|
||||
const auto* shstrtab = reinterpret_cast<const char*>(data.data() + shstrtab_off);
|
||||
|
||||
for (std::size_t i = 0; i < shnum; ++i)
|
||||
{
|
||||
const auto sect_hdr_off = shoff + i * sizeof(SH);
|
||||
if (sect_hdr_off + sizeof(SH) > data.size())
|
||||
continue;
|
||||
|
||||
const auto* section = reinterpret_cast<const SH*>(data.data() + sect_hdr_off);
|
||||
|
||||
if (std::cmp_greater_equal(section->sh_name, shstrtab_size))
|
||||
continue;
|
||||
|
||||
if (std::string_view{shstrtab + section->sh_name} != section_name)
|
||||
continue;
|
||||
|
||||
const auto raw_off = static_cast<std::size_t>(section->sh_offset);
|
||||
const auto sec_size = static_cast<std::size_t>(section->sh_size);
|
||||
|
||||
if (raw_off + sec_size > data.size())
|
||||
return std::nullopt;
|
||||
|
||||
ExtractedSection out;
|
||||
out.virtual_base_addr = static_cast<std::uintptr_t>(section->sh_addr);
|
||||
out.raw_base_addr = raw_off;
|
||||
out.data.assign(data.data() + raw_off, data.data() + raw_off + sec_size);
|
||||
return out;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<ExtractedSection> get_elf_section_by_name_from_memory(const std::span<const std::byte> data,
|
||||
const std::string_view& section_name)
|
||||
{
|
||||
constexpr std::string_view valid_elf_signature = "\x7F"
|
||||
"ELF";
|
||||
if (data.size() < ei_nident)
|
||||
return std::nullopt;
|
||||
|
||||
if (std::string_view{reinterpret_cast<const char*>(data.data()), valid_elf_signature.size()}
|
||||
!= valid_elf_signature)
|
||||
return std::nullopt;
|
||||
|
||||
const auto class_byte = static_cast<uint8_t>(data[ei_class]);
|
||||
|
||||
if (class_byte == elfclass64)
|
||||
return get_elf_section_from_memory_impl<FileArch::x64>(data, section_name);
|
||||
|
||||
if (class_byte == elfclass32)
|
||||
return get_elf_section_from_memory_impl<FileArch::x32>(data, section_name);
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
[[maybe_unused]]
|
||||
std::optional<ExtractedSection> get_elf_section_by_name(const std::filesystem::path& path,
|
||||
const std::string_view& section_name)
|
||||
@@ -322,4 +404,27 @@ namespace omath
|
||||
.raw_base_addr = pe_section->raw_base_addr,
|
||||
.target_offset = offset};
|
||||
}
|
||||
|
||||
std::optional<SectionScanResult>
|
||||
ElfPatternScanner::scan_for_pattern_in_memory_file(const std::span<const std::byte> file_data,
|
||||
const std::string_view& pattern,
|
||||
const std::string_view& target_section_name)
|
||||
{
|
||||
const auto section = get_elf_section_by_name_from_memory(file_data, target_section_name);
|
||||
|
||||
if (!section.has_value()) [[unlikely]]
|
||||
return std::nullopt;
|
||||
|
||||
const auto scan_result =
|
||||
PatternScanner::scan_for_pattern(section->data.cbegin(), section->data.cend(), pattern);
|
||||
|
||||
if (scan_result == section->data.cend())
|
||||
return std::nullopt;
|
||||
|
||||
const auto offset = std::distance(section->data.begin(), scan_result);
|
||||
|
||||
return SectionScanResult{.virtual_base_addr = section->virtual_base_addr,
|
||||
.raw_base_addr = section->raw_base_addr,
|
||||
.target_offset = offset};
|
||||
}
|
||||
} // namespace omath
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "omath/utility/pattern_scan.hpp"
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <span>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
@@ -231,6 +232,96 @@ namespace
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template<typename HeaderType, typename SegmentType, typename SectionType, std::uint32_t segment_cmd>
|
||||
std::optional<ExtractedSection> extract_section_from_memory_impl(const std::span<const std::byte> data,
|
||||
const std::string_view& section_name)
|
||||
{
|
||||
if (data.size() < sizeof(HeaderType))
|
||||
return std::nullopt;
|
||||
|
||||
const auto* header = reinterpret_cast<const HeaderType*>(data.data());
|
||||
|
||||
std::size_t cmd_offset = sizeof(HeaderType);
|
||||
|
||||
for (std::uint32_t i = 0; i < header->ncmds; ++i)
|
||||
{
|
||||
if (cmd_offset + sizeof(LoadCommand) > data.size())
|
||||
return std::nullopt;
|
||||
|
||||
const auto* lc = reinterpret_cast<const LoadCommand*>(data.data() + cmd_offset);
|
||||
|
||||
if (lc->cmd != segment_cmd)
|
||||
{
|
||||
cmd_offset += lc->cmdsize;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cmd_offset + sizeof(SegmentType) > data.size())
|
||||
return std::nullopt;
|
||||
|
||||
const auto* segment = reinterpret_cast<const SegmentType*>(data.data() + cmd_offset);
|
||||
|
||||
if (!segment->nsects)
|
||||
{
|
||||
cmd_offset += lc->cmdsize;
|
||||
continue;
|
||||
}
|
||||
|
||||
std::size_t sect_offset = cmd_offset + sizeof(SegmentType);
|
||||
|
||||
for (std::uint32_t j = 0; j < segment->nsects; ++j)
|
||||
{
|
||||
if (sect_offset + sizeof(SectionType) > data.size())
|
||||
return std::nullopt;
|
||||
|
||||
const auto* section = reinterpret_cast<const SectionType*>(data.data() + sect_offset);
|
||||
|
||||
if (get_section_name(section->sectname) != section_name)
|
||||
{
|
||||
sect_offset += sizeof(SectionType);
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto raw_off = static_cast<std::size_t>(section->offset);
|
||||
const auto sec_size = static_cast<std::size_t>(section->size);
|
||||
|
||||
if (raw_off + sec_size > data.size())
|
||||
return std::nullopt;
|
||||
|
||||
ExtractedSection out;
|
||||
out.virtual_base_addr = static_cast<std::uintptr_t>(section->addr);
|
||||
out.raw_base_addr = raw_off;
|
||||
out.data.assign(data.data() + raw_off, data.data() + raw_off + sec_size);
|
||||
return out;
|
||||
}
|
||||
|
||||
cmd_offset += lc->cmdsize;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
std::optional<ExtractedSection> get_macho_section_by_name_from_memory(const std::span<const std::byte> data,
|
||||
const std::string_view& section_name)
|
||||
{
|
||||
if (data.size() < sizeof(std::uint32_t))
|
||||
return std::nullopt;
|
||||
|
||||
std::uint32_t magic{};
|
||||
std::memcpy(&magic, data.data(), sizeof(magic));
|
||||
|
||||
if (magic == mh_magic_64 || magic == mh_cigam_64)
|
||||
return extract_section_from_memory_impl<MachHeader64, SegmentCommand64, Section64, lc_segment_64>(
|
||||
data, section_name);
|
||||
|
||||
if (magic == mh_magic_32 || magic == mh_cigam_32)
|
||||
return extract_section_from_memory_impl<MachHeader32, SegmentCommand32, Section32, lc_segment>(data,
|
||||
section_name);
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
std::optional<ExtractedSection> get_macho_section_by_name(const std::filesystem::path& path,
|
||||
const std::string_view& section_name)
|
||||
@@ -346,4 +437,27 @@ namespace omath
|
||||
.raw_base_addr = macho_section->raw_base_addr,
|
||||
.target_offset = offset};
|
||||
}
|
||||
|
||||
std::optional<SectionScanResult>
|
||||
MachOPatternScanner::scan_for_pattern_in_memory_file(const std::span<const std::byte> file_data,
|
||||
const std::string_view& pattern,
|
||||
const std::string_view& target_section_name)
|
||||
{
|
||||
const auto section = get_macho_section_by_name_from_memory(file_data, target_section_name);
|
||||
|
||||
if (!section.has_value()) [[unlikely]]
|
||||
return std::nullopt;
|
||||
|
||||
const auto scan_result =
|
||||
PatternScanner::scan_for_pattern(section->data.cbegin(), section->data.cend(), pattern);
|
||||
|
||||
if (scan_result == section->data.cend())
|
||||
return std::nullopt;
|
||||
|
||||
const auto offset = std::distance(section->data.begin(), scan_result);
|
||||
|
||||
return SectionScanResult{.virtual_base_addr = section->virtual_base_addr,
|
||||
.raw_base_addr = section->raw_base_addr,
|
||||
.target_offset = offset};
|
||||
}
|
||||
} // namespace omath
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <span>
|
||||
#include <stdexcept>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
// Internal PE shit defines
|
||||
// Big thx for linuxpe sources as ref
|
||||
@@ -244,6 +245,78 @@ namespace
|
||||
std::vector<std::byte> data;
|
||||
};
|
||||
|
||||
[[nodiscard]]
|
||||
std::optional<ExtractedSection> extract_section_from_pe_memory(const std::span<const std::byte> data,
|
||||
const std::string_view& section_name)
|
||||
{
|
||||
if (data.size() < sizeof(DosHeader))
|
||||
return std::nullopt;
|
||||
|
||||
const auto* dos_header = reinterpret_cast<const DosHeader*>(data.data());
|
||||
|
||||
if (invalid_dos_header_file(*dos_header))
|
||||
return std::nullopt;
|
||||
|
||||
const auto nt_off = static_cast<std::size_t>(dos_header->e_lfanew);
|
||||
|
||||
if (nt_off + sizeof(ImageNtHeaders<NtArchitecture::x32_bit>) > data.size())
|
||||
return std::nullopt;
|
||||
|
||||
const auto* x86_hdrs =
|
||||
reinterpret_cast<const ImageNtHeaders<NtArchitecture::x32_bit>*>(data.data() + nt_off);
|
||||
|
||||
NtHeaderVariant nt_headers;
|
||||
if (x86_hdrs->optional_header.magic == opt_hdr32_magic)
|
||||
nt_headers = *x86_hdrs;
|
||||
else if (x86_hdrs->optional_header.magic == opt_hdr64_magic)
|
||||
{
|
||||
if (nt_off + sizeof(ImageNtHeaders<NtArchitecture::x64_bit>) > data.size())
|
||||
return std::nullopt;
|
||||
nt_headers = *reinterpret_cast<const ImageNtHeaders<NtArchitecture::x64_bit>*>(data.data() + nt_off);
|
||||
}
|
||||
else
|
||||
return std::nullopt;
|
||||
|
||||
if (invalid_nt_header_file(nt_headers))
|
||||
return std::nullopt;
|
||||
|
||||
return std::visit(
|
||||
[&data, §ion_name, nt_off](const auto& concrete_headers) -> std::optional<ExtractedSection>
|
||||
{
|
||||
constexpr std::size_t sig_size = sizeof(concrete_headers.signature);
|
||||
const auto section_table_off = nt_off + sig_size + sizeof(FileHeader)
|
||||
+ concrete_headers.file_header.size_optional_header;
|
||||
|
||||
for (std::size_t i = 0; i < concrete_headers.file_header.num_sections; ++i)
|
||||
{
|
||||
const auto sh_off = section_table_off + i * sizeof(SectionHeader);
|
||||
if (sh_off + sizeof(SectionHeader) > data.size())
|
||||
return std::nullopt;
|
||||
|
||||
const auto* section = reinterpret_cast<const SectionHeader*>(data.data() + sh_off);
|
||||
|
||||
if (std::string_view(section->name) != section_name)
|
||||
continue;
|
||||
|
||||
const auto raw_off = static_cast<std::size_t>(section->ptr_raw_data);
|
||||
const auto raw_size = static_cast<std::size_t>(section->size_raw_data);
|
||||
|
||||
if (raw_off + raw_size > data.size())
|
||||
return std::nullopt;
|
||||
|
||||
std::vector<std::byte> section_data(data.data() + raw_off, data.data() + raw_off + raw_size);
|
||||
|
||||
return ExtractedSection{
|
||||
.virtual_base_addr = static_cast<std::uintptr_t>(
|
||||
section->virtual_address + concrete_headers.optional_header.image_base),
|
||||
.raw_base_addr = raw_off,
|
||||
.data = std::move(section_data)};
|
||||
}
|
||||
return std::nullopt;
|
||||
},
|
||||
nt_headers);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
std::optional<ExtractedSection> extract_section_from_pe_file(const std::filesystem::path& path_to_file,
|
||||
const std::string_view& section_name)
|
||||
@@ -383,4 +456,27 @@ namespace omath
|
||||
.raw_base_addr = pe_section->raw_base_addr,
|
||||
.target_offset = offset};
|
||||
}
|
||||
|
||||
std::optional<SectionScanResult>
|
||||
PePatternScanner::scan_for_pattern_in_memory_file(const std::span<const std::byte> file_data,
|
||||
const std::string_view& pattern,
|
||||
const std::string_view& target_section_name)
|
||||
{
|
||||
const auto pe_section = extract_section_from_pe_memory(file_data, target_section_name);
|
||||
|
||||
if (!pe_section.has_value()) [[unlikely]]
|
||||
return std::nullopt;
|
||||
|
||||
const auto scan_result =
|
||||
PatternScanner::scan_for_pattern(pe_section->data.cbegin(), pe_section->data.cend(), pattern);
|
||||
|
||||
if (scan_result == pe_section->data.cend())
|
||||
return std::nullopt;
|
||||
|
||||
const auto offset = std::distance(pe_section->data.begin(), scan_result);
|
||||
|
||||
return SectionScanResult{.virtual_base_addr = pe_section->virtual_base_addr,
|
||||
.raw_base_addr = pe_section->raw_base_addr,
|
||||
.target_offset = offset};
|
||||
}
|
||||
} // namespace omath
|
||||
Reference in New Issue
Block a user