Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Handle encoding errors (resolve #59)
  • Loading branch information
romainthomas committed Jul 15, 2017
1 parent b62ed28 commit 8c7ceaf
Show file tree
Hide file tree
Showing 23 changed files with 155 additions and 27 deletions.
4 changes: 3 additions & 1 deletion api/python/Abstract/objects/pySection.cpp
Expand Up @@ -27,7 +27,9 @@ void init_LIEF_Section_class(py::module& m) {
.def(py::init())

.def_property("name",
static_cast<getter_t<const std::string&>>(&LIEF::Section::name),
[] (const LIEF::Section& obj) {
return safe_string_converter(obj.name());
},
static_cast<setter_t<const std::string&>>(&LIEF::Section::name),
"Section's name")

Expand Down
4 changes: 3 additions & 1 deletion api/python/Abstract/objects/pySymbol.cpp
Expand Up @@ -46,7 +46,9 @@ void init_LIEF_Symbol_class(py::module& m) {
.def(py::init())

.def_property("name",
static_cast<getter_t<std::string>>(&LIEF::Symbol::name),
[] (const LIEF::Symbol& obj) {
return safe_string_converter(obj.name());
},
static_cast<setter_t<std::string>>(&LIEF::Symbol::name),
"Symbol's name")

Expand Down
8 changes: 6 additions & 2 deletions api/python/CMakeLists.txt
Expand Up @@ -56,7 +56,9 @@ set(LIEF_PYTHON_BASIC_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/pyUtils.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/pyJson.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/pyIterators.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/pyExceptions.cpp")
"${CMAKE_CURRENT_SOURCE_DIR}/pyExceptions.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/encoding.cpp"
)

set(LIEF_PYTHON_ABSTRACT_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/Abstract/init.cpp"
Expand All @@ -78,7 +80,9 @@ set(LIEF_PYTHON_ABSTRACT_HDR

set(LIEF_PYTHON_BASIC_HDR
"${CMAKE_CURRENT_SOURCE_DIR}/pyIterators.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/pyLIEF.hpp")
"${CMAKE_CURRENT_SOURCE_DIR}/pyLIEF.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/encoding.hpp"
)

set(LIEF_PYTHON_HDR
${LIEF_PYTHON_BASIC_HDR}
Expand Down
4 changes: 3 additions & 1 deletion api/python/ELF/objects/pyDynamicEntryLibrary.cpp
Expand Up @@ -37,7 +37,9 @@ void init_ELF_DynamicEntryLibrary_class(py::module& m) {
py::class_<DynamicEntryLibrary, DynamicEntry>(m, "DynamicEntryLibrary")
.def(py::init<const std::string &>())
.def_property("name",
static_cast<getter_t<const std::string&>>(&DynamicEntryLibrary::name),
[] (const DynamicEntryLibrary& obj) {
return safe_string_converter(obj.name());
},
static_cast<setter_t<const std::string&>>(&DynamicEntryLibrary::name),
"Return library's name")

Expand Down
8 changes: 6 additions & 2 deletions api/python/ELF/objects/pyDynamicEntryRpath.cpp
Expand Up @@ -37,12 +37,16 @@ void init_ELF_DynamicEntryRpath_class(py::module& m) {
py::class_<DynamicEntryRpath, DynamicEntry>(m, "DynamicEntryRpath")
.def(py::init<const std::string &>())
.def_property("name",
static_cast<getter_t<const std::string&>>(&DynamicEntryRpath::name),
[] (const DynamicEntryRpath& obj) {
return safe_string_converter(obj.name());
},
static_cast<setter_t<const std::string&>>(&DynamicEntryRpath::name),
"Return path value")

.def_property("rpath",
static_cast<getter_t<const std::string&>>(&DynamicEntryRpath::rpath),
[] (const DynamicEntryRpath& obj) {
return safe_string_converter(obj.rpath());
},
static_cast<setter_t<const std::string&>>(&DynamicEntryRpath::rpath),
"Return path value")

Expand Down
8 changes: 6 additions & 2 deletions api/python/ELF/objects/pyDynamicEntryRunPath.cpp
Expand Up @@ -37,12 +37,16 @@ void init_ELF_DynamicEntryRunPath_class(py::module& m) {
py::class_<DynamicEntryRunPath, DynamicEntry>(m, "DynamicEntryRunPath")
.def(py::init<const std::string &>())
.def_property("name",
static_cast<getter_t<const std::string&>>(&DynamicEntryRunPath::name),
[] (const DynamicEntryRunPath& obj) {
return safe_string_converter(obj.name());
},
static_cast<setter_t<const std::string&>>(&DynamicEntryRunPath::name),
"Return path value")

.def_property("runpath",
static_cast<getter_t<const std::string&>>(&DynamicEntryRunPath::runpath),
[] (const DynamicEntryRunPath& obj) {
return safe_string_converter(obj.runpath());
},
static_cast<setter_t<const std::string&>>(&DynamicEntryRunPath::runpath),
"Return path value")

Expand Down
4 changes: 3 additions & 1 deletion api/python/ELF/objects/pyDynamicSharedObject.cpp
Expand Up @@ -36,7 +36,9 @@ void init_ELF_DynamicSharedObject_class(py::module& m) {
//
py::class_<DynamicSharedObject, DynamicEntry>(m, "DynamicSharedObject")
.def_property("name",
static_cast<getter_t<const std::string&>>(&DynamicSharedObject::name),
[] (const DynamicSharedObject& obj) {
return safe_string_converter(obj.name());
},
static_cast<setter_t<const std::string&>>(&DynamicSharedObject::name),
"Return the library name")

Expand Down
4 changes: 3 additions & 1 deletion api/python/ELF/objects/pySymbolVersionAux.cpp
Expand Up @@ -34,7 +34,9 @@ void init_ELF_SymbolVersionAux_class(py::module& m) {
"Class which modelize an Auxiliary Symbol version")

.def_property("name",
static_cast<getter_t<const std::string&>>(&SymbolVersionAux::name),
[] (const SymbolVersionAux& obj) {
return safe_string_converter(obj.name());
},
static_cast<getter_t<const std::string&>>(&SymbolVersionAux::name),
"Symbol's name")

Expand Down
4 changes: 3 additions & 1 deletion api/python/MachO/objects/pySegmentCommand.cpp
Expand Up @@ -37,7 +37,9 @@ void init_MachO_SegmentCommand_class(py::module& m) {
.def(py::init<>())

.def_property("name",
static_cast<getter_t<const std::string&>>(&SegmentCommand::name),
[] (const SegmentCommand& obj) {
return safe_string_converter(obj.name());
},
static_cast<setter_t<const std::string&>>(&SegmentCommand::name),
"Segment's name"
)
Expand Down
4 changes: 3 additions & 1 deletion api/python/PE/objects/pyExport.cpp
Expand Up @@ -35,7 +35,9 @@ void init_PE_Export_class(py::module& m) {
.def(py::init<>())

.def_property("name",
static_cast<getter_t<const std::string&>>(&Export::name),
[] (const Export& obj) {
return safe_string_converter(obj.name());
},
static_cast<setter_t<const std::string&>>(&Export::name))

.def_property("export_flags",
Expand Down
4 changes: 3 additions & 1 deletion api/python/PE/objects/pyExportEntry.cpp
Expand Up @@ -32,7 +32,9 @@ void init_PE_ExportEntry_class(py::module& m) {
.def(py::init<>())

.def_property("name",
static_cast<getter_t<const std::string&>>(&ExportEntry::name),
[] (const ExportEntry& obj) {
return safe_string_converter(obj.name());
},
static_cast<setter_t<const std::string&>>(&ExportEntry::name))

.def_property("ordinal",
Expand Down
7 changes: 5 additions & 2 deletions api/python/PE/objects/pyImport.cpp
Expand Up @@ -47,8 +47,11 @@ void init_PE_Import_class(py::module& m) {
"Iterator to the imported " RST_CLASS_REF(lief.PE.ImportEntry) " (functions)",
py::return_value_policy::reference)

.def_property_readonly("name",
static_cast<no_const_getter<std::string&>>(&Import::name),
.def_property("name",
[] (const Import& obj) {
return safe_string_converter(obj.name());
},
static_cast<setter_t<const std::string&>>(&Import::name),
"Library name (e.g. ``kernel32.dll``)",
py::return_value_policy::reference)

Expand Down
4 changes: 3 additions & 1 deletion api/python/PE/objects/pyImportEntry.cpp
Expand Up @@ -32,7 +32,9 @@ void init_PE_ImportEntry_class(py::module& m) {
py::class_<ImportEntry>(m, "ImportEntry")
.def(py::init<>())
.def_property("name",
static_cast<getter_t<const std::string&>>(&ImportEntry::name),
[] (const ImportEntry& obj) {
return safe_string_converter(obj.name());
},
static_cast<setter_t<const std::string&>>(&ImportEntry::name),
"Import name if not ordinal")

Expand Down
2 changes: 1 addition & 1 deletion api/python/PE/objects/pyResourceNode.cpp
Expand Up @@ -50,7 +50,7 @@ void init_PE_ResourceNode_class(py::module& m) {

.def_property("name",
[] (const ResourceNode& node) {
return u16tou8(node.name());
return safe_string_converter(u16tou8(node.name()));
},
static_cast<void (ResourceNode::*)(const std::string&)>(&ResourceNode::name),
"Resource name")
Expand Down
4 changes: 3 additions & 1 deletion api/python/PE/objects/pyResourcesManager.cpp
Expand Up @@ -40,7 +40,9 @@ void init_PE_ResourcesManager_class(py::module& m) {
"``True`` if resources contain Manifest element")

.def_property("manifest",
static_cast<getter_t<std::string>>(&ResourcesManager::manifest),
[] (const ResourcesManager& obj) {
return safe_string_converter(obj.manifest());
},
static_cast<setter_t<const std::string&>>(&ResourcesManager::manifest),
"Manifest as a ``string``")

Expand Down
6 changes: 4 additions & 2 deletions api/python/PE/objects/signature/pyAuthenticatedAttributes.cpp
Expand Up @@ -44,12 +44,14 @@ void init_PE_AuthenticatedAttributes_class(py::module& m) {

.def_property_readonly("program_name",
[] (const AuthenticatedAttributes& authenticated_attributes) {
return u16tou8(authenticated_attributes.program_name());
return safe_string_converter(u16tou8(authenticated_attributes.program_name()));
},
"Return the program description (if any)")

.def_property_readonly("more_info",
&AuthenticatedAttributes::more_info,
[] (const AuthenticatedAttributes& obj) {
return safe_string_converter(obj.more_info());
},
"Return an URL to website with more information about the signer")

.def("__str__",
Expand Down
8 changes: 6 additions & 2 deletions api/python/PE/objects/signature/pyx509.cpp
Expand Up @@ -57,12 +57,16 @@ void init_PE_x509_class(py::module& m) {


.def_property_readonly("issuer",
&x509::issuer,
[] (const x509& object) {
return safe_string_converter(object.issuer());
},
"Issuer informations")


.def_property_readonly("subject",
&x509::subject,
[] (const x509& object) {
return safe_string_converter(object.subject());
},
"Subject informations")


Expand Down
55 changes: 55 additions & 0 deletions api/python/encoding.cpp
@@ -0,0 +1,55 @@
/* 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 "encoding.hpp"

py::object safe_string_converter(const std::string& str) {
auto global = py::dict(py::module::import("__main__").attr("__dict__"));
auto local = py::dict();
py::bytes name_bytes = py::bytes(str);
local["name_bytes"] = name_bytes;

#if PY_MAJOR_VERSION >= 3
py::eval<py::eval_statements>(R"(
encodings = ["big5", "big5hkscs", "cp037", "cp424", "cp437", "cp500", "cp737", "cp775", "cp850", "cp852", "cp855",
"cp856", "cp857", "cp860", "cp861", "cp862", "cp863", "cp864", "cp865", "cp866", "cp869", "cp874", "cp875", "cp932", "cp949",
"cp950", "cp1006", "cp1026", "cp1140", "cp1250", "cp1251", "cp1252", "cp1253", "cp1254", "cp1255", "cp1256", "cp1257", "cp1258",
"euc_jp", "euc_jis_2004", "euc_jisx0213", "euc_kr", "gb2312", "gbk", "gb18030", "hz", "iso2022_jp", "iso2022_jp_1", "iso2022_jp_2",
"iso2022_jp_2004", "iso2022_jp_3", "iso2022_jp_ext", "iso2022_kr", "latin_1", "iso8859_2", "iso8859_3", "iso8859_4", "iso8859_5",
"iso8859_6", "iso8859_7", "iso8859_8", "iso8859_9", "iso8859_10", "iso8859_13", "iso8859_14", "iso8859_15", "johab", "koi8_r", "koi8_u",
"mac_cyrillic", "mac_greek", "mac_iceland", "mac_latin2", "mac_roman", "mac_turkish", "ptcp154", "shift_jis", "shift_jis_2004",
"shift_jisx0213", "utf_32", "utf_32_be", "utf_32_le", "utf_16", "utf_16_be", "utf_16_le", "utf_7", "utf_8_sig" ]
for e in encodings:
try:
name_str = name_bytes.decode(e)
break
except (UnicodeEncodeError, UnicodeDecodeError) as e:
continue
name_str = name_bytes.decode('ascii', 'backslashreplace')
)", global, local);
#else
py::eval<py::eval_statements>(R"(
def handler(err):
start = err.start
end = err.end
return (u"".join([u"\\x{0:02x}".format(ord(err.object[i])) for i in range(start,end)]),end)
import codecs
codecs.register_error('backslashreplace_', handler)
name_str = name_bytes.decode('ascii', 'backslashreplace_')
)", global, local);
#endif
return local["name_str"];
}
27 changes: 27 additions & 0 deletions api/python/encoding.hpp
@@ -0,0 +1,27 @@
/* 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 PY_LIEF_ENCODING_H_
#define PY_LIEF_ENCODING_H_


#include <pybind11/pybind11.h>
#include <pybind11/eval.h>

namespace py = pybind11;

py::object safe_string_converter(const std::string& str);

#endif
2 changes: 2 additions & 0 deletions api/python/pyLIEF.hpp
Expand Up @@ -20,6 +20,8 @@
#include <pybind11/stl.h>
#include <functional>

#include "encoding.hpp"

#include "pyIterators.hpp"

namespace py = pybind11;
Expand Down
1 change: 0 additions & 1 deletion examples/python/pe_reader.py
Expand Up @@ -4,7 +4,6 @@
# Description
# -----------
# Print information about a PE file

import lief
from lief import PE
from lief.PE import oid_to_string
Expand Down
2 changes: 1 addition & 1 deletion include/LIEF/PE/Import.hpp
Expand Up @@ -87,7 +87,7 @@ class DLL_PUBLIC Import : public Visitable {
//!
//! e.g. `kernel32.dll`
const std::string& name(void) const;
std::string& name(void);
void name(const std::string& name);

//! @brief Return the @link PE::DataDirectory Data directory@endlink associated.
//! It should be the one at index PE::DATA_DIRECTORY::IMPORT_TABLE
Expand Down
8 changes: 6 additions & 2 deletions src/PE/Import.cpp
Expand Up @@ -166,8 +166,12 @@ const std::string& Import::name(void) const {
return this->name_;
}

std::string& Import::name(void) {
return const_cast<std::string&>(static_cast<const Import*>(this)->name());
//std::string& Import::name(void) {
// return const_cast<std::string&>(static_cast<const Import*>(this)->name());
//}

void Import::name(const std::string& name) {
this->name_ = name;
}


Expand Down

0 comments on commit 8c7ceaf

Please sign in to comment.