Nan Luo

64 papers A* 1B 4C 3Journal 41Unranked 15
YearRankTypeTitle / Venue / Authors
2025 A* conf
ACM Multimedia
Min Dang, Gang Liu, Jingqi Zhao, Adams Wai-Kin Kong, Nan Luo, Di Wang
2025 J jnl
IEEE Trans. Circuits Syst. Video Technol.
Nan Luo, Zhexuan Hu, Yuan Ding, Jiaxu Li, Hui Zhao, Gang Liu, Quan Wang
2025 conf
CSCW Companion
Yihui Cai, Zhitao Yu, Nan Luo, Shuzi Yin, Haipeng Mi
2025 J jnl
CoRR
Fuyu Dong, Ke Li, Di Wang, Nan Luo, Yiming Zhang, Kaiyu Li, Jianfei Yang, Quan Wang
2025 J jnl
CoRR
Nan Luo, Chenglin Ye, Jiaxu Li, Gang Liu, Bo Wan, Di Wang, Lupeng Liu, Jun Xiao
2025 J jnl
Parallel Comput.
Hui Zhao, Wentao Zhi, Xiaoqin Lu, Jing Wang, Nan Luo, Bo Wan, Quan Wang
2025 conf
CVPR Workshops
Feiyang Wang, Nan Luo, Wangyu Wu
2024 J jnl
IEEE Trans. Dependable Secur. Comput.
Runnan Zhang, Gang Liu, Hongzhaoning Kang, Quan Wang, Bo Wan, Nan Luo
2024 J jnl
Entertain. Comput.
Lixin Li, Lei Wang, Nan Luo
2024 J jnl
J. Parallel Distributed Comput.
Tian Chen, Yu-an Tan, Zheng Zhang, Nan Luo, Bin Li, Yuanzhang Li
2024 conf
CISP-BMEI
Kun Leng, Yuping Zhao, Shaoli Wang, Haichuan Ren, Huiqiang Hu, Nan Luo, Linjing Peng, Yige Liu, Ruiyi Duan, Xiaobo Mao
2023 J jnl
BMC Medical Informatics Decis. Mak.
Pengling Ren, Yi He, Ning Guo, Nan Luo, Fang Li, Zhenchang Wang, Zhenghan Yang
2023 J jnl
Comput. Secur.
Hongzhaoning Kang, Gang Liu, Quan Wang, Qi Zhang, Jiamin Niu, Nan Luo
2023 J jnl
Comput. Biol. Medicine
Nan Luo, Xiaojing Zhong, Luxin Su, Zilin Cheng, Wenyi Ma, Pingsheng Hao
2023 J jnl
Remote. Sens.
Jinlong Hu, Sicheng Qiu, Nan Luo, Guo Qing, Chunbo Huang
2023 conf
VTC2023-Spring
Nan Luo, Yong Li
2022 conf
NaNA
Xiao Liu, Zhao Huang, Quan Wang, Nan Luo
2022 J jnl
BMC Medical Imaging
Xianjun Han, Nan Luo, Lixue Xu, Jiaxin Cao, Ning Guo, Yi He, Min Hong, Xibin Jia, Zhenchang Wang, Zhenghan Yang
2022 J jnl
Patterns
Jia Lu, Ryan Tsoi, Nan Luo, Yuanchi Ha, Shangying Wang, Minjun Kwak, Yasa Baig, Nicole Moiseyev, Shari Tian, Alison Zhang, Neil Zhenqiang Gong, Lingchong You
2022 J jnl
CoRR
Nan Luo, Yuanzhang Li, Yajie Wang, Shangbo Wu, Yu-an Tan, Quanxin Zhang
2022 J jnl
Sensors
Zeyu Li, Zhao Huang, Quan Wang, Junjie Wang, Nan Luo
2022 J jnl
Comput. Ind. Eng.
Xurui Yang, Hongtao Hu, Jiangang Jin, Nan Luo
2022 conf
ISCIPT
Nan Luo, Ying Ma
2022 J jnl
Inf. Sci.
Gang Liu, Min Dang, Jing Liu, Ruotong Xiang, Yumin Tian, Nan Luo
2021 J jnl
IEEE Trans. Syst. Man Cybern. Syst.
Xu Liang, David Zhang, Guangming Lu, Zhenhua Guo, Nan Luo
2021 conf
ISPA/BDCloud/SocialCom/SustainCom
Yanqi Xie, Xirong Lv, Ying Jiang, Zanyou Su, Nan Luo, Ying Ma
2021 J jnl
Remote. Sens.
Nan Luo, Ling Huang, Quan Wang, Gang Liu
2021 J jnl
Remote. Sens.
Nan Luo, Hongquan Yu, Zhenfeng Huo, Jinhui Liu, Quan Wang, Ying Xu, Yun Gao
2021 J jnl
Int. J. Emerg. Technol. Learn.
Kyunghee Park, He Li, Nan Luo
2021 J jnl
Multim. Tools Appl.
Nan Luo, Ying Xu, Quan Wang, Bo Wan
2021 J jnl
Int. J. Pattern Recognit. Artif. Intell.
Nan Luo, Yuanyuan Jiang, Quan Wang
2021 J jnl
Pattern Recognit. Lett.
Nan Luo, Yifeng Wang, Yun Gao, Yumin Tian, Quan Wang, Chuan Jing
2019 conf
ICAIS (3)
Tianxiao Xue, Qingbao Li, Ping Zhang, Zhifeng Chen, Peijun Feng, Nan Luo
2019 J jnl
CAAI Trans. Intell. Technol.
Chunwei Tian, Yong Xu, Lunke Fei, Junqian Wang, Jie Wen, Nan Luo
2019 J jnl
IEEE Access
Nan Luo, Quan Wang, Qi Wei, Chuan Jing
2018 J jnl
IET Comput. Vis.
Nan Luo, Quan Wang
2018 J jnl
CoRR
Chunwei Tian, Yong Xu, Junqian Wang, Nan Luo, Haizhang Zou
2018 conf
CCBR
Xu Liang, Gang Wu, Yan He, Nan Luo
2018 C conf
CSCWD
Hui Zhao, Jing Wang, Feng Liu, Quan Wang, Nan Luo, Weizhan Zhang
2017 J jnl
Int. J. Comput. Appl. Technol.
Nan Luo, Quan Wang
2017 conf
SPAC
Di Yuan, Xiaohuan Lu, Donghao Li, Zhenyu He, Nan Luo
2017 conf
SPAC
Di Yuan, Guanglei Zhao, Donghao Li, Zhenyu He, Nan Luo
2016 J jnl
Computing
Jingying Chen, Nan Luo, Yuanyuan Liu, Leyuan Liu, Kun Zhang, Joanna Kolodziej
2016 conf
OFC
Nan Luo, Shifu Yuan, Hongliang Qu
2016 J jnl
Neurocomputing
Yuanyuan Liu, Jingying Chen, Zhiming Su, Zhenzhen Luo, Nan Luo, Leyuan Liu, Kun Zhang
2016 J jnl
Pattern Recognit. Lett.
Asongu L. Tambo, Bir Bhanu, Nolan Ung, Ninad Thakoor, Nan Luo, Zhenbiao Yang
2015 J jnl
Appl. Soft Comput.
Yucheng Dong, Nan Luo, Haiming Liang
2014 B conf
ICALT
Vincent W. L. Tam, Nan Luo
2014 C conf
ICPRAM
Yuanyuan Liu, Jingying Chen, Leyuan Liu, Yujiao Gong, Nan Luo
2014 B conf
ICPR
Asongu L. Tambo, Bir Bhanu, Nan Luo, Geoffrey Harlow, Zhenbiao Yang
2014 B conf
FUZZ-IEEE
Yucheng Dong, Nan Luo, Hengjie Zhang
2013 J jnl
J. Zhejiang Univ. Sci. C
Nan Luo, Lu-ping Xu, Hua Zhang, Qiang Xie
2012 J jnl
IEEE Trans. Syst. Man Cybern. Part A
Wei Li, David Zhang, Guangming Lu, Nan Luo
2012 C conf
CIS
Nan Luo, Quan Wang, Kefeng Zhang
2012 J jnl
Future Gener. Comput. Syst.
Min Liu, Mingrui Wang, Weiming Shen, Nan Luo, Junwei Yan
2011 J jnl
IEEE Trans. Instrum. Meas.
David Zhang, Feng Liu, Qijun Zhao, Guangming Lu, Nan Luo
2010 J jnl
Pattern Recognit.
Qijun Zhao, David Zhang, Lei Zhang, Nan Luo
2010 J jnl
Pattern Recognit.
Qijun Zhao, David Zhang, Lei Zhang, Nan Luo
2010 J jnl
Pattern Recognit.
David Zhang, Vivek Kanhangad, Nan Luo, Ajay Kumar
2009 conf
ICB
Qijun Zhao, Lei Zhang, David Zhang, Nan Luo
2009 J jnl
IEEE Trans. Syst. Man Cybern. Part C
David Zhang, Guangming Lu, Wei Li, Lei Zhang, Nan Luo
2008 B conf
ICPR
Qijun Zhao, Lei Zhang, David Zhang, Nan Luo, Jing Bao
2007 conf
IEEE SCC
Nan Luo, Junwei Yan, Min Liu
2006 conf
GCC
Nan Luo, Junwei Yan, Min Liu, Shuxin Yang
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"