Add Mach-O encryption info command

This commit is contained in:
Romain Thomas 2018-06-08 16:39:11 +02:00
parent 311c7951e6
commit f4e2d81bfe
21 changed files with 355 additions and 14 deletions

View File

@ -32,6 +32,7 @@ set(LIEF_PYTHON_MACHO_SRC
"${CMAKE_CURRENT_LIST_DIR}/objects/pyDataCodeEntry.cpp"
"${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}/pyEnums.cpp"
)

View File

@ -290,6 +290,16 @@ void create<Binary>(py::module& m) {
"Return binary's " RST_CLASS_REF(lief.MachO.DyldEnvironment) " if any.",
py::return_value_policy::reference)
.def_property_readonly("has_encryption_info",
&Binary::has_encryption_info,
"``True`` if the binary has a " RST_CLASS_REF(lief.MachO.EncryptionInfo) " command",
py::return_value_policy::reference_internal)
.def_property_readonly("encryption_info",
static_cast<no_const_getter<EncryptionInfo&>>(&Binary::encryption_info),
"Return binary's " RST_CLASS_REF(lief.MachO.EncryptionInfo) " if any.",
py::return_value_policy::reference)
.def("virtual_address_to_offset",
&Binary::virtual_address_to_offset,

View File

@ -0,0 +1,80 @@
/* 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/EncryptionInfo.hpp"
#include "pyMachO.hpp"
namespace LIEF {
namespace MachO {
template<class T>
using getter_t = T (EncryptionInfo::*)(void) const;
template<class T>
using setter_t = void (EncryptionInfo::*)(T);
template<>
void create<EncryptionInfo>(py::module& m) {
py::class_<EncryptionInfo, LoadCommand>(m, "EncryptionInfo")
.def_property("crypt_offset",
static_cast<getter_t<uint32_t>>(&EncryptionInfo::crypt_offset),
static_cast<setter_t<uint32_t>>(&EncryptionInfo::crypt_offset),
"File offset of encrypted range",
py::return_value_policy::reference_internal)
.def_property("crypt_size",
static_cast<getter_t<uint32_t>>(&EncryptionInfo::crypt_size),
static_cast<setter_t<uint32_t>>(&EncryptionInfo::crypt_size),
"File size of encrypted range",
py::return_value_policy::reference_internal)
.def_property("crypt_id",
static_cast<getter_t<uint32_t>>(&EncryptionInfo::crypt_id),
static_cast<setter_t<uint32_t>>(&EncryptionInfo::crypt_id),
"Which enryption system, 0 means not-encrypted yet",
py::return_value_policy::reference_internal)
.def("__eq__", &EncryptionInfo::operator==)
.def("__ne__", &EncryptionInfo::operator!=)
.def("__hash__",
[] (const EncryptionInfo& uuid) {
return Hash::hash(uuid);
})
.def("__str__",
[] (const EncryptionInfo& uuid)
{
std::ostringstream stream;
stream << uuid;
std::string str = stream.str();
return str;
});
}
}
}

View File

@ -63,6 +63,7 @@ void init_objects(py::module& m) {
CREATE(SegmentSplitInfo, m);
CREATE(SubFramework, m);
CREATE(DyldEnvironment, m);
CREATE(EncryptionInfo, m);
}
}

View File

@ -76,6 +76,7 @@ SPECIALIZE_CREATE(VersionMin);
SPECIALIZE_CREATE(SegmentSplitInfo);
SPECIALIZE_CREATE(SubFramework);
SPECIALIZE_CREATE(DyldEnvironment);
SPECIALIZE_CREATE(EncryptionInfo);
}
}

View File

@ -277,6 +277,14 @@ Dyld Environment
----------
Encryption Info
***************
.. doxygenclass:: LIEF::MachO::EncryptionInfo
:project: lief
----------
Utilities
*********

View File

@ -343,6 +343,17 @@ Dyld Environment
----------
Encryption Info
***************
.. autoclass:: lief.MachO.EncryptionInfo
:members:
:inherited-members:
:undoc-members:
----------
Enums
*****

View File

@ -615,6 +615,23 @@ def print_relocations(binary):
print("")
@exceptions_handler(Exception)
def print_encryption_info(binary):
format_str = "{:<13} {:<30}"
format_hex = "{:<13} 0x{:<28x}"
format_dec = "{:<13} {:<30d}"
print("== Encryption Info ==")
cmd = binary.encryption_info
print(format_hex.format("Offset:", cmd.crypt_offset))
print(format_hex.format("Size:", cmd.crypt_size))
print(format_dec.format("ID:", cmd.crypt_id))
print("")
def main():
parser = argparse.ArgumentParser(usage='%(prog)s [options] <macho-file>')
@ -714,6 +731,10 @@ def main():
action='store_true', dest='show_dyld_env',
help="Display the 'Dyld Environment' command")
parser.add_argument('--encryption-info',
action='store_true', dest='show_encrypt_info',
help="Display the 'Encryption Info' command")
parser.add_argument('--bind-opcodes',
action='store_true', dest='show_bind_opcodes',
help='Display the "Bind" opcodes')
@ -817,6 +838,9 @@ def main():
if (args.show_dyld_env or args.show_all) and binary.has_dyld_environment:
print_dyld_environment(binary)
if (args.show_encrypt_info or args.show_all) and binary.has_encryption_info:
print_encryption_info(binary)
if (args.show_rpath_command or args.show_all) and binary.has_rpath:
print_rpath_command(binary)

View File

@ -46,6 +46,7 @@
#include "LIEF/MachO/SegmentSplitInfo.hpp"
#include "LIEF/MachO/SubFramework.hpp"
#include "LIEF/MachO/DyldEnvironment.hpp"
#include "LIEF/MachO/EncryptionInfo.hpp"
namespace LIEF {
namespace MachO {
@ -330,6 +331,13 @@ class LIEF_API Binary : public LIEF::Binary {
DyldEnvironment& dyld_environment(void);
const DyldEnvironment& dyld_environment(void) const;
//! @brief ``true`` if the binary has Encryption Info.
bool has_encryption_info(void) const;
//! @brief Return the MachO::DyldEnvironment
EncryptionInfo& encryption_info(void);
const EncryptionInfo& encryption_info(void) const;
template<class T>
LIEF_LOCAL bool has_command(void) const;

View File

@ -0,0 +1,64 @@
/* 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_ENCRYPTION_INFO_COMMAND_H_
#define LIEF_MACHO_ENCRYPTION_INFO_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 LIEF_API EncryptionInfo : public LoadCommand {
public:
EncryptionInfo(void);
EncryptionInfo(const encryption_info_command *cmd);
EncryptionInfo& operator=(const EncryptionInfo& copy);
EncryptionInfo(const EncryptionInfo& copy);
virtual ~EncryptionInfo(void);
uint32_t crypt_offset(void) const;
uint32_t crypt_size(void) const;
uint32_t crypt_id(void) const;
void crypt_offset(uint32_t offset);
void crypt_size(uint32_t size);
void crypt_id(uint32_t id);
bool operator==(const EncryptionInfo& rhs) const;
bool operator!=(const EncryptionInfo& rhs) const;
virtual void accept(Visitor& visitor) const override;
virtual std::ostream& print(std::ostream& os) const override;
private:
uint32_t coff_;
uint32_t csize_;
uint32_t cid_;
};
}
}
#endif

View File

@ -68,7 +68,6 @@ namespace MachO {
using section = section_32;
using routines_command = routines_command_32;
using dylib_module = dylib_module_32;
using encryption_info_command = encryption_info_command_32;
using nlist = nlist_32;
using uint = uint32_t;
@ -81,7 +80,6 @@ namespace MachO {
using section = section_64;
using routines_command = routines_command_64;
using dylib_module = dylib_module_64;
using encryption_info_command = encryption_info_command_64;
using nlist = nlist_64;
using uint = uint64_t;

View File

@ -59,7 +59,8 @@ class LIEF_API Hash : public LIEF::Hash {
virtual void visit(const SourceVersion& sv) override;
virtual void visit(const SegmentSplitInfo& ssi) override;
virtual void visit(const SubFramework& sf) override;
virtual void visit(const DyldEnvironment& sf) override;
virtual void visit(const DyldEnvironment& sf) override;
virtual void visit(const EncryptionInfo& e) override;
virtual ~Hash(void);
};

View File

@ -63,7 +63,8 @@ class LIEF_API JsonVisitor : public LIEF::JsonVisitor {
virtual void visit(const VersionMin& vmin) override;
virtual void visit(const SegmentSplitInfo& ssi) override;
virtual void visit(const SubFramework& sf) override;
virtual void visit(const DyldEnvironment& sf) override;
virtual void visit(const DyldEnvironment& sf) override;
virtual void visit(const EncryptionInfo& e) override;
};
}

View File

@ -302,7 +302,7 @@ struct source_version_command {
uint64_t version;
};
struct encryption_info_command_32 {
struct encryption_info_command {
uint32_t cmd;
uint32_t cmdsize;
uint32_t cryptoff;
@ -310,15 +310,6 @@ struct encryption_info_command_32 {
uint32_t cryptid;
};
struct encryption_info_command_64 {
uint32_t cmd;
uint32_t cmdsize;
uint32_t cryptoff;
uint32_t cryptsize;
uint32_t cryptid;
uint32_t pad;
};
struct version_min_command {
uint32_t cmd; // LC_VERSION_MIN_MACOSX or
// LC_VERSION_MIN_IPHONEOS

View File

@ -147,6 +147,7 @@ LIEF_MACHO_FORWARD(VersionMin)
LIEF_MACHO_FORWARD(SegmentSplitInfo)
LIEF_MACHO_FORWARD(SubFramework)
LIEF_MACHO_FORWARD(DyldEnvironment)
LIEF_MACHO_FORWARD(EncryptionInfo)
// OAT
// ===============================
@ -461,6 +462,9 @@ class LIEF_API Visitor {
//! @brief Method to visit a LIEF::MachO::DyldEnvironment
LIEF_MACHO_VISITABLE(DyldEnvironment)
//! @brief Method to visit a LIEF::MachO::DyldEnvironment
LIEF_MACHO_VISITABLE(EncryptionInfo)
// OAT part
// ========

View File

@ -872,6 +872,21 @@ const DyldEnvironment& Binary::dyld_environment(void) const {
return this->command<DyldEnvironment>();
}
// EncryptionInfo command
// +++++++++++++++++++++++
bool Binary::has_encryption_info(void) const {
return this->has_command<EncryptionInfo>();
}
EncryptionInfo& Binary::encryption_info(void) {
return this->command<EncryptionInfo>();
}
const EncryptionInfo& Binary::encryption_info(void) const {
return this->command<EncryptionInfo>();
}

View File

@ -524,6 +524,19 @@ void BinaryParser::parse_load_commands(void) {
}
// ================
// Encryption Info
// ================
case LOAD_COMMAND_TYPES::LC_ENCRYPTION_INFO:
case LOAD_COMMAND_TYPES::LC_ENCRYPTION_INFO_64:
{
VLOG(VDEBUG) << "[+] Parsing " << to_string(static_cast<LOAD_COMMAND_TYPES>(command.cmd));
const encryption_info_command* cmd = &this->stream_->peek<encryption_info_command>(loadcommands_offset);
load_command = std::unique_ptr<EncryptionInfo>{new EncryptionInfo{cmd}};
break;
}
default:
{
LOG(WARNING) << "Command '" << to_string(static_cast<LOAD_COMMAND_TYPES>(command.cmd))

View File

@ -54,6 +54,7 @@ set(LIEF_MACHO_SRC
"${CMAKE_CURRENT_LIST_DIR}/DataCodeEntry.cpp"
"${CMAKE_CURRENT_LIST_DIR}/SubFramework.cpp"
"${CMAKE_CURRENT_LIST_DIR}/DyldEnvironment.cpp"
"${CMAKE_CURRENT_LIST_DIR}/EncryptionInfo.cpp"
)
set(LIEF_MACHO_INCLUDE_FILES
@ -96,6 +97,7 @@ set(LIEF_MACHO_INCLUDE_FILES
"${CMAKE_CURRENT_SOURCE_DIR}/include/LIEF/MachO/DataCodeEntry.hpp"
"${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"
)
# JSON Part

View File

@ -0,0 +1,87 @@
/* 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/EncryptionInfo.hpp"
namespace LIEF {
namespace MachO {
EncryptionInfo::EncryptionInfo(void) = default;
EncryptionInfo& EncryptionInfo::operator=(const EncryptionInfo&) = default;
EncryptionInfo::EncryptionInfo(const EncryptionInfo&) = default;
EncryptionInfo::~EncryptionInfo(void) = default;
EncryptionInfo::EncryptionInfo(const encryption_info_command *cmd) :
LoadCommand::LoadCommand{static_cast<LOAD_COMMAND_TYPES>(cmd->cmd), cmd->cmdsize},
coff_{cmd->cryptoff},
csize_{cmd->cryptsize},
cid_{cmd->cryptid}
{}
uint32_t EncryptionInfo::crypt_offset(void) const {
return this->coff_;
}
uint32_t EncryptionInfo::crypt_size(void) const {
return this->csize_;
}
uint32_t EncryptionInfo::crypt_id(void) const {
return this->cid_;
}
void EncryptionInfo::crypt_offset(uint32_t offset) {
this->coff_ = offset;
}
void EncryptionInfo::crypt_size(uint32_t size) {
this->csize_ = size;
}
void EncryptionInfo::crypt_id(uint32_t id) {
this->cid_ = id;
}
void EncryptionInfo::accept(Visitor& visitor) const {
visitor.visit(*this);
}
bool EncryptionInfo::operator==(const EncryptionInfo& rhs) const {
size_t hash_lhs = Hash::hash(*this);
size_t hash_rhs = Hash::hash(rhs);
return hash_lhs == hash_rhs;
}
bool EncryptionInfo::operator!=(const EncryptionInfo& rhs) const {
return not (*this == rhs);
}
std::ostream& EncryptionInfo::print(std::ostream& os) const {
LoadCommand::print(os);
return os;
}
}
}

View File

@ -288,6 +288,13 @@ void Hash::visit(const DyldEnvironment& de) {
this->process(de.value());
}
void Hash::visit(const EncryptionInfo& e) {
this->visit(*e.as<EncryptionInfo>());
this->process(e.crypt_offset());
this->process(e.crypt_size());
this->process(e.crypt_id());
}

View File

@ -167,6 +167,12 @@ void JsonVisitor::visit(const Binary& binary) {
v(binary.data_in_code());
this->node_["data_in_code"] = v.get();
}
if (binary.has_encryption_info()) {
JsonVisitor v;
v(binary.encryption_info());
this->node_["encryption_info"] = v.get();
}
}
@ -456,6 +462,14 @@ void JsonVisitor::visit(const DyldEnvironment& dv) {
}
void JsonVisitor::visit(const EncryptionInfo& e) {
this->visit(*e.as<LoadCommand>());
this->node_["crypt_offset"] = e.crypt_offset();
this->node_["crypt_size"] = e.crypt_size();
this->node_["crypt_id"] = e.crypt_id();
}
} // namespace MachO