Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parse the MachO LC_RPATH command #128

Merged
merged 2 commits into from Dec 17, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions api/python/MachO/CMakeLists.txt
Expand Up @@ -22,6 +22,7 @@ set(LIEF_PYTHON_MACHO_SRC
"${CMAKE_CURRENT_LIST_DIR}/objects/pyBindingInfo.cpp"
"${CMAKE_CURRENT_LIST_DIR}/objects/pyExportInfo.cpp"
"${CMAKE_CURRENT_LIST_DIR}/objects/pyThreadCommand.cpp"
"${CMAKE_CURRENT_LIST_DIR}/objects/pyRPathCommand.cpp"
"${CMAKE_CURRENT_LIST_DIR}/objects/pyParserConfig.cpp"
"${CMAKE_CURRENT_LIST_DIR}/pyMachOStructures.cpp"
)
Expand Down
61 changes: 61 additions & 0 deletions api/python/MachO/objects/pyRPathCommand.cpp
@@ -0,0 +1,61 @@
/* Copyright 2017 J.Rieck (based on R. Thomas's work)
* 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/visitors/Hash.hpp"
#include "LIEF/MachO/RPathCommand.hpp"

#include "pyMachO.hpp"

template<class T>
using getter_t = T (RPathCommand::*)(void) const;

template<class T>
using setter_t = void (RPathCommand::*)(T);


void init_MachO_RPathCommand_class(py::module& m) {

py::class_<RPathCommand, LoadCommand>(m, "RPathCommand")

.def_property("path",
static_cast<getter_t<const std::string&>>(&RPathCommand::path),
static_cast<setter_t<const std::string&>>(&RPathCommand::path),
"@rpath path",
py::return_value_policy::reference_internal)


.def("__eq__", &RPathCommand::operator==)
.def("__ne__", &RPathCommand::operator!=)
.def("__hash__",
[] (const RPathCommand& rpath_command) {
return LIEF::Hash::hash(rpath_command);
})


.def("__str__",
[] (const RPathCommand& rpath_command)
{
std::ostringstream stream;
stream << rpath_command;
std::string str = stream.str();
return str;
});

}
2 changes: 1 addition & 1 deletion api/python/MachO/pyMachO.cpp
Expand Up @@ -47,7 +47,7 @@ void init_MachO_module(py::module& m) {
init_MachO_BindingInfo_class(LIEF_MachO_module);
init_MachO_ExportInfo_class(LIEF_MachO_module);
init_MachO_ThreadCommand_class(LIEF_MachO_module);

init_MachO_RPathCommand_class(LIEF_MachO_module);

// Enums
init_MachO_Structures_enum(LIEF_MachO_module);
Expand Down
1 change: 1 addition & 0 deletions api/python/MachO/pyMachO.hpp
Expand Up @@ -49,6 +49,7 @@ void init_MachO_RelocationDyld_class(py::module&);
void init_MachO_BindingInfo_class(py::module&);
void init_MachO_ExportInfo_class(py::module&);
void init_MachO_ThreadCommand_class(py::module&);
void init_MachO_RPathCommand_class(py::module&);

// Enums
void init_MachO_Structures_enum(py::module&);
Expand Down
8 changes: 8 additions & 0 deletions doc/sphinx/api/cpp/macho.rst
Expand Up @@ -217,6 +217,14 @@ Thread Command

----------

RPath Command
*************

.. doxygenclass:: LIEF::MachO::RPathCommand
:project: lief

----------

Utilities
*********

Expand Down
11 changes: 11 additions & 0 deletions doc/sphinx/api/python/macho.rst
Expand Up @@ -251,6 +251,17 @@ Thread Command

----------

RPath Command
*************

.. autoclass:: lief.MachO.RPathCommand
:members:
:inherited-members:
:undoc-members:

----------


Enums
*****

Expand Down
1 change: 1 addition & 0 deletions include/LIEF/MachO/Binary.hpp
Expand Up @@ -40,6 +40,7 @@
#include "LIEF/MachO/SourceVersion.hpp"
#include "LIEF/MachO/VersionMin.hpp"
#include "LIEF/MachO/ThreadCommand.hpp"
#include "LIEF/MachO/RPathCommand.hpp"

namespace LIEF {
namespace MachO {
Expand Down
55 changes: 55 additions & 0 deletions include/LIEF/MachO/RPathCommand.hpp
@@ -0,0 +1,55 @@
/* Copyright 2017 J. Rieck (based on R. Thomas's work)
* 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_RPATH_COMMAND_H_
#define LIEF_MACHO_RPATH_COMMAND_H_
#include <string>
#include <iostream>

#include "LIEF/visibility.h"
#include "LIEF/types.hpp"

#include "LIEF/MachO/LoadCommand.hpp"

namespace LIEF {
namespace MachO {

class DLL_PUBLIC RPathCommand : public LoadCommand {
public:
RPathCommand(void);
RPathCommand(const rpath_command *rpathCmd);

RPathCommand& operator=(const RPathCommand& copy);
RPathCommand(const RPathCommand& copy);

virtual ~RPathCommand(void);

const std::string& path(void) const;
void path(const std::string& path);

bool operator==(const RPathCommand& rhs) const;
bool operator!=(const RPathCommand& rhs) const;

virtual void accept(Visitor& visitor) const override;

virtual std::ostream& print(std::ostream& os) const override;

private:
std::string path_;
};

}
}
#endif
4 changes: 4 additions & 0 deletions include/LIEF/Visitor.hpp
Expand Up @@ -146,6 +146,7 @@ class DynamicSymbolCommand;
class DylinkerCommand;
class DylibCommand;
class ThreadCommand;
class RPathCommand;

class Symbol;
class Relocation;
Expand Down Expand Up @@ -481,6 +482,9 @@ class DLL_PUBLIC Visitor {

//! @brief Method to visit a LIEF::MachO::ThreadCommand
virtual void visit(const MachO::ThreadCommand& thread);

//! @brief Method to visit a LIEF::MachO::RPathCommand
virtual void visit(const MachO::RPathCommand& rpath_command);
#endif

template<class T>
Expand Down
17 changes: 17 additions & 0 deletions src/MachO/BinaryParser.tcc
Expand Up @@ -158,6 +158,23 @@ void BinaryParser::parse_load_commands(void) {
break;
}

// =============
// RPath Command
// =============
case LOAD_COMMAND_TYPES::LC_RPATH:
{
const rpath_command* cmd =
reinterpret_cast<const rpath_command*>(
this->stream_->read(loadcommands_offset, sizeof(rpath_command)));

load_command = std::unique_ptr<RPathCommand>{new RPathCommand{cmd}};
const uint32_t str_path_offset = cmd->path;
std::string path = this->stream_->get_string(loadcommands_offset + str_path_offset);

dynamic_cast<RPathCommand*>(load_command.get())->path(path);
break;
}

// ====
// UUID
// ====
Expand Down
2 changes: 2 additions & 0 deletions src/MachO/CMakeLists.txt
Expand Up @@ -45,6 +45,7 @@ set(LIEF_MACHO_SRC
"${CMAKE_CURRENT_LIST_DIR}/BindingInfo.cpp"
"${CMAKE_CURRENT_LIST_DIR}/ExportInfo.cpp"
"${CMAKE_CURRENT_LIST_DIR}/ThreadCommand.cpp"
"${CMAKE_CURRENT_LIST_DIR}/RPathCommand.cpp"
"${CMAKE_CURRENT_LIST_DIR}/ParserConfig.cpp"
"${CMAKE_CURRENT_LIST_DIR}/Visitor.cpp"
)
Expand Down Expand Up @@ -79,6 +80,7 @@ set(LIEF_MACHO_INCLUDE_FILES
"${CMAKE_CURRENT_SOURCE_DIR}/include/LIEF/MachO/RelocationDyld.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/include/LIEF/MachO/BindingInfo.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/include/LIEF/MachO/ExportInfo.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/include/LIEF/MachO/RPathCommand.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/include/LIEF/MachO/ThreadCommand.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/include/LIEF/MachO/ParserConfig.hpp"
)
Expand Down
71 changes: 71 additions & 0 deletions src/MachO/RPathCommand.cpp
@@ -0,0 +1,71 @@
/* Copyright 2017 J.Rieck (based on R. Thomas's work)
* 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/visitors/Hash.hpp"

#include "LIEF/MachO/RPathCommand.hpp"

namespace LIEF {
namespace MachO {

RPathCommand::RPathCommand(void) = default;
RPathCommand& RPathCommand::operator=(const RPathCommand&) = default;
RPathCommand::RPathCommand(const RPathCommand&) = default;
RPathCommand::~RPathCommand(void) = default;

RPathCommand::RPathCommand(const rpath_command *rpathCmd) :
LoadCommand::LoadCommand{static_cast<LOAD_COMMAND_TYPES>(rpathCmd->cmd), rpathCmd->cmdsize}
{
}

const std::string& RPathCommand::path(void) const {
return this->path_;
}

void RPathCommand::path(const std::string& path) {
this->path_ = path;
}


void RPathCommand::accept(Visitor& visitor) const {
LoadCommand::accept(visitor);
visitor.visit(this->path());
}


bool RPathCommand::operator==(const RPathCommand& rhs) const {
size_t hash_lhs = Hash::hash(*this);
size_t hash_rhs = Hash::hash(rhs);
return hash_lhs == hash_rhs;
}

bool RPathCommand::operator!=(const RPathCommand& rhs) const {
return not (*this == rhs);
}


std::ostream& RPathCommand::print(std::ostream& os) const {
LoadCommand::print(os);
os << std::left
<< std::setw(10) << "Path: " << this->path();
return os;
}


}
}
4 changes: 4 additions & 0 deletions src/MachO/Visitor.cpp
Expand Up @@ -93,4 +93,8 @@ void Visitor::visit(const MachO::ThreadCommand& thread) {
thread.accept(*this);
}

void Visitor::visit(const MachO::RPathCommand& rpath_command) {
rpath_command.accept(*this);
}

}
5 changes: 5 additions & 0 deletions tests/macho/macho_tests.py
Expand Up @@ -62,6 +62,11 @@ def test_thread_cmd(self):
self.assertEqual(micromacho.thread_command.count, 16)
self.assertEqual(micromacho.entrypoint, 0x68)

def test_rpath_cmd(self):
rpathmacho = lief.parse(get_sample('MachO/MachO64_x86-64_binary_rpathtest.bin'))
load_cmds = list(rpathmacho.commands)
rpath_cmd = load_cmds[-3]
self.assertEqual(rpath_cmd.path, "@executable_path/../lib")

def test_relocations(self):
helloworld = lief.parse(get_sample('MachO/MachO64_x86-64_object_HelloWorld64.o'))
Expand Down