Skip to content

Commit

Permalink
Enhance Mach-O layout checks
Browse files Browse the repository at this point in the history
  • Loading branch information
romainthomas committed Dec 15, 2024
1 parent a5cf726 commit 2cd4d99
Show file tree
Hide file tree
Showing 23 changed files with 1,559 additions and 599 deletions.
12 changes: 12 additions & 0 deletions api/python/lief/MachO/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -1431,6 +1431,9 @@ class DyldInfo(LoadCommand):
class DylibCommand(LoadCommand):
name: str

@property
def name_offset(self) -> int: ...

timestamp: int

current_version: list[int]
Expand Down Expand Up @@ -1797,6 +1800,12 @@ class Header(lief.Object):
@property
def flags_list(self) -> list[Header.FLAGS]: ...

@property
def is_32bit(self) -> bool: ...

@property
def is_64bit(self) -> bool: ...

def add(self, flag: Header.FLAGS) -> None: ...

def remove(self, flag: Header.FLAGS) -> None: ...
Expand Down Expand Up @@ -2062,6 +2071,9 @@ class RPathCommand(LoadCommand):
@staticmethod
def create(path: str) -> Optional[RPathCommand]: ...

@property
def path_offset(self) -> int: ...

path: str

def __str__(self) -> str: ...
Expand Down
2 changes: 1 addition & 1 deletion api/python/lief/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from ._lief import __version__, __tag__, __commit__, __is_tagged__, __extended__

if __extended__:
from ._lief import __LIEF_MAIN_COMMIT__, __LIEF_EXTENDED_VERSION_STR__, __extended_version__
from ._lief_extended import __LIEF_MAIN_COMMIT__, __LIEF_EXTENDED_VERSION_STR__, __extended_version__

# cf. https://github.com/pytorch/pytorch/blob/60a3b7425dde97fe8b46183c154a9c3b24f0c733/torch/__init__.py#L467-L470
for attr in dir(_lief):
Expand Down
3 changes: 3 additions & 0 deletions api/python/src/MachO/objects/pyDylibCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ void create<DylibCommand>(nb::module_& m) {
"Library's name"_doc,
nb::rv_policy::reference_internal)

.def_prop_ro("name_offset", &DylibCommand::name_offset,
"Original string offset of the name")

.def_prop_rw("timestamp",
nb::overload_cast<>(&DylibCommand::timestamp, nb::const_),
nb::overload_cast<uint32_t>(&DylibCommand::timestamp),
Expand Down
6 changes: 6 additions & 0 deletions api/python/src/MachO/objects/pyHeader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,12 @@ void create<Header>(nb::module_& m) {
&Header::flags_list,
"" RST_CLASS_REF(lief.MachO.Header.FLAGS) " as a list"_doc)

.def_prop_ro("is_32bit", &Header::is_32bit,
R"doc(True is the binary is 32-bits)doc"_doc)

.def_prop_ro("is_64bit", &Header::is_64bit,
R"doc(True is the binary is 64-bits)doc"_doc)

.def("add",
nb::overload_cast<Header::FLAGS>(&Header::add),
"Add the given " RST_CLASS_REF(lief.MachO.Header.FLAGS) ""_doc,
Expand Down
3 changes: 3 additions & 0 deletions api/python/src/MachO/objects/pyRPathCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ void create<RPathCommand>(nb::module_& m) {
"path"_a
)

.def_prop_ro("path_offset", &RPathCommand::path_offset,
"Original string offset of the path")

.def_prop_rw("path",
nb::overload_cast<>(&RPathCommand::path, nb::const_),
nb::overload_cast<std::string>(&RPathCommand::path),
Expand Down
5 changes: 5 additions & 0 deletions api/rust/cargo/lief/src/macho/commands/dylib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ impl Dylib<'_> {
self.ptr.name().to_string()
}

/// Original string offset of the name
pub fn name_offset(&self) -> u32 {
self.ptr.name_offset()
}

/// Date and Time when the shared library was built
pub fn timestamp(&self) -> u32 {
self.ptr.timestamp()
Expand Down
5 changes: 5 additions & 0 deletions api/rust/cargo/lief/src/macho/commands/rpath.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ impl RPath<'_> {
pub fn path(&self) -> String {
self.ptr.path().to_string()
}

/// Original string offset of the path
pub fn path_offset(&self) -> u32 {
self.ptr.path_offset()
}
}

impl std::fmt::Debug for RPath<'_> {
Expand Down
10 changes: 10 additions & 0 deletions api/rust/cargo/lief/src/macho/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,16 @@ impl Header<'_> {
pub fn reserved(&self) -> u32 {
self.ptr.reserved()
}

/// True if the binary is 32-bit
pub fn is_32bit(&self) -> bool {
self.ptr.is_32bit()
}

/// True if the binary is 64-bit
pub fn is_64bit(&self) -> bool {
self.ptr.is_64bit()
}
}

impl fmt::Debug for Header<'_> {
Expand Down
1 change: 1 addition & 0 deletions api/rust/cargo/lief/tests/macho_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ fn explore_macho(_: &str, macho: &lief::macho::Binary) {
format!("{macho:?}");
format!("{}", macho.entrypoint());
format!("{:?}", macho.header());
format!("{}{}", macho.header().is_32bit(), macho.header().is_64bit());
println!("{:?}:{}:{}", macho.platform(), macho.is_ios(), macho.is_macos());
for section in macho.sections() {
format!("{section:?}");
Expand Down
2 changes: 2 additions & 0 deletions api/rust/include/LIEF/rust/MachO/Dylib.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ class MachO_Dylib : public MachO_Command {
std::string name() const { return impl().name(); }
uint32_t timestamp() const { return impl().timestamp(); }

auto name_offset() const { return impl().name_offset(); }

auto current_version() const {
return details::make_vector(impl().current_version());
}
Expand Down
3 changes: 3 additions & 0 deletions api/rust/include/LIEF/rust/MachO/Header.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,7 @@ class MachO_Header : private Mirror<LIEF::MachO::Header> {
auto sizeof_cmds() const { return get().sizeof_cmds(); }
auto flags() const { return get().flags(); }
auto reserved() const { return get().reserved(); }

bool is_32bit() const { return get().is_32bit(); }
bool is_64bit() const { return get().is_64bit(); }
};
2 changes: 2 additions & 0 deletions api/rust/include/LIEF/rust/MachO/RPathCommand.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ class MachO_RPathCommand : public MachO_Command {
MachO_RPathCommand(const lief_t& base) : MachO_Command(base) {}
std::string path() const { return impl().path(); };

auto path_offset() const { return impl().path_offset(); }

static bool classof(const MachO_Command& cmd) {
return lief_t::classof(&cmd.get());
}
Expand Down
8 changes: 8 additions & 0 deletions include/LIEF/MachO/DyldChainedFixups.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ class LIEF_API DyldChainedFixups : public LoadCommand {

LIEF_API friend std::ostream& operator<<(std::ostream& os, const chained_starts_in_segment& info);

static chained_starts_in_segment create_empty_chained(SegmentCommand& segment) {
return chained_starts_in_segment(0, segment);
}

private:
friend class BinaryParser;
friend class DyldChainedFixupsCreator;
Expand Down Expand Up @@ -192,6 +196,10 @@ class LIEF_API DyldChainedFixups : public LoadCommand {
DYLD_CHAINED_FORMAT imports_format() const { return imports_format_; }
void imports_format(DYLD_CHAINED_FORMAT fmt) { imports_format_ = fmt; }

chained_starts_in_segment& add(chained_starts_in_segment start_info) {
chained_starts_in_segment_.push_back(std::move(start_info));
return chained_starts_in_segment_.back();
}

void accept(Visitor& visitor) const override;

Expand Down
6 changes: 6 additions & 0 deletions include/LIEF/MachO/DylibCommand.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,11 @@ class LIEF_API DylibCommand : public LoadCommand {
return name_;
}

/// Original string offset of the name
uint32_t name_offset() const {
return name_offset_;
}

/// Date and Time when the shared library was built
uint32_t timestamp() const {
return timestamp_;
Expand Down Expand Up @@ -153,6 +158,7 @@ class LIEF_API DylibCommand : public LoadCommand {
uint32_t current_version, uint32_t compat_version);

std::string name_;
uint32_t name_offset_ = 0;
uint32_t timestamp_ = 0;
uint32_t current_version_ = 0;
uint32_t compatibility_version_ = 0;
Expand Down
12 changes: 12 additions & 0 deletions include/LIEF/MachO/Header.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,18 @@ class LIEF_API Header : public Object {
flags_ = flags;
}

/// True if the binary is 32-bit
bool is_32bit() const {
return magic_ == MACHO_TYPES::MH_MAGIC ||
magic_ == MACHO_TYPES::MH_CIGAM;
}

/// True if the binary is 64-bit
bool is_64bit() const {
return magic_ == MACHO_TYPES::MH_MAGIC_64 ||
magic_ == MACHO_TYPES::MH_CIGAM_64;
}

void remove(FLAGS flag);

void reserved(uint32_t reserved) {
Expand Down
6 changes: 6 additions & 0 deletions include/LIEF/MachO/RPathCommand.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ class LIEF_API RPathCommand : public LoadCommand {
return path_;
}

/// Original string offset of the path
uint32_t path_offset() const {
return path_offset_;
}

void path(std::string path) {
path_ = std::move(path);
}
Expand All @@ -71,6 +76,7 @@ class LIEF_API RPathCommand : public LoadCommand {
}

private:
uint32_t path_offset_ = 0;
std::string path_;
};

Expand Down
2 changes: 1 addition & 1 deletion include/LIEF/MachO/Section.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ class LIEF_API Section : public LIEF::Section {
}

/// Type of the section. This value can help to determine
/// the purpose of the section (e.g. MACHO_SECTION_TYPES::MACHO_SECTION_TYPES)
/// the purpose of the section (e.g. TYPE::INTERPOSING)
TYPE type() const {
return TYPE(flags_ & TYPE_MASK);
}
Expand Down
6 changes: 6 additions & 0 deletions src/MachO/Binary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1554,6 +1554,12 @@ LoadCommand* Binary::add(const SegmentCommand& segment) {
current_offset += section.size();
}

if (DyldChainedFixups* fixup = dyld_chained_fixups()) {
DyldChainedFixups::chained_starts_in_segment new_info =
DyldChainedFixups::chained_starts_in_segment::create_empty_chained(*segment_added);
fixup->add(std::move(new_info));
}

refresh_seg_offset();
return segment_added;
}
Expand Down
1 change: 1 addition & 0 deletions src/MachO/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ target_sources(LIB_LIEF PRIVATE
exports_trie.cpp
hash.cpp
json_api.cpp
layout_check.cpp
utils.cpp
)

Expand Down
1 change: 1 addition & 0 deletions src/MachO/DylibCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ namespace MachO {

DylibCommand::DylibCommand(const details::dylib_command& cmd) :
LoadCommand::LoadCommand{static_cast<LoadCommand::TYPE>(cmd.cmd), cmd.cmdsize},
name_offset_{cmd.name},
timestamp_{cmd.timestamp},
current_version_{cmd.current_version},
compatibility_version_{cmd.compatibility_version}
Expand Down
3 changes: 2 additions & 1 deletion src/MachO/RPathCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ RPathCommand::RPathCommand(std::string path) :
}

RPathCommand::RPathCommand(const details::rpath_command& rpath) :
LoadCommand::LoadCommand{LoadCommand::TYPE(rpath.cmd), rpath.cmdsize}
LoadCommand::LoadCommand{LoadCommand::TYPE(rpath.cmd), rpath.cmdsize},
path_offset_(rpath.path)
{}

void RPathCommand::accept(Visitor& visitor) const {
Expand Down
Loading

0 comments on commit 2cd4d99

Please sign in to comment.