A chain of scripts and downloads ran on the Lumma victim’s machine before the credential thief did. An infostealer may then complete its work in a single run, but an attacker who wants remote control needs the installed code to resume after every reboot. A startup service can provide that repeated execution.
Malware can also change the software that administrators use to search for and inspect it. An altered file-listing utility can omit a filename, and a kernel driver can conceal the same file from many utilities at once, so a defender inspecting that machine may be relying on software the attacker has already changed.
We continue the malware lifecycle with delivery: the components that carry a payload from its first execution to its final form. Persistence follows: how malware registers itself to run again, from startup items and services down to boot code and firmware, and how hardware verifies a machine’s startup. Concealment with rootkits and malware on mobile devices follow. Part 4 covers triggers, communication with an operator, payloads, propagation, and detection.
Delivery: Droppers, Loaders, and Stages
A malicious program has to reach execution and accomplish some objective. Those jobs can be implemented in a single file or distributed across several programs, scripts, and services.
Why Delivery Uses Stages
The Lumma chain from the April 2025 campaign had several components, each of which did one job and started the next:
-
The command the visitor pasted ran
mshta, a legitimate Windows utility that executes scripts. -
mshtaretrieved JavaScript from an attacker-controlled server and ran it. -
The JavaScript launched PowerShell, the Windows scripting and administration environment.
-
PowerShell downloaded additional PowerShell code, which in turn downloaded the Lumma executable.
-
The executable’s loader ran the payload in the memory of a legitimate process.
The visitor ran one command, but the credential thief arrived only at the end of that sequence.
A distributor faces a different problem from a payload developer. The distributor needs a small piece of code to execute under the permissions available at the entry point, while the payload may need additional libraries, configuration, or capabilities that do not belong in that first piece.
Multi-stage delivery divides those responsibilities across a sequence of components. An initial component starts a later component, which may retrieve configuration or another payload.
Staging provides several practical advantages. A small initial component can fit within an attachment or script; a later component can be selected for the operating system and architecture discovered on the target; and a network-fetched payload can be replaced without changing the original lure. Separating the delivery component from the final objective also allows the same access to be sold to different operators. Legitimate installers use staging for the same reasons: an installer can choose a package for the machine’s architecture and fetch an updated version from a server.
Staging also creates dependencies. Each required download is a step that defenders can interrupt: if the server is unavailable, the chain may stop before delivering its payload, and new process launches and network connections give defenders more events to inspect.
Later stages can execute directly in memory, but staging does not require that choice. A staged attack may write several files, and a single program may run a payload entirely from memory.
A delivery stage is also not the same as a stage of an intrusion. Every component in the Lumma chain, from the pasted command to the loader, accomplished only execution, which is getting the credential thief to run. Whether a payload then arranges to survive a reboot or contacts an operator is a separate job. Persistence is the next stage, and we cover communication with an operator in Part 4. A single program can do all of those jobs in one run, while a chain of several downloads can accomplish only the first. An infostealer, for example, may collect a browser profile and exit without creating any startup entry.
Droppers and Downloaders
A first component often has only enough functionality to install the component the attacker actually wants.
A dropper contains another payload and places it on the target. The embedded payload might be stored inside the dropper as ordinary data, as an archive, or in encoded form, and packaging the two together allows delivery even if the machine cannot immediately reach another server.
A downloader retrieves a later component from a network location. The initial file can remain small, and the operator can change the downloaded component independently, but the network request also gives defenders an opportunity to block delivery before the next component runs.
The two are not exclusive. A program can contain one embedded component and download another, and security companies may classify it as a dropper in one report and a downloader in another.
A downloader that runs under a restricted account inherits that restriction. Retrieving a larger payload does not grant additional authority on its own, so a later stage requires a separate exploit, credential, or previously granted permission to access protected resources.
Loaders and Process Injection
Before downloaded code can run, it has to be mapped into a process and prepared for execution.
A loader prepares and starts another component. The operating system’s normal loader maps an executable and its libraries into a process, and a malicious loader may perform related work itself, including decoding a payload and preparing code in memory. Doing so lets it avoid storing the final payload as an ordinary executable file.
Process injection places code inside another running process and makes that process execute it. One form, process hollowing, starts a legitimate program in a suspended state, replaces its code in memory with the malicious code, and then resumes it. The process keeps the legitimate program’s name, and the signed file on disk is unchanged, but the instructions it executes are the attacker’s.
A list of processes may therefore show a familiar Windows executable even when some of its executable memory did not come from the signed file on disk. The signature authenticates the file that was signed, but it does not authenticate code later placed in the process.
Injection also has an authority requirement. A process cannot arbitrarily write into every other process merely because both run on the same machine, since operating system access controls and containment can restrict the target. A successful injection indicates that the attacker had or obtained the access needed for that particular process.
Executing Malware from Memory
A final payload need not be saved as an ordinary executable file, since an exploit, script interpreter, or loader can prepare its instructions directly in memory.
Fileless malware is a broad label for execution that does not depend on a conventional payload executable on disk. The term includes memory-resident payloads, interpreter-based execution, and instructions stored in configuration data. A delivery chain can begin with a file and still have a memory-only final stage, so the label does not describe every component in the chain.
Memory is volatile, so code executing only in RAM disappears at a full reboot. Persistence requires something stored elsewhere that reloads or reconstructs the code, such as a startup entry that retrieves a script, and without that mechanism the attacker has to obtain execution again. Interpreters may also leave cached scripts, command history, logs, or data written from memory to a paging file, even when the final payload was never written to disk as an executable.
Living off the land uses programs and services already present on a system for the attacker’s own purposes. PowerShell and legitimate remote-management utilities supply capabilities useful to both administrators and attackers, and this technique appears in file-based attacks as well as fileless ones.
A valid signature on an interpreter authenticates the interpreter itself, but it does not authenticate a script supplied later. Detection therefore also needs information about the script, its origin, the process that started the interpreter, and the resources accessed, since the same signed program can execute a scheduled backup or a script that steals a browser profile.
Packers
A scanner examining a file sees the bytes present before execution, and a program can arrange for those bytes to differ substantially from the instructions that eventually run.
A packer transforms an executable, commonly through compression or encryption, and includes code that restores or interprets the protected program at runtime. The visible file contains the transformed representation and the startup component, and the original instructions become available only after the program starts.
Packing is not malicious in itself. Legitimate software also uses packaging and executable compression to reduce size or protect commercial code.
The unpacking code, and any key it needs, have to be in the file. An analyst can therefore run the program in a sandbox or a debugger and inspect it after it has unpacked itself, even when a scan of the file on disk cannot see the hidden instructions.
Interpreting a Delivery Chain
The following table separates each component’s delivery role from the trust boundary it crosses in a script-based Lumma chain. The number and arrangement of components vary among campaigns:
| Component | Role in delivery | Trust boundary crossed |
|---|---|---|
| A fake verification page | Persuades the user to initiate execution. | A web page gains influence over an operating system action. |
| A command launched by the user | Starts a legitimate interpreter that retrieves attacker-selected code. | Untrusted text becomes an instruction under the user’s identity. |
| A script or intermediate program | Downloads and prepares a later component. | A network response becomes locally executable content. |
| A loader | Starts the credential-stealing payload, possibly inside another process. | The visible program identity may differ from the code executing. |
The intermediate scripts are malicious when their purpose is unauthorized execution, even though the credential thief is the component the operator actually wants.
Persistence
Malicious code may run inside a browser process while a startup entry elsewhere arranges its return. Terminating the browser process stops its execution but leaves the mechanism that restarts it intact.
Persistence allows malicious code to resume execution after an interruption, such as logout, process termination, or reboot. It usually combines stored code or configuration with an event that triggers a component to load it: a startup service can launch an executable at boot, a library can load when an application starts, and an infected template can execute when a document application opens it.
A credential thief that completes its work in a single run does not need persistence. An attacker can also exploit an unchanged vulnerability again after each reboot, which restores access through another compromise rather than through an installed startup mechanism.
Malware can register itself to run again at three layers, each requiring more access than the one before and running earlier in startup:
-
The registration points the operating system and applications already provide: services, login items, scheduled tasks, shell profiles, document templates, and library loading.
-
The boot code that runs before the operating system: the boot sector on early PCs, and the boot loader files on modern ones.
-
The firmware that runs before the boot code.
The subsections below cover each layer, and the section ends with how firmware and hardware verify the startup sequence, which is the defense against the two deepest layers.
Registering Code to Run Again
An attacker who already has execution can arrange for ordinary software to restart the malicious code. Startup configuration, application files, extensions, add-ons, scheduled tasks, and login items can all provide repeated execution without a kernel exploit.
Every persistence mechanism is an event, such as the system booting or a user logging in, plus a place where code can be registered to run when that event occurs. Each operating system offers the same events under different names. On Windows, for example, programs listed under the key HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run in the Windows registry, the database of configuration settings that Windows and its applications read, start whenever that user logs in. The table below lists the common registration points:
| Code runs when… | Windows | Linux | macOS |
|---|---|---|---|
| The system boots | Windows service | systemd unit or init script |
launchd daemon |
| A user logs in | Registry Run key, Startup folder |
Desktop autostart entry | launchd agent, login item |
| A scheduled time or event arrives | Scheduled task | cron job, systemd timer |
cron job, launchd agent |
| The user opens a shell | PowerShell profile | .bashrc, .profile |
.zshrc, .profile |
| An application starts | Office template, browser extension | Browser extension | Office template, browser extension |
| A program loads a library | DLL search-order hijacking | LD_PRELOAD, library path hijacking |
Dynamic library hijacking |
The privileges a registered program receives depend on the account configured for it and on who may write the registration point. A service or daemon usually runs as the system, and a scheduled task runs in whatever security context it was configured with, which may be an ordinary user or an administrator. A login item, shell profile, or application template belongs to one user, runs as that user, and can be written by that user, so malware running as that user can register itself there without any further privilege.
In library hijacking, a program loads a library by name, and the attacker places a malicious library with that name in a directory the program searches first. Windows calls this DLL search-order hijacking, a DLL being the Windows form of a shared library.
Document applications have their own loading mechanisms. A macro virus can be stored in a template that the application loads when opening otherwise unrelated documents, and a scan limited to operating system startup entries misses that activation source.
Deleting a payload but leaving the downloader’s scheduled task can cause another download. Removing a startup entry does not stop a process that is already running. Cleaning the machine requires inspecting both the running program and the settings that will start it again.
Infecting Firmware and Boot Code
Malware that runs before the operating system can change code that the system will later execute. Each of those attacks replaces one step of the normal startup sequence, so we go through that sequence before the attacks.
At power-on, a PC begins executing firmware, software in nonvolatile storage that initializes or controls hardware. The platform firmware initializes the hardware needed for startup and starts a boot loader, a program that loads the operating system kernel into memory and transfers control to it. The kernel then initializes the operating system and starts the user-space processes that launch services and applications.
On a modern PC, the Unified Extensible Firmware Interface (UEFI) specifies the interface between platform firmware and the operating system’s startup environment. It succeeded the BIOS, the older PC firmware interface. An attacker can target the firmware itself or the boot-loader files on disk, and either provides execution before the kernel’s protections and ordinary security software are active.
Infecting Boot Sectors
Early PCs began startup by executing a small program from a disk’s boot sector (the first block on a disk). A boot sector virus replaces or modifies the boot sector program so its own instructions run first, and, once resident in memory, it can infect other disks the machine accesses.
An infected floppy disk could activate the virus when a PC attempted to boot from it, even if the disk did not contain a working operating system, because the firmware executed the infected boot sector before discovering that the remaining startup files were missing. Cleaning application directories left the infected boot code intact.
Installing Bootkits and Firmware Implants
A bootkit modifies or abuses the boot process to obtain early execution and maintain access, and its files may be on the disk partition used for startup. A firmware implant modifies code or data in firmware storage itself. Replacing a disk can eliminate a disk-based bootkit while leaving a firmware implant untouched.
Early execution lets a bootkit modify later code in memory, including code that otherwise has a valid signature on disk. The attacker still needs permission to modify the startup components or a vulnerability that permits the change. Running a downloaded application does not automatically grant that authority.
Verifying the Boot Process
A boot loader can look legitimate on disk while containing an unauthorized change, and no software that runs after it can be trusted to report that change. Modern platforms answer this with mechanisms in the firmware and in a hardware component, and we cover them in three steps:
-
Checking, before each boot component runs, that it is permitted to run.
-
Recording what actually ran, in a place the operating system cannot rewrite.
-
Letting another system verify that record.
The mechanisms below are the PC versions. Macs, iPhones, and Android phones each have their own versions of the same three steps under different names.
Blocking Unauthorized Boot Code with Secure Boot
The next component in the boot sequence should not gain execution merely because it occupies the expected file or disk partition.
Secure Boot verifies each boot component against an authorization policy before permitting it to execute. It is defined in the UEFI specification and has been in the firmware of nearly every PC since 2012, when Microsoft began requiring it for Windows certification. It belongs to the firmware rather than to any operating system, and Linux distributions boot under it as well. The firmware contains trusted public keys or certificates and a list of revoked components, so verification can accept code signed by an approved authority while rejecting revoked components.
A signature authenticates the signed code, but that code can still contain a vulnerability. Installing a fixed boot loader does not prevent an attacker from supplying an older signed copy if policy still permits it, so defending against that replacement also requires revoking the vulnerable boot components.
Revocation can also affect legitimate recovery media that contains an older boot loader. Administrators have to update that media before relying on it to recover a machine whose policy rejects the old component.
Recording Boot Measurements with a TPM
Secure Boot decides whether code may run, but it does not record what ran. A service that later requests a startup report from the operating system is relying on a system that may already be compromised, so a second mechanism keeps that record in hardware the operating system cannot rewrite.
A Trusted Platform Module (TPM) is a small protected cryptographic component, either a separate chip or a part of the processor, that generates keys, signs data, and holds a set of integrity registers. Software can request a signature with a key the TPM holds, but it cannot read the key out.
Measured boot uses those registers to record the startup sequence. Each stage of the boot hashes the next stage before handing control to it: the firmware hashes the boot loader, the boot loader hashes the kernel, and the kernel hashes the drivers it loads first. Each hash is sent to the TPM, which folds it into one of those registers (the specification calls them Platform Configuration Registers, and the formula below uses PCR for one). The TPM does not examine the code itself and does not decide whether it is malicious. It only records what it was given.
The registers are useful because of how they are updated. A register cannot be set to a chosen value. It can only be extended, which replaces its contents with the hash of the old contents together with the new measurement:
\[\mathrm{PCR}_{new} = H(\mathrm{PCR}_{old} \mathbin{\Vert} m)\]
Here \(H\) is a cryptographic hash function, \(m\) is the new measurement, and \(\Vert\) is concatenation. This is the same hash chain used for hash pointers and blockchains, kept inside the chip. The final value depends on every measurement and on their order, so malware that loads late in the boot cannot remove the record of itself, and a compromised kernel cannot rewrite the record of what loaded before it.
The record is only as good as the code that did the measuring, since the TPM records whatever it is given. That is why the first measurement comes from firmware that ordinary software cannot modify. The record also covers only what was measured. Code that is never measured leaves the registers unchanged.
Using the Measurements
The recorded values have a local use and a remote one.
Locally, a disk-encryption key can be sealed to a set of expected register values, meaning the TPM will release the key only when the registers hold those values. BitLocker, the Windows disk encryption system, works this way. If a change affects the measurements covered by BitLocker’s validation policy, the TPM withholds the key and the disk stays encrypted until an administrator intervenes with a recovery key. Which measurements count is a configuration choice, made so that ordinary updates to signed boot code do not force recovery.
Remotely, remote attestation lets a machine prove its boot state to another system, such as a company service deciding whether to admit a device:
-
The service sends the device a fresh random challenge, so an old report cannot be replayed.
-
The device requests a signature from its TPM over the current register values together with the challenge, using a key that never leaves the TPM. The operating system relays the report but cannot alter it without breaking the signature.
-
The service checks the signature with the TPM’s public key, which it recorded when the device was enrolled, and then compares the reported values with the values it expects for approved boot loaders, kernels, and settings.
For example, suppose an attacker replaces a company’s boot loader with an older signed version that Secure Boot still permits. Secure Boot accepts it, but its hash differs, so the register value differs and the service rejects the device. The signature on the report is still valid, because the TPM is reporting what ran. It is the content that fails the check. Checking the signature and comparing the measurements are separate steps, and a valid signature alone does not approve a device.
Updating a boot component changes its hash, so the service needs the expected values for every approved version rather than treating every change as an attack. A kernel exploit that runs after startup leaves the boot measurements unchanged, so detecting it requires watching what the system does afterward, which we cover in Part 4 under malware detection.
Concealing Malware with Rootkits
A malicious file can remain on disk while directory listings omit it, because the attacker changed the software that provides the listings rather than removing the file.
A rootkit conceals unauthorized activity or access by altering system programs, libraries, or the kernel. It can hide files, processes, connections, and configuration changes, and it may hide a backdoor while a startup service arranges for that backdoor to launch again.
Altering User-space Programs and Libraries
A user-mode rootkit changes programs or libraries outside the kernel. For example, a modified ls can omit a filename, while a modified ps can omit a process. The original Unix rootkits were collections of replacement utilities and modified login programs that accepted a hidden credential. Installing them usually required root access, which is where the name comes from.
Programs that use shared libraries obtain many of their functions from those libraries. Library interposition substitutes one implementation of a function for another. On Unix-like systems, the LD_PRELOAD environment variable instructs the dynamic loader to load a library before ordinary dependencies, allowing a function in that library to replace the usual implementation. For example, a malicious directory-reading function can remove selected filenames before returning the results to the calling program.
The loader ignores LD_PRELOAD for programs that run with more privilege than the user who started them, so an ordinary user cannot gain root access by supplying a replacement library to a privileged utility.
If the kernel has not been changed, it still maintains the underlying process and file information, so a trusted program that avoids the substituted utility or library can expose the discrepancy. For persistence, the attacker also has to ensure the library loads again, since a one-time change to a process’s environment disappears with that process.
Hiding Activity in the Kernel
A kernel-mode rootkit changes the operating system itself, often through a driver or kernel module. Instead of modifying one file-listing program, it can filter the directory records returned through kernel interfaces, so multiple unmodified utilities then display the same incomplete listing.
Another technique alters kernel data structures. A rootkit can remove a process from a list used for ordinary process enumeration while leaving it scheduled to run, but its processor time, memory usage, or network activity may then reveal it, even though the normal process listing omits it.
Kernel execution normally requires authority to load a driver or a vulnerability that permits kernel modification, and a downloaded application running as an ordinary user does not automatically have that access. Once the kernel is compromised, security software that depends on its reports can receive falsified information or be disabled.
Defending against Rootkits
A rootkit is found by looking from somewhere it has not changed. For a user-mode rootkit, that can be a trusted copy of the altered program or an inspection tool that does not load the altered library.
For a kernel rootkit, the view has to come from outside the running operating system: trusted recovery media can inspect the disk without starting the installed kernel, and cross-view detection compares what the kernel’s interfaces report with what the disk and registry structures actually contain. Microsoft’s RootkitRevealer works this way, and a file that a directory listing omits but the file system’s metadata still records is a discrepancy to investigate. Memory is lost at shutdown, so an investigation may also need a copy of memory captured while the machine is still running.
Driver signing restricts what may load into the kernel, but it does not prove a driver is harmless. Stuxnet used drivers signed with certificates stolen from Realtek and JMicron, companies that make computer components. An attacker can also load a legitimate signed driver and exploit a vulnerability in it, which is why Microsoft maintains a blocklist of known vulnerable drivers whose signatures are still valid.
Malware on Mobile Devices
Phones isolate apps and mediate access to shared resources through permissions, as described in the containment notes. Mobile malware can misuse a granted capability without defeating that isolation: an app permitted to read contacts can copy contacts, and an app with notification access can observe information exposed there.
Malware can arrive as a deliberately malicious app or as a trojanized application, a useful program altered to include hidden behavior. A compromised update or dependency can add that behavior after an initially benign installation, and the attacker can exploit the app’s useful purpose to obtain permission for unrelated collection.
On Android, an accessibility service assists users with disabilities by reading screen content and operating interface controls. Granting those capabilities to a malicious service can let it observe or interact with other apps without a sandbox escape. App-store review attempts to reject such behavior before distribution, while the sandbox continues to restrict the app’s other access.
System-level spyware follows a different route. An exploit chain can compromise a messaging component and escape its sandbox without a normal installation or permission decision, as the 2021 delivery of Pegasus through iMessage did: it began with an integer-overflow vulnerability in an image decoder rather than an app installation.