Skip to content

Commit 8473c8e

Browse files
committed
Enhance PE resources
* Improve Resource Manager * Fix bug when rebuilding resources (aligment issue) * Provide a Python API to access to the resource tree * Pretty print lang/sublang of resources * Parse resource dialog * Parse resource icons * Parse resource version * Add tests on the resource builder * Add tutorial (related to #28)
1 parent a9dcfb5 commit 8473c8e

File tree

135 files changed

+9757
-38240
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

135 files changed

+9757
-38240
lines changed

Diff for: api/python/PE/CMakeLists.txt

+13
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,17 @@
11
set(LIEF_PYTHON_PE_SRC
2+
"${CMAKE_CURRENT_LIST_DIR}/objects/pyResourceNode.cpp"
3+
"${CMAKE_CURRENT_LIST_DIR}/objects/pyResourceData.cpp"
4+
"${CMAKE_CURRENT_LIST_DIR}/objects/pyResourceDirectory.cpp"
5+
6+
"${CMAKE_CURRENT_LIST_DIR}/objects/resources/pyResourceIcon.cpp"
7+
"${CMAKE_CURRENT_LIST_DIR}/objects/resources/pyResourceVersion.cpp"
8+
"${CMAKE_CURRENT_LIST_DIR}/objects/resources/pyResourceVarFileInfo.cpp"
9+
"${CMAKE_CURRENT_LIST_DIR}/objects/resources/pyResourceFixedFileInfo.cpp"
10+
"${CMAKE_CURRENT_LIST_DIR}/objects/resources/pyResourceStringFileInfo.cpp"
11+
"${CMAKE_CURRENT_LIST_DIR}/objects/resources/pyLangCodeItem.cpp"
12+
"${CMAKE_CURRENT_LIST_DIR}/objects/resources/pyResourceDialog.cpp"
13+
"${CMAKE_CURRENT_LIST_DIR}/objects/resources/pyResourceDialogItem.cpp"
14+
215
"${CMAKE_CURRENT_LIST_DIR}/objects/signature/pySignerInfo.cpp"
316
"${CMAKE_CURRENT_LIST_DIR}/objects/signature/pyAuthenticatedAttributes.cpp"
417
"${CMAKE_CURRENT_LIST_DIR}/objects/signature/pyx509.cpp"

Diff for: api/python/PE/objects/pyBinary.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,11 @@ void init_PE_Binary_class(py::module& m) {
205205
static_cast<no_const_getter<ResourcesManager>>(&Binary::get_resources_manager),
206206
"Return the " RST_CLASS_REF(lief.PE.ResourcesManager) " to manage resources")
207207

208+
.def_property_readonly("resources",
209+
static_cast<no_const_getter<ResourceNode&>>(&Binary::get_resources),
210+
"Return the " RST_CLASS_REF(lief.PE.ResourceNode) " tree",
211+
py::return_value_policy::reference)
212+
208213
.def_property_readonly("overlay",
209214
static_cast<no_const_getter<std::vector<uint8_t>&>>(&Binary::overlay),
210215
"Return the overlay content",

Diff for: api/python/PE/objects/pyResourceData.cpp

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
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+
#include "pyPE.hpp"
17+
18+
#include "LIEF/visitors/Hash.hpp"
19+
#include "LIEF/PE/ResourceData.hpp"
20+
21+
#include <string>
22+
#include <sstream>
23+
24+
template<class T>
25+
using getter_t = T (ResourceData::*)(void) const;
26+
27+
template<class T>
28+
using setter_t = void (ResourceData::*)(T);
29+
30+
void init_PE_ResourceData_class(py::module& m) {
31+
py::class_<ResourceData, ResourceNode>(m, "ResourceData")
32+
.def(py::init<>(),
33+
"Default constructor")
34+
35+
.def(py::init<const std::vector<uint8_t>&, uint32_t>(),
36+
"content"_a, "code_page"_a)
37+
38+
.def_property("code_page",
39+
static_cast<getter_t<uint32_t>>(&ResourceData::code_page),
40+
static_cast<setter_t<uint32_t>>(&ResourceData::code_page),
41+
"The code page that is used to decode code point "
42+
"values within the resource data. Typically, the code "
43+
"page would be the Unicode code page")
44+
45+
.def_property("content",
46+
static_cast<getter_t<const std::vector<uint8_t>&>>(&ResourceData::content),
47+
static_cast<setter_t<const std::vector<uint8_t>&>>(&ResourceData::content),
48+
"Resource content")
49+
50+
.def_property("reserved",
51+
static_cast<getter_t<uint32_t>>(&ResourceData::reserved),
52+
static_cast<setter_t<uint32_t>>(&ResourceData::reserved),
53+
"Reserved value. Should be ``0``")
54+
55+
.def_property_readonly("offset",
56+
&ResourceData::offset,
57+
"Offset of the content within the resource")
58+
59+
.def("__eq__", &ResourceData::operator==)
60+
.def("__ne__", &ResourceData::operator!=)
61+
62+
.def("__hash__",
63+
[] (const ResourceData& node) {
64+
return LIEF::Hash::hash(node);
65+
})
66+
67+
.def("__str__",
68+
[] (const ResourceData& data) {
69+
std::ostringstream stream;
70+
stream << data;
71+
std::string str = stream.str();
72+
return str;
73+
});
74+
}

Diff for: api/python/PE/objects/pyResourceDirectory.cpp

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
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+
#include "pyPE.hpp"
17+
18+
#include "LIEF/visitors/Hash.hpp"
19+
#include "LIEF/PE/ResourceDirectory.hpp"
20+
21+
#include <string>
22+
#include <sstream>
23+
24+
template<class T>
25+
using getter_t = T (ResourceDirectory::*)(void) const;
26+
27+
template<class T>
28+
using setter_t = void (ResourceDirectory::*)(T);
29+
30+
void init_PE_ResourceDirectory_class(py::module& m) {
31+
py::class_<ResourceDirectory, ResourceNode>(m, "ResourceDirectory")
32+
.def(py::init<>(),
33+
"Default constructor")
34+
35+
.def_property("characteristics",
36+
static_cast<getter_t<uint32_t>>(&ResourceDirectory::characteristics),
37+
static_cast<setter_t<uint32_t>>(&ResourceDirectory::characteristics),
38+
"Resource flags. This field is reserved for future use. "
39+
"It is currently set to zero.")
40+
41+
.def_property("time_date_stamp",
42+
static_cast<getter_t<uint32_t>>(&ResourceDirectory::time_date_stamp),
43+
static_cast<setter_t<uint32_t>>(&ResourceDirectory::time_date_stamp),
44+
"The time that the resource data was created by the "
45+
"resource compiler.")
46+
47+
.def_property("major_version",
48+
static_cast<getter_t<uint16_t>>(&ResourceDirectory::major_version),
49+
static_cast<setter_t<uint16_t>>(&ResourceDirectory::major_version),
50+
"The major version number, set by the user.")
51+
52+
.def_property("minor_version",
53+
static_cast<getter_t<uint16_t>>(&ResourceDirectory::minor_version),
54+
static_cast<setter_t<uint16_t>>(&ResourceDirectory::minor_version),
55+
"The minor version number, set by the user.")
56+
57+
.def_property("numberof_name_entries",
58+
static_cast<getter_t<uint16_t>>(&ResourceDirectory::numberof_name_entries),
59+
static_cast<setter_t<uint16_t>>(&ResourceDirectory::numberof_name_entries),
60+
"The number of directory entries immediately "
61+
"following the table that use strings to identify Type, "
62+
"Name, or Language entries (depending on the level "
63+
"of the table")
64+
65+
.def_property("numberof_id_entries",
66+
static_cast<getter_t<uint16_t>>(&ResourceDirectory::numberof_id_entries),
67+
static_cast<setter_t<uint16_t>>(&ResourceDirectory::numberof_id_entries),
68+
"The number of directory entries immediately "
69+
"following the Name entries that use numeric IDs for "
70+
"Type, Name, or Language entries.")
71+
72+
73+
.def("__eq__", &ResourceDirectory::operator==)
74+
.def("__ne__", &ResourceDirectory::operator!=)
75+
76+
.def("__hash__",
77+
[] (const ResourceDirectory& node) {
78+
return LIEF::Hash::hash(node);
79+
})
80+
81+
.def("__str__",
82+
[] (const ResourceDirectory& directory) {
83+
std::ostringstream stream;
84+
stream << directory;
85+
std::string str = stream.str();
86+
return str;
87+
});
88+
89+
}

Diff for: api/python/PE/objects/pyResourceNode.cpp

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
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+
#include "pyPE.hpp"
17+
18+
#include "LIEF/visitors/Hash.hpp"
19+
#include "LIEF/PE/ResourceNode.hpp"
20+
21+
#include <string>
22+
#include <sstream>
23+
24+
template<class T>
25+
using getter_t = T (ResourceNode::*)(void) const;
26+
27+
template<class T>
28+
using setter_t = void (ResourceNode::*)(T);
29+
30+
void init_PE_ResourceNode_class(py::module& m) {
31+
py::class_<ResourceNode>(m, "ResourceNode")
32+
33+
.def_property("id",
34+
static_cast<getter_t<uint32_t>>(&ResourceNode::id),
35+
static_cast<setter_t<uint32_t>>(&ResourceNode::id),
36+
"Integer that identifies the Type, Name, or "
37+
"Language ID entry.")
38+
39+
.def_property_readonly("is_directory",
40+
&ResourceNode::is_directory,
41+
"``True`` if the current resource is a " RST_CLASS_REF(lief.PE.ResourceDirectory) "")
42+
43+
.def_property_readonly("is_data",
44+
&ResourceNode::is_data,
45+
"``True`` if the current resource is a " RST_CLASS_REF(lief.PE.ResourceData) "")
46+
47+
.def_property_readonly("has_name",
48+
&ResourceNode::has_name,
49+
"``True`` if the current resource uses a name")
50+
51+
.def_property("name",
52+
[] (const ResourceNode& node) {
53+
return u16tou8(node.name());
54+
},
55+
static_cast<void (ResourceNode::*)(const std::string&)>(&ResourceNode::name),
56+
"Resource name")
57+
58+
.def_property_readonly("childs",
59+
static_cast<it_childs (ResourceNode::*)(void)>(&ResourceNode::childs),
60+
"Node's childs")
61+
62+
.def("add_directory_node",
63+
static_cast<ResourceNode& (ResourceNode::*)(const ResourceDirectory&)>(&ResourceNode::add_child),
64+
"Add a " RST_CLASS_REF(lief.PE.ResourceDirectory) " to the current node",
65+
"resource_directory"_a)
66+
67+
.def("add_data_node",
68+
static_cast<ResourceNode& (ResourceNode::*)(const ResourceData&)>(&ResourceNode::add_child),
69+
"Add a " RST_CLASS_REF(lief.PE.ResourceData) " to the current node",
70+
"resource_data"_a)
71+
72+
.def("delete_child",
73+
static_cast<void (ResourceNode::*)(const ResourceNode&)>(&ResourceNode::delete_child),
74+
"Delete the given " RST_CLASS_REF(lief.PE.ResourceNode) " from childs",
75+
"node"_a)
76+
77+
.def("delete_child",
78+
static_cast<void (ResourceNode::*)(uint32_t)>(&ResourceNode::delete_child),
79+
"Delete the " RST_CLASS_REF(lief.PE.ResourceNode) " with the given :attr:`~lief.PE.ResourceNode.id` from childs",
80+
"id"_a)
81+
82+
.def("sort_by_id",
83+
&ResourceNode::sort_by_id,
84+
"Sort resource childs by ID")
85+
86+
.def_property_readonly("depth",
87+
&ResourceNode::depth,
88+
"Current depth of the entry in the resource tree")
89+
90+
.def("__eq__", &ResourceNode::operator==)
91+
.def("__ne__", &ResourceNode::operator!=)
92+
93+
.def("__hash__",
94+
[] (const ResourceNode& node) {
95+
return LIEF::Hash::hash(node);
96+
})
97+
98+
.def("__str__",
99+
[] (const ResourceNode& node) {
100+
std::ostringstream stream;
101+
stream << node;
102+
std::string str = stream.str();
103+
return str;
104+
});
105+
106+
107+
108+
}

Diff for: api/python/PE/objects/pyResourcesManager.cpp

+83-3
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,91 @@
2222
#include <sstream>
2323

2424

25+
template<class T>
26+
using getter_t = T (ResourcesManager::*)(void) const;
27+
28+
template<class T>
29+
using setter_t = void (ResourcesManager::*)(T);
30+
31+
template<class T, class P>
32+
using no_const_func = T (ResourcesManager::*)(P);
33+
2534
void init_PE_ResourcesManager_class(py::module& m) {
26-
py::class_<ResourcesManager>(m, "ResourcesManager")
35+
py::class_<ResourcesManager>(m, "ResourcesManager",
36+
"The Resource Manager provides an enhanced API to manipulate the resource tree")
37+
38+
.def_property_readonly("has_manifest",
39+
&ResourcesManager::has_manifest,
40+
"``True`` if resources contain Manifest element")
41+
42+
.def_property("manifest",
43+
static_cast<getter_t<std::string>>(&ResourcesManager::manifest),
44+
static_cast<setter_t<const std::string&>>(&ResourcesManager::manifest),
45+
"Manifest as a ``string``")
46+
47+
48+
.def_property_readonly("has_version",
49+
&ResourcesManager::has_version,
50+
"``true`` if resources contain " RST_CLASS_REF(lief.PE.ResourceVersion) "")
51+
52+
.def_property_readonly("version",
53+
static_cast<getter_t<ResourceVersion>>(&ResourcesManager::version),
54+
"Return the " RST_CLASS_REF(lief.PE.ResourceVersion) "")
55+
//static_cast<setter_t<const ResourceVersion&>>(&ResourcesManager::version))
56+
57+
58+
.def_property_readonly("has_icons",
59+
&ResourcesManager::has_icons,
60+
"``true`` if resources contain " RST_CLASS_REF(lief.PE.ResourceIcon) "")
61+
62+
.def_property_readonly("icons",
63+
&ResourcesManager::icons,
64+
"Return the list of the " RST_CLASS_REF(lief.PE.ResourceIcon) " present in the resource")
65+
66+
.def("change_icon",
67+
&ResourcesManager::change_icon,
68+
"Switch the given icons",
69+
"old_one"_a, "new_one"_a)
70+
71+
.def_property_readonly("has_dialogs",
72+
&ResourcesManager::has_dialogs,
73+
"``true`` if resources contain " RST_CLASS_REF(lief.PE.ResourceDialog) "")
74+
75+
.def_property_readonly("dialogs",
76+
&ResourcesManager::dialogs,
77+
"Return the list of the " RST_CLASS_REF(lief.PE.ResourceDialog) " present in the resource")
78+
79+
.def_property_readonly("types_available",
80+
&ResourcesManager::get_types_available,
81+
"Return list of " RST_CLASS_REF(lief.PE.RESOURCE_TYPES) " present in the resources")
82+
83+
.def_property_readonly("langs_available",
84+
&ResourcesManager::get_langs_available,
85+
"Return list of " RST_CLASS_REF(lief.PE.RESOURCE_LANGS) " present in the resources")
86+
87+
.def_property_readonly("sublangs_available",
88+
&ResourcesManager::get_sublangs_available,
89+
"Return list of " RST_CLASS_REF(lief.PE.RESOURCE_SUBLANGS) " present in the resources")
90+
91+
.def("add_icon",
92+
&ResourcesManager::add_icon,
93+
"Add an icon to the resources",
94+
"icon"_a)
95+
96+
.def("has_type",
97+
&ResourcesManager::has_type,
98+
"``True`` if the resource has the given " RST_CLASS_REF(lief.PE.RESOURCE_TYPES) "",
99+
"type"_a)
100+
101+
.def("get_node_type",
102+
static_cast<no_const_func<ResourceNode&, RESOURCE_TYPES>>(&ResourcesManager::get_node_type),
103+
"Return " RST_CLASS_REF(lief.PE.ResourceNode) " with "
104+
"the given " RST_CLASS_REF(lief.PE.RESOURCE_TYPES) "",
105+
"type"_a,
106+
py::return_value_policy::reference)
27107

28-
.def("__str__", [] (const ResourcesManager& manager)
29-
{
108+
.def("__str__",
109+
[] (const ResourcesManager& manager) {
30110
std::ostringstream stream;
31111
stream << manager;
32112
std::string str = stream.str();

0 commit comments

Comments
 (0)