Skip to content

Commit 6f96723

Browse files
committed
Introduce Mach-O Build Version command
New API: LIEF::MachO::BuildVersion LIEF::MachO::BuildToolVersion LIEF::MachO::Binary::has_build_version LIEF::MachO::Binary::build_version
1 parent 2c6f052 commit 6f96723

28 files changed

+741
-5
lines changed

api/python/MachO/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ set(LIEF_PYTHON_MACHO_SRC
3333
"${CMAKE_CURRENT_LIST_DIR}/objects/pySubFramework.cpp"
3434
"${CMAKE_CURRENT_LIST_DIR}/objects/pyDyldEnvironment.cpp"
3535
"${CMAKE_CURRENT_LIST_DIR}/objects/pyEncryptionInfo.cpp"
36+
"${CMAKE_CURRENT_LIST_DIR}/objects/pyBuildVersion.cpp"
3637
"${CMAKE_CURRENT_LIST_DIR}/pyEnums.cpp"
3738
)
3839

api/python/MachO/objects/pyBinary.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,16 @@ void create<Binary>(py::module& m) {
300300
"Return binary's " RST_CLASS_REF(lief.MachO.EncryptionInfo) " if any.",
301301
py::return_value_policy::reference)
302302

303+
.def_property_readonly("has_build_version",
304+
&Binary::has_build_version,
305+
"``True`` if the binary has a " RST_CLASS_REF(lief.MachO.BuildVersion) " command",
306+
py::return_value_policy::reference_internal)
307+
308+
.def_property_readonly("build_version",
309+
static_cast<no_const_getter<BuildVersion&>>(&Binary::build_version),
310+
"Return binary's " RST_CLASS_REF(lief.MachO.BuildVersion) " if any.",
311+
py::return_value_policy::reference)
312+
303313

304314
.def("virtual_address_to_offset",
305315
&Binary::virtual_address_to_offset,
+128
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/* Copyright 2017 R. Thomas
2+
* Copyright 2017 Quarkslab
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
#include <algorithm>
17+
18+
#include <string>
19+
#include <sstream>
20+
21+
#include "LIEF/MachO/hash.hpp"
22+
#include "LIEF/MachO/BuildVersion.hpp"
23+
#include "LIEF/MachO/EnumToString.hpp"
24+
25+
#include "enums_wrapper.hpp"
26+
27+
#include "pyMachO.hpp"
28+
29+
#define PY_ENUM(x) LIEF::MachO::to_string(x), x
30+
31+
namespace LIEF {
32+
namespace MachO {
33+
34+
template<class T>
35+
using getter_t = T (BuildVersion::*)(void) const;
36+
37+
template<class T>
38+
using setter_t = void (BuildVersion::*)(T);
39+
40+
41+
template<>
42+
void create<BuildVersion>(py::module& m) {
43+
44+
py::class_<BuildVersion, LoadCommand> cls(m, "BuildVersion");
45+
py::class_<BuildToolVersion, LIEF::Object> tool_version_cls(m, "BuildToolVersion");
46+
47+
48+
// Build Tool Version
49+
// ==================
50+
tool_version_cls
51+
.def_property_readonly("tool",
52+
&BuildToolVersion::tool,
53+
"" RST_CLASS_REF(.BuildeVersion.TOOLS) " type")
54+
55+
.def_property_readonly("version",
56+
&BuildToolVersion::version,
57+
"Version of the tool")
58+
59+
.def("__eq__", &BuildToolVersion::operator==)
60+
.def("__ne__", &BuildToolVersion::operator!=)
61+
.def("__hash__",
62+
[] (const BuildToolVersion& version) {
63+
return Hash::hash(version);
64+
})
65+
66+
.def("__str__",
67+
[] (const BuildToolVersion& version)
68+
{
69+
std::ostringstream stream;
70+
stream << version;
71+
return stream.str();
72+
});
73+
74+
75+
LIEF::enum_<BuildToolVersion::TOOLS>(tool_version_cls, "TOOLS")
76+
.value(PY_ENUM(BuildToolVersion::TOOLS::UNKNOWN))
77+
.value(PY_ENUM(BuildToolVersion::TOOLS::CLANG))
78+
.value(PY_ENUM(BuildToolVersion::TOOLS::SWIFT))
79+
.value(PY_ENUM(BuildToolVersion::TOOLS::LD));
80+
81+
cls
82+
83+
.def_property("platform",
84+
static_cast<getter_t<BuildVersion::PLATFORMS>>(&BuildVersion::platform),
85+
static_cast<setter_t<BuildVersion::PLATFORMS>>(&BuildVersion::platform),
86+
"Target " RST_CLASS_REF(.BuildVersion.PLATFORMS) "")
87+
88+
.def_property("minos",
89+
static_cast<getter_t<BuildVersion::version_t>>(&BuildVersion::minos),
90+
static_cast<setter_t<BuildVersion::version_t>>(&BuildVersion::minos),
91+
"Minimal OS version on which this binary was built to run")
92+
93+
.def_property("sdk",
94+
static_cast<getter_t<BuildVersion::version_t>>(&BuildVersion::minos),
95+
static_cast<setter_t<BuildVersion::version_t>>(&BuildVersion::minos),
96+
"SDK Version")
97+
98+
.def_property_readonly("tools",
99+
static_cast<getter_t<BuildVersion::tools_list_t>>(&BuildVersion::tools),
100+
"List of " RST_CLASS_REF(BuildToolVersion) " used when while this binary")
101+
102+
.def("__eq__", &BuildVersion::operator==)
103+
.def("__ne__", &BuildVersion::operator!=)
104+
.def("__hash__",
105+
[] (const BuildVersion& version) {
106+
return Hash::hash(version);
107+
})
108+
109+
.def("__str__",
110+
[] (const BuildVersion& version)
111+
{
112+
std::ostringstream stream;
113+
stream << version;
114+
return stream.str();
115+
});
116+
117+
118+
LIEF::enum_<BuildVersion::PLATFORMS>(cls, "PLATFORMS")
119+
.value(PY_ENUM(BuildVersion::PLATFORMS::UNKNOWN))
120+
.value(PY_ENUM(BuildVersion::PLATFORMS::MACOS))
121+
.value(PY_ENUM(BuildVersion::PLATFORMS::IOS))
122+
.value(PY_ENUM(BuildVersion::PLATFORMS::TVOS))
123+
.value(PY_ENUM(BuildVersion::PLATFORMS::WATCHOS));
124+
125+
}
126+
127+
}
128+
}

api/python/MachO/pyEnums.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,9 @@ void init_enums(py::module& m) {
138138
.value(PY_ENUM(LIEF::MachO::LOAD_COMMAND_TYPES::LC_LINKER_OPTION))
139139
.value(PY_ENUM(LIEF::MachO::LOAD_COMMAND_TYPES::LC_LINKER_OPTIMIZATION_HINT))
140140
.value(PY_ENUM(LIEF::MachO::LOAD_COMMAND_TYPES::LC_VERSION_MIN_TVOS))
141-
.value(PY_ENUM(LIEF::MachO::LOAD_COMMAND_TYPES::LC_VERSION_MIN_WATCHOS));
141+
.value(PY_ENUM(LIEF::MachO::LOAD_COMMAND_TYPES::LC_VERSION_MIN_WATCHOS))
142+
.value(PY_ENUM(LIEF::MachO::LOAD_COMMAND_TYPES::LC_NOTE))
143+
.value(PY_ENUM(LIEF::MachO::LOAD_COMMAND_TYPES::LC_BUILD_VERSION));
142144

143145

144146
LIEF::enum_<LIEF::MachO::MACHO_SECTION_TYPES>(m, "SECTION_TYPES")

api/python/MachO/pyMachO.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ void init_objects(py::module& m) {
6464
CREATE(SubFramework, m);
6565
CREATE(DyldEnvironment, m);
6666
CREATE(EncryptionInfo, m);
67+
CREATE(BuildVersion, m);
6768
}
6869

6970
}

api/python/MachO/pyMachO.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ SPECIALIZE_CREATE(SegmentSplitInfo);
7777
SPECIALIZE_CREATE(SubFramework);
7878
SPECIALIZE_CREATE(DyldEnvironment);
7979
SPECIALIZE_CREATE(EncryptionInfo);
80+
SPECIALIZE_CREATE(BuildVersion);
8081

8182
}
8283
}

doc/sphinx/api/cpp/macho.rst

+18
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,24 @@ Encryption Info
285285

286286
----------
287287

288+
289+
Build Version
290+
*************
291+
292+
.. doxygenclass:: LIEF::MachO::BuildVersion
293+
:project: lief
294+
295+
----------
296+
297+
298+
Build Tool Version
299+
******************
300+
301+
.. doxygenclass:: LIEF::MachO::BuildToolVersion
302+
:project: lief
303+
304+
----------
305+
288306
Utilities
289307
*********
290308

doc/sphinx/api/python/macho.rst

+21
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,27 @@ Encryption Info
353353

354354
----------
355355

356+
Build Version
357+
*************
358+
359+
.. autoclass:: lief.MachO.BuildVersion
360+
:members:
361+
:inherited-members:
362+
:undoc-members:
363+
364+
----------
365+
366+
Build Tool Version
367+
******************
368+
369+
.. autoclass:: lief.MachO.BuildToolVersion
370+
:members:
371+
:inherited-members:
372+
:undoc-members:
373+
374+
----------
375+
376+
356377

357378

358379
Enums

examples/python/macho_reader.py

+22
Original file line numberDiff line numberDiff line change
@@ -672,7 +672,22 @@ def print_functions(binary):
672672
for idx, f in enumerate(binary.functions):
673673
print(" [{:d}] {}: 0x{:x}".format(idx, f.name, f.address))
674674

675+
@exceptions_handler(Exception)
676+
def print_build_version(binary):
677+
print("== Build Version ==\n")
678+
679+
build_version = binary.build_version
680+
681+
print("Platform: {}".format(str(build_version.platform).split(".")[-1]))
682+
print("Min OS: {:d}.{:d}.{:d}".format(*build_version.minos))
683+
print("SDK: {:d}.{:d}.{:d}".format(*build_version.sdk))
675684

685+
tools = build_version.tools
686+
if len(tools) > 0:
687+
print("~~ Tools ({}) ~~".format(len(tools)))
688+
for tool in tools:
689+
tool_str = str(tool.tool).split(".")[-1]
690+
print(" {} - {}.{}.{}".format(tool_str, *tool.version))
676691

677692
def main():
678693
parser = argparse.ArgumentParser(usage='%(prog)s [options] <macho-file>')
@@ -808,6 +823,10 @@ def main():
808823
action='store_true', dest='show_functions',
809824
help='All functions found in the binary')
810825

826+
parser.add_argument('--build-version',
827+
action='store_true', dest='show_build_version',
828+
help='Show build version')
829+
811830
parser.add_argument("binary",
812831
metavar="<macho-file>",
813832
help='Target Mach-O File')
@@ -924,6 +943,9 @@ def main():
924943
if args.show_functions or args.show_all:
925944
print_functions(binary)
926945

946+
if (args.show_build_version or args.show_all) and binary.has_build_version:
947+
print_build_version(binary)
948+
927949
sys.exit(EXIT_STATUS)
928950

929951

include/LIEF/MachO/Binary.hpp

+8
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
#include "LIEF/MachO/SubFramework.hpp"
4848
#include "LIEF/MachO/DyldEnvironment.hpp"
4949
#include "LIEF/MachO/EncryptionInfo.hpp"
50+
#include "LIEF/MachO/BuildVersion.hpp"
5051

5152
namespace LIEF {
5253
namespace MachO {
@@ -403,6 +404,13 @@ class LIEF_API Binary : public LIEF::Binary {
403404
DyldEnvironment& dyld_environment(void);
404405
const DyldEnvironment& dyld_environment(void) const;
405406

407+
//! ``true`` if the binary has Build Version command.
408+
bool has_build_version(void) const;
409+
410+
//! Return the MachO::BuildVersion
411+
BuildVersion& build_version(void);
412+
const BuildVersion& build_version(void) const;
413+
406414
template<class T>
407415
LIEF_LOCAL bool has_command(void) const;
408416

0 commit comments

Comments
 (0)