From 96e6fc66adafdbfb7ed04e1c528c76dcdbd2a182 Mon Sep 17 00:00:00 2001
From: "Koh M. Nakagawa" <tsunekou1019@gmail.com>
Date: Thu, 25 Jun 2020 23:06:27 +0900
Subject: [PATCH] fix ResourcesManager to parse string table entry

Signed-off-by: Koh M. Nakagawa <tsunekou1019@gmail.com>
---
 api/python/PE/CMakeLists.txt                  |  1 +
 api/python/PE/objects/pyResourcesManager.cpp  |  9 +++
 .../resources/pyResourceStringTable.cpp       | 65 +++++++++++++++++
 api/python/PE/pyPE.cpp                        |  2 +
 api/python/PE/pyPE.hpp                        |  2 +
 doc/sphinx/api/cpp/pe.rst                     |  9 +++
 doc/sphinx/api/python/pe.rst                  | 10 +++
 include/LIEF/PE/ResourcesManager.hpp          | 11 +++
 include/LIEF/PE/hash.hpp                      |  2 +
 include/LIEF/PE/json.hpp                      |  2 +
 .../LIEF/PE/resources/ResourceStringTable.hpp | 63 +++++++++++++++++
 include/LIEF/Visitor.hpp                      |  5 ++
 src/PE/CMakeLists.txt                         |  1 +
 src/PE/ResourcesManager.cpp                   | 57 +++++++++++++++
 src/PE/hash.cpp                               |  6 ++
 src/PE/json.cpp                               | 20 ++++++
 src/PE/resources/ResourceStringTable.cpp      | 69 +++++++++++++++++++
 tests/pe/test_resources.py                    | 14 ++++
 18 files changed, 348 insertions(+)
 create mode 100644 api/python/PE/objects/resources/pyResourceStringTable.cpp
 create mode 100644 include/LIEF/PE/resources/ResourceStringTable.hpp
 create mode 100644 src/PE/resources/ResourceStringTable.cpp

diff --git a/api/python/PE/CMakeLists.txt b/api/python/PE/CMakeLists.txt
index 9c5500a..7de6297 100644
--- a/api/python/PE/CMakeLists.txt
+++ b/api/python/PE/CMakeLists.txt
@@ -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"
diff --git a/api/python/PE/objects/pyResourcesManager.cpp b/api/python/PE/objects/pyResourcesManager.cpp
index d078e34..8da8921 100644
--- a/api/python/PE/objects/pyResourcesManager.cpp
+++ b/api/python/PE/objects/pyResourcesManager.cpp
@@ -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 "
diff --git a/api/python/PE/objects/resources/pyResourceStringTable.cpp b/api/python/PE/objects/resources/pyResourceStringTable.cpp
new file mode 100644
index 0000000..d8529a4
--- /dev/null
+++ b/api/python/PE/objects/resources/pyResourceStringTable.cpp
@@ -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;
+        });
+}
+
+}
+}
diff --git a/api/python/PE/pyPE.cpp b/api/python/PE/pyPE.cpp
index 9c5d822..c82bef0 100644
--- a/api/python/PE/pyPE.cpp
+++ b/api/python/PE/pyPE.cpp
@@ -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);
diff --git a/api/python/PE/pyPE.hpp b/api/python/PE/pyPE.hpp
index 8ed6366..20f68be 100644
--- a/api/python/PE/pyPE.hpp
+++ b/api/python/PE/pyPE.hpp
@@ -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);
diff --git a/doc/sphinx/api/cpp/pe.rst b/doc/sphinx/api/cpp/pe.rst
index ae4f825..be693b5 100644
--- a/doc/sphinx/api/cpp/pe.rst
+++ b/doc/sphinx/api/cpp/pe.rst
@@ -311,6 +311,15 @@ Lang code item
   :project: lief
 
 
+----------
+
+Resource String Table
+*********************
+
+.. doxygenclass:: LIEF::PE::ResourceStringTable
+  :project: lief
+
+
 ----------
 
 Rich Header
diff --git a/doc/sphinx/api/python/pe.rst b/doc/sphinx/api/python/pe.rst
index a7f868e..1719cd0 100644
--- a/doc/sphinx/api/python/pe.rst
+++ b/doc/sphinx/api/python/pe.rst
@@ -351,6 +351,16 @@ Lang code item
 
 ----------
 
+Resource String Table
+*********************
+
+.. autoclass:: lief.PE.ResourceStringTable
+  :members:
+  :inherited-members:
+  :undoc-members:
+
+----------
+
 Rich Header
 ***********
 
diff --git a/include/LIEF/PE/ResourcesManager.hpp b/include/LIEF/PE/ResourcesManager.hpp
index 8142048..1f40351 100644
--- a/include/LIEF/PE/ResourcesManager.hpp
+++ b/include/LIEF/PE/ResourcesManager.hpp
@@ -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
   // =====
 
diff --git a/include/LIEF/PE/hash.hpp b/include/LIEF/PE/hash.hpp
index 515c109..bc17c53 100644
--- a/include/LIEF/PE/hash.hpp
+++ b/include/LIEF/PE/hash.hpp
@@ -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;
diff --git a/include/LIEF/PE/json.hpp b/include/LIEF/PE/json.hpp
index 0fb8623..30bf139 100644
--- a/include/LIEF/PE/json.hpp
+++ b/include/LIEF/PE/json.hpp
@@ -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;
diff --git a/include/LIEF/PE/resources/ResourceStringTable.hpp b/include/LIEF/PE/resources/ResourceStringTable.hpp
new file mode 100644
index 0000000..d6c61c8
--- /dev/null
+++ b/include/LIEF/PE/resources/ResourceStringTable.hpp
@@ -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
\ No newline at end of file
diff --git a/include/LIEF/Visitor.hpp b/include/LIEF/Visitor.hpp
index 635c3b9..c25477f 100644
--- a/include/LIEF/Visitor.hpp
+++ b/include/LIEF/Visitor.hpp
@@ -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)
 
diff --git a/src/PE/CMakeLists.txt b/src/PE/CMakeLists.txt
index c791ec2..693cb29 100644
--- a/src/PE/CMakeLists.txt
+++ b/src/PE/CMakeLists.txt
@@ -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
diff --git a/src/PE/ResourcesManager.cpp b/src/PE/ResourcesManager.cpp
index fb16f86..23ca55c 100644
--- a/src/PE/ResourcesManager.cpp
+++ b/src/PE/ResourcesManager.cpp
@@ -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
 // ======
 
diff --git a/src/PE/hash.cpp b/src/PE/hash.cpp
index 38523c6..cac3651 100644
--- a/src/PE/hash.cpp
+++ b/src/PE/hash.cpp
@@ -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());
diff --git a/src/PE/json.cpp b/src/PE/json.cpp
index 8f651d2..2a04c7f 100644
--- a/src/PE/json.cpp
+++ b/src/PE/json.cpp
@@ -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;
diff --git a/src/PE/resources/ResourceStringTable.cpp b/src/PE/resources/ResourceStringTable.cpp
new file mode 100644
index 0000000..0393411
--- /dev/null
+++ b/src/PE/resources/ResourceStringTable.cpp
@@ -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;
+}
+
+}
+}
\ No newline at end of file
diff --git a/tests/pe/test_resources.py b/tests/pe/test_resources.py
index df28d84..503b1bf 100644
--- a/tests/pe/test_resources.py
+++ b/tests/pe/test_resources.py
@@ -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')