Skip to main content
As a seasoned Linux person (and of course a security researcher :)), I never really wanted to dig into Windows systems. Lately that has started to change. For some reason, I feel this sudden burning curiosity, so this is the start of a short, practical series where I map what I already know from the Linux kernel and userland onto how Windows actually works.
My main goal across these four phases is mapping my Linux knowledge to Windows internals, and being honest about where that mapping breaks.
Before any of the deep internals, we need one mental model that colours everything else. Linux lives by “everything is a file”. Windows does not. Windows leans on “everything is an object”, and we will see that idea leak into places we would not expect, starting with the shell. We come back to it properly in Phase 4.

A graphical shell that grew a kernel

The first version of Windows was a graphical operating system shell sitting on top of MS-DOS. That framing helps: early Windows was closer to a desktop environment bolted onto a separate OS than to a kernel in its own right. The Windows we care about today runs on the NT kernel, but the historical shape still shows: a lot of the system is reached through tooling and a GUI rather than through plain files in a tree. So the starting mapping is simple: kernel, userland, and a shell I trust. On Windows the shell is the first thing that feels different, so that is where we start.

PowerShell is not bash with different command names

It is tempting to read PowerShell as “bash, but Microsoft”. That mapping breaks almost immediately. In bash, the pipeline carries text. Every tool reads bytes, writes bytes, and we spend our lives in grep, awk, and cut reassembling structure out of that text. In PowerShell the unit is the cmdlet, a lightweight command for the PowerShell environment, and a cmdlet does not return text. It returns a Microsoft .NET object to the pipeline.
  • cmdlet: a small Verb-Noun command (like Get-Process) backed by a .NET class.
  • the pipeline: passes structured objects with properties and methods, not a flat byte stream.
That is the “everything is an object” philosophy showing up before we even touch the kernel.
When something looks like text in PowerShell, it is usually an object that printed itself. The question stops being “which column do I awk?” and becomes “which property do I select?”.

WMI: one query interface for the whole machine

On Linux, asking the system about itself means a scattered toolbox: ps for processes, systemctl for services, dmidecode for firmware, uname and /etc/os-release for the OS, plus a lot of reading under /proc and /sys. Windows centralises much of that into WMI (Windows Management Instrumentation). One classic way in is the Get-WmiObject cmdlet, which queries Win32_* classes:
  • Win32_Process: process listing — the ps view.
  • Win32_Service: service listing — the systemctl list-units view.
  • Win32_Bios: firmware information — roughly dmidecode.
  • Win32_OperatingSystem: OS version and build — roughly uname -a plus /etc/os-release.
Because these are objects, the -ComputerName parameter lets us aim the same query at another machine over the network, without opening a shell on it. The instinct is ssh host 'command'; here the query itself travels over RPC/DCOM and comes back as objects.
One honest note: Get-WmiObject is the old door. Modern Windows and PowerShell push us to Get-CimInstance, which queries the same classes over WS-Man instead of legacy DCOM. The mental model is identical; only the transport changed.
For a security researcher this is the first real recon surface. Get-CimInstance Win32_Process -ComputerName target is process enumeration on a remote host, and remote WMI is something both attackers and defenders watch closely.

RDP: the GUI is the remote shell

On Linux, “remote access” defaults to SSH: a text session on port 22, usually with sshd already running. Windows inverts both halves of that. The default remote model is RDP (Remote Desktop Protocol). Instead of a text shell, it ships the actual graphical desktop to us. The server listens on port 3389.
Two differences matter here:
  • RDP is graphical first. The remote experience is the desktop, not a pipe of text.
  • RDP is not allowed by default. Unlike a box already running sshd, a fresh Windows install does not accept remote desktop until someone turns it on.
So when we find 3389 open on a Windows host, that is a deliberate decision someone made. Normally I read an open port as “a daemon is listening”; here it also means “remote desktop was enabled”, which is a meaningful fact during recon.
That is enough to move around and talk to a Windows box. In Phase 2 we walk the filesystem and see how to read the C:\ tree.