Skip to content

Commit 8c7ceaf

Browse files
committed
Handle encoding errors (resolve #59)
1 parent b62ed28 commit 8c7ceaf

23 files changed

+155
-27
lines changed

api/python/Abstract/objects/pySection.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ void init_LIEF_Section_class(py::module& m) {
2727
.def(py::init())
2828

2929
.def_property("name",
30-
static_cast<getter_t<const std::string&>>(&LIEF::Section::name),
30+
[] (const LIEF::Section& obj) {
31+
return safe_string_converter(obj.name());
32+
},
3133
static_cast<setter_t<const std::string&>>(&LIEF::Section::name),
3234
"Section's name")
3335

api/python/Abstract/objects/pySymbol.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@ void init_LIEF_Symbol_class(py::module& m) {
4646
.def(py::init())
4747

4848
.def_property("name",
49-
static_cast<getter_t<std::string>>(&LIEF::Symbol::name),
49+
[] (const LIEF::Symbol& obj) {
50+
return safe_string_converter(obj.name());
51+
},
5052
static_cast<setter_t<std::string>>(&LIEF::Symbol::name),
5153
"Symbol's name")
5254

api/python/CMakeLists.txt

+6-2
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@ set(LIEF_PYTHON_BASIC_SRC
5656
"${CMAKE_CURRENT_SOURCE_DIR}/pyUtils.cpp"
5757
"${CMAKE_CURRENT_SOURCE_DIR}/pyJson.cpp"
5858
"${CMAKE_CURRENT_SOURCE_DIR}/pyIterators.cpp"
59-
"${CMAKE_CURRENT_SOURCE_DIR}/pyExceptions.cpp")
59+
"${CMAKE_CURRENT_SOURCE_DIR}/pyExceptions.cpp"
60+
"${CMAKE_CURRENT_SOURCE_DIR}/encoding.cpp"
61+
)
6062

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

7981
set(LIEF_PYTHON_BASIC_HDR
8082
"${CMAKE_CURRENT_SOURCE_DIR}/pyIterators.hpp"
81-
"${CMAKE_CURRENT_SOURCE_DIR}/pyLIEF.hpp")
83+
"${CMAKE_CURRENT_SOURCE_DIR}/pyLIEF.hpp"
84+
"${CMAKE_CURRENT_SOURCE_DIR}/encoding.hpp"
85+
)
8286

8387
set(LIEF_PYTHON_HDR
8488
${LIEF_PYTHON_BASIC_HDR}

api/python/ELF/objects/pyDynamicEntryLibrary.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ void init_ELF_DynamicEntryLibrary_class(py::module& m) {
3737
py::class_<DynamicEntryLibrary, DynamicEntry>(m, "DynamicEntryLibrary")
3838
.def(py::init<const std::string &>())
3939
.def_property("name",
40-
static_cast<getter_t<const std::string&>>(&DynamicEntryLibrary::name),
40+
[] (const DynamicEntryLibrary& obj) {
41+
return safe_string_converter(obj.name());
42+
},
4143
static_cast<setter_t<const std::string&>>(&DynamicEntryLibrary::name),
4244
"Return library's name")
4345

api/python/ELF/objects/pyDynamicEntryRpath.cpp

+6-2
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,16 @@ void init_ELF_DynamicEntryRpath_class(py::module& m) {
3737
py::class_<DynamicEntryRpath, DynamicEntry>(m, "DynamicEntryRpath")
3838
.def(py::init<const std::string &>())
3939
.def_property("name",
40-
static_cast<getter_t<const std::string&>>(&DynamicEntryRpath::name),
40+
[] (const DynamicEntryRpath& obj) {
41+
return safe_string_converter(obj.name());
42+
},
4143
static_cast<setter_t<const std::string&>>(&DynamicEntryRpath::name),
4244
"Return path value")
4345

4446
.def_property("rpath",
45-
static_cast<getter_t<const std::string&>>(&DynamicEntryRpath::rpath),
47+
[] (const DynamicEntryRpath& obj) {
48+
return safe_string_converter(obj.rpath());
49+
},
4650
static_cast<setter_t<const std::string&>>(&DynamicEntryRpath::rpath),
4751
"Return path value")
4852

api/python/ELF/objects/pyDynamicEntryRunPath.cpp

+6-2
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,16 @@ void init_ELF_DynamicEntryRunPath_class(py::module& m) {
3737
py::class_<DynamicEntryRunPath, DynamicEntry>(m, "DynamicEntryRunPath")
3838
.def(py::init<const std::string &>())
3939
.def_property("name",
40-
static_cast<getter_t<const std::string&>>(&DynamicEntryRunPath::name),
40+
[] (const DynamicEntryRunPath& obj) {
41+
return safe_string_converter(obj.name());
42+
},
4143
static_cast<setter_t<const std::string&>>(&DynamicEntryRunPath::name),
4244
"Return path value")
4345

4446
.def_property("runpath",
45-
static_cast<getter_t<const std::string&>>(&DynamicEntryRunPath::runpath),
47+
[] (const DynamicEntryRunPath& obj) {
48+
return safe_string_converter(obj.runpath());
49+
},
4650
static_cast<setter_t<const std::string&>>(&DynamicEntryRunPath::runpath),
4751
"Return path value")
4852

api/python/ELF/objects/pyDynamicSharedObject.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ void init_ELF_DynamicSharedObject_class(py::module& m) {
3636
//
3737
py::class_<DynamicSharedObject, DynamicEntry>(m, "DynamicSharedObject")
3838
.def_property("name",
39-
static_cast<getter_t<const std::string&>>(&DynamicSharedObject::name),
39+
[] (const DynamicSharedObject& obj) {
40+
return safe_string_converter(obj.name());
41+
},
4042
static_cast<setter_t<const std::string&>>(&DynamicSharedObject::name),
4143
"Return the library name")
4244

api/python/ELF/objects/pySymbolVersionAux.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ void init_ELF_SymbolVersionAux_class(py::module& m) {
3434
"Class which modelize an Auxiliary Symbol version")
3535

3636
.def_property("name",
37-
static_cast<getter_t<const std::string&>>(&SymbolVersionAux::name),
37+
[] (const SymbolVersionAux& obj) {
38+
return safe_string_converter(obj.name());
39+
},
3840
static_cast<getter_t<const std::string&>>(&SymbolVersionAux::name),
3941
"Symbol's name")
4042

api/python/MachO/objects/pySegmentCommand.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ void init_MachO_SegmentCommand_class(py::module& m) {
3737
.def(py::init<>())
3838

3939
.def_property("name",
40-
static_cast<getter_t<const std::string&>>(&SegmentCommand::name),
40+
[] (const SegmentCommand& obj) {
41+
return safe_string_converter(obj.name());
42+
},
4143
static_cast<setter_t<const std::string&>>(&SegmentCommand::name),
4244
"Segment's name"
4345
)

api/python/PE/objects/pyExport.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ void init_PE_Export_class(py::module& m) {
3535
.def(py::init<>())
3636

3737
.def_property("name",
38-
static_cast<getter_t<const std::string&>>(&Export::name),
38+
[] (const Export& obj) {
39+
return safe_string_converter(obj.name());
40+
},
3941
static_cast<setter_t<const std::string&>>(&Export::name))
4042

4143
.def_property("export_flags",

api/python/PE/objects/pyExportEntry.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ void init_PE_ExportEntry_class(py::module& m) {
3232
.def(py::init<>())
3333

3434
.def_property("name",
35-
static_cast<getter_t<const std::string&>>(&ExportEntry::name),
35+
[] (const ExportEntry& obj) {
36+
return safe_string_converter(obj.name());
37+
},
3638
static_cast<setter_t<const std::string&>>(&ExportEntry::name))
3739

3840
.def_property("ordinal",

api/python/PE/objects/pyImport.cpp

+5-2
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,11 @@ void init_PE_Import_class(py::module& m) {
4747
"Iterator to the imported " RST_CLASS_REF(lief.PE.ImportEntry) " (functions)",
4848
py::return_value_policy::reference)
4949

50-
.def_property_readonly("name",
51-
static_cast<no_const_getter<std::string&>>(&Import::name),
50+
.def_property("name",
51+
[] (const Import& obj) {
52+
return safe_string_converter(obj.name());
53+
},
54+
static_cast<setter_t<const std::string&>>(&Import::name),
5255
"Library name (e.g. ``kernel32.dll``)",
5356
py::return_value_policy::reference)
5457

api/python/PE/objects/pyImportEntry.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ void init_PE_ImportEntry_class(py::module& m) {
3232
py::class_<ImportEntry>(m, "ImportEntry")
3333
.def(py::init<>())
3434
.def_property("name",
35-
static_cast<getter_t<const std::string&>>(&ImportEntry::name),
35+
[] (const ImportEntry& obj) {
36+
return safe_string_converter(obj.name());
37+
},
3638
static_cast<setter_t<const std::string&>>(&ImportEntry::name),
3739
"Import name if not ordinal")
3840

api/python/PE/objects/pyResourceNode.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ void init_PE_ResourceNode_class(py::module& m) {
5050

5151
.def_property("name",
5252
[] (const ResourceNode& node) {
53-
return u16tou8(node.name());
53+
return safe_string_converter(u16tou8(node.name()));
5454
},
5555
static_cast<void (ResourceNode::*)(const std::string&)>(&ResourceNode::name),
5656
"Resource name")

api/python/PE/objects/pyResourcesManager.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@ void init_PE_ResourcesManager_class(py::module& m) {
4040
"``True`` if resources contain Manifest element")
4141

4242
.def_property("manifest",
43-
static_cast<getter_t<std::string>>(&ResourcesManager::manifest),
43+
[] (const ResourcesManager& obj) {
44+
return safe_string_converter(obj.manifest());
45+
},
4446
static_cast<setter_t<const std::string&>>(&ResourcesManager::manifest),
4547
"Manifest as a ``string``")
4648

api/python/PE/objects/signature/pyAuthenticatedAttributes.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,14 @@ void init_PE_AuthenticatedAttributes_class(py::module& m) {
4444

4545
.def_property_readonly("program_name",
4646
[] (const AuthenticatedAttributes& authenticated_attributes) {
47-
return u16tou8(authenticated_attributes.program_name());
47+
return safe_string_converter(u16tou8(authenticated_attributes.program_name()));
4848
},
4949
"Return the program description (if any)")
5050

5151
.def_property_readonly("more_info",
52-
&AuthenticatedAttributes::more_info,
52+
[] (const AuthenticatedAttributes& obj) {
53+
return safe_string_converter(obj.more_info());
54+
},
5355
"Return an URL to website with more information about the signer")
5456

5557
.def("__str__",

api/python/PE/objects/signature/pyx509.cpp

+6-2
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,16 @@ void init_PE_x509_class(py::module& m) {
5757

5858

5959
.def_property_readonly("issuer",
60-
&x509::issuer,
60+
[] (const x509& object) {
61+
return safe_string_converter(object.issuer());
62+
},
6163
"Issuer informations")
6264

6365

6466
.def_property_readonly("subject",
65-
&x509::subject,
67+
[] (const x509& object) {
68+
return safe_string_converter(object.subject());
69+
},
6670
"Subject informations")
6771

6872

api/python/encoding.cpp

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
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+
17+
#include "encoding.hpp"
18+
19+
py::object safe_string_converter(const std::string& str) {
20+
auto global = py::dict(py::module::import("__main__").attr("__dict__"));
21+
auto local = py::dict();
22+
py::bytes name_bytes = py::bytes(str);
23+
local["name_bytes"] = name_bytes;
24+
25+
#if PY_MAJOR_VERSION >= 3
26+
py::eval<py::eval_statements>(R"(
27+
encodings = ["big5", "big5hkscs", "cp037", "cp424", "cp437", "cp500", "cp737", "cp775", "cp850", "cp852", "cp855",
28+
"cp856", "cp857", "cp860", "cp861", "cp862", "cp863", "cp864", "cp865", "cp866", "cp869", "cp874", "cp875", "cp932", "cp949",
29+
"cp950", "cp1006", "cp1026", "cp1140", "cp1250", "cp1251", "cp1252", "cp1253", "cp1254", "cp1255", "cp1256", "cp1257", "cp1258",
30+
"euc_jp", "euc_jis_2004", "euc_jisx0213", "euc_kr", "gb2312", "gbk", "gb18030", "hz", "iso2022_jp", "iso2022_jp_1", "iso2022_jp_2",
31+
"iso2022_jp_2004", "iso2022_jp_3", "iso2022_jp_ext", "iso2022_kr", "latin_1", "iso8859_2", "iso8859_3", "iso8859_4", "iso8859_5",
32+
"iso8859_6", "iso8859_7", "iso8859_8", "iso8859_9", "iso8859_10", "iso8859_13", "iso8859_14", "iso8859_15", "johab", "koi8_r", "koi8_u",
33+
"mac_cyrillic", "mac_greek", "mac_iceland", "mac_latin2", "mac_roman", "mac_turkish", "ptcp154", "shift_jis", "shift_jis_2004",
34+
"shift_jisx0213", "utf_32", "utf_32_be", "utf_32_le", "utf_16", "utf_16_be", "utf_16_le", "utf_7", "utf_8_sig" ]
35+
for e in encodings:
36+
try:
37+
name_str = name_bytes.decode(e)
38+
break
39+
except (UnicodeEncodeError, UnicodeDecodeError) as e:
40+
continue
41+
name_str = name_bytes.decode('ascii', 'backslashreplace')
42+
)", global, local);
43+
#else
44+
py::eval<py::eval_statements>(R"(
45+
def handler(err):
46+
start = err.start
47+
end = err.end
48+
return (u"".join([u"\\x{0:02x}".format(ord(err.object[i])) for i in range(start,end)]),end)
49+
import codecs
50+
codecs.register_error('backslashreplace_', handler)
51+
name_str = name_bytes.decode('ascii', 'backslashreplace_')
52+
)", global, local);
53+
#endif
54+
return local["name_str"];
55+
}

api/python/encoding.hpp

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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 PY_LIEF_ENCODING_H_
17+
#define PY_LIEF_ENCODING_H_
18+
19+
20+
#include <pybind11/pybind11.h>
21+
#include <pybind11/eval.h>
22+
23+
namespace py = pybind11;
24+
25+
py::object safe_string_converter(const std::string& str);
26+
27+
#endif

api/python/pyLIEF.hpp

+2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
#include <pybind11/stl.h>
2121
#include <functional>
2222

23+
#include "encoding.hpp"
24+
2325
#include "pyIterators.hpp"
2426

2527
namespace py = pybind11;

examples/python/pe_reader.py

-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
# Description
55
# -----------
66
# Print information about a PE file
7-
87
import lief
98
from lief import PE
109
from lief.PE import oid_to_string

include/LIEF/PE/Import.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ class DLL_PUBLIC Import : public Visitable {
8787
//!
8888
//! e.g. `kernel32.dll`
8989
const std::string& name(void) const;
90-
std::string& name(void);
90+
void name(const std::string& name);
9191

9292
//! @brief Return the @link PE::DataDirectory Data directory@endlink associated.
9393
//! It should be the one at index PE::DATA_DIRECTORY::IMPORT_TABLE

src/PE/Import.cpp

+6-2
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,12 @@ const std::string& Import::name(void) const {
166166
return this->name_;
167167
}
168168

169-
std::string& Import::name(void) {
170-
return const_cast<std::string&>(static_cast<const Import*>(this)->name());
169+
//std::string& Import::name(void) {
170+
// return const_cast<std::string&>(static_cast<const Import*>(this)->name());
171+
//}
172+
173+
void Import::name(const std::string& name) {
174+
this->name_ = name;
171175
}
172176

173177

0 commit comments

Comments
 (0)