Skip to content

Commit eab4a76

Browse files
committed
Parse PE Code View (PDB 7.0)
Resolve: #138
1 parent 6cb9519 commit eab4a76

31 files changed

+936
-37
lines changed

api/python/PE/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ set(LIEF_PYTHON_PE_SRC
3333
"${CMAKE_CURRENT_LIST_DIR}/objects/pyResourcesManager.cpp"
3434
"${CMAKE_CURRENT_LIST_DIR}/objects/pyHeader.cpp"
3535
"${CMAKE_CURRENT_LIST_DIR}/objects/pyDebug.cpp"
36+
"${CMAKE_CURRENT_LIST_DIR}/objects/pyCodeView.cpp"
37+
"${CMAKE_CURRENT_LIST_DIR}/objects/pyCodeViewPDB.cpp"
3638
"${CMAKE_CURRENT_LIST_DIR}/objects/pySection.cpp"
3739
"${CMAKE_CURRENT_LIST_DIR}/objects/pyExport.cpp"
3840
"${CMAKE_CURRENT_LIST_DIR}/objects/pyImport.cpp"

api/python/PE/objects/pyCodeView.cpp

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
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/CodeView.hpp"
20+
21+
#include <string>
22+
#include <sstream>
23+
24+
template<class T>
25+
using getter_t = T (CodeView::*)(void) const;
26+
27+
template<class T>
28+
using setter_t = void (CodeView::*)(T);
29+
30+
void init_PE_CodeView_class(py::module& m) {
31+
py::class_<CodeView>(m, "CodeView")
32+
.def_property_readonly("cv_signature",
33+
static_cast<getter_t<CODE_VIEW_SIGNATURES>>(&CodeView::cv_signature),
34+
"Type of the code view (" RST_CLASS_REF(lief.PE.CODE_VIEW_SIGNATURES) ")")
35+
36+
.def("__eq__", &CodeView::operator==)
37+
.def("__ne__", &CodeView::operator!=)
38+
.def("__hash__",
39+
[] (const CodeView& codeview) {
40+
return LIEF::Hash::hash(codeview);
41+
})
42+
43+
.def("__str__", [] (const CodeView& cv)
44+
{
45+
std::ostringstream stream;
46+
stream << cv;
47+
return stream.str();
48+
});
49+
50+
51+
}
+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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/CodeViewPDB.hpp"
20+
21+
#include <string>
22+
#include <sstream>
23+
24+
template<class T>
25+
using getter_t = T (CodeViewPDB::*)(void) const;
26+
27+
template<class T>
28+
using setter_t = void (CodeViewPDB::*)(T);
29+
30+
void init_PE_CodeViewPDB_class(py::module& m) {
31+
py::class_<CodeViewPDB, CodeView>(m, "CodeViewPDB")
32+
.def(py::init<>())
33+
34+
.def_property("signature",
35+
static_cast<getter_t<CodeViewPDB::signature_t>>(&CodeViewPDB::signature),
36+
static_cast<setter_t<CodeViewPDB::signature_t>>(&CodeViewPDB::signature))
37+
38+
.def_property("age",
39+
static_cast<getter_t<uint32_t>>(&CodeViewPDB::age),
40+
static_cast<setter_t<uint32_t>>(&CodeViewPDB::age))
41+
42+
.def_property("filename",
43+
static_cast<getter_t<const std::string&>>(&CodeViewPDB::filename),
44+
static_cast<setter_t<const std::string&>>(&CodeViewPDB::filename))
45+
46+
.def("__eq__", &CodeViewPDB::operator==)
47+
.def("__ne__", &CodeViewPDB::operator!=)
48+
.def("__hash__",
49+
[] (const CodeViewPDB& codeview) {
50+
return LIEF::Hash::hash(codeview);
51+
})
52+
53+
.def("__str__", [] (const CodeViewPDB& cv)
54+
{
55+
std::ostringstream stream;
56+
stream << cv;
57+
return stream.str();
58+
});
59+
60+
61+
}

api/python/PE/objects/pyDebug.cpp

+27-8
Original file line numberDiff line numberDiff line change
@@ -33,35 +33,54 @@ void init_PE_Debug_class(py::module& m) {
3333

3434
.def_property("characteristics",
3535
static_cast<getter_t<uint32_t>>(&Debug::characteristics),
36-
static_cast<setter_t<uint32_t>>(&Debug::characteristics))
36+
static_cast<setter_t<uint32_t>>(&Debug::characteristics),
37+
"Reserved should be 0")
3738

3839
.def_property("timestamp",
3940
static_cast<getter_t<uint32_t>>(&Debug::timestamp),
40-
static_cast<setter_t<uint32_t>>(&Debug::timestamp))
41+
static_cast<setter_t<uint32_t>>(&Debug::timestamp),
42+
"The time and date that the debug data was created.")
4143

4244
.def_property("major_version",
4345
static_cast<getter_t<uint16_t>>(&Debug::major_version),
44-
static_cast<setter_t<uint16_t>>(&Debug::major_version))
46+
static_cast<setter_t<uint16_t>>(&Debug::major_version),
47+
"The major version number of the debug data format.")
4548

4649
.def_property("minor_version",
4750
static_cast<getter_t<uint16_t>>(&Debug::minor_version),
48-
static_cast<setter_t<uint16_t>>(&Debug::minor_version))
51+
static_cast<setter_t<uint16_t>>(&Debug::minor_version),
52+
"The minor version number of the debug data format.")
4953

5054
.def_property("type",
5155
static_cast<getter_t<DEBUG_TYPES>>(&Debug::type),
52-
static_cast<setter_t<DEBUG_TYPES>>(&Debug::type))
56+
static_cast<setter_t<DEBUG_TYPES>>(&Debug::type),
57+
"The format (" RST_CLASS_REF(lief.PE.DEBUG_TYPES) ") of the debugging information")
5358

5459
.def_property("sizeof_data",
5560
static_cast<getter_t<uint32_t>>(&Debug::sizeof_data),
56-
static_cast<setter_t<uint32_t>>(&Debug::sizeof_data))
61+
static_cast<setter_t<uint32_t>>(&Debug::sizeof_data),
62+
"Size of the debug data")
5763

5864
.def_property("addressof_rawdata",
5965
static_cast<getter_t<uint32_t>>(&Debug::addressof_rawdata),
60-
static_cast<setter_t<uint32_t>>(&Debug::addressof_rawdata))
66+
static_cast<setter_t<uint32_t>>(&Debug::addressof_rawdata),
67+
"Address of the debug data relative to the image base")
6168

6269
.def_property("pointerto_rawdata",
6370
static_cast<getter_t<uint32_t>>(&Debug::pointerto_rawdata),
64-
static_cast<setter_t<uint32_t>>(&Debug::pointerto_rawdata))
71+
static_cast<setter_t<uint32_t>>(&Debug::pointerto_rawdata),
72+
"File offset of the debug data")
73+
74+
.def_property_readonly("has_code_view",
75+
&Debug::has_code_view,
76+
"Whether or not a code view is present")
77+
78+
.def_property_readonly("code_view",
79+
static_cast<CodeView& (Debug::*)(void)>(&Debug::code_view),
80+
"Return an object which subclass " RST_CLASS_REF(lief.PE.CodeView) " representing the code view \n\n"
81+
"The subclassed object can be one of: \n\n"
82+
" * " RST_CLASS_REF(lief.PE.CodeViewPDB) "\n",
83+
py::return_value_policy::reference)
6584

6685
.def("__eq__", &Debug::operator==)
6786
.def("__ne__", &Debug::operator!=)

api/python/PE/pyPE.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ void init_PE_module(py::module& m) {
5454
init_PE_ExportEntry_class(LIEF_PE_module);
5555
init_PE_Builder_class(LIEF_PE_module);
5656
init_PE_Debug_class(LIEF_PE_module);
57+
init_PE_CodeView_class(LIEF_PE_module);
58+
init_PE_CodeViewPDB_class(LIEF_PE_module);
5759
init_PE_CodeIntegrity_class(LIEF_PE_module);
5860
init_PE_load_configurations(LIEF_PE_module);
5961

api/python/PE/pyPE.hpp

+2
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ void init_PE_Export_class(py::module&);
4848
void init_PE_ExportEntry_class(py::module&);
4949
void init_PE_Builder_class(py::module&);
5050
void init_PE_Debug_class(py::module&);
51+
void init_PE_CodeView_class(py::module&);
52+
void init_PE_CodeViewPDB_class(py::module&);
5153
void init_PE_CodeIntegrity_class(py::module&);
5254
void init_PE_load_configurations(py::module&);
5355

api/python/PE/pyPEStructures.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -786,4 +786,12 @@ void init_PE_Structures_enum(py::module& m) {
786786
.value(PY_ENUM(LIEF::PE::GUARD_RF_FLAGS::GRF_ENABLE))
787787
.value(PY_ENUM(LIEF::PE::GUARD_RF_FLAGS::GRF_STRICT))
788788
.export_values();
789+
790+
py::enum_<LIEF::PE::CODE_VIEW_SIGNATURES>(m, "CODE_VIEW_SIGNATURES")
791+
.value(PY_ENUM(LIEF::PE::CODE_VIEW_SIGNATURES::CVS_UNKNOWN))
792+
.value(PY_ENUM(LIEF::PE::CODE_VIEW_SIGNATURES::CVS_PDB_70))
793+
.value(PY_ENUM(LIEF::PE::CODE_VIEW_SIGNATURES::CVS_PDB_20))
794+
.value(PY_ENUM(LIEF::PE::CODE_VIEW_SIGNATURES::CVS_CV_50))
795+
.value(PY_ENUM(LIEF::PE::CODE_VIEW_SIGNATURES::CVS_CV_41))
796+
.export_values();
789797
}

doc/sphinx/api/cpp/pe.rst

+25
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,31 @@ TLS
7575

7676
----------
7777

78+
Debug
79+
*****
80+
81+
.. doxygenclass:: LIEF::PE::Debug
82+
:project: lief
83+
84+
----------
85+
86+
Code View
87+
*********
88+
89+
.. doxygenclass:: LIEF::PE::CodeView
90+
:project: lief
91+
92+
----------
93+
94+
Code View PDB
95+
*************
96+
97+
.. doxygenclass:: LIEF::PE::CodeViewPDB
98+
:project: lief
99+
100+
----------
101+
102+
78103
Symbol
79104
*******
80105

doc/sphinx/api/python/pe.rst

+22
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,28 @@ Debug
381381

382382
----------
383383

384+
385+
Code View
386+
*********
387+
388+
.. autoclass:: lief.PE.CodeView
389+
:members:
390+
:inherited-members:
391+
:undoc-members:
392+
393+
----------
394+
395+
396+
Code View PDB
397+
**************
398+
399+
.. autoclass:: lief.PE.CodeViewPDB
400+
:members:
401+
:inherited-members:
402+
:undoc-members:
403+
404+
----------
405+
384406
Code Integrity
385407
**************
386408

examples/cpp/pe_reader.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@
1717
#include <memory>
1818

1919
#include <LIEF/PE.hpp>
20+
#include <LIEF/logging.hpp>
2021

2122
using namespace LIEF::PE;
2223

2324
int main(int argc, char **argv) {
25+
LIEF::Logger::set_level(LIEF::LOGGING_LEVEL::LOG_DEBUG);
2426
std::cout << "PE Reader" << std::endl;
2527
if (argc != 2) {
2628
std::cerr << "Usage: " << argv[0] << " <PE binary>" << std::endl;

examples/python/pe_reader.py

+12
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,18 @@ def print_debug(binary):
273273
print(format_hex.format("Size of data:", debug.sizeof_data))
274274
print(format_hex.format("Address of raw data:", debug.addressof_rawdata))
275275
print(format_hex.format("Pointer to raw data:", debug.pointerto_rawdata))
276+
277+
if debug.has_code_view:
278+
code_view = debug.code_view
279+
cv_signature = code_view.cv_signature
280+
281+
if cv_signature in (lief.PE.CODE_VIEW_SIGNATURES.PDB_70, lief.PE.CODE_VIEW_SIGNATURES.PDB_70):
282+
sig_str = " ".join(map(lambda e : "{:02x}".format(e), code_view.signature))
283+
print(format_str.format("Code View Signature:", str(cv_signature).split(".")[-1]))
284+
print(format_str.format("Signature:", sig_str))
285+
print(format_dec.format("Age:", code_view.age))
286+
print(format_str.format("Filename:", code_view.filename))
287+
276288
print("")
277289

278290

include/LIEF/PE.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "LIEF/PE/Parser.hpp"
2121
#include "LIEF/PE/Builder.hpp"
2222
#include "LIEF/PE/Binary.hpp"
23+
#include "LIEF/PE/CodeViewPDB.hpp"
2324
#include "LIEF/PE/signature/OIDToString.hpp"
2425

2526
#include "LIEF/PE/utils.hpp"

include/LIEF/PE/CodeView.hpp

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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 LIEF_PE_CODE_VIEW_H_
17+
#define LIEF_PE_CODE_VIEW_H_
18+
#include <array>
19+
#include <set>
20+
#include <functional>
21+
#include <algorithm>
22+
#include <iostream>
23+
24+
#include "LIEF/Visitable.hpp"
25+
#include "LIEF/visibility.h"
26+
27+
#include "LIEF/PE/Structures.hpp"
28+
29+
namespace LIEF {
30+
namespace PE {
31+
class DLL_PUBLIC CodeView : public Visitable {
32+
public:
33+
34+
CodeView(void);
35+
CodeView(CODE_VIEW_SIGNATURES cv_signature);
36+
37+
CodeView(const CodeView&);
38+
CodeView& operator=(const CodeView&);
39+
40+
virtual CodeView* clone(void) const = 0;
41+
42+
//! The Code View signature
43+
CODE_VIEW_SIGNATURES cv_signature(void) const;
44+
45+
virtual void accept(Visitor& visitor) const override;
46+
47+
bool operator==(const CodeView& rhs) const;
48+
bool operator!=(const CodeView& rhs) const;
49+
50+
DLL_PUBLIC friend std::ostream& operator<<(std::ostream& os, const CodeView& entry);
51+
52+
virtual ~CodeView(void);
53+
54+
protected:
55+
CODE_VIEW_SIGNATURES cv_signature_;
56+
};
57+
58+
} // Namespace PE
59+
} // Namespace LIEF
60+
61+
#endif

0 commit comments

Comments
 (0)