Ramon F. Hanssen

103 papers C 54Journal 45Unranked 4
YearRankTypeTitle / Venue / Authors
2026 J jnl
Comput. Geosci.
Gert Mulder, Freek J. van Leijen, Paco López-Dekker, Ramon F. Hanssen
2024 C conf
IGARSS
Yuqing Wang, Wietske S. Brouwer, Freek J. van Leijen, Ramon F. Hanssen
2024 C conf
IGARSS
Philip Conroy, Yustisi A. Lumban-Gaol, Simon A. N. van Diepen, Freek J. van Leijen, Ramon F. Hanssen
2024 C conf
IGARSS
Yustisi A. Lumban-Gaol, Ramon F. Hanssen
2024 C conf
IGARSS
Wietske S. Brouwer, Ramon F. Hanssen
2024 C conf
IGARSS
Ou Ku, Fakhereh Alidoost, Pranav Chandramouli, Thijs van Lankveld, Francesco Nattino, Meiert W. Grootes, Freek J. van Leijen, Ramon F. Hanssen
2023 J jnl
IEEE Trans. Geosci. Remote. Sens.
Gert Mulder, Freek J. van Leijen, Ramon F. Hanssen
2023 J jnl
IEEE Trans. Geosci. Remote. Sens.
Wietske S. Brouwer, Ramon F. Hanssen
2023 C conf
IGARSS
Philip Conroy, Simon A. N. van Diepen, Freek J. van Leijen, Ramon F. Hanssen
2023 J jnl
IEEE Trans. Geosci. Remote. Sens.
Philip Conroy, Simon A. N. van Diepen, Freek J. van Leijen, Ramon F. Hanssen
2023 C conf
IGARSS
Yuqing Wang, Wietske S. Brouwer, Freek J. van Leijen, Ramon F. Hanssen
2023 C conf
IGARSS
Wietske S. Brouwer, Yuqing Wang, Freek J. van Leijen, Ramon F. Hanssen
2022 J jnl
IEEE Trans. Geosci. Remote. Sens.
Fengming Hu, Freek J. van Leijen, Ling Chang, Jicang Wu, Ramon F. Hanssen
2022 J jnl
IEEE Geosci. Remote. Sens. Lett.
Richard Czikhardt, Hans van der Marel, Freek J. van Leijen, Ramon F. Hanssen
2022 J jnl
IEEE Trans. Geosci. Remote. Sens.
Gert Mulder, Freek J. van Leijen, Jan Barkmeijer, Siebren de Haan, Ramon F. Hanssen
2022 C conf
IGARSS
Philip Conroy, Simon A. N. van Diepen, Freek J. van Leijen, Ramon F. Hanssen
2022 J jnl
IEEE Trans. Geosci. Remote. Sens.
Richard Czikhardt, Hans van der Marel, Juraj Papco, Ramon F. Hanssen
2022 J jnl
IEEE J. Sel. Top. Appl. Earth Obs. Remote. Sens.
Fengming Hu, Kevin C. Helfer, Pier Siebesma, Ramon F. Hanssen
2022 J jnl
IEEE Trans. Geosci. Remote. Sens.
Philip Conroy, Simon A. N. van Diepen, Sanneke Van Asselen, Gilles Erkens, Freek J. van Leijen, Ramon F. Hanssen
2022 J jnl
Int. J. Appl. Earth Obs. Geoinformation
Adriaan L. van Natijne, Thom Bogaard, Freek J. van Leijen, Ramon F. Hanssen, Roderik C. Lindenbergh
2021 C conf
IGARSS
Marc F. D. Bruna, Freek J. van Leijen, Ramon F. Hanssen
2021 C conf
IGARSS
Sami Samiei-Esfahany, Freek J. van Leijen, Ramon F. Hanssen
2021 C conf
IGARSS
Wietske S. Brouwer, Ramon F. Hanssen
2021 J jnl
Remote. Sens.
Valeria Di Biase, Ramon F. Hanssen
2021 J jnl
Remote. Sens.
Valeria Di Biase, Ramon F. Hanssen, Sander E. Vos
2021 C conf
IGARSS
Fengming Hu, Ramon F. Hanssen
2021 J jnl
Remote. Sens.
Fabio Rocca, Deren Li, Stefano Tebaldini, Mingsheng Liao, Lu Zhang, Fabrizio Lombardini, Timo Balz, Norbert Haala, Xiaoli Ding, Ramon F. Hanssen
2021 C conf
IGARSS
Philip Conroy, Ramon F. Hanssen
2021 C conf
IGARSS
Freek J. van Leijen, Hans van der Marel, Ramon F. Hanssen
2020 J jnl
IEEE Trans. Geosci. Remote. Sens.
Bas van de Kerkhof, Victor Pankratius, Ling Chang, Rob van Swol, Ramon F. Hanssen
2020 C conf
IGARSS
Floris M. G. Heuff, Ramon F. Hanssen
2020 J jnl
Remote. Sens.
José Manuel Delgado Blasco, Fabio Cian, Ramon F. Hanssen, Gert Verstraeten
2020 J jnl
Remote. Sens.
Dinh Ho Tong Minh, Ramon F. Hanssen, Fabio Rocca
2020 J jnl
Remote. Sens.
José Manuel Delgado Blasco, Marco Chini, Gert Verstraeten, Ramon F. Hanssen
2019 J jnl
IEEE Trans. Geosci. Remote. Sens.
Fengming Hu, Jicang Wu, Ling Chang, Ramon F. Hanssen
2019 J jnl
IEEE Trans. Geosci. Remote. Sens.
Mengshi Yang, Paco López-Dekker, Prabu Dheenathayalan, Filip Biljecki, Mingsheng Liao, Ramon F. Hanssen
2019 J jnl
Remote. Sens.
Fengming Hu, Freek J. van Leijen, Ling Chang, Jicang Wu, Ramon F. Hanssen
2019 J jnl
Remote. Sens.
Ramses A. Molijn, Lorenzo Iannini, Jansle Vieira Rocha, Ramon F. Hanssen
2018 J jnl
IEEE Trans. Geosci. Remote. Sens.
Prabu Dheenathayalan, David Small, Ramon F. Hanssen
2018 C conf
IGARSS
Sami Samiei-Esfahany, Ramon F. Hanssen
2018 C conf
IGARSS
Bas van de Kerkhof, Victor Pankratius, Ling Chang, Rob van Swol, Ramon F. Hanssen
2018 J jnl
Remote. Sens.
Ramses A. Molijn, Lorenzo Iannini, Paco López-Dekker, Paulo Sergio Graziano Magalhães, Ramon F. Hanssen
2018 C conf
IGARSS
Hans van der Marel, Freek J. van Leijen, Ramon F. Hanssen
2018 J jnl
IEEE J. Sel. Top. Appl. Earth Obs. Remote. Sens.
Ling Chang, Rolf P. B. J. Dollevoet, Ramon F. Hanssen
2018 C conf
IGARSS
Antonio M. Ruiz-Armenteros, J. Manuel Delgado, Francisco Lamas-Fernández, Rafael Bravo-Pareja, Milan Lazecký, Matus Bakon, Joaquim João Sousa, Miguel Caro Cuenca, Gert Verstraeten, Ramon F. Hanssen
2018 C conf
IGARSS
Ling Chang, Rolf P. B. J. Dollevoet, Ramon F. Hanssen
2018 C conf
IGARSS
Ramses A. Molijn, Lorenzo Iannini, Carlos Henrique Wachholz de Souza, Diego Della Justina, Jansle Vieira Rocha, Ramon F. Hanssen
2018 J jnl
Remote. Sens.
Ramses A. Molijn, Lorenzo Iannini, Paco López-Dekker, Paulo Sergio Graziano Magalhães, Ramon F. Hanssen
2017 C conf
IGARSS
Freek J. van Leijen, Sami Samiei-Esfahany, Hans van der Marel, Ramon F. Hanssen
2017 C conf
IGARSS
Ramses A. Molijn, Lorenzo Iannini, Ramon F. Hanssen, Freek J. van Leijen, Rubens A. C. Lamparelli, Alexandre Camargo Coutinho
2017 J jnl
IEEE J. Sel. Top. Appl. Earth Obs. Remote. Sens.
Ling Chang, Rolf P. B. J. Dollevoet, Ramon F. Hanssen
2017 J jnl
Remote. Sens.
Elena Vandebroek, Roderik Lindenbergh, Freek J. van Leijen, Matthieu de Schipper, Sierd de Vries, Ramon F. Hanssen
2017 J jnl
IEEE Trans. Geosci. Remote. Sens.
Prabu Dheenathayalan, Miguel Caro Cuenca, Peter Hoogeboom, Ramon F. Hanssen
2016 C conf
IGARSS
Lorenzo Iannini, Ramses A. Molijn, Alijafar Mousivand, Ramon F. Hanssen, Rubens A. C. Lamparelli
2016 J jnl
IEEE Trans. Geosci. Remote. Sens.
Ling Chang, Ramon F. Hanssen
2016 C conf
IGARSS
Ling Chang, Ramon F. Hanssen
2016 J jnl
IEEE Trans. Geosci. Remote. Sens.
Xiaoxiang Zhu, Sina Montazeri, Christoph Gisinger, Ramon F. Hanssen, Richard Bamler
2016 C conf
IGARSS
Pooja S. Mahapatra, Hans van der Marel, Freek J. van Leijen, Sami Samiei-Esfahany, Roland Klees, Ramon F. Hanssen
2016 J jnl
IEEE Trans. Geosci. Remote. Sens.
Guang Liu, Ramon F. Hanssen, Huadong Guo, Huanyin Yue, Zbigniew Perski
2016 J jnl
IEEE Trans. Geosci. Remote. Sens.
Sami Samiei-Esfahany, Joana Esteves Martins, Freek J. van Leijen, Ramon F. Hanssen
2016 C conf
IGARSS
Ramses A. Molijn, Lorenzo Iannini, Ramon F. Hanssen, Jansle Vieira Rocha
2015 J jnl
IEEE Trans. Geosci. Remote. Sens.
Yu Morishita, Ramon F. Hanssen
2015 J jnl
IEEE Trans. Geosci. Remote. Sens.
Mi Jiang, Xiaoli Ding, Ramon F. Hanssen, Rakesh Malhotra, Ling Chang
2015 J jnl
IEEE Trans. Geosci. Remote. Sens.
Pooja S. Mahapatra, Sami Samiei-Esfahany, Ramon F. Hanssen
2015 C conf
IGARSS
Ramon F. Hanssen, Freek J. van Leijen, Nazzareno Pierdicca, Nicolas Floury, Urs Wegmüller
2015 C conf
IGARSS
Lorenzo Iannini, Ramses A. Molijn, Alijafar Mousivand, Ramon F. Hanssen
2015 J jnl
IEEE Trans. Geosci. Remote. Sens.
Yu Morishita, Ramon F. Hanssen
2015 J jnl
IEEE Trans. Geosci. Remote. Sens.
Wenyu Gong, Franz J. Meyer, Shizhuo Liu, Ramon F. Hanssen
2015 C conf
IGARSS
Freek J. van Leijen, Björn Rommen, Malcolm Davidson, Ramon F. Hanssen
2015 C conf
IGARSS
Maria J. Sanjuan-Ferrer, Mariantonietta Zonno, Paco López-Dekker, Freek J. van Leijen, Ramon F. Hanssen
2014 C conf
IGARSS
Xiaoxiang Zhu, Sina Montazeri, Christoph Gisinger, Ramon F. Hanssen, Richard Bamler
2014 C conf
IGARSS
Pooja S. Mahapatra, Sami Samiei-Esfahany, Ramon F. Hanssen
2014 J jnl
IEEE Geosci. Remote. Sens. Lett.
Teng Wang, Sigurjón Jónsson, Ramon F. Hanssen
2014 J jnl
IEEE Trans. Geosci. Remote. Sens.
Pooja S. Mahapatra, Sami Samiei-Esfahany, Hans van der Marel, Ramon F. Hanssen
2013 C conf
IGARSS
Pooja S. Mahapatra, Sami Samiei-Esfahany, Ramon F. Hanssen, Hans van der Marel
2013 C conf
IGARSS
Sami Samiei-Esfahany, Ramon F. Hanssen
2013 C conf
IGARSS
Prabu Dheenathayalan, Ramon F. Hanssen
2012 C conf
IGARSS
Ling Chang, Ramon F. Hanssen
2012 C conf
IGARSS
Pooja S. Mahapatra, Hans van der Marel, Ramon F. Hanssen, Rachel Holley, Sami Samiei-Esfahany, Marko Komac, Alan F. Fromberg
2011 J jnl
IEEE Trans. Geosci. Remote. Sens.
Miguel Caro Cuenca, Andrew J. Hooper, Ramon F. Hanssen
2011 J jnl
IEEE Trans. Geosci. Remote. Sens.
Davide Oscar Nitti, Ramon F. Hanssen, Alberto Refice, Fabio Bovenga, Raffaele Nutricato
2011 J jnl
IEEE Trans. Geosci. Remote. Sens.
João Catalão Fernandes, Giovanni Nico, Ramon F. Hanssen, Cristina Catita
2011 C conf
IGARSS
Shizhou Liu, Ágnes Mika, Wenyu Gong, Ramon F. Hanssen, Franz Meyer, Don Morton, Peter W. Webley
2009 conf
IGARSS (2)
Christelle Wauthier, Anneleen Oyen, Petar Marinkovic, Valérie Cayol, José Fernández, Pablo J. González, Ramon F. Hanssen, François Kervyn, Nicolas d'Oreye, Manoochehr Shirzaei, Thomas R. Walter
2009 conf
IGARSS (2)
Shizhuo Liu, Ágnes Mika, Ramon F. Hanssen
2009 conf
IGARSS (5)
Ramon F. Hanssen, Freek J. van Leijen
2009 conf
IGARSS (1)
Ramon F. Hanssen, Fabio Rocca
2007 C conf
IGARSS
Petar Marinkovic, Ramon F. Hanssen
2007 C conf
IGARSS
Gini Ketelaar, Freek J. van Leijen, Petar Marinkovic, Ramon F. Hanssen
2007 C conf
IGARSS
Freek J. van Leijen, Ramon F. Hanssen
2005 C conf
IGARSS
Gini Ketelaar, Freek J. van Leijen, Petar Marinkovic, Ramon F. Hanssen
2005 C conf
IGARSS
Petar Marinkovic, Freek J. van Leijen, Gini Ketelaar, Ramon F. Hanssen
2004 C conf
IGARSS
Petar Marinkovic, Ramon F. Hanssen
2004 J jnl
IEEE Trans. Geosci. Remote. Sens.
Bert M. Kampes, Ramon F. Hanssen
2004 C conf
IGARSS
Ramon F. Hanssen
2003 C conf
IGARSS
Alain Arnaud, Nico Adam, Ramon F. Hanssen, Jordi Inglada, Javier Duro, Josep Closa, Michael Eineder
2003 C conf
IGARSS
Roderik Lindenbergh, Ramon F. Hanssen
2003 C conf
IGARSS
Dmitri Moisseev, Ramon F. Hanssen
2003 C conf
IGARSS
Joaquín Muñoz Sabater, Ramon F. Hanssen, Bert M. Kampes, Adele Fusco, Nico Adam
2003 C conf
IGARSS
A. Hommels, K. H. Scholte, Joaquín Muñoz Sabater, Ramon F. Hanssen, Freek D. van der Meer, S. B. Kroonenberg, E. Aliyeva, D. Huseynov, I. Guliev
2003 C conf
IGARSS
Ramon F. Hanssen, Dmitri Moisseev, Steven Businger
2003 C conf
IGARSS
Dmitri Moisseev, Ramon F. Hanssen, Joaquín Muñoz Sabater
1999 J jnl
IEEE Trans. Geosci. Remote. Sens.
Ramon F. Hanssen, Richard Bamler
redb/extractors/pe_extractors/pe_dotnet.py
← Index redb/extractors/pe_extractors/pe_dotnet.py python
import inspect
import pefile
from dotnetfile import DotNetPE

import base64
from hashlib import md5
from pprint import pprint

import magic
import pefile

from redb.extractors.enum import Tag
from redb.extractors.pe_extractor import PEExtractor
from redb.models.dataclasses import PEDotNet
from datetime import datetime, timezone
import json
from typing import Any


class PEDotNetExtractor(PEExtractor):

    def __init__(
        self,
        filepath,
        log,
        exporters=None,
        index_prefix=None,
        elastic_index=None,
        known_benign=False,
        known_malicious=False,
        pe=None,
    ):
        super().__init__(
            filepath,
            log,
            exporters,
            index_prefix,
            elastic_index,
            known_benign,
            known_malicious,
            pe,
        )
        # self.pe_features = None
        self.elastic_index = self.index_prefix + "-pe_dotnet"
        self.dotnet, self.error = self._generate_dotnetfile_object()
        self.log.debug(inspect.currentframe().f_code.co_name)

    def _decode_assembly_flags(self, flag_value):
        self.log.debug(inspect.currentframe().f_code.co_name)
        ASSEMBLY_FLAGS = {
            0x00000001: "COMIMAGE_FLAGS_ILONLY",
            0x00000002: "COMIMAGE_FLAGS_32BITREQUIRED",
            0x00000004: "COMIMAGE_FLAGS_IL_LIBRARY",
            0x00000008: "COMIMAGE_FLAGS_STRONGNAMESIGNED",
            0x00000010: "COMIMAGE_FLAGS_NATIVE_ENTRYPOINT",
            0x00010000: "COMIMAGE_FLAGS_TRACKDEBUGDATA",
            0x00020000: "COMIMAGE_FLAGS_32BITPREFERRED",
        }
        flags = []
        for bit, name in ASSEMBLY_FLAGS.items():
            if flag_value & bit:
                flags.append(name)
        return flags

    def _normalize_data(self, data):
        self.log.debug(inspect.currentframe().f_code.co_name)
        if isinstance(data, str):
            return {"value": data}
        return data

    def _compute_md5(self, data):
        self.log.debug(inspect.currentframe().f_code.co_name)
        if isinstance(data, str):
            # If it's a string, encode it to first
            return md5(data.encode("raw_unicode_escape")).hexdigest()
        elif not isinstance(data, bytes):
            # If it's neither string nor bytes, convert it to string and then to bytes
            return md5(str(data).encode("raw_unicode_escape")).hexdigest()
        else:
            return md5(data).hexdigest()

    def tag(self):
        return Tag.PE_DOTNET.value

    def extract(self):
        self.log.debug(inspect.currentframe().f_code.co_name)
        metadata = {}

        if self.error:
            metadata["Corrupted"] = self.error.args[0]
            dotnet = PEDotNet(metadata)
            self.dotnet = dotnet  # Store for later use in prepare_export_data
            return dotnet  # Return the extracted data instead of exporting directly

        metadata["info"] = {}
        try:
            available_tables = self.dotnet.existent_metadata_tables()
        except Exception as e:
            self.log.error(f"Error getting metadata tables for {self.hash.sha256}: {e}")
            available_tables = []
            metadata["info"]["PotentiallyCorrupted"] = True

        # GUID extraction
        try:
            input_string = self.dotnet.guid_stream_guids[0].string_representation
            
            formatted_uuid = (
                f"{input_string[6:8]}{input_string[4:6]}{input_string[2:4]}{input_string[0:2]}"
                f"-{input_string[10:12]}{input_string[8:10]}"
                f"-{input_string[14:16]}{input_string[12:14]}"
                f"-{input_string[16:20]}"
                f"-{input_string[20:]}"
            )
            metadata["info"]["ModuleVersionID"] = formatted_uuid
        except Exception as e:
            self.log.error(f"Error extracting GUID for {self.hash.sha256}: {e}")

        # CLR Version
        try:
            metadata["info"]["CLRversion"] = self.dotnet.get_runtime_target_version()
        except Exception as e:
            self.log.error(f"Error getting CLR version for {self.hash.sha256}: {e}")

        # Module information
        try:
            if self.dotnet.metadata_table_exists("Module"):
                metadata["info"]["AssemblyModuleName"] = self.dotnet.Module.get_module_name()
        except Exception as e:
            self.log.error(f"Error getting module info for {self.hash.sha256}: {e}")

        # Basic properties
        try:
            metadata["info"].update({
                "IsNativeNgenImage": self.dotnet.is_native_image(),
                "IsMixedAssembly": self.dotnet.is_mixed_assembly(),
                "IsWindowsFormsApp": self.dotnet.is_windows_forms_app(),
                "EntryPointToken": self.dotnet.clr_header.EntryPointToken.value,
                "HasNativeEntryPoint": self.dotnet.has_native_entry_point(),
            })
        except Exception as e:
            self.log.error(f"Error getting basic properties for {self.hash.sha256}: {e}")

        # Assembly flags
        try:
            metadata["info"]["AssemblyFlags"] = self._decode_assembly_flags(
                self.dotnet.clr_header.Flags.value
            )
        except Exception as e:
            self.log.error(f"Error getting assembly flags for {self.hash.sha256}: {e}")

        # More Metadata/Info CLR Header
        try:
            metadata["info"]["NumOfStreams"] = self.dotnet.get_number_of_streams()
            # [TODO] The following two on VT are "RVA entry point"
            #  and "Resources va" respectively. To verify.
            metadata["info"][
                "ResourcesDirectoryAddress"
            ] = self.dotnet.clr_header.ResourcesDirectoryAddress.value
            metadata["info"][
                "ResourcesDirectorySize"
            ] = self.dotnet.clr_header.ResourcesDirectorySize.value
            metadata["info"][
                "StrongNameSignatureAddress"
            ] = self.dotnet.clr_header.StrongNameSignatureAddress.value
            metadata["info"][
                "StrongNameSignatureSize"
            ] = self.dotnet.clr_header.StrongNameSignatureSize.value
            metadata["info"][
                "CodeManagerTableAddress"
            ] = self.dotnet.clr_header.CodeManagerTableAddress.value
            metadata["info"][
                "CodeManagerTableSize"
            ] = self.dotnet.clr_header.CodeManagerTableSize.value
            metadata["info"][
                "VTableFixupsAddress"
            ] = self.dotnet.clr_header.VTableFixupsAddress.value
            metadata["info"][
                "VTableFixupsSize"
            ] = self.dotnet.clr_header.VTableFixupsSize.value
            metadata["info"][
                "ExportAddressTableJumpsAddress"
            ] = self.dotnet.clr_header.ExportAddressTableJumpsAddress.value
            metadata["info"][
                "ExportAddressTableJumpsSize"
            ] = self.dotnet.clr_header.ExportAddressTableJumpsSize.value
            metadata["info"][
                "ManagedNativeHeaderAddress"
            ] = self.dotnet.clr_header.ManagedNativeHeaderAddress.value
            metadata["info"][
                "ManagedNativeHeaderSize"
            ] = self.dotnet.clr_header.ManagedNativeHeaderSize.value
        except Exception as e:
            self.log.error(f"Error getting more metadata/info clr header for {self.hash.sha256}: {e}")

        # Streams section
        try:
            metadata["Streams"] = {}
            stream_names = self.dotnet.get_stream_names()
            for name in stream_names:
                indx = stream_names.index(name)
                stream_header = self.dotnet.dotnet_stream_headers[indx]
                stream_address = self.dotnet.dotnet_streams[indx].address
                metadata["Streams"][name] = {}
                metadata["Streams"][name]["raw_name"] = base64.b64encode(
                    stream_header.Name.value
                ).decode()
                # metadata["Streams"][name]["raw_name"] = name
                metadata["Streams"][name]["size"] = stream_header.Size.value
                # Retrieve the stream data directly using the given address and size
                stream_data = self.pe.get_data(stream_address, stream_header.Size.value)
                metadata["Streams"][name]["entropy"] = (
                    "%.2f" % pefile.SectionStructure.entropy_H(self.pe, stream_data)
                )
                metadata["Streams"][name]["md5"] = md5(stream_data).hexdigest()
        except Exception as e:
            self.log.error(f"Error getting streams for {self.hash.sha256}: {e}")

        # ManifestResource
        try:
            metadata["ManifestResource"] = ()
            if "ManifestResource" in available_tables:
                metadata["info"]["HasManifestResource"] = True
                metadata["ManifestResource"] = (
                    self.dotnet.ManifestResource.get_resource_names()
                )
        except Exception as e:
            self.log.error(f"Error getting manifest resource for {self.hash.sha256}: {e}")

        # ExternalAssemblyRef
        try:
            metadata["ExternalAssemblyRef"] = {}
            if "AssemblyRef" in available_tables:
                metadata["ExternalAssemblyRef"][
                    "names"
                ] = self.dotnet.AssemblyRef.get_assemblyref_names()
                metadata["ExternalAssemblyRef"][
                    "cultures"
                ] = self.dotnet.AssemblyRef.get_assemblyref_cultures()
        except Exception as e:
            self.log.error(f"Error getting external assembly ref for {self.hash.sha256}: {e}")

        # AssemblyData
        try:
            metadata["AssemblyData"] = {}
            if "Assembly" in available_tables:
                metadata["AssemblyData"][
                    "name"
                ] = self.dotnet.Assembly.get_assembly_name()
                # It's officially a one-row table, but there are ITW files with more than one row.
                # It stores information about the current assembly. It is documented in ECMA-335.
                assembly_table = self.dotnet.metadata_tables_lookup[
                    "Assembly"
                ].table_rows[0]
                metadata["AssemblyData"][
                    "MajorVersion"
                ] = assembly_table.MajorVersion.value
                metadata["AssemblyData"][
                    "MinorVersion"
                ] = assembly_table.MinorVersion.value
                metadata["AssemblyData"]["hashalgid"] = assembly_table.HashAlgId.value
                metadata["AssemblyData"][
                    "BuildNumber"
                ] = assembly_table.BuildNumber.value
                metadata["AssemblyData"][
                    "RevisionNumber"
                ] = assembly_table.RevisionNumber.value
                metadata["AssemblyData"][
                    "culture"
                ] = self.dotnet.Assembly.get_assembly_culture()
        except Exception as e:
            self.log.error(f"Error getting assembly data for {self.hash.sha256}: {e}")

        # TypeDef handling
        try:
            metadata["TypeDef"] = {}
            if "TypeDef" in available_tables:
                metadata["info"]["HasTypeDef"] = True
                # Get basic type definitions
                try:
                    # Get all types (ANY visibility)
                    type_defs = self.dotnet.TypeDef.get_type_names()
                    metadata["TypeDef"]["names"] = type_defs if type_defs else []
                    
                    # Get detailed type information with methods
                    types_with_methods = self.dotnet.TypeDef.get_type_names_with_methods()
                    if types_with_methods:
                        metadata["TypeDef"]["detailed"] = []
                        for type_info in types_with_methods:
                            type_data = {
                                "type": type_info.Type,
                                "namespace": type_info.Namespace,
                                "flags": type_info.Flags,
                                "methods": []
                            }
                            for method in type_info.Methods:
                                method_data = {
                                    "name": method.Name,
                                    "flags": method.Flags
                                }
                                if method.Signature:
                                    method_data["signature"] = {
                                        "parameters": method.Signature.get("parameter", []),
                                        "return_type": method.Signature.get("return", ""),
                                        "has_this": method.Signature.get("hasthis", False)
                                    }
                                type_data["methods"].append(method_data)
                            metadata["TypeDef"]["detailed"].append(type_data)
                except AttributeError as e:
                    self.log.warning(f"TypeDef table exists but attributes missing for {self.hash.sha256}: {e}")
                    # metadata["info"]["TypeDefParsingError"] = f"Missing attributes: {str(e)}"
                except Exception as e:
                    self.log.error(f"Error parsing TypeDef table for {self.hash.sha256}: {e}")
                    # metadata["info"]["TypeDefParsingError"] = str(e)
        except Exception as e:
            self.log.error(f"Error handling TypeDef section for {self.hash.sha256}: {e}")
            metadata["TypeDef"] = {"names": [], "detailed": []}
            # metadata["info"]["TypeDefParsingError"] = str(e)

        # ExternalUnmanagedModules
        try:
            metadata["ExternalUnmanagedModules"] = ()
            if "ModuleRef" in available_tables:
                metadata["info"]["HasModuleRef"] = True
                metadata["ExternalUnmanagedModules"] = (
                    self.dotnet.ModuleRef.get_unmanaged_module_names(
                        self.dotnet.Type.UnmanagedModules.RAW
                    )
                )
        except Exception as e:
            self.log.error(f"Error getting external unmanaged modules for {self.hash.sha256}: {e}")

        # ExternalUnmanagedMethods
        try:
            metadata["ExternalUnmanagedMethods"] = ()
            if "ImplMap" in available_tables:
                metadata["info"]["HasImplMap"] = True
                metadata["ExternalUnmanagedMethods"] = (
                    self.dotnet.ImplMap.get_unmanaged_functions()
                )
        except Exception as e:
            self.log.error(f"Error getting external unmanaged methods for {self.hash.sha256}: {e}")

        # Event
        try:
            metadata["Event"] = ()
            if "Event" in available_tables:
                metadata["info"]["HasEvent"] = True
                metadata["Event"] = self.dotnet.Event.get_event_names()
        except Exception as e:
            self.log.error(f"Error getting event for {self.hash.sha256}: {e}")

        # Resources
        try:
            metadata["Resources"] = []
            if self.dotnet.has_resources():
                tmp_resources_list = []
                resource_data = self.dotnet.get_resources()
                for data in resource_data:
                    tmp_dict = {}
                    for resource_item in data.items():
                        if resource_item[0] == "SubResources":
                            if resource_item[1]:
                                tmp_dict["SubResources"] = {}
                                for sub_resource in resource_item[1]:
                                    for sub_resource_item in sub_resource.items():
                                        if sub_resource_item[0] == "Data":
                                            # Check if data is a sequence type that supports len()
                                            if hasattr(sub_resource_item[1], '__len__') and len(sub_resource_item[1]) > 100:
                                                tmp_dict["SubResources"]["Data"] = {}
                                                try:
                                                    # tmp_dict["SubResources"]["Data"][
                                                    #     "md5"
                                                    # ] = md5(
                                                    #     sub_resource_item[1].encode()
                                                    # ).hexdigest()
                                                    tmp_dict["SubResources"]["Data"][
                                                        "md5"
                                                    ] = self._compute_md5(
                                                        sub_resource_item[1]
                                                    )
                                                except Exception as e:
                                                    self.log.error(
                                                        f"Error in dotnet resources"
                                                        f" extraction {self.hash.sha256}: {e}"
                                                    )
                                                guess = magic.from_buffer(
                                                    sub_resource_item[1], mime=True
                                                )
                                                tmp_dict["SubResources"]["Data"][
                                                    "MimeType"
                                                ] = (guess if guess else None)
                                            else:
                                                normalized_data = self._normalize_data(
                                                    sub_resource_item[1].decode()
                                                    if isinstance(
                                                        sub_resource_item[1], bytes
                                                    )
                                                    else sub_resource_item[1]
                                                )
                                                tmp_dict["SubResources"][
                                                    sub_resource_item[0]
                                                ] = normalized_data
                                        else:
                                            tmp_dict["SubResources"][
                                                sub_resource_item[0]
                                            ] = (
                                                sub_resource_item[1].decode()
                                                if isinstance(
                                                    sub_resource_item[1], bytes
                                                )
                                                else sub_resource_item[1]
                                            )
                        elif resource_item[0] == "Data":
                            # Check if data is a sequence type that supports len()
                            if hasattr(resource_item[1], '__len__') and len(resource_item[1]) > 100:
                                tmp_dict["Data"] = {}
                                tmp_dict["Data"]["md5"] = self._compute_md5(
                                    resource_item[1]
                                )
                                guess = magic.from_buffer(resource_item[1], mime=True)
                                tmp_dict["Data"]["MimeType"] = guess if guess else None
                            else:
                                normalized_data = self._normalize_data(
                                    resource_item[1].decode()
                                    if isinstance(resource_item[1], bytes)
                                    else resource_item[1]
                                )
                                tmp_dict["Data"] = normalized_data
                        else:
                            tmp_dict[resource_item[0]] = (
                                resource_item[1].decode()
                                if isinstance(resource_item[1], bytes)
                                else resource_item[1]
                            )
                    tmp_resources_list.append(tmp_dict)
                metadata["Resources"] = tmp_resources_list
        except Exception as e:
            self.log.error(f"Error getting resources for {self.hash.sha256}: {e}")
            metadata["Resources"] = []  # Ensure we always have a valid list even on error

        dotnet = PEDotNet(metadata)
        self.dotnet = dotnet  # Store for later use in prepare_export_data
        return dotnet  # Return the extracted data instead of exporting directly


    def prepare_export_data(self, exporter_type: str) -> Any:
        if exporter_type == "ElasticsearchExporter":
            return self.dotnet
        elif exporter_type == "ClickHouseExporter":
            # Convert metadata to JSON string
            metadata_json = json.dumps(self.dotnet.dotnet)
            
            data = [[
                self.sha256,
                self.md5,
                self.sha1,
                metadata_json,
                datetime.now(timezone.utc)
            ]]
            
            column_names = [
                'sha256', 'md5', 'sha1', 'dotnet', 'analysis_date'
            ]
            
            if not data:
                return None

            column_type_names = [
                'String', 'String', 'String', 'JSON', 'DateTime64(3, \'UTC\')'
            ]

            return (data, column_names, column_type_names)

    def get_clickhouse_table(self) -> str:
        return "redb_pe_dotnet"