Project 4: Stack Canary Implementation

Your own stack canary protection mechanism—generating random canaries, inserting them in function prologues, and checking them in epilogues.

Quick Reference

Attribute Value
Primary Language C (with inline assembly)
Alternative Languages Assembly
Difficulty Level 3: Advanced
Time Estimate 2 weeks
Knowledge Area Exploit Defense / Compiler Security Features
Tooling GCC, objdump, GDB
Prerequisites Project 3, assembly language basics

What You Will Build

Your own stack canary protection mechanism—generating random canaries, inserting them in function prologues, and checking them in epilogues.

Why It Matters

This project builds core skills that appear repeatedly in real-world systems and tooling.

Core Challenges

  • Generating random canaries → maps to entropy sources, /dev/urandom
  • Storing the master canary → maps to TLS or global storage
  • Inserting checks → maps to function prologue/epilogue modification
  • Terminating on failure → maps to safe crash behavior

Key Concepts

  • Stack Frame Layout: “CSAPP” Ch. 3.7
  • Function Prologue/Epilogue: “The Art of Assembly” Ch. 5
  • Thread-Local Storage: “The Linux Programming Interface” Ch. 31

Real-World Outcome

$ ./canary_demo
Initializing stack canary protection...
Canary value: 0x00a83f9b7c4d2e1f (randomized)

Running protected function...
Function prologue: Canary placed on stack
Function body: Simulating buffer overflow...
Function epilogue: Checking canary...
*** STACK SMASHING DETECTED ***
Canary corrupted: expected 0x00a83f9b7c4d2e1f, got 0x4141414141414141
Aborting.

$ ./compare_with_gcc
GCC -fstack-protector-strong generates:
  mov    rax, QWORD PTR fs:0x28    ; Load canary from TLS
  mov    QWORD PTR [rbp-0x8], rax  ; Store on stack
  ...
  mov    rax, QWORD PTR [rbp-0x8]  ; Load from stack
  xor    rax, QWORD PTR fs:0x28    ; Compare with TLS
  jne    __stack_chk_fail          ; Abort if different

Our implementation generates similar code!

Implementation Guide

  1. Reproduce the simplest happy-path scenario.
  2. Build the smallest working version of the core feature.
  3. Add input validation and error handling.
  4. Add instrumentation/logging to confirm behavior.
  5. Refactor into clean modules with tests.

Milestones

  • Milestone 1: Minimal working program that runs end-to-end.
  • Milestone 2: Correct outputs for typical inputs.
  • Milestone 3: Robust handling of edge cases.
  • Milestone 4: Clean structure and documented usage.

Validation Checklist

  • Output matches the real-world outcome example
  • Handles invalid inputs safely
  • Provides clear errors and exit codes
  • Repeatable results across runs

References

  • Main guide: LEARN_SECURE_C_AND_EXPLOIT_AWARENESS.md
  • “Computer Systems: A Programmer’s Perspective” by Bryant & O’Hallaron