mirror of
https://github.com/QuasarApp/LIEF.git
synced 2025-05-10 18:59:33 +00:00
Merge branch 'feature/build_version'
This commit is contained in:
commit
f2b93bf796
api/python/MachO
doc/sphinx/api
examples/python
include/LIEF
MachO
Visitor.hppsrc/MachO
Binary.cppBinaryParser.tccBuildVersion.cppBuilder.cppBuilder.tccCMakeLists.txtEnumToString.cpphash.cppjson.cpp
tests/macho
@ -33,6 +33,7 @@ set(LIEF_PYTHON_MACHO_SRC
|
||||
"${CMAKE_CURRENT_LIST_DIR}/objects/pySubFramework.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/objects/pyDyldEnvironment.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/objects/pyEncryptionInfo.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/objects/pyBuildVersion.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/pyEnums.cpp"
|
||||
)
|
||||
|
||||
|
@ -300,6 +300,16 @@ void create<Binary>(py::module& m) {
|
||||
"Return binary's " RST_CLASS_REF(lief.MachO.EncryptionInfo) " if any.",
|
||||
py::return_value_policy::reference)
|
||||
|
||||
.def_property_readonly("has_build_version",
|
||||
&Binary::has_build_version,
|
||||
"``True`` if the binary has a " RST_CLASS_REF(lief.MachO.BuildVersion) " command",
|
||||
py::return_value_policy::reference_internal)
|
||||
|
||||
.def_property_readonly("build_version",
|
||||
static_cast<no_const_getter<BuildVersion&>>(&Binary::build_version),
|
||||
"Return binary's " RST_CLASS_REF(lief.MachO.BuildVersion) " if any.",
|
||||
py::return_value_policy::reference)
|
||||
|
||||
|
||||
.def("virtual_address_to_offset",
|
||||
&Binary::virtual_address_to_offset,
|
||||
|
128
api/python/MachO/objects/pyBuildVersion.cpp
Normal file
128
api/python/MachO/objects/pyBuildVersion.cpp
Normal file
@ -0,0 +1,128 @@
|
||||
/* Copyright 2017 R. Thomas
|
||||
* Copyright 2017 Quarkslab
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include <algorithm>
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include "LIEF/MachO/hash.hpp"
|
||||
#include "LIEF/MachO/BuildVersion.hpp"
|
||||
#include "LIEF/MachO/EnumToString.hpp"
|
||||
|
||||
#include "enums_wrapper.hpp"
|
||||
|
||||
#include "pyMachO.hpp"
|
||||
|
||||
#define PY_ENUM(x) LIEF::MachO::to_string(x), x
|
||||
|
||||
namespace LIEF {
|
||||
namespace MachO {
|
||||
|
||||
template<class T>
|
||||
using getter_t = T (BuildVersion::*)(void) const;
|
||||
|
||||
template<class T>
|
||||
using setter_t = void (BuildVersion::*)(T);
|
||||
|
||||
|
||||
template<>
|
||||
void create<BuildVersion>(py::module& m) {
|
||||
|
||||
py::class_<BuildVersion, LoadCommand> cls(m, "BuildVersion");
|
||||
py::class_<BuildToolVersion, LIEF::Object> tool_version_cls(m, "BuildToolVersion");
|
||||
|
||||
|
||||
// Build Tool Version
|
||||
// ==================
|
||||
tool_version_cls
|
||||
.def_property_readonly("tool",
|
||||
&BuildToolVersion::tool,
|
||||
"" RST_CLASS_REF(.BuildeVersion.TOOLS) " type")
|
||||
|
||||
.def_property_readonly("version",
|
||||
&BuildToolVersion::version,
|
||||
"Version of the tool")
|
||||
|
||||
.def("__eq__", &BuildToolVersion::operator==)
|
||||
.def("__ne__", &BuildToolVersion::operator!=)
|
||||
.def("__hash__",
|
||||
[] (const BuildToolVersion& version) {
|
||||
return Hash::hash(version);
|
||||
})
|
||||
|
||||
.def("__str__",
|
||||
[] (const BuildToolVersion& version)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
stream << version;
|
||||
return stream.str();
|
||||
});
|
||||
|
||||
|
||||
LIEF::enum_<BuildToolVersion::TOOLS>(tool_version_cls, "TOOLS")
|
||||
.value(PY_ENUM(BuildToolVersion::TOOLS::UNKNOWN))
|
||||
.value(PY_ENUM(BuildToolVersion::TOOLS::CLANG))
|
||||
.value(PY_ENUM(BuildToolVersion::TOOLS::SWIFT))
|
||||
.value(PY_ENUM(BuildToolVersion::TOOLS::LD));
|
||||
|
||||
cls
|
||||
|
||||
.def_property("platform",
|
||||
static_cast<getter_t<BuildVersion::PLATFORMS>>(&BuildVersion::platform),
|
||||
static_cast<setter_t<BuildVersion::PLATFORMS>>(&BuildVersion::platform),
|
||||
"Target " RST_CLASS_REF(.BuildVersion.PLATFORMS) "")
|
||||
|
||||
.def_property("minos",
|
||||
static_cast<getter_t<BuildVersion::version_t>>(&BuildVersion::minos),
|
||||
static_cast<setter_t<BuildVersion::version_t>>(&BuildVersion::minos),
|
||||
"Minimal OS version on which this binary was built to run")
|
||||
|
||||
.def_property("sdk",
|
||||
static_cast<getter_t<BuildVersion::version_t>>(&BuildVersion::minos),
|
||||
static_cast<setter_t<BuildVersion::version_t>>(&BuildVersion::minos),
|
||||
"SDK Version")
|
||||
|
||||
.def_property_readonly("tools",
|
||||
static_cast<getter_t<BuildVersion::tools_list_t>>(&BuildVersion::tools),
|
||||
"List of " RST_CLASS_REF(BuildToolVersion) " used when while this binary")
|
||||
|
||||
.def("__eq__", &BuildVersion::operator==)
|
||||
.def("__ne__", &BuildVersion::operator!=)
|
||||
.def("__hash__",
|
||||
[] (const BuildVersion& version) {
|
||||
return Hash::hash(version);
|
||||
})
|
||||
|
||||
.def("__str__",
|
||||
[] (const BuildVersion& version)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
stream << version;
|
||||
return stream.str();
|
||||
});
|
||||
|
||||
|
||||
LIEF::enum_<BuildVersion::PLATFORMS>(cls, "PLATFORMS")
|
||||
.value(PY_ENUM(BuildVersion::PLATFORMS::UNKNOWN))
|
||||
.value(PY_ENUM(BuildVersion::PLATFORMS::MACOS))
|
||||
.value(PY_ENUM(BuildVersion::PLATFORMS::IOS))
|
||||
.value(PY_ENUM(BuildVersion::PLATFORMS::TVOS))
|
||||
.value(PY_ENUM(BuildVersion::PLATFORMS::WATCHOS));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -138,7 +138,9 @@ void init_enums(py::module& m) {
|
||||
.value(PY_ENUM(LIEF::MachO::LOAD_COMMAND_TYPES::LC_LINKER_OPTION))
|
||||
.value(PY_ENUM(LIEF::MachO::LOAD_COMMAND_TYPES::LC_LINKER_OPTIMIZATION_HINT))
|
||||
.value(PY_ENUM(LIEF::MachO::LOAD_COMMAND_TYPES::LC_VERSION_MIN_TVOS))
|
||||
.value(PY_ENUM(LIEF::MachO::LOAD_COMMAND_TYPES::LC_VERSION_MIN_WATCHOS));
|
||||
.value(PY_ENUM(LIEF::MachO::LOAD_COMMAND_TYPES::LC_VERSION_MIN_WATCHOS))
|
||||
.value(PY_ENUM(LIEF::MachO::LOAD_COMMAND_TYPES::LC_NOTE))
|
||||
.value(PY_ENUM(LIEF::MachO::LOAD_COMMAND_TYPES::LC_BUILD_VERSION));
|
||||
|
||||
|
||||
LIEF::enum_<LIEF::MachO::MACHO_SECTION_TYPES>(m, "SECTION_TYPES")
|
||||
|
@ -64,6 +64,7 @@ void init_objects(py::module& m) {
|
||||
CREATE(SubFramework, m);
|
||||
CREATE(DyldEnvironment, m);
|
||||
CREATE(EncryptionInfo, m);
|
||||
CREATE(BuildVersion, m);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -77,6 +77,7 @@ SPECIALIZE_CREATE(SegmentSplitInfo);
|
||||
SPECIALIZE_CREATE(SubFramework);
|
||||
SPECIALIZE_CREATE(DyldEnvironment);
|
||||
SPECIALIZE_CREATE(EncryptionInfo);
|
||||
SPECIALIZE_CREATE(BuildVersion);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -285,6 +285,24 @@ Encryption Info
|
||||
|
||||
----------
|
||||
|
||||
|
||||
Build Version
|
||||
*************
|
||||
|
||||
.. doxygenclass:: LIEF::MachO::BuildVersion
|
||||
:project: lief
|
||||
|
||||
----------
|
||||
|
||||
|
||||
Build Tool Version
|
||||
******************
|
||||
|
||||
.. doxygenclass:: LIEF::MachO::BuildToolVersion
|
||||
:project: lief
|
||||
|
||||
----------
|
||||
|
||||
Utilities
|
||||
*********
|
||||
|
||||
|
@ -353,6 +353,27 @@ Encryption Info
|
||||
|
||||
----------
|
||||
|
||||
Build Version
|
||||
*************
|
||||
|
||||
.. autoclass:: lief.MachO.BuildVersion
|
||||
:members:
|
||||
:inherited-members:
|
||||
:undoc-members:
|
||||
|
||||
----------
|
||||
|
||||
Build Tool Version
|
||||
******************
|
||||
|
||||
.. autoclass:: lief.MachO.BuildToolVersion
|
||||
:members:
|
||||
:inherited-members:
|
||||
:undoc-members:
|
||||
|
||||
----------
|
||||
|
||||
|
||||
|
||||
|
||||
Enums
|
||||
|
@ -672,7 +672,22 @@ def print_functions(binary):
|
||||
for idx, f in enumerate(binary.functions):
|
||||
print(" [{:d}] {}: 0x{:x}".format(idx, f.name, f.address))
|
||||
|
||||
@exceptions_handler(Exception)
|
||||
def print_build_version(binary):
|
||||
print("== Build Version ==\n")
|
||||
|
||||
build_version = binary.build_version
|
||||
|
||||
print("Platform: {}".format(str(build_version.platform).split(".")[-1]))
|
||||
print("Min OS: {:d}.{:d}.{:d}".format(*build_version.minos))
|
||||
print("SDK: {:d}.{:d}.{:d}".format(*build_version.sdk))
|
||||
|
||||
tools = build_version.tools
|
||||
if len(tools) > 0:
|
||||
print("~~ Tools ({}) ~~".format(len(tools)))
|
||||
for tool in tools:
|
||||
tool_str = str(tool.tool).split(".")[-1]
|
||||
print(" {} - {}.{}.{}".format(tool_str, *tool.version))
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(usage='%(prog)s [options] <macho-file>')
|
||||
@ -808,6 +823,10 @@ def main():
|
||||
action='store_true', dest='show_functions',
|
||||
help='All functions found in the binary')
|
||||
|
||||
parser.add_argument('--build-version',
|
||||
action='store_true', dest='show_build_version',
|
||||
help='Show build version')
|
||||
|
||||
parser.add_argument("binary",
|
||||
metavar="<macho-file>",
|
||||
help='Target Mach-O File')
|
||||
@ -924,6 +943,9 @@ def main():
|
||||
if args.show_functions or args.show_all:
|
||||
print_functions(binary)
|
||||
|
||||
if (args.show_build_version or args.show_all) and binary.has_build_version:
|
||||
print_build_version(binary)
|
||||
|
||||
sys.exit(EXIT_STATUS)
|
||||
|
||||
|
||||
|
@ -47,6 +47,7 @@
|
||||
#include "LIEF/MachO/SubFramework.hpp"
|
||||
#include "LIEF/MachO/DyldEnvironment.hpp"
|
||||
#include "LIEF/MachO/EncryptionInfo.hpp"
|
||||
#include "LIEF/MachO/BuildVersion.hpp"
|
||||
|
||||
namespace LIEF {
|
||||
namespace MachO {
|
||||
@ -403,6 +404,13 @@ class LIEF_API Binary : public LIEF::Binary {
|
||||
DyldEnvironment& dyld_environment(void);
|
||||
const DyldEnvironment& dyld_environment(void) const;
|
||||
|
||||
//! ``true`` if the binary has Build Version command.
|
||||
bool has_build_version(void) const;
|
||||
|
||||
//! Return the MachO::BuildVersion
|
||||
BuildVersion& build_version(void);
|
||||
const BuildVersion& build_version(void) const;
|
||||
|
||||
template<class T>
|
||||
LIEF_LOCAL bool has_command(void) const;
|
||||
|
||||
|
125
include/LIEF/MachO/BuildVersion.hpp
Normal file
125
include/LIEF/MachO/BuildVersion.hpp
Normal file
@ -0,0 +1,125 @@
|
||||
/* Copyright 2017 R. Thomas
|
||||
* Copyright 2017 Quarkslab
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef LIEF_MACHO_BUILD_VERSION_COMMAND_H_
|
||||
#define LIEF_MACHO_BUILD_VERSION_COMMAND_H_
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <array>
|
||||
|
||||
#include "LIEF/visibility.h"
|
||||
#include "LIEF/types.hpp"
|
||||
|
||||
#include "LIEF/MachO/LoadCommand.hpp"
|
||||
|
||||
namespace LIEF {
|
||||
namespace MachO {
|
||||
|
||||
|
||||
class BuildToolVersion : public LIEF::Object {
|
||||
public:
|
||||
//! @brief Version is an array of **3** integers
|
||||
using version_t = std::array<uint32_t, 3>;
|
||||
|
||||
public:
|
||||
enum class TOOLS {
|
||||
UNKNOWN = 0,
|
||||
CLANG = 1,
|
||||
SWIFT = 2,
|
||||
LD = 3,
|
||||
};
|
||||
|
||||
public:
|
||||
BuildToolVersion(void);
|
||||
BuildToolVersion(const build_tool_version& tool);
|
||||
|
||||
//! TOOL used
|
||||
TOOLS tool(void) const;
|
||||
|
||||
//! Version associated with the tool
|
||||
version_t version(void) const;
|
||||
|
||||
virtual ~BuildToolVersion(void);
|
||||
|
||||
bool operator==(const BuildToolVersion& rhs) const;
|
||||
bool operator!=(const BuildToolVersion& rhs) const;
|
||||
|
||||
virtual void accept(Visitor& visitor) const override;
|
||||
|
||||
LIEF_API friend std::ostream& operator<<(std::ostream& os, const BuildToolVersion& tool);
|
||||
|
||||
private:
|
||||
TOOLS tool_{TOOLS::UNKNOWN};
|
||||
version_t version_;
|
||||
};
|
||||
|
||||
class LIEF_API BuildVersion : public LoadCommand {
|
||||
friend class BinaryParser;
|
||||
|
||||
public:
|
||||
//! @brief Version is an array of **3** integers
|
||||
using version_t = std::array<uint32_t, 3>;
|
||||
|
||||
using tools_list_t = std::vector<BuildToolVersion>;
|
||||
|
||||
public:
|
||||
enum class PLATFORMS {
|
||||
UNKNOWN = 0,
|
||||
MACOS = 1,
|
||||
IOS = 2,
|
||||
TVOS = 3,
|
||||
WATCHOS = 4,
|
||||
};
|
||||
|
||||
public:
|
||||
BuildVersion(void);
|
||||
BuildVersion(const build_version_command *version_cmd);
|
||||
|
||||
BuildVersion& operator=(const BuildVersion& copy);
|
||||
BuildVersion(const BuildVersion& copy);
|
||||
|
||||
virtual BuildVersion* clone(void) const override;
|
||||
|
||||
version_t minos(void) const;
|
||||
void minos(version_t version);
|
||||
|
||||
version_t sdk(void) const;
|
||||
void sdk(version_t version);
|
||||
|
||||
PLATFORMS platform(void) const;
|
||||
void platform(PLATFORMS plat);
|
||||
|
||||
tools_list_t tools(void) const;
|
||||
|
||||
virtual ~BuildVersion(void);
|
||||
|
||||
bool operator==(const BuildVersion& rhs) const;
|
||||
bool operator!=(const BuildVersion& rhs) const;
|
||||
|
||||
virtual void accept(Visitor& visitor) const override;
|
||||
|
||||
virtual std::ostream& print(std::ostream& os) const override;
|
||||
|
||||
private:
|
||||
PLATFORMS platform_{PLATFORMS::UNKNOWN};
|
||||
version_t minos_;
|
||||
version_t sdk_;
|
||||
tools_list_t tools_;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
@ -106,8 +106,12 @@ class LIEF_API Builder {
|
||||
template <typename T>
|
||||
void build_segments(void);
|
||||
|
||||
template<class T>
|
||||
void build(BuildVersion* bv);
|
||||
|
||||
void build_uuid(void);
|
||||
|
||||
|
||||
template <typename T>
|
||||
void build_symbols(void);
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include "LIEF/MachO/Structures.hpp"
|
||||
#include "LIEF/MachO/DataCodeEntry.hpp"
|
||||
#include "LIEF/MachO/BuildVersion.hpp"
|
||||
|
||||
namespace LIEF {
|
||||
namespace MachO {
|
||||
@ -51,6 +52,8 @@ LIEF_API const char* to_string(VM_PROTECTIONS e);
|
||||
LIEF_API const char* to_string(SYMBOL_ORIGINS e);
|
||||
LIEF_API const char* to_string(EXPORT_SYMBOL_FLAGS e);
|
||||
LIEF_API const char* to_string(DataCodeEntry::TYPES e);
|
||||
LIEF_API const char* to_string(BuildVersion::PLATFORMS e);
|
||||
LIEF_API const char* to_string(BuildToolVersion::TOOLS e);
|
||||
|
||||
|
||||
} // namespace MachO
|
||||
|
@ -105,6 +105,8 @@ enum _LIEF_EN(LOAD_COMMAND_TYPES) {
|
||||
_LIEF_EI(LC_LINKER_OPTIMIZATION_HINT) = 0x0000002Eu,
|
||||
_LIEF_EI(LC_VERSION_MIN_TVOS) = 0x0000002Fu,
|
||||
_LIEF_EI(LC_VERSION_MIN_WATCHOS) = 0x00000030u,
|
||||
_LIEF_EI(LC_NOTE) = 0x00000031u,
|
||||
_LIEF_EI(LC_BUILD_VERSION) = 0x00000032u,
|
||||
};
|
||||
|
||||
|
||||
@ -586,4 +588,3 @@ enum _LIEF_EN(CPU_SUBTYPES_POWERPC) {
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
@ -61,6 +61,8 @@ class LIEF_API Hash : public LIEF::Hash {
|
||||
virtual void visit(const SubFramework& sf) override;
|
||||
virtual void visit(const DyldEnvironment& sf) override;
|
||||
virtual void visit(const EncryptionInfo& e) override;
|
||||
virtual void visit(const BuildVersion& e) override;
|
||||
virtual void visit(const BuildToolVersion& e) override;
|
||||
|
||||
virtual ~Hash(void);
|
||||
};
|
||||
|
@ -65,6 +65,8 @@ class LIEF_API JsonVisitor : public LIEF::JsonVisitor {
|
||||
virtual void visit(const SubFramework& sf) override;
|
||||
virtual void visit(const DyldEnvironment& sf) override;
|
||||
virtual void visit(const EncryptionInfo& e) override;
|
||||
virtual void visit(const BuildVersion& e) override;
|
||||
virtual void visit(const BuildToolVersion& e) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -318,6 +318,22 @@ struct version_min_command {
|
||||
uint32_t sdk; // X.Y.Z is encoded in nibbles xxxx.yy.zz
|
||||
};
|
||||
|
||||
|
||||
struct build_version_command {
|
||||
uint32_t cmd;
|
||||
uint32_t cmdsize;
|
||||
|
||||
uint32_t platform;
|
||||
uint32_t minos;
|
||||
uint32_t sdk;
|
||||
uint32_t ntools;
|
||||
};
|
||||
|
||||
struct build_tool_version {
|
||||
uint32_t tool;
|
||||
uint32_t version;
|
||||
};
|
||||
|
||||
struct dyld_info_command {
|
||||
uint32_t cmd;
|
||||
uint32_t cmdsize;
|
||||
@ -592,3 +608,4 @@ struct unwind_info_compressed_second_level_page_header {
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -149,6 +149,8 @@ LIEF_MACHO_FORWARD(SegmentSplitInfo)
|
||||
LIEF_MACHO_FORWARD(SubFramework)
|
||||
LIEF_MACHO_FORWARD(DyldEnvironment)
|
||||
LIEF_MACHO_FORWARD(EncryptionInfo)
|
||||
LIEF_MACHO_FORWARD(BuildVersion)
|
||||
LIEF_MACHO_FORWARD(BuildToolVersion)
|
||||
|
||||
// OAT
|
||||
// ===============================
|
||||
@ -469,6 +471,12 @@ class LIEF_API Visitor {
|
||||
//! @brief Method to visit a LIEF::MachO::DyldEnvironment
|
||||
LIEF_MACHO_VISITABLE(EncryptionInfo)
|
||||
|
||||
//! @brief Method to visit a LIEF::MachO:BuildVersion:
|
||||
LIEF_MACHO_VISITABLE(BuildVersion)
|
||||
|
||||
//! @brief Method to visit a LIEF::MachO:BuildToolVersion:
|
||||
LIEF_MACHO_VISITABLE(BuildToolVersion)
|
||||
|
||||
// OAT part
|
||||
// ========
|
||||
|
||||
|
@ -1808,6 +1808,21 @@ const EncryptionInfo& Binary::encryption_info(void) const {
|
||||
}
|
||||
|
||||
|
||||
// BuildVersion command
|
||||
// ++++++++++++++++++++
|
||||
bool Binary::has_build_version(void) const {
|
||||
return this->has_command<BuildVersion>();
|
||||
}
|
||||
|
||||
BuildVersion& Binary::build_version(void) {
|
||||
return this->command<BuildVersion>();
|
||||
}
|
||||
|
||||
const BuildVersion& Binary::build_version(void) const {
|
||||
return this->command<BuildVersion>();
|
||||
}
|
||||
|
||||
|
||||
LoadCommand& Binary::operator[](LOAD_COMMAND_TYPES type) {
|
||||
return this->get(type);
|
||||
}
|
||||
|
@ -388,6 +388,29 @@ void BinaryParser::parse_load_commands(void) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case LOAD_COMMAND_TYPES::LC_BUILD_VERSION:
|
||||
{
|
||||
VLOG(VDEBUG) << "[+] Parsing " << to_string(static_cast<LOAD_COMMAND_TYPES>(command.cmd));
|
||||
|
||||
const auto cmd = &this->stream_->peek<build_version_command>(loadcommands_offset);
|
||||
//VLOG(VDEBUG) << "Version: " << std::hex << cmd->version;
|
||||
//VLOG(VDEBUG) << "SDK: " << std::hex << cmd->sdk;
|
||||
|
||||
load_command = std::unique_ptr<BuildVersion>{new BuildVersion{cmd}};
|
||||
BuildVersion* build_version = load_command->as<BuildVersion>();
|
||||
for (size_t i = 0; i < cmd->ntools; ++i) {
|
||||
const uint64_t cmd_offset = loadcommands_offset + sizeof(build_version_command) + i * sizeof(build_tool_version);
|
||||
if (not this->stream_->can_read<build_tool_version>(cmd_offset)) {
|
||||
break;
|
||||
}
|
||||
|
||||
auto&& tool_struct = this->stream_->peek<build_tool_version>(cmd_offset);
|
||||
build_version->tools_.emplace_back(tool_struct);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// =================
|
||||
// Code Signature
|
||||
// =================
|
||||
|
173
src/MachO/BuildVersion.cpp
Normal file
173
src/MachO/BuildVersion.cpp
Normal file
@ -0,0 +1,173 @@
|
||||
/* Copyright 2017 R. Thomas
|
||||
* Copyright 2017 Quarkslab
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include <numeric>
|
||||
#include <iomanip>
|
||||
|
||||
#include "LIEF/MachO/hash.hpp"
|
||||
|
||||
#include "LIEF/MachO/BuildVersion.hpp"
|
||||
|
||||
namespace LIEF {
|
||||
namespace MachO {
|
||||
|
||||
|
||||
BuildToolVersion::BuildToolVersion(void) = default;
|
||||
BuildToolVersion::BuildToolVersion(const build_tool_version& tool) :
|
||||
tool_{static_cast<BuildToolVersion::TOOLS>(tool.tool)},
|
||||
version_{{
|
||||
static_cast<uint32_t>((tool.version >> 16) & 0xFFFF),
|
||||
static_cast<uint32_t>((tool.version >> 8) & 0xFF),
|
||||
static_cast<uint32_t>((tool.version >> 0) & 0xFF)
|
||||
}}
|
||||
{}
|
||||
|
||||
BuildToolVersion::TOOLS BuildToolVersion::tool(void) const {
|
||||
return this->tool_;
|
||||
}
|
||||
|
||||
BuildToolVersion::version_t BuildToolVersion::version(void) const {
|
||||
return this->version_;
|
||||
}
|
||||
|
||||
BuildToolVersion::~BuildToolVersion(void) = default;
|
||||
|
||||
bool BuildToolVersion::operator==(const BuildToolVersion& rhs) const {
|
||||
size_t hash_lhs = Hash::hash(*this);
|
||||
size_t hash_rhs = Hash::hash(rhs);
|
||||
return hash_lhs == hash_rhs;
|
||||
}
|
||||
|
||||
bool BuildToolVersion::operator!=(const BuildToolVersion& rhs) const {
|
||||
return not (*this == rhs);
|
||||
}
|
||||
|
||||
void BuildToolVersion::accept(Visitor& visitor) const {
|
||||
visitor.visit(*this);
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const BuildToolVersion& tool) {
|
||||
BuildToolVersion::version_t version = tool.version();
|
||||
|
||||
os << to_string(tool.tool()) << " - ";
|
||||
os << std::dec
|
||||
<< version[0] << "."
|
||||
<< version[1] << "."
|
||||
<< version[2] << std::endl;
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
// Build Version
|
||||
// =============
|
||||
|
||||
BuildVersion::BuildVersion(void) = default;
|
||||
BuildVersion& BuildVersion::operator=(const BuildVersion&) = default;
|
||||
BuildVersion::BuildVersion(const BuildVersion&) = default;
|
||||
BuildVersion::~BuildVersion(void) = default;
|
||||
|
||||
BuildVersion::BuildVersion(const build_version_command *version_cmd) :
|
||||
LoadCommand::LoadCommand{static_cast<LOAD_COMMAND_TYPES>(version_cmd->cmd), version_cmd->cmdsize},
|
||||
platform_{static_cast<BuildVersion::PLATFORMS>(version_cmd->platform)},
|
||||
minos_{{
|
||||
static_cast<uint32_t>((version_cmd->minos >> 16) & 0xFFFF),
|
||||
static_cast<uint32_t>((version_cmd->minos >> 8) & 0xFF),
|
||||
static_cast<uint32_t>((version_cmd->minos >> 0) & 0xFF)
|
||||
}},
|
||||
sdk_{{
|
||||
static_cast<uint32_t>((version_cmd->sdk >> 16) & 0xFFFF),
|
||||
static_cast<uint32_t>((version_cmd->sdk >> 8) & 0xFF),
|
||||
static_cast<uint32_t>((version_cmd->sdk >> 0) & 0xFF)
|
||||
}}
|
||||
{
|
||||
}
|
||||
|
||||
BuildVersion* BuildVersion::clone(void) const {
|
||||
return new BuildVersion(*this);
|
||||
}
|
||||
|
||||
|
||||
BuildVersion::version_t BuildVersion::minos(void) const {
|
||||
return this->minos_;
|
||||
}
|
||||
|
||||
void BuildVersion::minos(BuildVersion::version_t version) {
|
||||
this->minos_ = version;
|
||||
}
|
||||
|
||||
BuildVersion::version_t BuildVersion::sdk(void) const {
|
||||
return this->sdk_;
|
||||
}
|
||||
|
||||
void BuildVersion::sdk(BuildVersion::version_t version) {
|
||||
this->sdk_ = version;
|
||||
}
|
||||
|
||||
BuildVersion::PLATFORMS BuildVersion::platform(void) const {
|
||||
return this->platform_;
|
||||
}
|
||||
|
||||
void BuildVersion::platform(BuildVersion::PLATFORMS plat) {
|
||||
this->platform_ = plat;
|
||||
}
|
||||
|
||||
|
||||
BuildVersion::tools_list_t BuildVersion::tools(void) const {
|
||||
return this->tools_;
|
||||
}
|
||||
|
||||
void BuildVersion::accept(Visitor& visitor) const {
|
||||
visitor.visit(*this);
|
||||
}
|
||||
|
||||
|
||||
bool BuildVersion::operator==(const BuildVersion& rhs) const {
|
||||
size_t hash_lhs = Hash::hash(*this);
|
||||
size_t hash_rhs = Hash::hash(rhs);
|
||||
return hash_lhs == hash_rhs;
|
||||
}
|
||||
|
||||
bool BuildVersion::operator!=(const BuildVersion& rhs) const {
|
||||
return not (*this == rhs);
|
||||
}
|
||||
|
||||
|
||||
std::ostream& BuildVersion::print(std::ostream& os) const {
|
||||
LoadCommand::print(os);
|
||||
|
||||
BuildVersion::version_t minos = this->minos();
|
||||
BuildVersion::version_t sdk = this->sdk();
|
||||
|
||||
os << std::setw(10) << "Platform: " << to_string(this->platform()) << std::endl;
|
||||
|
||||
os << std::setw(10) << "Min OS: " << std::dec
|
||||
<< minos[0] << "."
|
||||
<< minos[1] << "."
|
||||
<< minos[2] << std::endl;
|
||||
|
||||
os << std::setw(10) << "SDK: " << std::dec
|
||||
<< sdk[0] << "."
|
||||
<< sdk[1] << "."
|
||||
<< sdk[2] << std::endl;
|
||||
|
||||
for (const BuildToolVersion& tool_version : this->tools()) {
|
||||
os << " " << tool_version << std::endl;
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -152,6 +152,11 @@ void Builder::build(void) {
|
||||
this->build<T>(cmd->as<DyldEnvironment>());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cmd->is<BuildVersion>()) {
|
||||
this->build<T>(cmd->as<BuildVersion>());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
this->build_segments<T>();
|
||||
@ -311,7 +316,6 @@ void Builder::build_uuid(void) {
|
||||
uuid_cmd->originalData_.data());
|
||||
}
|
||||
|
||||
|
||||
const std::vector<uint8_t>& Builder::get_build(void) {
|
||||
return this->raw_.raw();
|
||||
}
|
||||
|
@ -928,6 +928,63 @@ void Builder::build(DyldEnvironment* de) {
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
void Builder::build(BuildVersion* bv) {
|
||||
build_version_command raw_cmd;
|
||||
const BuildVersion::tools_list_t& tools = bv->tools();
|
||||
|
||||
const uint32_t raw_size = sizeof(build_version_command) + tools.size() * sizeof(build_tool_version);
|
||||
const uint32_t size_needed = align(raw_size, sizeof(typename T::uint));
|
||||
const uint32_t padding = size_needed - raw_size;
|
||||
|
||||
if (bv->originalData_.size() != size_needed or
|
||||
bv->size() != size_needed) {
|
||||
//LOG(WARNING) << "Not enough spaces to rebuild " << bv->value() << ": Skip!";
|
||||
//LOG(WARNING) << std::hex << bv->originalData_.size() << " vs " << size_needed;
|
||||
}
|
||||
|
||||
const BuildVersion::version_t& minos = bv->minos();
|
||||
const BuildVersion::version_t& sdk = bv->sdk();
|
||||
|
||||
std::fill(
|
||||
reinterpret_cast<uint8_t*>(&raw_cmd),
|
||||
reinterpret_cast<uint8_t*>(&raw_cmd) + sizeof(build_version_command),
|
||||
0);
|
||||
|
||||
raw_cmd.cmd = static_cast<uint32_t>(bv->command());
|
||||
raw_cmd.cmdsize = static_cast<uint32_t>(size_needed);
|
||||
|
||||
raw_cmd.minos = static_cast<uint32_t>(minos[0] << 16 | minos[1] << 8 | minos[2]);
|
||||
raw_cmd.sdk = static_cast<uint32_t>(sdk[0] << 16 | sdk[1] << 8 | sdk[2]);
|
||||
raw_cmd.platform = static_cast<uint32_t>(bv->platform());
|
||||
raw_cmd.ntools = tools.size();
|
||||
//raw_cmd.name = static_cast<uint32_t>(sizeof(build_version_command));
|
||||
std::vector<uint8_t> raw_tools(raw_cmd.ntools * sizeof(build_tool_version), 0);
|
||||
auto tools_array = reinterpret_cast<build_tool_version*>(raw_tools.data());
|
||||
for (size_t i = 0; i < tools.size(); ++i) {
|
||||
BuildToolVersion::version_t version = tools[i].version();
|
||||
tools_array[i].tool = static_cast<uint32_t>(tools[i].tool());
|
||||
tools_array[i].version = static_cast<uint32_t>(version[0] << 16 | version[1] << 8 | version[2]);
|
||||
}
|
||||
|
||||
bv->size_ = size_needed;
|
||||
bv->originalData_.clear();
|
||||
|
||||
// Write Header
|
||||
std::move(
|
||||
reinterpret_cast<uint8_t*>(&raw_cmd),
|
||||
reinterpret_cast<uint8_t*>(&raw_cmd) + sizeof(raw_cmd),
|
||||
std::back_inserter(bv->originalData_));
|
||||
|
||||
std::move(
|
||||
std::begin(raw_tools),
|
||||
std::end(raw_tools),
|
||||
std::back_inserter(bv->originalData_));
|
||||
|
||||
bv->originalData_.insert(std::end(bv->originalData_), padding, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -56,6 +56,7 @@ set(LIEF_MACHO_SRC
|
||||
"${CMAKE_CURRENT_LIST_DIR}/DyldEnvironment.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/EncryptionInfo.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/TrieNode.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/BuildVersion.cpp"
|
||||
)
|
||||
|
||||
set(LIEF_MACHO_INCLUDE_FILES
|
||||
@ -99,6 +100,7 @@ set(LIEF_MACHO_INCLUDE_FILES
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/LIEF/MachO/SubFramework.hpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/LIEF/MachO/DyldEnvironment.hpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/LIEF/MachO/EncryptionInfo.hpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/LIEF/MachO/BuildVersion.hpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/TrieNode.hpp"
|
||||
)
|
||||
|
||||
|
@ -54,7 +54,7 @@ const char* to_string(FILE_TYPES e) {
|
||||
}
|
||||
|
||||
const char* to_string(LOAD_COMMAND_TYPES e) {
|
||||
CONST_MAP(LOAD_COMMAND_TYPES, const char*, 49) enumStrings {
|
||||
CONST_MAP(LOAD_COMMAND_TYPES, const char*, 51) enumStrings {
|
||||
{ LOAD_COMMAND_TYPES::LC_SEGMENT, "SEGMENT"},
|
||||
{ LOAD_COMMAND_TYPES::LC_SYMTAB, "SYMTAB"},
|
||||
{ LOAD_COMMAND_TYPES::LC_SYMSEG, "SYMSEG"},
|
||||
@ -103,7 +103,9 @@ const char* to_string(LOAD_COMMAND_TYPES e) {
|
||||
{ LOAD_COMMAND_TYPES::LC_LINKER_OPTION, "LINKER_OPTION"},
|
||||
{ LOAD_COMMAND_TYPES::LC_LINKER_OPTIMIZATION_HINT, "LINKER_OPTIMIZATION_HINT"},
|
||||
{ LOAD_COMMAND_TYPES::LC_VERSION_MIN_TVOS, "VERSION_MIN_TVOS"},
|
||||
{ LOAD_COMMAND_TYPES::LC_VERSION_MIN_WATCHOS, "VERSION_MIN_WATCHOS"}
|
||||
{ LOAD_COMMAND_TYPES::LC_VERSION_MIN_WATCHOS, "VERSION_MIN_WATCHOS"},
|
||||
{ LOAD_COMMAND_TYPES::LC_NOTE, "NOTE"},
|
||||
{ LOAD_COMMAND_TYPES::LC_BUILD_VERSION, "BUILD_VERSION"}
|
||||
};
|
||||
auto it = enumStrings.find(e);
|
||||
return it == enumStrings.end() ? "Out of range" : it->second;
|
||||
@ -494,5 +496,29 @@ const char* to_string(DataCodeEntry::TYPES e) {
|
||||
return it == enumStrings.end() ? "UNKNOWN" : it->second;
|
||||
}
|
||||
|
||||
const char* to_string(BuildVersion::PLATFORMS e) {
|
||||
CONST_MAP(BuildVersion::PLATFORMS, const char*, 5) enumStrings {
|
||||
{ BuildVersion::PLATFORMS::UNKNOWN, "UNKNOWN" },
|
||||
{ BuildVersion::PLATFORMS::MACOS, "MACOS" },
|
||||
{ BuildVersion::PLATFORMS::IOS, "IOS" },
|
||||
{ BuildVersion::PLATFORMS::TVOS, "TVOS" },
|
||||
{ BuildVersion::PLATFORMS::WATCHOS, "WATCHOS" },
|
||||
};
|
||||
auto it = enumStrings.find(e);
|
||||
return it == enumStrings.end() ? "UNKNOWN" : it->second;
|
||||
}
|
||||
|
||||
|
||||
const char* to_string(BuildToolVersion::TOOLS e) {
|
||||
CONST_MAP(BuildToolVersion::TOOLS, const char*, 4) enumStrings {
|
||||
{ BuildToolVersion::TOOLS::UNKNOWN, "UNKNOWN" },
|
||||
{ BuildToolVersion::TOOLS::SWIFT, "SWIFT" },
|
||||
{ BuildToolVersion::TOOLS::CLANG, "CLANG" },
|
||||
{ BuildToolVersion::TOOLS::LD, "LD" },
|
||||
};
|
||||
auto it = enumStrings.find(e);
|
||||
return it == enumStrings.end() ? "UNKNOWN" : it->second;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -295,6 +295,21 @@ void Hash::visit(const EncryptionInfo& e) {
|
||||
this->process(e.crypt_id());
|
||||
}
|
||||
|
||||
void Hash::visit(const BuildVersion& e) {
|
||||
BuildVersion::tools_list_t tools = e.tools();
|
||||
|
||||
this->visit(*e.as<LoadCommand>());
|
||||
this->process(e.platform());
|
||||
this->process(e.minos());
|
||||
this->process(e.sdk());
|
||||
this->process(std::begin(tools), std::end(tools));
|
||||
}
|
||||
|
||||
void Hash::visit(const BuildToolVersion& e) {
|
||||
this->process(e.tool());
|
||||
this->process(e.version());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -173,6 +173,12 @@ void JsonVisitor::visit(const Binary& binary) {
|
||||
v(binary.encryption_info());
|
||||
this->node_["encryption_info"] = v.get();
|
||||
}
|
||||
|
||||
if (binary.has_build_version()) {
|
||||
JsonVisitor v;
|
||||
v(binary.build_version());
|
||||
this->node_["build_version"] = v.get();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -472,6 +478,30 @@ void JsonVisitor::visit(const EncryptionInfo& e) {
|
||||
}
|
||||
|
||||
|
||||
void JsonVisitor::visit(const BuildVersion& e) {
|
||||
this->visit(*e.as<LoadCommand>());
|
||||
|
||||
this->node_["platform"] = to_string(e.platform());
|
||||
this->node_["minos"] = e.minos();
|
||||
this->node_["sdk"] = e.sdk();
|
||||
|
||||
std::vector<json> tools;
|
||||
|
||||
for (const BuildToolVersion& toolv : e.tools()) {
|
||||
JsonVisitor v;
|
||||
v(toolv);
|
||||
tools.emplace_back(std::move(v.get()));
|
||||
}
|
||||
this->node_["tools"] = tools;
|
||||
}
|
||||
|
||||
|
||||
void JsonVisitor::visit(const BuildToolVersion& e) {
|
||||
this->node_["tool"] = to_string(e.tool());
|
||||
this->node_["version"] = e.version();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace MachO
|
||||
|
@ -179,6 +179,23 @@ class TestMachO(TestCase):
|
||||
self.assertEqual(functions[-1].name, "ctor_0")
|
||||
|
||||
|
||||
def test_build_version(self):
|
||||
binary = lief.MachO.parse(get_sample('MachO/FAT_MachO_arm-arm64-binary-helloworld.bin'))
|
||||
target = binary[1]
|
||||
|
||||
self.assertTrue(target.has_build_version)
|
||||
build_version = target.build_version
|
||||
|
||||
self.assertEqual(build_version.minos, [12, 1, 0])
|
||||
self.assertEqual(build_version.sdk, [12, 1, 0])
|
||||
self.assertEqual(build_version.platform, lief.MachO.BuildVersion.PLATFORMS.IOS)
|
||||
|
||||
tools = build_version.tools
|
||||
self.assertEqual(len(tools), 1)
|
||||
self.assertEqual(tools[0].version, [409, 12, 0])
|
||||
self.assertEqual(tools[0].tool, lief.MachO.BuildToolVersion.TOOLS.LD)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user