It is common to hear statements like “Linux is more secure because it is open source” or “Windows is insecure because its users are dumb.” These explanations are popular, but they oversimplify a much deeper reality. Security is not a property that emerges automatically from openness or secrecy; it is a consequence of design assumptions, trust models, and threat environments.
This write‑up aims to move beyond surface‑level arguments and examine why Windows and Linux behave differently under attack, even though both are mature, heavily scrutinized operating systems.
Open Source ≠ Automatically Secure
A common argument in favor of Linux security is that open source allows “more eyes” to find bugs early. While transparency can help, it does not guarantee security. Vulnerabilities still exist in widely audited open‑source projects, sometimes for years. Security depends not only on visibility, but on who is motivated to look, how attackers interact with the system, and what assumptions the system makes about its users.
Availability of source code may reduce the barrier to understanding internals, but modern attacks rarely depend on source code alone. Stable interfaces, predictable behavior, and long‑term compatibility often matter more than whether the source is public.
Different Users, Different Threat Models
One of the most important differences between Windows and Linux is the assumed user model.
Linux historically evolved as a technical project, primarily adopted by developers, researchers, and later by server environments. Its security philosophy assumes a relatively competent user who explicitly controls execution and privileges. Linux generally allows users to run arbitrary programs in their own context, trusting that privilege boundaries will prevent system‑wide damage.
Windows, on the other hand, was designed as a mass‑market operating system from the beginning. Its threat model assumes non‑technical users, frequent execution of untrusted binaries, and a hostile software ecosystem. As a result, Windows implements proactive mechanisms such as SmartScreen, Defender, AMSI, and aggressive loader checks. These measures often feel restrictive, but they reflect a defensive posture shaped by user behavior and scale, not inferior engineering.
If Windows Is Closed Source, Why Is It Still Exploited?
Windows being closed source does not prevent exploitation. Attackers do not rely on leaked source code; they rely on reverse engineering, stable binary formats, documented behavior, and long‑standing ABI guarantees. The PE format, Windows loader behavior, and backward compatibility across decades make execution paths predictable and reusable.
From an attacker’s perspective, market share also matters. A larger user base means higher return on investment. This has historically made Windows a more attractive target, regardless of source code availability.
Architectural Differences in Execution and Trust
The contrast between Windows and Linux becomes clearer when examining early process initialization, before a program’s user-defined entry point is reached.
On Windows, execution begins inside the loader, not at main or even the program entry point. The Portable Executable (PE) format allows metadata-driven execution hooks that are invoked implicitly during process initialization. One such mechanism is Thread Local Storage (TLS) callbacks.
TLS callbacks are listed in the PE’s TLS directory and are executed by the Windows loader before the program entry point is invoked, and in many cases before debuggers gain full user-mode control. These callbacks are trusted by design because they are treated as part of the binary’s initialization contract.
The following example demonstrates a TLS callback executing before main:
#include <windows.h>
extern "C" void NTAPI MyTlsCallback(PVOID, DWORD, PVOID);
#pragma comment(linker, "/INCLUDE:_tls_used")
#ifdef _WIN64
#pragma comment(linker, "/INCLUDE:tls_callback_func")
#else
#pragma comment(linker, "/INCLUDE:_tls_callback_func")
#endif
#pragma section(".CRT$XLB", read)
extern "C" __declspec(allocate(".CRT$XLB"))
PIMAGE_TLS_CALLBACK tls_callback_func = MyTlsCallback;
extern "C" void NTAPI MyTlsCallback(
PVOID,
DWORD dwReason,
PVOID
)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
MessageBoxA(nullptr, "TLS CALLBACK EXECUTED", "TLS", MB_OK);
}
}
int main()
{
MessageBoxA(nullptr, "MAIN EXECUTED", "MAIN", MB_OK);
return 0;
}
When debugging this binary, TLS callbacks may execute before the debugger’s first user-visible breakpoint. Even if a debugger resolves TLS callback addresses from the TLS directory, execution may have already passed unless the debugger attaches before loader initialization.
This behavior is not accidental. Windows prioritizes backward compatibility and flexible initialization semantics, allowing binaries to register early-execution logic without requiring explicit control-flow changes.
Early Execution, DEP, and Loader-Owned State
During TLS execution, the process is still in a transitional state:
- Loader locks may be held
- Thread contexts may not be fully initialized
- Certain memory regions may not yet be executable
- The debugger’s notion of “entry” may not reflect actual execution order
Attempting to manually redirect execution (e.g., modifying RIP) during this phase often results in undefined behavior, not because TLS callbacks are fragile, but because the surrounding loader context is missing.
In the observed crash:
This occurs because execution was redirected to a memory region that is non-executable by design. DEP (NX) correctly prevents execution from heap or private memory regions, even if the original TLS callback code was modified or removed.
Importantly, nopping out a TLS callback does not restore valid execution, because the loader expects the callback to either complete or properly unwind. Once that contract is broken, subsequent execution may jump into memory that was never intended to be executable.
Linux Comparison: Explicit Roots vs Metadata Trust
Linux also provides early-execution mechanisms, such as ELF constructors (.init_array) that run before main. For example, a small C program like this:
#include<stdio.h>
int main() {
printf("Hello\n");
}
When debugging it with GDB:
gdb ./program
run
info file
_
small excercise: try to map entry point's address and segment's address and figure out what constructors are intialized before
_start.
You’ll see references to /lib64/ld-linux-x86-64.so.2 and /lib/x86_64-linux-gnu/libc.so.6. These are the loader and standard C library performing initialization—setting up the process before main is called. Unlike Windows’ TLS callbacks, Linux uses a single, linear entry path (_start) and executes constructors in a predictable, centralized order.
This doesn’t mean Linux is “simpler” or “better engineered”: it just places trust differently:
Linux loaders and constructors execute as part of an explicit startup path. Tools like GDB can intercept them early.
Windows loaders execute PE metadata-driven hooks (TLS callbacks) before the program entry point, trusting the binary’s declared intentions.
Historically, this difference affected exploitation. Linux loaders once allowed environment variables like LD_PRELOAD or files such as /etc/ld.so.preload to override shared objects, creating a wide attack surface. Modern Linux mitigations ignore these overrides for setuid/setgid binaries and enforce stricter checks, illustrating how the OS adjusts trust boundaries in response to threats.
one of the example of such
Linux provides comparable early-execution mechanisms via ELF constructors such as .init_array. However, Linux maintains a more centralized execution model, with _start acting as the explicit root of control flow.
- Windows trusts PE metadata to drive early execution
- Linux emphasizes a single, explicit entry path with additive initialization stages
These design decisions directly influence how certain attack techniques are implemented.
For example, MITRE ATT&CK documents TLS callback abuse as a Windows-specific injection vector (T1055.005), reflecting Windows’ trust in loader-executed metadata. This does not indicate a flaw, but rather a different trust boundary compared to Linux’s more centralized startup model.
And maybe next time someone says "Real hackers use Kali Linux", maybe 1337 hackers on Windows are trying to find another zero day...?
Written By: Akanksha Sawant
From: THM Nagpur Team
Disclaimer
This article reflects a practical, opinion-based exploration of how system architecture influences security in Windows and Linux. While care has been taken to ensure technical accuracy, some interpretations may be incomplete or context-dependent. Constructive corrections or clarifications are welcome.





Top comments (0)