Measuring a Broadcom chip pad with no voltage detected at the circuit connection
A Broadcom chip is being tested at a circuit pad connected to one of its many pins after a failure was detected. Measurements show no voltage entering or leaving the affected area, indicating a completely inactive section of the circuit that requires further diagnosis. This repair image is an independent work sample and is not an illustration of the educational subject discussed below.

Understanding Control Flow Guard

A Program Normally Knows Where Its Instructions Should Go Next

Software execution follows an intended path.

Functions call other functions, branches select different sections of code, and the processor moves through instructions according to decisions made by the program. Although that path can become extremely complicated, legitimate software is not supposed to jump randomly to arbitrary locations in memory.

Attackers learned that corrupting this path could turn an ordinary software bug into something much more dangerous.

Changing Data Can Eventually Change Execution

A memory corruption vulnerability becomes especially serious when an attacker can manipulate information that influences where the processor will execute code next.

A Buffer Overflow Could Reach Something the Program Never Intended to Change

Programs reserve areas of memory for the information they expect to process.

If vulnerable software accepts more data than the allocated space can safely contain, the excess may overwrite neighboring memory. What gets damaged depends on the layout of the program and the vulnerability involved.

Sometimes the overwritten information can influence program control.

Writing Beyond a Buffer Can Cross a Security Boundary

A buffer overflow is not merely a case of storing too much information. If adjacent control data can be modified, the error may provide an attacker with a way to influence execution.

Some Memory Locations Tell a Program Where a Function Can Be Found

Programs do not always call functions through fixed destinations embedded directly in the instruction stream.

They can also use function pointers and other indirect-call mechanisms. Instead of saying that execution must always go to one predetermined address, the program retrieves the destination from data available while it is running.

That flexibility is useful, but corrupted destination information can become dangerous.

An Indirect Call Trusts a Destination Determined at Runtime

If an attacker can alter the value used by an indirect function call, vulnerable software may attempt to transfer execution somewhere the original developer never intended.

Redirecting Execution Could Turn a Bug Into an Exploit

Corrupting memory alone does not necessarily give an attacker useful control.

The attacker needs the corruption to influence the program in a predictable way. Redirecting an indirect call can provide that opportunity because the processor may begin executing instructions at an attacker-selected location.

The normal control flow has been hijacked.

The Vulnerability Opens the Door but Control Flow Determines Where It Leads

Many exploit techniques depend not only on corrupting memory but on converting that corruption into control over the sequence of instructions executed by the processor.

DEP Made Data Memory a Less Convenient Place to Execute Code

Data Execution Prevention helped prevent software from executing instructions from memory regions intended only to contain data.

This disrupted straightforward attacks in which malicious machine code was placed into writable memory and execution was redirected directly into that injected code.

Attackers adapted by looking for code that was already executable.

Blocking New Code Did Not Eliminate Existing Code

Even when data pages cannot be executed, legitimate executable instructions remain inside the application and its loaded libraries, giving attackers another resource to target.

Randomized Memory Layouts Removed Predictable Addresses

Address Space Layout Randomization changed where important executable components were placed in memory.

An exploit that depended on a fixed address could therefore become unreliable because the desired instructions might appear somewhere different when the program or computer was restarted.

Again, the attack became harder rather than impossible.

Unpredictable Location Is Different From Invalid Destination

ASLR makes useful code more difficult to locate reliably. It does not by itself establish whether an indirect call is logically supposed to reach a particular executable address.

Was This Actually a Valid Place for an Indirect Call to Go?

Control Flow Guard added another layer to exploit mitigation.

Instead of focusing only on whether memory was executable or where code happened to be located, CFG could verify that the destination of a protected indirect call belonged to the set of locations considered legitimate call targets.

The destination needed more than executable memory. It needed validity.

Executable Did Not Automatically Mean Acceptable

Control Flow Guard narrows the locations that protected indirect calls are permitted to reach, making arbitrary redirection more difficult even when an attacker finds executable code in memory.

Valid Function Targets Could Be Identified Before the Program Ever Ran

CFG combined compiler support with runtime enforcement.

When developers compiled compatible software with Control Flow Guard enabled, the compiler analyzed the application’s indirect-call behavior and identified functions that could legitimately serve as destinations.

That information became part of the protected binary.

The Developer Did Not Have to Handwrite Every Check

Visual Studio could instrument compatible C and C++ software with Control Flow Guard during compilation and linking, allowing the toolchain to generate the information and checks required by the mitigation.

The Program Could Verify the Destination Before Committing to the Jump

CFG instrumentation adds lightweight checks around protected indirect calls.

Before control is transferred through the runtime-selected destination, Windows can determine whether that destination is recognized as a valid target for the process.

An unexpected destination can therefore be caught before execution continues there.

The Dangerous Jump Could Be Stopped at the Last Moment

Even if memory corruption changes an indirect-call destination, CFG can intervene before the processor follows that corrupted value into an invalid target.

The Operating System Knew Which Targets Were Considered Valid

The compiler supplied information needed for CFG, but runtime enforcement required operating-system support.

Windows maintains state representing valid indirect-call targets and provides the logic used to evaluate protected calls while the application is running.

The mitigation therefore spans both the program and the platform beneath it.

Compiler

Analyzes indirect calls, identifies legitimate targets, and inserts the instrumentation required for Control Flow Guard checks.

Windows

Maintains runtime information about valid call targets and verifies protected indirect-call destinations before execution continues.

Windows Could Terminate the Application Instead of Following the Corrupted Pointer

If a CFG-protected indirect call attempts to reach an invalid destination, continuing execution could allow an exploit to proceed.

The safer response is to stop the affected process. Windows can terminate the application when the Control Flow Guard check fails rather than allowing the suspicious transfer of execution.

The crash becomes preferable to compromise.

Stopping the Program Is the Protection Working

From the user’s perspective, sudden application termination can look like a failure. From the security perspective, terminating a process can be the correct response when its control flow has reached a state associated with exploitation.

The Buffer Overflow Could Still Exist in the Program

Exploit mitigation and vulnerability removal are different things.

If software contains a programming error that allows memory corruption, enabling CFG does not rewrite the vulnerable code or make the underlying defect disappear. Instead, it attempts to prevent certain exploitation techniques from converting that defect into arbitrary execution.

The bug still deserves a patch.

Mitigation Is Not a Substitute for Fixing the Code

Control Flow Guard can interfere with exploitation of memory corruption, but developers should still correct the vulnerability responsible for the corruption whenever a fix is available.

The Protection Did Not Need to Know Which Bug an Attacker Would Find

Traditional vulnerability patches address specific defects after those defects have been identified.

An exploit mitigation works at a more general level. CFG focuses on suspicious control-flow behavior associated with exploitation rather than requiring advance knowledge of the exact vulnerability that produced the corrupted destination.

That makes the mitigation valuable against classes of attack.

The Guard Could Be Present Before the Vulnerability Was Discovered

A CFG-enabled application can benefit from indirect-call protection even when the particular memory corruption bug being exploited was unknown when the software was compiled.

Attackers Could Face Several Obstacles Instead of One

Modern exploit resistance rarely depends on a single protection.

DEP can restrict execution from data memory. ASLR can make useful code locations unpredictable. Stack protections can detect certain forms of memory corruption. CFG can restrict destinations available to indirect calls.

Each layer interferes with a different part of the exploitation process.

DEP and ASLR

Complicate where attackers can execute code and how reliably they can locate useful executable instructions in memory.

Control Flow Guard

Complicates attempts to redirect protected indirect calls toward destinations that are not recognized as legitimate targets.

Existing Instructions Could Be Rearranged Into an Attack

When executing injected code became more difficult, attackers increasingly relied on instructions already present in executable memory.

Code-reuse techniques can chain existing instruction sequences together to accomplish operations the original program never intended. This allows an attack to work within memory that is already executable.

Preventing arbitrary control transfers therefore became increasingly important.

The Attacker Did Not Always Need to Bring New Instructions

If existing executable code can be reached in a carefully controlled sequence, an attacker may be able to construct malicious behavior from pieces of software already loaded into memory.

CFG Was Not a Complete Map of Every Possible Transfer

Programs change execution through several mechanisms.

Control Flow Guard was specifically designed to protect important indirect-call behavior. It did not mean that every branch, return, or conceivable control-flow transition in every application suddenly received identical protection.

The scope of the mitigation matters when evaluating what it can prevent.

Control Flow Guard Is Not Complete Control Flow Integrity

CFG significantly restricts protected indirect-call destinations, but it should not be interpreted as proof that every possible control-flow manipulation technique has been eliminated.

An Old Application Did Not Automatically Gain Full CFG Instrumentation

Control Flow Guard depends on information and checks inserted when compatible software is built.

Applications compiled without CFG support do not suddenly acquire the same instrumentation merely because they run on a CFG-aware version of Windows. Developers and software vendors therefore played an important role in adoption.

The operating system could provide the mechanism, but applications needed to participate.

Platform Support and Application Support Are Different

A computer can run an operating system capable of enforcing Control Flow Guard while individual applications still vary according to whether their binaries were compiled and linked with CFG support.

Adoption Did Not Require Every Library to Change at Once

Software ecosystems rarely migrate to a new security technology simultaneously.

CFG-enabled code can operate alongside code that was not compiled with the mitigation. This compatibility allowed developers to introduce protection incrementally rather than waiting for every dependency to support it.

The tradeoff is that unprotected code can leave gaps.

Partial Protection Is Still Partial

An application containing a mixture of CFG-enabled and non-CFG code may receive useful protection, but code that lacks the instrumentation does not gain the same indirect-call enforcement.

The Protection Was Not Merely an Option for Outside Developers

Microsoft integrated Control Flow Guard into important Windows software.

Windows 10 binaries were built with the technology enabled, and Microsoft also used CFG in components such as its browsers and security tooling. The mitigation therefore became part of Microsoft’s own effort to make exploitation more difficult across the platform.

The compiler feature had operating-system consequences.

The Toolchain and the Operating System Were Designed Together

CFG combined information generated while software was compiled with runtime enforcement provided by Windows, allowing the development tools and operating system to participate in the same mitigation strategy.

A Security Check Performed Constantly Had to Be Fast

Indirect function calls occur during ordinary application execution.

If every protection check introduced substantial delay, developers would face pressure to disable the feature in performance-sensitive software. CFG was therefore designed as a highly optimized mitigation with lightweight runtime checks.

Security needed to remain practical during normal use.

Protection That Is Too Expensive Is Difficult to Deploy Broadly

Exploit mitigations intended for widespread use must balance stronger validation with sufficiently low overhead that applications can keep the protection enabled during everyday operation.

The Protection Left Evidence Inside the Executable

Microsoft development tools can inspect executable headers and load-configuration information.

A binary built with Control Flow Guard contains indicators showing that it was instrumented and includes the information required for valid indirect-call targets. Developers can therefore verify that the expected protection made it into the finished program.

Security configuration could be checked rather than assumed.

Verify the Finished Binary

Build settings may express the developer’s intention, but examining the resulting executable provides stronger confirmation that Control Flow Guard instrumentation and target information are actually present.

Application Termination Did Not Automatically Prove an Attack

CFG is intended to stop invalid control transfers, but abnormal program state can have different causes.

Software defects, memory corruption from faulty hardware, incompatible components, and malicious exploitation can all produce serious failures. A terminated process therefore requires investigation rather than an immediate conclusion about attacker activity.

The security mechanism identifies a dangerous condition, not necessarily the motive behind it.

Security Failure and Hardware Failure Can Look Similar From the Outside

Unexpected application termination should be evaluated with crash information, event logs, software history, memory diagnostics, and other evidence before deciding whether the cause was exploitation, defective code, or unstable hardware.

Not Every Damaged Pointer Came From an Attacker

Physical memory stores the same program data that security mitigations are trying to protect from malicious manipulation.

If RAM is defective or the memory subsystem is unstable, bits can change unexpectedly and applications may crash in ways that resemble software corruption. This is one reason hardware diagnostics remain important when a computer produces unexplained failures across unrelated applications.

Security and hardware reliability meet in the same memory.

Repeated Random Crashes Deserve Hardware Testing

When unrelated programs fail unpredictably and software repair does not explain the pattern, memory testing and broader hardware diagnostics can help distinguish physical instability from an application-specific defect.

An Exploit Had to Survive More Conditions Before It Became Useful

Security mitigations do not need to make exploitation mathematically impossible to provide value.

If an attacker must defeat memory randomization, execution restrictions, stack protections, control-flow validation, and other defenses before reaching useful code execution, development becomes more complicated and less reliable.

Every additional obstacle raises the cost of the attack.

Making Exploitation Unreliable Is Itself a Defense

An exploit that crashes frequently, depends on narrow conditions, or requires additional vulnerabilities is less useful to an attacker than one that reliably turns a single memory corruption bug into code execution.

Control Flow Was No Longer Something Windows Had to Trust Blindly

Before mitigations such as CFG, a processor following a corrupted indirect destination might simply execute whatever valid executable address the program supplied.

Control Flow Guard added knowledge about which destinations were legitimate for protected calls. That transformed part of the application’s intended structure into something Windows could enforce at runtime.

The program’s design became part of its defense.

The Destination Needed to Make Sense to the Program

CFG makes exploitation harder by reducing the freedom an attacker gains after corrupting an indirect-call target. The program cannot simply be redirected toward any executable location the attacker finds useful.

The Shortcut an Exploit Expected Could End at a Guard

Memory corruption remains dangerous because software can still contain defects and attackers continue developing techniques for exploiting them.

Control Flow Guard addressed a particularly valuable stage of that process: converting corrupted control information into an arbitrary transfer of execution. By validating protected indirect-call destinations, Windows could terminate the program instead of obediently following an invalid pointer.

The attacker might still corrupt the address, but corruption no longer guaranteed control.

Changing where a program wants to jump is much less useful when the operating system checks whether that destination was ever supposed to be reachable.

Control Flow Guard Put a Checkpoint in Front of the Hijacked Jump

Control Flow Guard strengthened Windows against exploitation of memory corruption without needing to know which specific vulnerability an attacker would target next.

The compiler identified legitimate indirect-call targets and inserted the required checks, while Windows provided runtime enforcement. If corrupted program state attempted to redirect a protected call toward an invalid destination, the process could be terminated before the attacker obtained the execution path being sought.

The vulnerability could still exist, but one of the most valuable ways to exploit it had become harder to use.