def dump_info(self, dump=None, encoding="ascii"):
        """Dump all the PE header information into human readable string."""

        if dump is None:
            dump = Dump()

        warnings = self.get_warnings()
        if warnings:
            dump.add_header("Parsing Warnings")
            for warning in warnings:
                dump.add_line(warning)
                dump.add_newline()

        dump.add_header("DOS_HEADER")
        dump.add_lines(self.DOS_HEADER.dump())
        dump.add_newline()

        dump.add_header("NT_HEADERS")
        dump.add_lines(self.NT_HEADERS.dump())
        dump.add_newline()

        dump.add_header("FILE_HEADER")
        dump.add_lines(self.FILE_HEADER.dump())

        image_flags = retrieve_flags(IMAGE_CHARACTERISTICS, "IMAGE_FILE_")

        dump.add("Flags: ")
        flags = []
        for flag in sorted(image_flags):
            if getattr(self.FILE_HEADER, flag[0]):
                flags.append(flag[0])
        dump.add_line(", ".join(flags))
        dump.add_newline()

        if hasattr(self, "OPTIONAL_HEADER") and self.OPTIONAL_HEADER is not None:
            dump.add_header("OPTIONAL_HEADER")
            dump.add_lines(self.OPTIONAL_HEADER.dump())

        dll_characteristics_flags = retrieve_flags(
            DLL_CHARACTERISTICS, "IMAGE_DLLCHARACTERISTICS_"
        )

        dump.add("DllCharacteristics: ")
        flags = []
        for flag in sorted(dll_characteristics_flags):
            if getattr(self.OPTIONAL_HEADER, flag[0]):
                flags.append(flag[0])
        dump.add_line(", ".join(flags))

        ex_dll_characteristics_flags = retrieve_flags(
            EX_DLL_CHARACTERISTICS, "IMAGE_DLLCHARACTERISTICS_EX_"
        )
        if ex_dll_characteristics_flags:
            flags = []
            if (
                hasattr(self, "DIRECTORY_ENTRY_DEBUG")
                and self.DIRECTORY_ENTRY_DEBUG is not None
            ):
                for debug_entry in self.DIRECTORY_ENTRY_DEBUG:
                    if (
                        debug_entry.struct.Type
                        == DEBUG_TYPE["IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS"]
                    ):
                        for flag in sorted(ex_dll_characteristics_flags):
                            if getattr(debug_entry.entry, flag[0]):
                                flags.append(flag[0])
            if flags:
                dump.add("ExDllCharacteristics: ")
                dump.add_line(", ".join(flags))
        dump.add_newline()

        dump.add_header("PE Sections")

        section_flags = retrieve_flags(SECTION_CHARACTERISTICS, "IMAGE_SCN_")

        for section in self.sections:
            dump.add_lines(section.dump())
            dump.add("Flags: ")
            flags = []
            for flag in sorted(section_flags):
                if getattr(section, flag[0]):
                    flags.append(flag[0])
            dump.add_line(", ".join(flags))
            dump.add_line(
                "Entropy: {0:f} (Min=0.0, Max=8.0)".format(section.get_entropy())
            )
            if md5 is not None:
                dump.add_line("MD5     hash: {0}".format(section.get_hash_md5()))
            if sha1 is not None:
                dump.add_line("SHA-1   hash: %s" % section.get_hash_sha1())
            if sha256 is not None:
                dump.add_line("SHA-256 hash: %s" % section.get_hash_sha256())
            if sha512 is not None:
                dump.add_line("SHA-512 hash: %s" % section.get_hash_sha512())
            dump.add_newline()

        if hasattr(self, "OPTIONAL_HEADER") and hasattr(
            self.OPTIONAL_HEADER, "DATA_DIRECTORY"
        ):
            dump.add_header("Directories")
            for directory in self.OPTIONAL_HEADER.DATA_DIRECTORY:
                if directory is not None:
                    dump.add_lines(directory.dump())
            dump.add_newline()

        if hasattr(self, "VS_VERSIONINFO"):
            for idx, vinfo_entry in enumerate(self.VS_VERSIONINFO):
                if len(self.VS_VERSIONINFO) > 1:
                    dump.add_header(f"Version Information {idx + 1}")
                else:
                    dump.add_header("Version Information")
                if vinfo_entry is not None:
                    dump.add_lines(vinfo_entry.dump())
                dump.add_newline()

                if hasattr(self, "VS_FIXEDFILEINFO"):
                    dump.add_lines(self.VS_FIXEDFILEINFO[idx].dump())
                    dump.add_newline()

                if hasattr(self, "FileInfo") and len(self.FileInfo) > idx:
                    for entry in self.FileInfo[idx]:
                        dump.add_lines(entry.dump())
                        dump.add_newline()

                        if hasattr(entry, "StringTable"):
                            for st_entry in entry.StringTable:
                                [dump.add_line("  " + line) for line in st_entry.dump()]
                                dump.add_line(
                                    "  LangID: {0}".format(
                                        st_entry.LangID.decode(
                                            encoding, "backslashreplace_"
                                        )
                                    )
                                )
                                dump.add_newline()
                                for str_entry in sorted(list(st_entry.entries.items())):
                                    # try:
                                    dump.add_line(
                                        "    {0}: {1}".format(
                                            str_entry[0].decode(
                                                encoding, "backslashreplace_"
                                            ),
                                            str_entry[1].decode(
                                                encoding, "backslashreplace_"
                                            ),
                                        )
                                    )

                            dump.add_newline()

                        elif hasattr(entry, "Var"):
                            for var_entry in entry.Var:
                                if hasattr(var_entry, "entry"):
                                    [
                                        dump.add_line("  " + line)
                                        for line in var_entry.dump()
                                    ]
                                    dump.add_line(
                                        "    {0}: {1}".format(
                                            list(var_entry.entry.keys())[0].decode(
                                                "utf-8", "backslashreplace_"
                                            ),
                                            list(var_entry.entry.values())[0],
                                        )
                                    )

                            dump.add_newline()

        if hasattr(self, "DIRECTORY_ENTRY_EXPORT"):
            dump.add_header("Exported symbols")
            dump.add_lines(self.DIRECTORY_ENTRY_EXPORT.struct.dump())
            dump.add_newline()
            dump.add_line("%-10s   %-10s  %s" % ("Ordinal", "RVA", "Name"))
            for export in self.DIRECTORY_ENTRY_EXPORT.symbols:
                if export.address is not None:
                    name = b"None"
                    if export.name:
                        name = export.name
                    dump.add(
                        "%-10d 0x%08X    %s"
                        % (export.ordinal, export.address, name.decode(encoding))
                    )
                    if export.forwarder:
                        dump.add_line(
                            " forwarder: {0}".format(
                                export.forwarder.decode(encoding, "backslashreplace_")
                            )
                        )
                    else:
                        dump.add_newline()

            dump.add_newline()

        if hasattr(self, "DIRECTORY_ENTRY_IMPORT"):
            dump.add_header("Imported symbols")
            for module in self.DIRECTORY_ENTRY_IMPORT:
                dump.add_lines(module.struct.dump())
                # Print the name of the DLL if there are no imports.
                if not module.imports:
                    dump.add(
                        "  Name -> {0}".format(
                            self.get_string_at_rva(module.struct.Name).decode(
                                encoding, "backslashreplace_"
                            )
                        )
                    )
                    dump.add_newline()
                dump.add_newline()
                for symbol in module.imports:
                    if symbol.import_by_ordinal is True:
                        if symbol.name is not None:
                            dump.add(
                                "{0}.{1} Ordinal[{2}] (Imported by Ordinal)".format(
                                    module.dll.decode("utf-8"),
                                    symbol.name.decode("utf-8"),
                                    symbol.ordinal,
                                )
                            )
                        else:
                            dump.add(
                                "{0} Ordinal[{1}] (Imported by Ordinal)".format(
                                    module.dll.decode("utf-8"), symbol.ordinal
                                )
                            )
                    else:
                        dump.add(
                            "{0}.{1} Hint[{2:d}]".format(
                                module.dll.decode(encoding, "backslashreplace_"),
                                symbol.name.decode(encoding, "backslashreplace_"),
                                symbol.hint,
                            )
                        )

                    if symbol.bound:
                        dump.add_line(" Bound: 0x{0:08X}".format(symbol.bound))
                    else:
                        dump.add_newline()
                dump.add_newline()

        if hasattr(self, "DIRECTORY_ENTRY_BOUND_IMPORT"):
            dump.add_header("Bound imports")
            for bound_imp_desc in self.DIRECTORY_ENTRY_BOUND_IMPORT:
                dump.add_lines(bound_imp_desc.struct.dump())
                dump.add_line(
                    "DLL: {0}".format(
                        bound_imp_desc.name.decode(encoding, "backslashreplace_")
                    )
                )
                dump.add_newline()

                for bound_imp_ref in bound_imp_desc.entries:
                    dump.add_lines(bound_imp_ref.struct.dump(), 4)
                    dump.add_line(
                        "DLL: {0}".format(
                            bound_imp_ref.name.decode(encoding, "backslashreplace_")
                        ),
                        4,
                    )
                    dump.add_newline()

        if hasattr(self, "DIRECTORY_ENTRY_DELAY_IMPORT"):
            dump.add_header("Delay Imported symbols")
            for module in self.DIRECTORY_ENTRY_DELAY_IMPORT:
                dump.add_lines(module.struct.dump())
                dump.add_newline()

                for symbol in module.imports:
                    if symbol.import_by_ordinal is True:
                        dump.add(
                            "{0} Ordinal[{1:d}] (Imported by Ordinal)".format(
                                module.dll.decode(encoding, "backslashreplace_"),
                                symbol.ordinal,
                            )
                        )
                    else:
                        dump.add(
                            "{0}.{1} Hint[{2}]".format(
                                module.dll.decode(encoding, "backslashreplace_"),
                                symbol.name.decode(encoding, "backslashreplace_"),
                                symbol.hint,
                            )
                        )

                    if symbol.bound:
                        dump.add_line(" Bound: 0x{0:08X}".format(symbol.bound))
                    else:
                        dump.add_newline()
                dump.add_newline()

        if hasattr(self, "DIRECTORY_ENTRY_RESOURCE"):
            dump.add_header("Resource directory")

            dump.add_lines(self.DIRECTORY_ENTRY_RESOURCE.struct.dump())

            for res_type in self.DIRECTORY_ENTRY_RESOURCE.entries:
                if res_type.name is not None:
                    name = res_type.name.decode(encoding, "backslashreplace_")
                    dump.add_line(
                        f"Name: [{name}]",
                        2,
                    )
                else:
                    res_type_id = RESOURCE_TYPE.get(res_type.struct.Id, "-")
                    dump.add_line(
                        f"Id: [0x{res_type.struct.Id:X}] ({res_type_id})",
                        2,
                    )

                dump.add_lines(res_type.struct.dump(), 2)

                if hasattr(res_type, "directory"):
                    dump.add_lines(res_type.directory.struct.dump(), 4)

                    for resource_id in res_type.directory.entries:
                        if resource_id.name is not None:
                            name = resource_id.name.decode("utf-8", "backslashreplace_")
                            dump.add_line(
                                f"Name: [{name}]",
                                6,
                            )
                        else:
                            dump.add_line(f"Id: [0x{resource_id.struct.Id:X}]", 6)

                        dump.add_lines(resource_id.struct.dump(), 6)

                        if hasattr(resource_id, "directory"):
                            dump.add_lines(resource_id.directory.struct.dump(), 8)

                            for resource_lang in resource_id.directory.entries:
                                if hasattr(resource_lang, "data"):
                                    dump.add_line(
                                        "\\--- LANG [%d,%d][%s,%s]"
                                        % (
                                            resource_lang.data.lang,
                                            resource_lang.data.sublang,
                                            LANG.get(
                                                resource_lang.data.lang, "*unknown*"
                                            ),
                                            get_sublang_name_for_lang(
                                                resource_lang.data.lang,
                                                resource_lang.data.sublang,
                                            ),
                                        ),
                                        8,
                                    )
                                    dump.add_lines(resource_lang.struct.dump(), 10)
                                    dump.add_lines(resource_lang.data.struct.dump(), 12)
                            if (
                                hasattr(resource_id.directory, "strings")
                                and resource_id.directory.strings
                            ):
                                dump.add_line("[STRINGS]", 10)
                                for idx, res_string in list(
                                    sorted(resource_id.directory.strings.items())
                                ):
                                    dump.add_line(
                                        "{0:6d}: {1}".format(
                                            idx,
                                            res_string.encode(
                                                "unicode-escape", "backslashreplace"
                                            ).decode("ascii"),
                                        ),
                                        12,
                                    )

                dump.add_newline()

            dump.add_newline()

        if (
            hasattr(self, "DIRECTORY_ENTRY_TLS")
            and self.DIRECTORY_ENTRY_TLS
            and self.DIRECTORY_ENTRY_TLS.struct
        ):
            dump.add_header("TLS")
            dump.add_lines(self.DIRECTORY_ENTRY_TLS.struct.dump())
            dump.add_newline()

        if (
            hasattr(self, "DIRECTORY_ENTRY_LOAD_CONFIG")
            and self.DIRECTORY_ENTRY_LOAD_CONFIG
            and self.DIRECTORY_ENTRY_LOAD_CONFIG.struct
        ):
            dump.add_header("LOAD_CONFIG")
            dump.add_lines(self.DIRECTORY_ENTRY_LOAD_CONFIG.struct.dump())
            dump.add_newline()

        if hasattr(self, "DIRECTORY_ENTRY_DEBUG"):
            dump.add_header("Debug information")
            for dbg in self.DIRECTORY_ENTRY_DEBUG:
                dump.add_lines(dbg.struct.dump())
                try:
                    dump.add_line("Type: " + DEBUG_TYPE[dbg.struct.Type])
                except KeyError:
                    dump.add_line("Type: 0x{0:x}(Unknown)".format(dbg.struct.Type))
                dump.add_newline()
                if dbg.entry:
                    dump.add_lines(dbg.entry.dump(), 4)
                    dump.add_newline()

        if self.has_relocs():
            dump.add_header("Base relocations")
            for base_reloc in self.DIRECTORY_ENTRY_BASERELOC:
                dump.add_lines(base_reloc.struct.dump())
                for reloc in base_reloc.entries:
                    try:
                        dump.add_line(
                            "%08Xh %s" % (reloc.rva, RELOCATION_TYPE[reloc.type][16:]),
                            4,
                        )
                    except KeyError:
                        dump.add_line(
                            "0x%08X 0x%x(Unknown)" % (reloc.rva, reloc.type), 4
                        )
                dump.add_newline()

        if (
            hasattr(self, "DIRECTORY_ENTRY_EXCEPTION")
            and len(self.DIRECTORY_ENTRY_EXCEPTION) > 0
        ):
            dump.add_header("Unwind data for exception handling")
            for rf in self.DIRECTORY_ENTRY_EXCEPTION:
                dump.add_lines(rf.struct.dump())
                if hasattr(rf, "unwindinfo") and rf.unwindinfo is not None:
                    dump.add_lines(rf.unwindinfo.dump(), 4)

        return dump.get_text()
Dump all the PE header information into human readable string.
pefile.py