Skip to content

Commit c359778

Browse files
committed
Parse LC_SOURCE_VERSION. Resolve #45
1 parent ba9be1f commit c359778

File tree

14 files changed

+322
-0
lines changed

14 files changed

+322
-0
lines changed

api/python/MachO/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ set(LIEF_PYTHON_MACHO_SRC
99
"${CMAKE_CURRENT_LIST_DIR}/objects/pyParser.cpp"
1010
"${CMAKE_CURRENT_LIST_DIR}/objects/pySymbol.cpp"
1111
"${CMAKE_CURRENT_LIST_DIR}/objects/pyUUID.cpp"
12+
"${CMAKE_CURRENT_LIST_DIR}/objects/pySourceVersion.cpp"
1213
"${CMAKE_CURRENT_LIST_DIR}/objects/pyMainCommand.cpp"
1314
"${CMAKE_CURRENT_LIST_DIR}/objects/pyDylinker.cpp"
1415
"${CMAKE_CURRENT_LIST_DIR}/objects/pyDyldInfo.cpp"

api/python/MachO/objects/pyBinary.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,16 @@ void init_MachO_Binary_class(py::module& m) {
144144
"Return binary's " RST_CLASS_REF(lief.MachO.FunctionStarts) " if any.",
145145
py::return_value_policy::reference)
146146

147+
.def_property_readonly("has_source_version",
148+
&Binary::has_source_version,
149+
"``True`` if the binary has a " RST_CLASS_REF(lief.MachO.SourceVersion) " command.",
150+
py::return_value_policy::reference_internal)
151+
152+
.def_property_readonly("source_version",
153+
static_cast<no_const_getter<SourceVersion&>>(&Binary::source_version),
154+
"Return binary's " RST_CLASS_REF(lief.MachO.SourceVersion) " if any.",
155+
py::return_value_policy::reference)
156+
147157

148158

149159
.def("__str__",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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/visitors/Hash.hpp"
22+
#include "LIEF/MachO/SourceVersion.hpp"
23+
24+
#include "pyMachO.hpp"
25+
26+
template<class T>
27+
using getter_t = T (SourceVersion::*)(void) const;
28+
29+
template<class T>
30+
using setter_t = void (SourceVersion::*)(T);
31+
32+
33+
void init_MachO_SourceVersion_class(py::module& m) {
34+
35+
py::class_<SourceVersion, LoadCommand>(m, "SourceVersion")
36+
37+
.def_property("version",
38+
static_cast<getter_t<const version_t&>>(&SourceVersion::version),
39+
static_cast<setter_t<const version_t&>>(&SourceVersion::version),
40+
"TODO",
41+
py::return_value_policy::reference_internal)
42+
43+
44+
.def("__eq__", &SourceVersion::operator==)
45+
.def("__ne__", &SourceVersion::operator!=)
46+
.def("__hash__",
47+
[] (const SourceVersion& version) {
48+
return LIEF::Hash::hash(version);
49+
})
50+
51+
52+
.def("__str__",
53+
[] (const SourceVersion& version)
54+
{
55+
std::ostringstream stream;
56+
stream << version;
57+
std::string str = stream.str();
58+
return str;
59+
});
60+
61+
}

api/python/MachO/pyMachO.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ void init_MachO_module(py::module& m) {
3939
init_MachO_DylinkerCommand_class(LIEF_MachO_module);
4040
init_MachO_DyldInfo_class(LIEF_MachO_module);
4141
init_MachO_FunctionStarts_class(LIEF_MachO_module);
42+
init_MachO_SourceVersion_class(LIEF_MachO_module);
4243

4344

4445
// Enums

api/python/MachO/pyMachO.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ void init_MachO_MainCommand_class(py::module&);
3939
void init_MachO_DylinkerCommand_class(py::module&);
4040
void init_MachO_DyldInfo_class(py::module&);
4141
void init_MachO_FunctionStarts_class(py::module&);
42+
void init_MachO_SourceVersion_class(py::module&);
4243

4344
// Enums
4445
void init_MachO_Structures_enum(py::module&);

doc/sphinx/api/cpp/macho.rst

+16
Original file line numberDiff line numberDiff line change
@@ -124,3 +124,19 @@ Dyld Info
124124

125125
.. doxygenclass:: LIEF::MachO::DyldInfo
126126
:project: lief
127+
128+
129+
Function starts
130+
***************
131+
132+
.. doxygenclass:: LIEF::MachO::FunctionStarts
133+
:project: lief
134+
135+
136+
----------
137+
138+
Source Version
139+
**************
140+
141+
.. doxygenclass:: LIEF::MachO::SourceVersion
142+
:project: lief

doc/sphinx/api/python/macho.rst

+11
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,17 @@ Function starts
141141

142142
----------
143143

144+
Source Version
145+
**************
146+
147+
.. autoclass:: lief.MachO.SourceVersion
148+
:members:
149+
:inherited-members:
150+
:undoc-members:
151+
152+
----------
153+
154+
144155

145156
Enum
146157
****

examples/python/macho_reader.py

+18
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,17 @@ def print_dyld_info(binary):
253253

254254
print("")
255255

256+
@exceptions_handler(Exception)
257+
def print_source_version(binary):
258+
print("== Source Version ==")
259+
260+
version = binary.source_version.version
261+
262+
print("Version: {:d}.{:d}.{:d}.{:d}.{:d}".format(*version))
263+
264+
print("")
265+
266+
256267
def main():
257268
parser = argparse.ArgumentParser(usage='%(prog)s [options] <macho-file>')
258269
parser.add_argument('-a', '--all',
@@ -303,6 +314,10 @@ def main():
303314
action='store_true', dest='show_function_starts',
304315
help='Display the FunctionStarts command')
305316

317+
parser.add_argument('--source-version',
318+
action='store_true', dest='show_source_version',
319+
help="Display the 'Source Version' command")
320+
306321
parser.add_argument("binary",
307322
metavar="<macho-file>",
308323
help='Target Mach-O File')
@@ -353,6 +368,9 @@ def main():
353368
if (args.show_function_starts or args.show_all) and binary.has_function_starts:
354369
print_function_starts(binary)
355370

371+
if (args.show_source_version or args.show_all) and binary.has_source_version:
372+
print_source_version(binary)
373+
356374

357375
if __name__ == "__main__":
358376
main()

include/LIEF/MachO/Binary.hpp

+8
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include "LIEF/MachO/DynamicSymbolCommand.hpp"
3838
#include "LIEF/MachO/DyldInfo.hpp"
3939
#include "LIEF/MachO/FunctionStarts.hpp"
40+
#include "LIEF/MachO/SourceVersion.hpp"
4041

4142
namespace LIEF {
4243
namespace MachO {
@@ -202,6 +203,13 @@ class DLL_PUBLIC Binary : public LIEF::Binary {
202203
FunctionStarts& function_starts(void);
203204
const FunctionStarts& function_starts(void) const;
204205

206+
//! @brief ``true`` if the binary has a MachO::SourceVersion command.
207+
bool has_source_version(void) const;
208+
209+
//! @brief Return the MachO::SourceVersion command
210+
SourceVersion& source_version(void);
211+
const SourceVersion& source_version(void) const;
212+
205213
template<class T>
206214
bool has_command(void) const;
207215

include/LIEF/MachO/SourceVersion.hpp

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
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+
#ifndef LIEF_MACHO_SOURCE_VERSION_COMMAND_H_
17+
#define LIEF_MACHO_SOURCE_VERSION_COMMAND_H_
18+
#include <string>
19+
#include <vector>
20+
#include <iostream>
21+
#include <array>
22+
23+
#include "LIEF/visibility.h"
24+
#include "LIEF/types.hpp"
25+
26+
#include "LIEF/MachO/LoadCommand.hpp"
27+
28+
namespace LIEF {
29+
namespace MachO {
30+
using version_t = std::array<uint32_t, 5>;
31+
32+
class DLL_PUBLIC SourceVersion : public LoadCommand {
33+
public:
34+
SourceVersion(void);
35+
SourceVersion(const source_version_command *version_cmd);
36+
37+
SourceVersion& operator=(const SourceVersion& copy);
38+
SourceVersion(const SourceVersion& copy);
39+
40+
virtual ~SourceVersion(void);
41+
42+
const version_t& version(void) const;
43+
void version(const version_t& version);
44+
45+
bool operator==(const SourceVersion& rhs) const;
46+
bool operator!=(const SourceVersion& rhs) const;
47+
48+
virtual void accept(Visitor& visitor) const override;
49+
50+
virtual std::ostream& print(std::ostream& os) const override;
51+
52+
private:
53+
version_t version_;
54+
};
55+
56+
}
57+
}
58+
#endif

src/MachO/Binary.cpp

+15
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,21 @@ const FunctionStarts& Binary::function_starts(void) const {
554554
return this->get_command<FunctionStarts>();
555555
}
556556

557+
// Source Version
558+
// ++++++++++++++
559+
bool Binary::has_source_version(void) const {
560+
return this->has_command<SourceVersion>();
561+
}
562+
563+
SourceVersion& Binary::source_version(void) {
564+
return this->get_command<SourceVersion>();
565+
}
566+
567+
const SourceVersion& Binary::source_version(void) const {
568+
return this->get_command<SourceVersion>();
569+
}
570+
571+
557572

558573

559574
void Binary::accept(LIEF::Visitor& visitor) const {

src/MachO/BinaryParser.tcc

+34
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
#include "LIEF/MachO/DyldInfo.hpp"
1717
#include "LIEF/MachO/FunctionStarts.hpp"
18+
#include "LIEF/MachO/SourceVersion.hpp"
1819

1920
#include "easylogging++.h"
2021

@@ -247,6 +248,39 @@ void BinaryParser::parse_load_commands(void) {
247248
break;
248249
}
249250

251+
// ===============
252+
// Source Version
253+
// ===============
254+
case LOAD_COMMAND_TYPES::LC_SOURCE_VERSION:
255+
{
256+
LOG(DEBUG) << "[+] Parsing LC_SOURCE_VERSION";
257+
258+
const source_version_command* cmd =
259+
reinterpret_cast<const source_version_command*>(
260+
this->stream_->read(loadcommands_offset, sizeof(version_min_command)));
261+
262+
load_command = new SourceVersion{cmd};
263+
LOG(DEBUG) << "Version: " << std::hex << cmd->version;
264+
break;
265+
}
266+
267+
//case LOAD_COMMAND_TYPES::LC_VERSION_MIN_MACOSX:
268+
//case LOAD_COMMAND_TYPES::LC_VERSION_MIN_IPHONEOS:
269+
// {
270+
// LOG(DEBUG) << "[+] Parsing " << to_string(static_cast<LOAD_COMMAND_TYPES>(command->cmd));
271+
272+
// const version_min_command* cmd =
273+
// reinterpret_cast<const version_min_command*>(
274+
// this->stream_->read(loadcommands_offset, sizeof(version_min_command)));
275+
// LOG(DEBUG) << "Version: " << std::hex << cmd->version;
276+
// LOG(DEBUG) << "SDK: " << std::hex << cmd->sdk;
277+
278+
// load_command = new LoadCommand{command};
279+
// break;
280+
// }
281+
282+
283+
250284

251285
//case LOAD_COMMAND_TYPES::LC_TWOLEVEL_HINTS:
252286
// {

src/MachO/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ set(LIEF_MACHO_SRC
3636
"${CMAKE_CURRENT_LIST_DIR}/Binary.tcc"
3737
"${CMAKE_CURRENT_LIST_DIR}/BinaryParser.tcc"
3838
"${CMAKE_CURRENT_LIST_DIR}/FunctionStarts.cpp"
39+
"${CMAKE_CURRENT_LIST_DIR}/SourceVersion.cpp"
3940
)
4041

4142
set(LIEF_MACHO_INCLUDE_FILES
@@ -60,6 +61,7 @@ set(LIEF_MACHO_INCLUDE_FILES
6061
"${CMAKE_CURRENT_SOURCE_DIR}/include/LIEF/MachO/FunctionStarts.hpp"
6162
"${CMAKE_CURRENT_BINARY_DIR}/include/LIEF/MachO/Structures.hpp"
6263
"${CMAKE_CURRENT_BINARY_DIR}/include/LIEF/MachO/enums.hpp"
64+
"${CMAKE_CURRENT_SOURCE_DIR}/include/LIEF/MachO/SourceVersion.hpp"
6365
)
6466

6567
source_group("Header Files\\MachO" FILES ${LIEF_MACHO_INCLUDE_FILES})

0 commit comments

Comments
 (0)