Skip to content

Commit 406115c

Browse files
committed
Enhance Mach-O modification
* Add load command * Add sections * Add segments Resolve #46 (partially)
1 parent 5ec8956 commit 406115c

File tree

102 files changed

+5679
-895
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

102 files changed

+5679
-895
lines changed

api/c/include/LIEF/MachO/enums.h.in

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,18 @@
66
extern "C" {
77
#endif
88

9+
#ifdef _LIEF_EN
10+
#undef _LIEF_EN
11+
#endif
12+
13+
#ifdef _LIEF_EN_2
14+
#undef _LIEF_EN_2
15+
#endif
16+
17+
#ifdef _LIEF_EI
18+
#undef _LIEF_EI
19+
#endif
20+
921
#define _LIEF_EN(N) LIEF_MACHO_##N // enum LIEF_N {
1022
#define _LIEF_EN_2(N, TYPE) LIEF_MACHO_##N // enum LIEF_N {
1123
#define _LIEF_EI(X) LIEF_MACHO_##X // LIEF_X

api/python/MachO/objects/pyBinary.cpp

Lines changed: 126 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,22 +105,22 @@ void create<Binary>(py::module& m) {
105105
py::return_value_policy::copy)
106106

107107
.def("section_from_offset",
108-
static_cast<Section& (Binary::*)(uint64_t)>(&Binary::section_from_offset),
108+
static_cast<Section* (Binary::*)(uint64_t)>(&Binary::section_from_offset),
109109
"Return the " RST_CLASS_REF(lief.MachO.Section) " which contains the offset",
110110
py::return_value_policy::reference)
111111

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

117117
.def("segment_from_offset",
118-
static_cast<SegmentCommand& (Binary::*)(uint64_t)>(&Binary::segment_from_offset),
118+
static_cast<SegmentCommand* (Binary::*)(uint64_t)>(&Binary::segment_from_offset),
119119
"Return the " RST_CLASS_REF(lief.MachO.SegmentCommand) " which contains the offset",
120120
py::return_value_policy::reference)
121121

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

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

320+
.def("has_segment",
321+
&Binary::has_segment,
322+
"Check if a " RST_CLASS_REF(lief.MachO.SegmentCommand) " with the given name exists",
323+
"name"_a)
324+
325+
.def("get_segment",
326+
static_cast<SegmentCommand* (Binary::*)(const std::string&)>(&Binary::get_segment),
327+
"Return the " RST_CLASS_REF(lief.MachO.SegmentCommand) " from the given name",
328+
"name"_a,
329+
py::return_value_policy::reference)
330+
320331
.def_property_readonly("va_ranges",
321332
&Binary::va_ranges,
322333
"Return the range of virtual addresses as a tuple ``(va_start, va_end)``")
323334

335+
.def_property_readonly("off_ranges",
336+
&Binary::off_ranges,
337+
"Return the range of offsets as a tuple ``(off_start, off_end)``")
338+
324339
.def("is_valid_addr",
325340
&Binary::is_valid_addr,
326341
"Check if the given address is comprise between the lowest "
327342
"virtual address and the biggest one",
328343
"address"_a)
329344

345+
.def("write",
346+
&Binary::write,
347+
"Rebuild the binary and write it in a file",
348+
"output"_a,
349+
py::return_value_policy::reference_internal)
350+
351+
.def("add",
352+
static_cast<LoadCommand& (Binary::*)(const DylibCommand&)>(&Binary::add),
353+
"Add a new " RST_CLASS_REF(lief.MachO.DylibCommand) "",
354+
"dylib_command"_a,
355+
py::return_value_policy::reference)
356+
357+
.def("add",
358+
static_cast<LoadCommand& (Binary::*)(const SegmentCommand&)>(&Binary::add),
359+
"Add a new " RST_CLASS_REF(lief.MachO.SegmentCommand) "",
360+
"segment"_a,
361+
py::return_value_policy::reference)
362+
363+
.def("add",
364+
static_cast<LoadCommand& (Binary::*)(const LoadCommand&)>(&Binary::add),
365+
"Add a new " RST_CLASS_REF(lief.MachO.LoadCommand) "",
366+
"load_command"_a,
367+
py::return_value_policy::reference)
368+
369+
.def("add",
370+
static_cast<LoadCommand& (Binary::*)(const LoadCommand&, size_t)>(&Binary::add),
371+
"Add a new " RST_CLASS_REF(lief.MachO.LoadCommand) " at ``index``",
372+
"load_command"_a, "index"_a,
373+
py::return_value_policy::reference)
374+
375+
376+
.def("remove",
377+
static_cast<bool (Binary::*)(const LoadCommand&)>(&Binary::remove),
378+
"Remove a " RST_CLASS_REF(lief.MachO.LoadCommand) "",
379+
"load_command"_a)
380+
381+
.def("remove",
382+
static_cast<bool (Binary::*)(LOAD_COMMAND_TYPES)>(&Binary::remove),
383+
"Remove **all** " RST_CLASS_REF(lief.MachO.LoadCommand) " having the given "
384+
"" RST_CLASS_REF(lief.MachO.LOAD_COMMAND_TYPES) "",
385+
"type"_a)
386+
387+
.def("remove_command",
388+
static_cast<bool (Binary::*)(size_t)>(&Binary::remove_command),
389+
"Remove the " RST_CLASS_REF(lief.MachO.LoadCommand) " at ``index``",
390+
"index"_a)
391+
392+
.def("remove_signature",
393+
static_cast<bool (Binary::*)(void)>(&Binary::remove_signature),
394+
"Remove the " RST_CLASS_REF(lief.MachO.CodeSignature) " (if any)")
395+
396+
.def("extend",
397+
static_cast<bool (Binary::*)(const LoadCommand&, uint64_t)>(&Binary::extend),
398+
"Extend a " RST_CLASS_REF(lief.MachO.LoadCommand) " by ``size``",
399+
"load_command"_a, "size"_a)
400+
401+
.def("extend_segment",
402+
static_cast<bool (Binary::*)(const SegmentCommand&, size_t)>(&Binary::extend_segment),
403+
"Extend the **content** of the given " RST_CLASS_REF(lief.MachO.SegmentCommand) " by ``size``",
404+
"segment_command"_a, "size"_a)
405+
406+
.def("add_section",
407+
static_cast<Section* (Binary::*)(const SegmentCommand&, const Section&)>(&Binary::add_section),
408+
"Add a new " RST_CLASS_REF(lief.MachO.Section) " in the given " RST_CLASS_REF(lief.MachO.SegmentCommand) "",
409+
"segment"_a, "section"_a,
410+
py::return_value_policy::reference)
411+
412+
.def("add_section",
413+
static_cast<Section* (Binary::*)(const Section&)>(&Binary::add_section),
414+
"Add a new " RST_CLASS_REF(lief.MachO.Section) " within the ``__TEXT`` segment",
415+
"section"_a,
416+
py::return_value_policy::reference)
417+
418+
419+
.def("add_section",
420+
static_cast<Section* (Binary::*)(const SegmentCommand&, const Section&)>(&Binary::add_section),
421+
"Add a new " RST_CLASS_REF(lief.MachO.Section) " in the given " RST_CLASS_REF(lief.MachO.SegmentCommand) "",
422+
"section"_a, "section"_a,
423+
py::return_value_policy::reference)
424+
425+
.def("add_library",
426+
static_cast<LoadCommand& (Binary::*)(const std::string&)>(&Binary::add_library),
427+
"Add a new library dependency",
428+
"library_name"_a,
429+
py::return_value_policy::reference)
430+
431+
.def("get",
432+
static_cast<LoadCommand& (Binary::*)(LOAD_COMMAND_TYPES)>(&Binary::get),
433+
"Return the **first** " RST_CLASS_REF(lief.MachO.LoadCommand) " having the given "
434+
"" RST_CLASS_REF(lief.MachO.LOAD_COMMAND_TYPES) "",
435+
"type"_a,
436+
py::return_value_policy::reference)
437+
438+
.def("has",
439+
static_cast<bool(Binary::*)(LOAD_COMMAND_TYPES) const>(&Binary::has),
440+
"Check if the current binary has a " RST_CLASS_REF(lief.MachO.LoadCommand) " with the given "
441+
"" RST_CLASS_REF(lief.MachO.LOAD_COMMAND_TYPES) "",
442+
"type"_a)
443+
444+
.def("__getitem__",
445+
static_cast<LoadCommand& (Binary::*)(LOAD_COMMAND_TYPES)>(&Binary::operator[]),
446+
"",
447+
py::return_value_policy::reference)
448+
449+
.def("__contains__",
450+
static_cast<bool(Binary::*)(LOAD_COMMAND_TYPES) const>(&Binary::has))
451+
330452

331453
.def("__str__",
332454
[] (const Binary& binary)

api/python/MachO/objects/pyDyldInfo.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,6 @@ void create<DyldInfo>(py::module& m) {
263263
&DyldInfo::set_export_size,
264264
"size"_a)
265265

266-
267266
.def("__eq__", &DyldInfo::operator==)
268267
.def("__ne__", &DyldInfo::operator!=)
269268
.def("__hash__",

api/python/MachO/objects/pyDylibCommand.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,35 @@ void create<DylibCommand>(py::module& m) {
6262
"Library's compatibility version",
6363
py::return_value_policy::reference_internal)
6464

65+
.def_static("weak_lib",
66+
&DylibCommand::weak_dylib,
67+
"Factory function to generate a " RST_CLASS_REF(lief.MachO.LOAD_COMMAND_TYPES.LC_LOAD_WEAK_DYLIB) " library",
68+
"name"_a, "timestamp"_a = 0, "current_version"_a = 0, "compat_version"_a = 0)
69+
70+
.def_static("id_dylib",
71+
&DylibCommand::id_dylib,
72+
"Factory function to generate a " RST_CLASS_REF(lief.MachO.LOAD_COMMAND_TYPES.ID_DYLIB) " library",
73+
"name"_a, "timestamp"_a = 0, "current_version"_a = 0, "compat_version"_a = 0)
74+
75+
.def_static("load_dylib",
76+
&DylibCommand::load_dylib,
77+
"Factory function to generate a " RST_CLASS_REF(lief.MachO.LOAD_COMMAND_TYPES.LOAD_DYLIB) " library",
78+
"name"_a, "timestamp"_a = 0, "current_version"_a = 0, "compat_version"_a = 0)
79+
80+
.def_static("reexport_dylib",
81+
&DylibCommand::reexport_dylib,
82+
"Factory function to generate a " RST_CLASS_REF(lief.MachO.LOAD_COMMAND_TYPES.REEXPORT_DYLIB) " library",
83+
"name"_a, "timestamp"_a = 0, "current_version"_a = 0, "compat_version"_a = 0)
84+
85+
.def_static("load_upward_dylib",
86+
&DylibCommand::load_upward_dylib,
87+
"Factory function to generate a " RST_CLASS_REF(lief.MachO.LOAD_COMMAND_TYPES.LOAD_UPWARD_DYLIB) " library",
88+
"name"_a, "timestamp"_a = 0, "current_version"_a = 0, "compat_version"_a = 0)
89+
90+
.def_static("lazy_load_dylib",
91+
&DylibCommand::lazy_load_dylib,
92+
"Factory function to generate a " RST_CLASS_REF(lief.MachO.LOAD_COMMAND_TYPES.LAZY_LOAD_DYLIB) " library",
93+
"name"_a, "timestamp"_a = 0, "current_version"_a = 0, "compat_version"_a = 0)
6594

6695
.def("__eq__", &DylibCommand::operator==)
6796
.def("__ne__", &DylibCommand::operator!=)

api/python/MachO/objects/pyExportInfo.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ namespace MachO {
2929
template<class T>
3030
using getter_t = T (ExportInfo::*)(void) const;
3131

32+
template<class T>
33+
using no_const_getter_t = T (ExportInfo::*)(void);
34+
3235
template<class T>
3336
using setter_t = void (ExportInfo::*)(T);
3437

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

47+
.def_property_readonly("kind",
48+
static_cast<getter_t<EXPORT_SYMBOL_KINDS>>(&ExportInfo::kind),
49+
"Type of the symbol associated with the export (" RST_CLASS_REF(lief.MachO.EXPORT_SYMBOL_KINDS) ")")
50+
51+
.def_property_readonly("flags_list",
52+
static_cast<getter_t<ExportInfo::flag_list_t>>(&ExportInfo::flags_list),
53+
"Return flags as a list of " RST_CLASS_REF(lief.MachO.EXPORT_SYMBOL_KINDS) "")
54+
4455
.def_property("flags",
4556
static_cast<getter_t<uint64_t>>(&ExportInfo::flags),
4657
static_cast<setter_t<uint64_t>>(&ExportInfo::flags),
@@ -51,10 +62,26 @@ void create<ExportInfo>(py::module& m) {
5162
static_cast<setter_t<uint64_t>>(&ExportInfo::address),
5263
py::return_value_policy::reference_internal)
5364

65+
.def_property_readonly("alias",
66+
static_cast<no_const_getter_t<Symbol*>>(&ExportInfo::alias),
67+
"" RST_CLASS_REF(lief.MachO.Symbol) " alias if the current symbol is a re-exported one",
68+
py::return_value_policy::reference)
69+
70+
.def_property_readonly("alias_library",
71+
static_cast<no_const_getter_t<DylibCommand*>>(&ExportInfo::alias_library),
72+
"If the current symbol has an alias, it returns the " RST_CLASS_REF(lief.MachO.DylibCommand) " "
73+
" command associated with",
74+
py::return_value_policy::reference)
75+
5476
.def_property_readonly("has_symbol",
5577
&ExportInfo::has_symbol,
5678
"``True`` if the export info has a " RST_CLASS_REF(lief.MachO.Symbol) " associated with")
5779

80+
.def("has",
81+
&ExportInfo::has,
82+
"Check if the flag " RST_CLASS_REF(lief.MachO.EXPORT_SYMBOL_FLAGS) " given in first parameter is present"
83+
"flag"_a)
84+
5885
.def_property_readonly("symbol",
5986
static_cast<Symbol& (ExportInfo::*)(void)>(&ExportInfo::symbol),
6087
"" RST_CLASS_REF(lief.MachO.Symbol) " associated with the export (if any)",

api/python/MachO/objects/pyLoadCommand.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,17 +46,17 @@ void create<LoadCommand>(py::module& m) {
4646
.def_property("size",
4747
static_cast<getter_t<uint32_t>>(&LoadCommand::size),
4848
static_cast<setter_t<uint32_t>>(&LoadCommand::size),
49-
"Command size")
49+
"Size of the command (should be greather than ``sizeof(load_command)``)")
5050

5151
.def_property("data",
52-
static_cast<getter_t<const std::vector<uint8_t>&>>(&LoadCommand::data),
53-
static_cast<setter_t<const std::vector<uint8_t>&>>(&LoadCommand::data),
52+
static_cast<getter_t<const LoadCommand::raw_t&>>(&LoadCommand::data),
53+
static_cast<setter_t<const LoadCommand::raw_t&>>(&LoadCommand::data),
5454
"Command's data")
5555

5656
.def_property("command_offset",
5757
static_cast<getter_t<uint64_t>>(&LoadCommand::command_offset),
5858
static_cast<setter_t<uint64_t>>(&LoadCommand::command_offset),
59-
"Offset to the comand")
59+
"Offset of the command within the *Load Command Table*")
6060

6161
.def("__eq__", &LoadCommand::operator==)
6262
.def("__ne__", &LoadCommand::operator!=)

api/python/MachO/objects/pyRelocationDyld.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ void create<RelocationDyld>(py::module& m) {
3838

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

41+
.def("__le__", &RelocationDyld::operator<=)
42+
.def("__lt__", &RelocationDyld::operator<)
43+
.def("__ge__", &RelocationDyld::operator>=)
44+
.def("__gt__", &RelocationDyld::operator>)
4145
.def("__eq__", &RelocationDyld::operator==)
4246
.def("__ne__", &RelocationDyld::operator!=)
4347
.def("__hash__",

api/python/MachO/objects/pySection.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@ void create<Section>(py::module& m) {
4040
py::class_<Section, LIEF::Section>(m, "Section")
4141
.def(py::init<>())
4242

43+
.def(py::init<const std::string&>(),
44+
"Constructor with the section name",
45+
"section_name"_a)
46+
47+
.def(py::init<const std::string&, const Section::content_t&>(),
48+
"Constructor with the section name and its content",
49+
"section_name"_a, "content"_a)
50+
4351
.def_property("alignment",
4452
static_cast<getter_t<uint32_t>>(&Section::alignment),
4553
static_cast<setter_t<uint32_t>>(&Section::alignment),
@@ -65,6 +73,53 @@ void create<Section>(py::module& m) {
6573
"Iterator over " RST_CLASS_REF(lief.MachO.Relocation) " (if any)",
6674
py::return_value_policy::reference_internal)
6775

76+
.def_property("reserved1",
77+
static_cast<getter_t<uint32_t>>(&Section::reserved1),
78+
static_cast<setter_t<uint32_t>>(&Section::reserved1),
79+
"")
80+
81+
.def_property("reserved2",
82+
static_cast<getter_t<uint32_t>>(&Section::reserved2),
83+
static_cast<setter_t<uint32_t>>(&Section::reserved2),
84+
"")
85+
86+
.def_property("reserved3",
87+
static_cast<getter_t<uint32_t>>(&Section::reserved3),
88+
static_cast<setter_t<uint32_t>>(&Section::reserved3),
89+
"")
90+
91+
.def_property("flags",
92+
static_cast<getter_t<uint32_t>>(&Section::flags),
93+
static_cast<setter_t<uint32_t>>(&Section::flags),
94+
"")
95+
96+
.def_property_readonly("flags_list",
97+
static_cast<getter_t<Section::flag_list_t>>(&Section::flags_list),
98+
py::return_value_policy::reference_internal)
99+
100+
.def("has",
101+
static_cast<bool(Section::*)(MACHO_SECTION_FLAGS) const>(&Section::has),
102+
"Check if the section has the given " RST_CLASS_REF(lief.MachO.SECTION_FLAGS) "",
103+
"flag"_a)
104+
105+
.def("add",
106+
static_cast<void(Section::*)(MACHO_SECTION_FLAGS)>(&Section::add),
107+
"Add the given " RST_CLASS_REF(lief.MachO.SECTION_FLAGS) "",
108+
"flag"_a)
109+
110+
.def("remove",
111+
static_cast<void(Section::*)(MACHO_SECTION_FLAGS)>(&Section::remove),
112+
"Remove the given " RST_CLASS_REF(lief.MachO.SECTION_FLAGS) "",
113+
"flag"_a)
114+
115+
.def(py::self += MACHO_SECTION_FLAGS())
116+
.def(py::self -= MACHO_SECTION_FLAGS())
117+
118+
.def("__contains__",
119+
static_cast<bool (Section::*)(MACHO_SECTION_FLAGS) const>(&Section::has),
120+
"Check if the given " RST_CLASS_REF(lief.MachO.MACHO_SECTION_FLAGS) " is present")
121+
122+
68123

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

0 commit comments

Comments
 (0)