Skip to content
Permalink
Browse files
Enhance Mach-O modification
  * Add load command
  * Add sections
  * Add segments

Resolve #46 (partially)
  • Loading branch information
romainthomas committed Jun 27, 2018
1 parent 5ec8956 commit 406115c
Show file tree
Hide file tree
Showing 102 changed files with 5,679 additions and 895 deletions.
@@ -6,6 +6,18 @@
extern "C" {
#endif

#ifdef _LIEF_EN
#undef _LIEF_EN
#endif

#ifdef _LIEF_EN_2
#undef _LIEF_EN_2
#endif

#ifdef _LIEF_EI
#undef _LIEF_EI
#endif

#define _LIEF_EN(N) LIEF_MACHO_##N // enum LIEF_N {
#define _LIEF_EN_2(N, TYPE) LIEF_MACHO_##N // enum LIEF_N {
#define _LIEF_EI(X) LIEF_MACHO_##X // LIEF_X
@@ -105,22 +105,22 @@ void create<Binary>(py::module& m) {
py::return_value_policy::copy)

.def("section_from_offset",
static_cast<Section& (Binary::*)(uint64_t)>(&Binary::section_from_offset),
static_cast<Section* (Binary::*)(uint64_t)>(&Binary::section_from_offset),
"Return the " RST_CLASS_REF(lief.MachO.Section) " which contains the offset",
py::return_value_policy::reference)

.def("section_from_virtual_address",
static_cast<Section& (Binary::*)(uint64_t)>(&Binary::section_from_virtual_address),
static_cast<Section* (Binary::*)(uint64_t)>(&Binary::section_from_virtual_address),
"Return the " RST_CLASS_REF(lief.MachO.Section) " which contains the virtual address",
py::return_value_policy::reference)

.def("segment_from_offset",
static_cast<SegmentCommand& (Binary::*)(uint64_t)>(&Binary::segment_from_offset),
static_cast<SegmentCommand* (Binary::*)(uint64_t)>(&Binary::segment_from_offset),
"Return the " RST_CLASS_REF(lief.MachO.SegmentCommand) " which contains the offset",
py::return_value_policy::reference)

.def("segment_from_virtual_address",
static_cast<SegmentCommand& (Binary::*)(uint64_t)>(&Binary::segment_from_virtual_address),
static_cast<SegmentCommand* (Binary::*)(uint64_t)>(&Binary::segment_from_virtual_address),
"Return the " RST_CLASS_REF(lief.MachO.SegmentCommand) " which contains the virtual address",
py::return_value_policy::reference)

@@ -317,16 +317,138 @@ void create<Binary>(py::module& m) {
"name"_a,
py::return_value_policy::reference)

.def("has_segment",
&Binary::has_segment,
"Check if a " RST_CLASS_REF(lief.MachO.SegmentCommand) " with the given name exists",
"name"_a)

.def("get_segment",
static_cast<SegmentCommand* (Binary::*)(const std::string&)>(&Binary::get_segment),
"Return the " RST_CLASS_REF(lief.MachO.SegmentCommand) " from the given name",
"name"_a,
py::return_value_policy::reference)

.def_property_readonly("va_ranges",
&Binary::va_ranges,
"Return the range of virtual addresses as a tuple ``(va_start, va_end)``")

.def_property_readonly("off_ranges",
&Binary::off_ranges,
"Return the range of offsets as a tuple ``(off_start, off_end)``")

.def("is_valid_addr",
&Binary::is_valid_addr,
"Check if the given address is comprise between the lowest "
"virtual address and the biggest one",
"address"_a)

.def("write",
&Binary::write,
"Rebuild the binary and write it in a file",
"output"_a,
py::return_value_policy::reference_internal)

.def("add",
static_cast<LoadCommand& (Binary::*)(const DylibCommand&)>(&Binary::add),
"Add a new " RST_CLASS_REF(lief.MachO.DylibCommand) "",
"dylib_command"_a,
py::return_value_policy::reference)

.def("add",
static_cast<LoadCommand& (Binary::*)(const SegmentCommand&)>(&Binary::add),
"Add a new " RST_CLASS_REF(lief.MachO.SegmentCommand) "",
"segment"_a,
py::return_value_policy::reference)

.def("add",
static_cast<LoadCommand& (Binary::*)(const LoadCommand&)>(&Binary::add),
"Add a new " RST_CLASS_REF(lief.MachO.LoadCommand) "",
"load_command"_a,
py::return_value_policy::reference)

.def("add",
static_cast<LoadCommand& (Binary::*)(const LoadCommand&, size_t)>(&Binary::add),
"Add a new " RST_CLASS_REF(lief.MachO.LoadCommand) " at ``index``",
"load_command"_a, "index"_a,
py::return_value_policy::reference)


.def("remove",
static_cast<bool (Binary::*)(const LoadCommand&)>(&Binary::remove),
"Remove a " RST_CLASS_REF(lief.MachO.LoadCommand) "",
"load_command"_a)

.def("remove",
static_cast<bool (Binary::*)(LOAD_COMMAND_TYPES)>(&Binary::remove),
"Remove **all** " RST_CLASS_REF(lief.MachO.LoadCommand) " having the given "
"" RST_CLASS_REF(lief.MachO.LOAD_COMMAND_TYPES) "",
"type"_a)

.def("remove_command",
static_cast<bool (Binary::*)(size_t)>(&Binary::remove_command),
"Remove the " RST_CLASS_REF(lief.MachO.LoadCommand) " at ``index``",
"index"_a)

.def("remove_signature",
static_cast<bool (Binary::*)(void)>(&Binary::remove_signature),
"Remove the " RST_CLASS_REF(lief.MachO.CodeSignature) " (if any)")

.def("extend",
static_cast<bool (Binary::*)(const LoadCommand&, uint64_t)>(&Binary::extend),
"Extend a " RST_CLASS_REF(lief.MachO.LoadCommand) " by ``size``",
"load_command"_a, "size"_a)

.def("extend_segment",
static_cast<bool (Binary::*)(const SegmentCommand&, size_t)>(&Binary::extend_segment),
"Extend the **content** of the given " RST_CLASS_REF(lief.MachO.SegmentCommand) " by ``size``",
"segment_command"_a, "size"_a)

.def("add_section",
static_cast<Section* (Binary::*)(const SegmentCommand&, const Section&)>(&Binary::add_section),
"Add a new " RST_CLASS_REF(lief.MachO.Section) " in the given " RST_CLASS_REF(lief.MachO.SegmentCommand) "",
"segment"_a, "section"_a,
py::return_value_policy::reference)

.def("add_section",
static_cast<Section* (Binary::*)(const Section&)>(&Binary::add_section),
"Add a new " RST_CLASS_REF(lief.MachO.Section) " within the ``__TEXT`` segment",
"section"_a,
py::return_value_policy::reference)


.def("add_section",
static_cast<Section* (Binary::*)(const SegmentCommand&, const Section&)>(&Binary::add_section),
"Add a new " RST_CLASS_REF(lief.MachO.Section) " in the given " RST_CLASS_REF(lief.MachO.SegmentCommand) "",
"section"_a, "section"_a,
py::return_value_policy::reference)

.def("add_library",
static_cast<LoadCommand& (Binary::*)(const std::string&)>(&Binary::add_library),
"Add a new library dependency",
"library_name"_a,
py::return_value_policy::reference)

.def("get",
static_cast<LoadCommand& (Binary::*)(LOAD_COMMAND_TYPES)>(&Binary::get),
"Return the **first** " RST_CLASS_REF(lief.MachO.LoadCommand) " having the given "
"" RST_CLASS_REF(lief.MachO.LOAD_COMMAND_TYPES) "",
"type"_a,
py::return_value_policy::reference)

.def("has",
static_cast<bool(Binary::*)(LOAD_COMMAND_TYPES) const>(&Binary::has),
"Check if the current binary has a " RST_CLASS_REF(lief.MachO.LoadCommand) " with the given "
"" RST_CLASS_REF(lief.MachO.LOAD_COMMAND_TYPES) "",
"type"_a)

.def("__getitem__",
static_cast<LoadCommand& (Binary::*)(LOAD_COMMAND_TYPES)>(&Binary::operator[]),
"",
py::return_value_policy::reference)

.def("__contains__",
static_cast<bool(Binary::*)(LOAD_COMMAND_TYPES) const>(&Binary::has))


.def("__str__",
[] (const Binary& binary)
@@ -263,7 +263,6 @@ void create<DyldInfo>(py::module& m) {
&DyldInfo::set_export_size,
"size"_a)


.def("__eq__", &DyldInfo::operator==)
.def("__ne__", &DyldInfo::operator!=)
.def("__hash__",
@@ -62,6 +62,35 @@ void create<DylibCommand>(py::module& m) {
"Library's compatibility version",
py::return_value_policy::reference_internal)

.def_static("weak_lib",
&DylibCommand::weak_dylib,
"Factory function to generate a " RST_CLASS_REF(lief.MachO.LOAD_COMMAND_TYPES.LC_LOAD_WEAK_DYLIB) " library",
"name"_a, "timestamp"_a = 0, "current_version"_a = 0, "compat_version"_a = 0)

.def_static("id_dylib",
&DylibCommand::id_dylib,
"Factory function to generate a " RST_CLASS_REF(lief.MachO.LOAD_COMMAND_TYPES.ID_DYLIB) " library",
"name"_a, "timestamp"_a = 0, "current_version"_a = 0, "compat_version"_a = 0)

.def_static("load_dylib",
&DylibCommand::load_dylib,
"Factory function to generate a " RST_CLASS_REF(lief.MachO.LOAD_COMMAND_TYPES.LOAD_DYLIB) " library",
"name"_a, "timestamp"_a = 0, "current_version"_a = 0, "compat_version"_a = 0)

.def_static("reexport_dylib",
&DylibCommand::reexport_dylib,
"Factory function to generate a " RST_CLASS_REF(lief.MachO.LOAD_COMMAND_TYPES.REEXPORT_DYLIB) " library",
"name"_a, "timestamp"_a = 0, "current_version"_a = 0, "compat_version"_a = 0)

.def_static("load_upward_dylib",
&DylibCommand::load_upward_dylib,
"Factory function to generate a " RST_CLASS_REF(lief.MachO.LOAD_COMMAND_TYPES.LOAD_UPWARD_DYLIB) " library",
"name"_a, "timestamp"_a = 0, "current_version"_a = 0, "compat_version"_a = 0)

.def_static("lazy_load_dylib",
&DylibCommand::lazy_load_dylib,
"Factory function to generate a " RST_CLASS_REF(lief.MachO.LOAD_COMMAND_TYPES.LAZY_LOAD_DYLIB) " library",
"name"_a, "timestamp"_a = 0, "current_version"_a = 0, "compat_version"_a = 0)

.def("__eq__", &DylibCommand::operator==)
.def("__ne__", &DylibCommand::operator!=)
@@ -29,6 +29,9 @@ namespace MachO {
template<class T>
using getter_t = T (ExportInfo::*)(void) const;

template<class T>
using no_const_getter_t = T (ExportInfo::*)(void);

template<class T>
using setter_t = void (ExportInfo::*)(T);

@@ -41,6 +44,14 @@ void create<ExportInfo>(py::module& m) {
.def_property_readonly("node_offset",
static_cast<getter_t<uint64_t>>(&ExportInfo::node_offset))

.def_property_readonly("kind",
static_cast<getter_t<EXPORT_SYMBOL_KINDS>>(&ExportInfo::kind),
"Type of the symbol associated with the export (" RST_CLASS_REF(lief.MachO.EXPORT_SYMBOL_KINDS) ")")

.def_property_readonly("flags_list",
static_cast<getter_t<ExportInfo::flag_list_t>>(&ExportInfo::flags_list),
"Return flags as a list of " RST_CLASS_REF(lief.MachO.EXPORT_SYMBOL_KINDS) "")

.def_property("flags",
static_cast<getter_t<uint64_t>>(&ExportInfo::flags),
static_cast<setter_t<uint64_t>>(&ExportInfo::flags),
@@ -51,10 +62,26 @@ void create<ExportInfo>(py::module& m) {
static_cast<setter_t<uint64_t>>(&ExportInfo::address),
py::return_value_policy::reference_internal)

.def_property_readonly("alias",
static_cast<no_const_getter_t<Symbol*>>(&ExportInfo::alias),
"" RST_CLASS_REF(lief.MachO.Symbol) " alias if the current symbol is a re-exported one",
py::return_value_policy::reference)

.def_property_readonly("alias_library",
static_cast<no_const_getter_t<DylibCommand*>>(&ExportInfo::alias_library),
"If the current symbol has an alias, it returns the " RST_CLASS_REF(lief.MachO.DylibCommand) " "
" command associated with",
py::return_value_policy::reference)

.def_property_readonly("has_symbol",
&ExportInfo::has_symbol,
"``True`` if the export info has a " RST_CLASS_REF(lief.MachO.Symbol) " associated with")

.def("has",
&ExportInfo::has,
"Check if the flag " RST_CLASS_REF(lief.MachO.EXPORT_SYMBOL_FLAGS) " given in first parameter is present"
"flag"_a)

.def_property_readonly("symbol",
static_cast<Symbol& (ExportInfo::*)(void)>(&ExportInfo::symbol),
"" RST_CLASS_REF(lief.MachO.Symbol) " associated with the export (if any)",
@@ -46,17 +46,17 @@ void create<LoadCommand>(py::module& m) {
.def_property("size",
static_cast<getter_t<uint32_t>>(&LoadCommand::size),
static_cast<setter_t<uint32_t>>(&LoadCommand::size),
"Command size")
"Size of the command (should be greather than ``sizeof(load_command)``)")

.def_property("data",
static_cast<getter_t<const std::vector<uint8_t>&>>(&LoadCommand::data),
static_cast<setter_t<const std::vector<uint8_t>&>>(&LoadCommand::data),
static_cast<getter_t<const LoadCommand::raw_t&>>(&LoadCommand::data),
static_cast<setter_t<const LoadCommand::raw_t&>>(&LoadCommand::data),
"Command's data")

.def_property("command_offset",
static_cast<getter_t<uint64_t>>(&LoadCommand::command_offset),
static_cast<setter_t<uint64_t>>(&LoadCommand::command_offset),
"Offset to the comand")
"Offset of the command within the *Load Command Table*")

.def("__eq__", &LoadCommand::operator==)
.def("__ne__", &LoadCommand::operator!=)
@@ -38,6 +38,10 @@ void create<RelocationDyld>(py::module& m) {

py::class_<RelocationDyld, Relocation>(m, "RelocationDyld")

.def("__le__", &RelocationDyld::operator<=)
.def("__lt__", &RelocationDyld::operator<)
.def("__ge__", &RelocationDyld::operator>=)
.def("__gt__", &RelocationDyld::operator>)
.def("__eq__", &RelocationDyld::operator==)
.def("__ne__", &RelocationDyld::operator!=)
.def("__hash__",
@@ -40,6 +40,14 @@ void create<Section>(py::module& m) {
py::class_<Section, LIEF::Section>(m, "Section")
.def(py::init<>())

.def(py::init<const std::string&>(),
"Constructor with the section name",
"section_name"_a)

.def(py::init<const std::string&, const Section::content_t&>(),
"Constructor with the section name and its content",
"section_name"_a, "content"_a)

.def_property("alignment",
static_cast<getter_t<uint32_t>>(&Section::alignment),
static_cast<setter_t<uint32_t>>(&Section::alignment),
@@ -65,6 +73,53 @@ void create<Section>(py::module& m) {
"Iterator over " RST_CLASS_REF(lief.MachO.Relocation) " (if any)",
py::return_value_policy::reference_internal)

.def_property("reserved1",
static_cast<getter_t<uint32_t>>(&Section::reserved1),
static_cast<setter_t<uint32_t>>(&Section::reserved1),
"")

.def_property("reserved2",
static_cast<getter_t<uint32_t>>(&Section::reserved2),
static_cast<setter_t<uint32_t>>(&Section::reserved2),
"")

.def_property("reserved3",
static_cast<getter_t<uint32_t>>(&Section::reserved3),
static_cast<setter_t<uint32_t>>(&Section::reserved3),
"")

.def_property("flags",
static_cast<getter_t<uint32_t>>(&Section::flags),
static_cast<setter_t<uint32_t>>(&Section::flags),
"")

.def_property_readonly("flags_list",
static_cast<getter_t<Section::flag_list_t>>(&Section::flags_list),
py::return_value_policy::reference_internal)

.def("has",
static_cast<bool(Section::*)(MACHO_SECTION_FLAGS) const>(&Section::has),
"Check if the section has the given " RST_CLASS_REF(lief.MachO.SECTION_FLAGS) "",
"flag"_a)

.def("add",
static_cast<void(Section::*)(MACHO_SECTION_FLAGS)>(&Section::add),
"Add the given " RST_CLASS_REF(lief.MachO.SECTION_FLAGS) "",
"flag"_a)

.def("remove",
static_cast<void(Section::*)(MACHO_SECTION_FLAGS)>(&Section::remove),
"Remove the given " RST_CLASS_REF(lief.MachO.SECTION_FLAGS) "",
"flag"_a)

.def(py::self += MACHO_SECTION_FLAGS())
.def(py::self -= MACHO_SECTION_FLAGS())

.def("__contains__",
static_cast<bool (Section::*)(MACHO_SECTION_FLAGS) const>(&Section::has),
"Check if the given " RST_CLASS_REF(lief.MachO.MACHO_SECTION_FLAGS) " is present")



.def("__eq__", &Section::operator==)
.def("__ne__", &Section::operator!=)

0 comments on commit 406115c

Please sign in to comment.