Content area
Consistent detection of malicious loaders across varied programming languages and build tools remains a significant cybersecurity challenge. This study empirically measures how compiler and language choices affect the detectability of standard in-memory Windows loaders. We implement functionally equivalent loaders (allocate, copy, protect, execute) in C, C#, Fortran, and COBOL, embedding an identical x64 test payload to isolate behavior. Our results reveal significant detection gaps: loaders compiled in legacy languages (Fortran, COBOL) consistently evade static and dynamic antivirus engines that easily flag their C and C# counterparts. We demonstrate this evasion is not due to behavioral differences, but to compiler-specific static artifacts. These artifacts, such as interleaved zero-bytes in Fortran and fragmented payload-construction logic in COBOL, effectively break common signature matching. These findings indicate that many detection tools are overly sensitive to the static build surface rather than true semantic behavior. We provide actionable guidance favoring behavior-focused analysis, such as tracking API call order and memory protection changes, to address this critical legacy code blind spot.
Full text
1. Introduction
The influence of programming languages on antivirus evasion is a critical area of study in malware research [1]. Different languages offer varying degrees of control over system resources, which attackers leverage to bypass antivirus detection. Low-level languages such as C, C++, and Assembly allow for precise memory manipulation and direct interaction with the operating system [2], facilitating techniques such as packing [3], obfuscation [4], and polymorphism [5,6]. These methods effectively evade traditional signature-based detection, as they manipulate the structure of the executable, making it harder for antivirus software to recognize [7].
Recent trends in malware development include the use of multi-language attacks, where different components of the malware are written in various languages such as Go and Rust. As malware developers explore the strengths and weaknesses of various programming languages, the interplay between language choice and antivirus evasion strategies remains a critical area of ongoing research. Understanding these dynamics is essential for advancing both offensive and defensive cybersecurity measures, as well as for developing more resilient antivirus solutions capable of countering increasingly complex threats.
The impact of programming languages on antivirus evasion is crucial for understanding the current trends and predicting future developments in malware. As languages evolve, so do the tactics employed by attackers, necessitating continuous research into the potential malicious exploitation of these languages. The need for advanced detection systems incorporating behavioral analysis and machine learning becomes increasingly apparent as malware grows more sophisticated and linguistically diverse [8]. This research aimed to bridge the knowledge gap by examining how different programming languages affect malware’s evasion capabilities and exploring the implications for the future of cybersecurity.
The principal contributions of this study are summarized as follows: Cross-language, cross-compiler measurement. We conduct a controlled, functionally equivalent implementation of canonical in-memory shellcode loaders across multiple languages (e.g., C, C#, Fortran, and COBOL) and compiler/linker configurations, keeping the payload and loader logic fixed to isolate the effect of language and toolchain choices. Generalizable detection signals. We identify language-agnostic behavioral cues—API-call sequences, memory-protection transitions ( Actionable guidance for anti-virus. We analyze failure modes that arise with legacy or non-mainstream toolchains and outline practical hardening guidelines, including language-aware binary normalization and behavior-centric triage that reduces dependence on byte-patterns. Reproducible baseline. We provide a reproducible build recipe and evaluation protocol that can serve as a reference baseline for future studies incorporating packers, encoders, or evasive techniques.
This work is academic and defensive research only. All studies use inert payload simulators to recreate allocation–copy–protection–dispatch semantics without network or file I/O in offline, isolated contexts. Instead of executable binaries or weaponizable payloads, exploits, packers, or obfuscation, build recipes, metadata, and aggregate results are employed for qualified replication. Laws, institutional regulations, and responsible research standards are followed in the study. To exploit these concepts or artifacts for offensive or illegal purposes is strictly banned. Readers must ensure ethical, legal use in their areas and organizations.
This paper is organized as follows: Section 2 reviews prior work on shellcode detection, language-aware malware analysis, and behavioral models for in-memory execution. Section 3 details our experimental design and the implementation of functionally equivalent loaders across languages, together with the compiler/linker matrix. Section 4 describes the scanning protocol, metrics, and statistical methods. Section 5 reports the empirical results and answers the research questions. Section 6 discusses implications, limitations, and threats to validity concludes the paper and outlines directions for the future work.
2. Related Work
In the realm of antivirus evasion, programming languages play a pivotal role in shaping malware’s characteristics and its ability to bypass detection systems. Traditionally, malware has been written in low-level languages such as C and C++ due to their direct access to system resources [9,10], allowing attackers to exploit memory management and hardware manipulation. These languages provide a high degree of control over the executable’s structure, enabling techniques such as packing, polymorphism, and self-modifying code, all of which are designed to evade static signature-based detection by antivirus engines [11]. In particular, malware written in these languages often utilizes advanced obfuscation methods to thwart reverse engineering and evade heuristic analysis.
More recently, high-level languages such as Python, Java, and C# have also come to play a significant role in antivirus evasion, albeit through different mechanisms. While these languages abstract much of the low-level memory management, they provide powerful libraries and frameworks that can be used to dynamically load and execute code at runtime [12]. For instance, the researchers have demonstrated the use of Python to evade antivirus detection without relying on obfuscation techniques [13]. Python-based malware can evade antivirus detection through various methods, including encryption, compression, and the use of packers such as PyInstaller [14,15]. Research indicates that, when Python is combined with these evasion mechanisms and incorporates obfuscation techniques, it poses a significant challenge to dynamic analysis engines, particularly in evading runtime detection. Further advanced obfuscation strategies have also been explored, such as utilizing fountain codes to fragment payloads [16] or applying chaotic-based encryption to randomize shellcode [17].
Programming languages such as Rust have begun to attract attention in the context of antivirus evasion. Rust’s memory safety features, combined with its ability to generate efficient binaries, make it more challenging for antivirus systems to perform reverse engineering and detect malicious behavior [18]. Studies have demonstrated that malware written in Rust tends to evade detection more effectively than C-based malware, highlighting the limitations of current antivirus tools in analyzing newer languages [19]. This emphasizes the need for antivirus systems to evolve, integrating more advanced detection mechanisms such as behavioral monitoring and machine learning to address the increasing diversity of malware development languages [20].
Cybercriminals are increasingly leveraging Microsoft’s .NET and PowerShell frameworks to develop sophisticated malware [21]. These powerful tools make it easier to develop ransomware and targeted attacks, presenting significant challenges for defenders. The rapid development cycles and high-level programming environments associated with these frameworks underscore the need for greater and continuous attention in combating these evolving threats [22].
Advanced threat groups, such as APT28 (Fancy Bear) and APT29 (Cozy Bear) [23], have shifted to using more obscure programming languages such as Go and Rust in their malware to enhance evasion [24]. Go, in particular has become a favorite in advanced persistent threats (APTs) due to its cross-platform compatibility and the difficulty it presents for reverse engineering. For instance, APT28 used Go to rewrite its Zebrocy malware, previously built in Delphi [25], while APT29 deployed Go in its WellMess malware to target both Windows and Linux systems. The WellMess malware even added capabilities such as running PowerShell scripts post-infection [24]. These adaptations significantly sidestep traditional antivirus detection methods, emphasizing the need for more advanced security solutions.
According to the TIOBE index in 2024, Python is the most popular programming language [26], followed by C++, Java, and C. This ranking reflects current trends in the software development industry, with Python’s versatility, simplicity, and widespread use in fields such as data science, web development, and automation contributing to its top position. Other languages such as Go and Rust are also gaining traction, indicating a growing interest in modern, efficient, and performance-oriented languages. In light of these trends and concerns, we propose an experiment focusing on shellcode loaders without any obfuscation, encryption, or encoding. This approach aims to provide a baseline understanding of how different programming languages, both modern and legacy, interact with antivirus systems in their most basic form. To provide a clear overview of the discussed literature as Table 1 presents a comparative analysis summarizing the influence of these language families on malware evasion.
3. Methodology
We implement functionally equivalent loaders in C, C#, Fortran, and COBOL to compare their antivirus detection outcomes under a fixed in-memory execution semantics [27]. To avoid distributing weaponizable artifacts, we use a benign inert payload emulator that exercises the same memory-allocation, copying, permission-transition, and thread-creation primitives as a typical loader, but performs no network or file I/O. This design preserves detection-relevant behavior while eliminating exploit content. All builds are produced with pinned toolchains and deterministic settings where available.
This command utilizes msfvenom, a payload generator from the Metasploit Framework, to create a Meterpreter reverse shell payload for Windows in C. A reverse shell is a cybersecurity technique where a compromised system initiates a connection back to an attacker’s machine [28,29]. This approach allows the attacker to remotely execute commands on the compromised system. Once the payload is executed on the target machine, it initiates a connection back to the attacker’s system. This connection provides remote access to the compromised machine, allowing the attacker to interact with it as if they had access.
On Windows operating systems, shellcode is typically executed by allocating memory, copying the shellcode into that memory, and then marking it as executable before jumping to it. This process often involves using Windows API functions such as
All binaries are built in isolated VM (Virtual Machine) with pinned compilers/linkers; we record toolchain versions, options, and PE/CLR metadata hashes. Specifically, all build and execution tasks were conducted within a VMware Workstation 17.6.3 virtual machine running a 64-bit Windows 10 Professional guest OS. To create the isolated sandbox, the VM’s network was configured to a host-only (internal) setting. This setup permitted VM-to-VM communication (required for the inert payload’s C2 simulation) but strictly disabled all external file, registry, and network egress, preventing any external I/O.
4. Experiment
This section reports the cross-language scanning results and the associated analysis. To isolate the effect of language and toolchain choices, all artifacts implement a functionally equivalent in-memory dispatch path while holding execution semantics constant (allocation → copy → protection transition → dispatch). For safety and reproducibility, we use a benign inert payload emulator that exercises the same Windows API primitives but performs no network or file I/O. This preserves detection-relevant behavior without distributing weaponizable content. All binaries are scanned on
4.1. Artifacts and Build Matrix
We consider four languages and their representative toolchains: C (native): Visual Studio 2022, Release, static and dynamic CRT variants; deterministic build enabled when available. C# (.NET 6.0): Visual Studio 2022, Release, AnyCPU/x64, single-file publish off; P/Invoke used only for required Win32 APIs. Fortran (native): Intel® Fortran Compiler integrated with MSVC; Release profile; native linkage. COBOL (native): GnuCOBOL via MSYS2 for Windows; Release-equivalent flags; native calls to Win32.
Each artifact conforms to a shared equivalence oracle: (i) presence of the canonical API sequence; (ii) RW→RX protection transition (no RWX pages); (iii) absence of file/registry/network side effects. We record compiler/linker versions, selected flags, PE/CLR metadata, import table shape, section sizes, and content hashes.
To visually represent the shared logic across all loaders, Figure 1 illustrates the canonical flowchart implemented in all four languages.
4.2. Programming C Language
As shown in Listing 1, the source codes in the C programming language were compiled using Visual Studio 2022 in release mode, and the Run-Time Library was set with and without debug symbols [33].
| Listing 1. Executing the shellcode in the C programming language. |
| |
4.3. C# Programming Language
As shown in Listing 2, the source codes in the C# programming language were compiled using Visual Studio 2022 in release mode and using .NET 6.0, without debug symbols.
4.4. FORTRAN Programming Language
As shown in Listing 3, the source codes in the Fortran programming language were compiled using an Intel® Fortran Compiler [34]; this compiler can be used with Microsoft Visual Studio 2019 and 2022. Fortran is primarily used in scientific computing, numerical analysis, and engineering applications [35]. It is favored for tasks that require high-performance computations, such as simulations, complex mathematical modeling, weather forecasting, computational fluid dynamics, and large-scale data processing. Its strength lies in handling large arrays and matrices efficiently, making it a common choice in physics, chemistry, and engineering research.
| Listing 2. Executing the shellcode in the C# programming language. |
| |
4.5. COBOL Programming Language
As shown in Listing 4, the source codes in the COBOL programming language were compiled using GnuCobol (version 1 3.2-9) with MSYS2. COBOL (Common Business-Oriented Language) is widely used in the financial industry, particularly in banking, insurance, and credit card systems. It excels in handling large-scale financial transactions and batch processing, making it a go-to choice for core banking systems, transaction processing, and accounting operations. Many legacy systems in financial institutions still rely on COBOL due to its stability, scalability, and ability to manage complex data processing tasks. Despite being an older language, it continues to play a crucial role in the financial sector, particularly in maintaining and updating legacy systems that require high reliability.
| Listing 3. Executing the shellcode in the Fortran programming language. |
| |
| Listing 4. Executing the shellcode in the COBOL programming language. |
| |
5. Result
5.1. Antivirus Scan Results
We evaluated one functionally equivalent artifact per language under identical build profiles and uploaded each artifact once per engine aggregator session with caches cleared. Engines are reported anonymously (E1–En). For each artifact we recorded: (i) the number of engines that flagged the binary (DR), (ii) any family or heuristic name when available, and (iii) whether the flag was from static inspection or from on-execution emulation. Table 2 and Table A1 lists vendor-facing names for traceability.
Across the four ecosystems, C and C# showed higher static DR than Fortran and COBOL. The effect persists when normalizing by binary size and number of imports. On-execution results reduced the gap but did not remove it. The variance is consistent with differences in runtime libraries, metadata layouts, and how each compiler materializes byte arrays or immediate constants. We observed no flags for samples that failed the equivalence oracle (missing protection transition or extra side effects); such samples were excluded from aggregation.
5.2. Comparison of the Shellcode Patterns
Figure 2 shows the byte prefix extracted from the stub used to exercise the dispatch path; the leading six bytes are
Two causes explain the absence of a contiguous prefix in some builds: (i) when the stub is represented as an array of integers rather than
5.3. Disassembling the Samples
As shown in Figure 4 and Figure 5, panel (a) places the code and data views side by side. The instruction
As shown in Figure 6, the upper panel shows the compiler emitting the stub under the symbol
5.4. Per-Language Observations
To provide a clearer, side-by-side comparison of these syntactic and structural differences, Figure 7 visually depicts how the exact same shellcode payload is represented and loaded in C, C#, Python, and COBOL.
C (native): The stub is embedded as a contiguous
C# (.NET 6): The artifact uses managed control flow with P/Invoke for the required Win32 calls. IL metadata, the assembly manifest, and P/Invoke descriptors enlarge the static surface compared with C. The stub appears as a contiguous blob in resources or
Fortran (native): The compiler stores the stub as wider integer elements, which produces interleaved zeros in the data section (
COBOL (native): The toolchain materializes bytes via immediate moves and stores into a buffer, distributing the prefix across instruction boundaries instead of emitting a single array. Allocation, RW→RX, and dispatch follow the same APIs as other languages, satisfying equivalence checks. Hex-prefix searches over the file image rarely return a continuous match, so static short signatures trigger less often, while behavioral checks still record the protection transition and thread start. Runtime initialization affects import density and section layout but not the underlying dispatch semantics.
5.5. Robustness Checks and Limitations
We repeated the scans after rebuilding with deterministic build options when available. The detection ordering by language remained unchanged. We also repeated the grep check using a longer prefix (≥16 bytes) and confirmed the same outcome: contiguous matches in C/C#, fragmented representations in Fortran/COBOL. These checks support the interpretation that byte-materialization strategies, not semantic differences, explain the pattern results. Limitations include aggregator-dependent emulation coverage and vendor policy drift; to mitigate, we report both static and on-execution outcomes and log build metadata for replication.
A further limitation is the study’s specific linguistic scope. As noted in our related work, modern languages such as Go, Rust, and Python are increasingly leveraged for malware development. However, this study intentionally focused on establishing a baseline comparison between mainstream, high-detection languages (C, C#) and legacy languages (Fortran, COBOL). The rationale for this focus is that these legacy toolchains, while less scrutinized by modern security tools, remain in active use in critical financial, scientific, and infrastructure sectors, creating the “legacy code, live risk“ scenario we aimed to investigate. Therefore, a comprehensive experimental comparison incorporating Go, Rust, and Python remains a critical and immediate next step for future work.
6. Conclusions and Future Work
6.1. Conclusions
The experiments conducted on shellcode execution across different languages such as Fortran, COBOL, and C# demonstrate that the core shellcode remained unchanged, but the rates of detection by antivirus software differed. Fortran and COBOL exhibited lower detection rates than C and C#, indicating that language choice may influence the evasion of antivirus mechanisms. This highlights the potential for unconventional programming languages, such as COBOL and Fortran, to be leveraged for stealthier malware, emphasizing the importance of addressing security challenges across diverse programming environments.
It is important to note that this research did not implement any advanced evasion techniques such as encryption, encoding, or obfuscation. The shellcode was tested in its raw form, without modifications intended to bypass analysis tools. However, had techniques such as encryption or obfuscation been applied, the difficulty of reverse engineering and analyzing the malware would likely have increased, further impairing detection by antivirus software. This highlights the potential for malicious actors to leverage both unconventional programming languages and additional techniques to enhance the stealthiness of malware.
The results of this study underscore the potential for older, unconventional programming languages such as Fortran and COBOL to be exploited by attackers seeking to bypass modern security measures. These languages, often associated with legacy systems, are less scrutinized by contemporary antivirus engines, creating a blind spot that sophisticated malware could exploit. In environments where Fortran and COBOL are still used—such as critical infrastructure, financial systems, and scientific computing—this presents a considerable risk. Attackers could leverage the lower detection rates and relative obscurity of these languages to launch stealthier attacks, particularly against systems that rely heavily on legacy code. As such, it is imperative that security strategies evolve to encompass not only modern languages but also those that underpin vital legacy systems. Addressing the security challenges posed by Fortran, COBOL, and similar languages will be crucial in mitigating potential threats and enhancing the resilience of legacy systems in the face of evolving cyber attacks.
6.2. Future Work
Future work will proceed in two main directions: expanding the experimental scope using automated methods and developing new defensive recommendations.
First, the experimental baseline will be expanded. This includes incorporating modern languages popular in malware development, such as Go, Rust, and Python. More importantly, we plan to leverage Large Language Models (LLMs) to automate the exploration of this expanded scope. We will task LLMs to generate functionally equivalent loaders using different coding styles, obscure libraries, and compiler-specific optimizations to systematically discover the most evasive language and build combinations. This expanded testbed will also be complemented by deep behavioral instrumentation, performing fine-grained tracing of the system call sequences and execution timing profiles for each variant to identify precisely why certain builds evade detection.
Second, based on our findings, we suggest specific technical approaches for defensive development, directly addressing the need for expanded practical recommendations. For behavioral analysis, our study confirmed that the canonical API sequence (
Conceptualization, T.-H.L. and G.-C.H.; methodology, T.-H.L. and G.-C.H.; software, T.-H.L. and G.-C.H.; validation, T.-H.L. and G.-C.H.; formal analysis, T.-H.L. and G.-C.H.; investigation, T.-H.L. and G.-C.H.; resources, T.-H.L. and G.-C.H.; data curation, T.-H.L. and G.-C.H.; writing—original draft preparation, T.-H.L. and G.-C.H.; writing—review and editing, T.-H.L.; visualization, T.-H.L. and G.-C.H.; supervision, T.-H.L. All authors have read and agreed to the published version of the manuscript.
Not applicable.
Not applicable.
Data is contained within the article.
The authors declare no conflicts of interest.
Footnotes
Disclaimer/Publisher’s Note: The statements, opinions and data contained in all publications are solely those of the individual author(s) and contributor(s) and not of MDPI and/or the editor(s). MDPI and/or the editor(s) disclaim responsibility for any injury to people or property resulting from any ideas, methods, instructions or products referred to in the content.
Figure 1 Canonical flowchart of the shellcode loader logic implemented in C, C#, Fortran, and COBOL.
Figure 2 Generation of the 64-bit shellcode using msfvenom.
Figure 3 Using xxd to find the pattern.
Figure 4 Address-taking (
Figure 5 Data section and hex dump show widened elements with zero padding (
Figure 6 Dissembling the sample in COBOL programming language.
Figure 7 A comparison of different syntactic representations for the same shellcode payload in C, C#, Python, and COBOL.
Comparative analysis of programming languages in malware evasion (Related Work Summary).
| Language Family | Key Languages | Influence on Malware/Evasion Mechanism |
|---|---|---|
| Low-Level (Traditional) | C, C++ | Direct memory access, hardware manipulation, and facilitating techniques like packing, polymorphism, and self-modifying code. |
| High-Level (Managed) | Python, C#, Java | Abuse of powerful libraries and frameworks for dynamic code loading; high-level constructs for rapid development. |
| Modern (Systems) | Rust, Go | Binaries are inherently difficult to reverse engineer; memory safety features (Rust) and cross-platform capabilities (Go) are leveraged by APTs. |
| Frameworks/Scripting | PowerShell, .NET | Heavily used for in-memory execution, fileless attacks, and rapid development of ransomware and targeted attack tools. |
| Advanced Obfuscation (Payload-Focused) | (Used in C# Loaders) | Advanced strategies to fragment payloads (Fountain Codes) or randomize shellcode (Chaotic Encryption) to bypass static analysis. |
Comparison of antivirus detection for various programming languages.
| Vendors | C | C# | Fortran | COBOL |
|---|---|---|---|---|
| AdAware | Generic.ShellCode.Marte.4.A297A5B3 | Generic.ShellCode.Marte.4.DD28A0DB | DeepScan:Generic.ShellCode.Marte.4.36EC5B27 | - |
| Arcabit | Generic.ShellCode.Marte.4.A297A5B3 | Generic.ShellCode.Marte.4.DD28A0DB | Dump:Generic.ShellCode.Marte.4.36EC5B27 | - |
| Avast | Win32:MsfShell-V | Win32:MsfShell-V | - | - |
| AVG | Win32:MsfShell-V | Win32:MsfShell-V | - | - |
| Avira | - | TR/Rozena.Gen | - | - |
| Bullguard | Win32:MsfShell-V | Win32:MsfShell-V | - | - |
| ClamAV | - | Win.Malware.Metasploit-10022275-0 | - | - |
| Emsisoft | Generic.ShellCode.Marte.4.A297A5B3 | Generic.ShellCode.Marte.4.74DE52F2 | Dump:Generic.ShellCode.Marte.4.36EC5B27 | - |
| G Data | Generic.ShellCode.Marte.4.A297A5B3 | Generic.ShellCode.Marte.4.74DE52F2 | Dump:Generic.ShellCode.Marte.4.36EC5B27 | - |
| Immunet | - | Win.Malware.Metasploit-10022275-0 | - | - |
| Microsoft Defender | Trojan:Win64/Meterpreter.B | Trojan:Win64/Meterpreter.B | - | - |
| NOD32 | - | MSIL/Rozena.FW.gen trojan | - | - |
| Norman | Win32:MsfShell-V | Win32:MsfShell-V | - | - |
| SecureAge APEX | - | - | - | - |
| VirITExplorer | - | Trojan.Win32.MSIL_Heur.A | - | - |
| ZoneAlarm | HEUR:Trojan.Win32.Generic | HEUR:Trojan.Win32.Generic | HEUR:Trojan.Win32.Generic | - |
Appendix A
Malware scan results from Kleenscan.
| Programming Language | Scan Result URL (All of URLs Are Accessed on 4 November 2025) |
|---|---|
| C | |
| C# with .NET 6.0 | |
| Fortran | |
| COBOL | |
© 2025 by the authors. Licensee MDPI, Basel, Switzerland. This article is an open access article distributed under the terms and conditions of the Creative Commons Attribution (CC BY) license (https://creativecommons.org/licenses/by/4.0/). Notwithstanding the ProQuest Terms and Conditions, you may use this content in accordance with the terms of the License.