Merge pull request #432 from kohnakagawa/feature/parse_resource_string

fix ResourcesManager to parse string table entry
This commit is contained in:
Romain 2020-07-05 12:22:18 +02:00 committed by GitHub
commit 20f9d04ae8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 348 additions and 0 deletions

View File

@ -13,6 +13,7 @@ set(LIEF_PYTHON_PE_SRC
"${CMAKE_CURRENT_LIST_DIR}/objects/resources/pyLangCodeItem.cpp"
"${CMAKE_CURRENT_LIST_DIR}/objects/resources/pyResourceDialog.cpp"
"${CMAKE_CURRENT_LIST_DIR}/objects/resources/pyResourceDialogItem.cpp"
"${CMAKE_CURRENT_LIST_DIR}/objects/resources/pyResourceStringTable.cpp"
"${CMAKE_CURRENT_LIST_DIR}/objects/signature/pySignerInfo.cpp"
"${CMAKE_CURRENT_LIST_DIR}/objects/signature/pyAuthenticatedAttributes.cpp"

View File

@ -1,5 +1,6 @@
/* Copyright 2017 R. Thomas
* Copyright 2017 Quarkslab
* Copyright 2020 K. Nakagawa
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -104,6 +105,14 @@ void create<ResourcesManager>(py::module& m) {
"``True`` if the resource has the given " RST_CLASS_REF(lief.PE.RESOURCE_TYPES) "",
"type"_a)
.def_property_readonly("has_string_table",
&ResourcesManager::has_string_table,
"``True`` if resources contain " RST_CLASS_REF(lief.PE.ResourceStringTable) "")
.def_property_readonly("string_table",
&ResourcesManager::string_table,
"Return list of " RST_CLASS_REF(lief.PE.ResourceStringTable) " present in the resource")
.def("get_node_type",
static_cast<no_const_func<ResourceNode&, RESOURCE_TYPES>>(&ResourcesManager::get_node_type),
"Return " RST_CLASS_REF(lief.PE.ResourceNode) " with "

View File

@ -0,0 +1,65 @@
/* Copyright 2017 R. Thomas
* Copyright 2017 Quarkslab
* Copyright 2020 K. Nakagawa
*
* 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 "pyPE.hpp"
#include "LIEF/PE/hash.hpp"
#include "LIEF/PE/resources/ResourceStringTable.hpp"
#include <string>
#include <sstream>
namespace LIEF {
namespace PE {
template<class T>
using getter_t = T (ResourceStringTable::*)(void) const;
template<class T>
using setter_t = void (ResourceStringTable::*)(T);
template<>
void create<ResourceStringTable>(py::module& m) {
py::class_<ResourceStringTable, LIEF::Object>(m, "ResourceStringTable")
.def_property_readonly("length",
static_cast<getter_t<int16_t>>(&ResourceStringTable::length),
"The size of the string, not including length field itself.")
.def_property_readonly("name",
static_cast<getter_t<const std::u16string&>>(&ResourceStringTable::name),
"The variable-length Unicode string data, word-aligned."
)
.def("__eq__", &ResourceStringTable::operator==)
.def("__ne__", &ResourceStringTable::operator!=)
.def("__hash__",
[] (const ResourceStringTable& string_table) {
return Hash::hash(string_table);
})
.def("__str__",
[] (const ResourceStringTable& string_table) {
std::ostringstream stream;
stream << string_table;
std::string str = stream.str();
return str;
});
}
}
}

View File

@ -1,5 +1,6 @@
/* Copyright 2017 R. Thomas
* Copyright 2017 Quarkslab
* Copyright 2020 K. Nakagawa
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -73,6 +74,7 @@ void init_objects(py::module& m) {
CREATE(ResourceIcon, m);
CREATE(ResourceDialog, m);
CREATE(ResourceDialogItem, m);
CREATE(ResourceStringTable, m);
CREATE(Signature, m);
CREATE(x509, m);
CREATE(SignerInfo, m);

View File

@ -1,5 +1,6 @@
/* Copyright 2017 R. Thomas
* Copyright 2017 Quarkslab
* Copyright 2020 K. Nakagawa
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -76,6 +77,7 @@ SPECIALIZE_CREATE(ResourceFixedFileInfo);
SPECIALIZE_CREATE(ResourceVarFileInfo);
SPECIALIZE_CREATE(LangCodeItem);
SPECIALIZE_CREATE(ResourceIcon);
SPECIALIZE_CREATE(ResourceStringTable);
SPECIALIZE_CREATE(ResourceDialog);
SPECIALIZE_CREATE(ResourceDialogItem);
SPECIALIZE_CREATE(Signature);

View File

@ -311,6 +311,15 @@ Lang code item
:project: lief
----------
Resource String Table
*********************
.. doxygenclass:: LIEF::PE::ResourceStringTable
:project: lief
----------
Rich Header

View File

@ -351,6 +351,16 @@ Lang code item
----------
Resource String Table
*********************
.. autoclass:: lief.PE.ResourceStringTable
:members:
:inherited-members:
:undoc-members:
----------
Rich Header
***********

View File

@ -1,5 +1,6 @@
/* Copyright 2017 R. Thomas
* Copyright 2017 Quarkslab
* Copyright 2020 K. Nakagawa
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -29,6 +30,7 @@
#include "LIEF/PE/resources/ResourceVersion.hpp"
#include "LIEF/PE/resources/ResourceIcon.hpp"
#include "LIEF/PE/resources/ResourceDialog.hpp"
#include "LIEF/PE/resources/ResourceStringTable.hpp"
namespace LIEF {
namespace PE {
@ -116,6 +118,15 @@ class LIEF_API ResourcesManager : public Object {
//! @brief Return the list of the dialogs present in the resource
std::vector<ResourceDialog> dialogs(void) const;
// String table
// =====
//! @brief ``true`` if resources contain @link LIEF::PE::ResourceStringTable @endlink
bool has_string_table(void) const;
//! @brief Return the list of the string table in the resource
std::vector<ResourceStringTable> string_table(void) const;
// Print
// =====

View File

@ -1,5 +1,6 @@
/* Copyright 2017 R. Thomas
* Copyright 2017 Quarkslab
* Copyright 2020 K. Nakagawa
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -65,6 +66,7 @@ class LIEF_API Hash : public LIEF::Hash {
virtual void visit(const ResourceIcon& resource_icon) override;
virtual void visit(const ResourceDialog& dialog) override;
virtual void visit(const ResourceDialogItem& dialog_item) override;
virtual void visit(const ResourceStringTable& string_table) override;
virtual void visit(const Signature& signature) override;
virtual void visit(const x509& x509) override;
virtual void visit(const SignerInfo& signerinfo) override;

View File

@ -1,5 +1,6 @@
/* Copyright 2017 R. Thomas
* Copyright 2017 Quarkslab
* Copyright 2020 K. Nakagawa
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -58,6 +59,7 @@ class LIEF_API JsonVisitor : public LIEF::JsonVisitor {
virtual void visit(const ResourceStringFileInfo& resource_sfi) override;
virtual void visit(const ResourceFixedFileInfo& resource_ffi) override;
virtual void visit(const ResourceVarFileInfo& resource_vfi) override;
virtual void visit(const ResourceStringTable& resource_st) override;
virtual void visit(const LangCodeItem& resource_lci) override;
virtual void visit(const ResourceIcon& resource_icon) override;
virtual void visit(const ResourceDialog& dialog) override;

View File

@ -0,0 +1,63 @@
/* Copyright 2017 R. Thomas
* Copyright 2017 Quarkslab
* Copyright 2020 K. Nakagawa
*
* 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_PE_RESOURCE_STRING_TABLE_H_
#define LIEF_PE_RESOURCE_STRING_TABLE_H_
#include <string>
#include "LIEF/visibility.h"
#include "LIEF/Object.hpp"
#include "LIEF/PE/Structures.hpp"
#include "LIEF/PE/type_traits.hpp"
namespace LIEF {
namespace PE {
class ResourcesManager;
class LIEF_API ResourceStringTable : public Object {
friend class ResourcesManager;
public:
ResourceStringTable(void);
ResourceStringTable(int16_t length, const std::u16string& name);
ResourceStringTable(const ResourceStringTable&);
ResourceStringTable& operator=(const ResourceStringTable&);
virtual ~ResourceStringTable(void);
virtual void accept(Visitor& visitor) const override;
int16_t length(void) const;
const std::u16string& name(void) const;
bool operator==(const ResourceStringTable& rhs) const;
bool operator!=(const ResourceStringTable& rhs) const;
LIEF_API friend std::ostream& operator<<(std::ostream& os, const ResourceStringTable& string_table);
private:
std::u16string name_;
int16_t length_;
};
}
}
#endif

View File

@ -1,5 +1,6 @@
/* Copyright 2017 R. Thomas
* Copyright 2017 Quarkslab
* Copyright 2020 K. Nakagawa
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -76,6 +77,7 @@ LIEF_PE_FORWARD(LangCodeItem)
LIEF_PE_FORWARD(ResourceIcon)
LIEF_PE_FORWARD(ResourceDialog)
LIEF_PE_FORWARD(ResourceDialogItem)
LIEF_PE_FORWARD(ResourceStringTable)
LIEF_PE_FORWARD(Signature)
LIEF_PE_FORWARD(x509)
LIEF_PE_FORWARD(SignerInfo)
@ -338,6 +340,9 @@ class LIEF_API Visitor {
//! Method to visit a LIEF::PE::ResourceVarFileInfo
LIEF_PE_VISITABLE(ResourceVarFileInfo)
//! Method to visit a LIEF::PE::ResourceStringTable
LIEF_PE_VISITABLE(ResourceStringTable)
//! Method to visit a LIEF::PE::LangCodeItem
LIEF_PE_VISITABLE(LangCodeItem)

View File

@ -47,6 +47,7 @@ set(LIEF_PE_SRC
"${CMAKE_CURRENT_LIST_DIR}/resources/ResourceStringFileInfo.cpp"
"${CMAKE_CURRENT_LIST_DIR}/resources/LangCodeItem.cpp"
"${CMAKE_CURRENT_LIST_DIR}/resources/ResourceIcon.cpp"
"${CMAKE_CURRENT_LIST_DIR}/resources/ResourceStringTable.cpp"
)
set(LIEF_PE_LOAD_CONFIGURATION_SRC

View File

@ -1,5 +1,6 @@
/* Copyright 2017 R. Thomas
* Copyright 2017 Quarkslab
* Copyright 2020 K. Nakagawa
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -34,6 +35,7 @@
#include "LIEF/PE/ResourceData.hpp"
#include "LIEF/PE/resources/LangCodeItem.hpp"
#include "LIEF/PE/resources/ResourceStringTable.hpp"
namespace LIEF {
namespace PE {
@ -1191,6 +1193,61 @@ bool ResourcesManager::has_dialogs(void) const {
return this->has_type(RESOURCE_TYPES::DIALOG);
}
// String table entry
std::vector<ResourceStringTable> ResourcesManager::string_table(void) const {
it_childs nodes = this->resources_->childs();
auto&& it_string_table = std::find_if(
std::begin(nodes),
std::end(nodes),
[] (const ResourceNode& node) {
return static_cast<RESOURCE_TYPES>(node.id()) == RESOURCE_TYPES::STRING;
}
);
if (it_string_table == std::end(nodes)) {
throw not_found(std::string("Missing '") + to_string(RESOURCE_TYPES::STRING) + "' entry");
}
std::vector<ResourceStringTable> string_table;
for (const ResourceNode& child_l1 : it_string_table->childs()) {
for (const ResourceNode& child_l2 : child_l1.childs()) {
const ResourceData* string_table_node = dynamic_cast<const ResourceData*>(&child_l2);
if (!string_table_node) {
LOG(ERROR) << "String table node is null";
continue;
}
const std::vector<uint8_t>& content = string_table_node->content();
if (content.empty()) {
LOG(ERROR) << "String table content is empty";
continue;
}
const auto content_size = content.size();
VectorStream stream{content};
stream.setpos(0);
VLOG(VDEBUG) << "Will parse content whoose size is " << content_size;
while (stream.pos() < content_size) {
if (not stream.can_read<int16_t>()) break;
const auto len = stream.read<uint16_t>();
if (len > 0 && ((len * 2) < content_size)) {
const auto name = stream.read_u16string(len);
string_table.emplace_back(ResourceStringTable(len, name));
}
}
}
}
return string_table;
}
bool ResourcesManager::has_string_table(void) const {
return this->has_type(RESOURCE_TYPES::STRING);
}
// Prints
// ======

View File

@ -1,5 +1,6 @@
/* Copyright 2017 R. Thomas
* Copyright 2017 Quarkslab
* Copyright 2020 K. Nakagawa
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -423,6 +424,11 @@ void Hash::visit(const ResourceDialogItem& dialog_item) {
}
}
void Hash::visit(const ResourceStringTable& string_table) {
this->process(string_table.length());
this->process(string_table.name());
}
void Hash::visit(const Signature& signature) {
this->process(signature.version());

View File

@ -1,5 +1,6 @@
/* Copyright 2017 R. Thomas
* Copyright 2017 Quarkslab
* Copyright 2020 K. Nakagawa
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -543,6 +544,20 @@ void JsonVisitor::visit(const ResourcesManager& resources_manager) {
LOG(WARNING) << e.what();
}
}
if (resources_manager.has_string_table()) {
std::vector<json> string_table_json;
try {
for (const ResourceStringTable& string_table : resources_manager.string_table()) {
JsonVisitor string_table_visitor;
string_table_visitor(string_table);
string_table_json.emplace_back(string_table_visitor.get());
this->node_["string_table"] = string_table_json;
}
} catch (const LIEF::exception& e) {
LOG(WARNING) << e.what();
}
}
}
void JsonVisitor::visit(const ResourceStringFileInfo& resource_sfi) {
@ -683,6 +698,11 @@ void JsonVisitor::visit(const ResourceDialogItem& dialog_item) {
}
void JsonVisitor::visit(const ResourceStringTable& string_table) {
this->node_["length"] = string_table.length();
this->node_["name"] = u16tou8(string_table.name());
}
void JsonVisitor::visit(const Signature& signature) {
JsonVisitor content_info_visitor;

View File

@ -0,0 +1,69 @@
/* Copyright 2017 R. Thomas
* Copyright 2017 Quarkslab
* Copyright 2020 K. Nakagawa
*
* 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 "LIEF/PE/utils.hpp"
#include "LIEF/PE/hash.hpp"
#include "LIEF/PE/EnumToString.hpp"
#include "LIEF/PE/resources/ResourceStringTable.hpp"
namespace LIEF {
namespace PE {
ResourceStringTable::ResourceStringTable(const ResourceStringTable&) = default;
ResourceStringTable& ResourceStringTable::operator=(const ResourceStringTable&) = default;
ResourceStringTable::~ResourceStringTable(void) = default;
ResourceStringTable::ResourceStringTable(void) :
name_{},
length_{0}
{}
ResourceStringTable::ResourceStringTable(int16_t length, const std::u16string& name) :
name_{name},
length_{length}
{}
int16_t ResourceStringTable::length(void) const {
return this->length_;
}
const std::u16string& ResourceStringTable::name(void) const {
return this->name_;
}
void ResourceStringTable::accept(Visitor& visitor) const {
visitor.visit(*this);
}
bool ResourceStringTable::operator==(const ResourceStringTable& rhs) const {
return Hash::hash(*this) == Hash::hash(rhs);
}
bool ResourceStringTable::operator!=(const ResourceStringTable& rhs) const {
return not (*this == rhs);
}
std::ostream& operator<<(std::ostream& os, const ResourceStringTable& string_table) {
os << std::dec << "Length: " << string_table.length() << std::endl;
os << "Name: \"" << u16tou8(string_table.name()) << "\"" << std::endl;
return os;
}
}
}

View File

@ -71,6 +71,20 @@ class TestResource(TestCase):
self.assertEqual(q.returncode, 0)
def test_resource_string_table(self):
sample_path = get_sample('PE/PE64_x86-64_binary_WinApp.exe')
mfc = lief.parse(sample_path)
resources_manager = mfc.resources_manager
self.assertEqual(resources_manager.has_string_table, True)
string_table = resources_manager.string_table
self.assertEqual(string_table[0].name, "WinApp")
self.assertEqual(string_table[0].length, 6)
self.assertEqual(string_table[1].name, "WINAPP")
self.assertEqual(string_table[1].length, 6)
def test_resource_version(self):
sample_path = get_sample('PE/PE64_x86-64_binary_mfc-application.exe')