DedSec Project

Memory Corruption Mechanics and Mitigation Analysis — DedSec Project

Memory Corruption Mechanics and Mitigation Analysis Purpose: Go beyond the introductory memory-safety module and understand how corruption changes program state, how modern mitigations…

Purpose: Go beyond the introductory memory-safety module and understand how corruption changes program state, how modern mitigations constrain impact, and how to diagnose the bug class without constructing weaponized exploits.

Learning objectives

Spatial and temporal safety

Spatial safety means an access stays within the bounds of the object it is intended to access. Out-of-bounds reads/writes violate this property. Temporal safety means the object is still alive when it is accessed. Use-after-free and double-free failures violate lifetime assumptions.

This distinction is useful because mitigations differ. Bounds-checked abstractions help spatial safety; ownership and lifetime systems help temporal safety. Some allocators add quarantine or metadata checks, but they do not turn unsafe code into memory-safe code.

Stack objects

A function may have local variables, saved registers, spill slots, alignment padding, and call metadata in or around its stack frame. Exact layout is compiler-, architecture-, ABI-, and optimization-dependent. Security analysis should therefore derive layout from the build rather than from a diagram copied from another platform.

A stack out-of-bounds write can corrupt adjacent locals or control data. But the result depends on layout and protections. Modern stack protectors can detect some corruption before a return, while shadow stacks or control-flow protections can defend control data separately.

Heap objects

The heap is managed by an allocator that maps requests to blocks and maintains metadata. Different allocators organize size classes, arenas, caches, freelists, quarantine, and metadata differently. A heap bug should be analyzed at the object-lifetime level first: which allocation created the object, who owns it, when was it freed, and which reference outlived that event?

Avoid learning allocator internals only through exploitation recipes. The durable skill is reconstructing allocation and reference lifetimes.

Integer errors as memory precursors

Many memory bugs begin before a pointer is dereferenced. A size can overflow during multiplication, be truncated into a narrower integer, change sign, or be validated in one unit and used in another. For every length, track:

The allocation and the later use must agree on the same validated quantity.

Type confusion

Type confusion occurs when memory holding one object type is interpreted as another incompatible type. In native code this can arise from unsafe casts or corrupted metadata; in managed runtimes it can arise from engine/runtime bugs. Security impact depends on what fields are subsequently treated as pointers, lengths, function references, or security state.

The defensive review question is: what establishes the type invariant, and can untrusted state violate it?

Control data versus ordinary data

Not all corruption needs to change instruction flow to be serious. Data-only corruption can change authorization flags, object identities, lengths, or policy decisions. Modern control-flow defenses therefore reduce one class of impact while leaving data integrity as a major concern.

When triaging, ask what semantic field was corrupted before asking whether control flow was hijacked.

ASLR in detail

ASLR randomizes selected virtual address locations. Its effectiveness depends on entropy, architecture, process lifetime, module configuration, memory disclosures, and whether code/data has fixed mappings. Position-independent executables and libraries allow more components to move.

An information disclosure can weaken ASLR because addresses reveal layout. This is why an apparently “read-only” memory bug can materially change the impact of a separate write bug.

NX / DEP and executable permissions

NX/DEP marks data regions non-executable when supported. This prevents directly executing injected bytes from ordinary writable data pages, but it does not stop corruption itself. Attack research historically shifted toward reusing existing code and manipulating data because of this separation.

The defensive lesson is layered controls: W^X, CFI, sandboxing, memory-safe code, and least privilege complement one another.

Stack canaries

A compiler can place a random/integrity value near sensitive stack state and verify it before function return. If a sequential overwrite crosses the canary, the process aborts. Coverage and implementation vary; a corruption that does not touch the canary may remain undetected.

Use compiler metadata or hardening inspection rather than assuming every build has a protector enabled.

RELRO and relocation hardening

On ELF systems, relocation metadata and dynamic-linking structures can be made read-only after startup. Full RELRO reduces the amount of loader-related state that remains writable at runtime. This is an example of a general principle: initialization data that should not change after setup should become immutable.

Control-Flow Integrity, CET, and shadow stacks

Control-Flow Integrity constrains indirect branches to expected targets based on compiler/runtime policy. Intel CET includes mechanisms such as shadow stacks and indirect branch tracking. Shadow stacks maintain protected return-address state separately from ordinary writable stack memory.

These controls make some control-flow corruption substantially harder, but they do not prevent all logic/data attacks. Security assessment should identify what class each control covers.

ARM pointer authentication and branch protection

ARMv8.3-A and later architectures can support Pointer Authentication (PAC), which adds authentication information to selected pointers using secret keys held in architectural state. Modern ARM64 platforms may also use branch target identification. Exact adoption differs by OS, device, and compiler.

For Android/mobile analysis, recognize PAC-related instructions as mitigation evidence rather than ordinary application logic.

Memory tagging

Memory tagging associates metadata with allocations/pointers so invalid spatial or temporal accesses can be detected probabilistically or deterministically depending on the technology. ARM Memory Tagging Extension (MTE) is especially relevant to modern Android devices. Tagging improves detection/containment but does not remove the need for correct ownership and bounds.

Safe code-reuse concepts

When data pages are non-executable, historic exploitation research demonstrated that existing instruction sequences can be chained rather than injecting new code. You should understand this as a reason NX alone is insufficient. This guide intentionally stops at the concept and defensive implications; it does not provide gadget-chain construction or payload instructions.

Exploitability triage matrix

For a memory bug in owned code, record:

Question Why it matters
Can untrusted input reach it? Reachability
Read, write, execute, or lifetime error? Primitive class
Which object/state is affected? Semantic impact
Is the corruption attacker-controlled? Reliability/impact
Are addresses disclosed? ASLR context
Is the process sandboxed? Blast radius
What privileges/credentials exist? Security boundary
Which mitigations are enabled? Constraints
Is reproduction deterministic? Engineering confidence

Do not reduce the analysis to one “exploitable/not exploitable” guess without evidence.

Sanitizer-guided local lab

Use a deliberately buggy training program from a course or create a toy out-of-bounds example that only runs locally. Compile with AddressSanitizer/UndefinedBehaviorSanitizer where supported. Your deliverable is not a payload; it is a root-cause report containing allocation/object bounds, the first invalid access, source line, fix, and regression test.

Then rebuild with hardening enabled and document what mitigations exist. Note that hardening should remain enabled even after the source bug is fixed.

Guided study workflow

Before you begin

Complete Modules 53, 62, 63, 64, and 65.

Practice task

Analyze one sanitizer-detected bug in toy code. Classify it as spatial/temporal, identify the violated invariant, and produce a source-level fix plus regression test. Inventory platform mitigations separately.

Evidence to keep

Keep source, sanitizer report, build flags, mitigation inventory, and regression test. Do not create or retain weaponized payloads.

Common mistakes to avoid

Mastery check

Explain how an out-of-bounds write differs from use-after-free, how NX and ASLR constrain different things, and why data-only corruption can still be critical.

Continue with

Modules 67, 68, 79, 82, and 84.