# Memory Layout Essentials: Understanding Program Memory Have you ever wondered how your computer keeps track of everything running in memory? It's actually a bit like organising a massive library - every book (or in our case, every piece of data) needs its own spot on the shelf, and we need a system to find it quickly. Let's dive into how modern computers organise their memory "library"! ## The Big Picture This isn't just some random arrangement - it's carefully designed to keep things running smoothly and securely. The way the stack and heap grow towards each other is pretty clever - it helps use memory efficiently while making it super obvious if they ever bump into each other (which would be bad news!). Think of program memory like a tall building where different departments each get their own floor. Everyone knows where they need to go, and there's a method to the madness of how everything's arranged. ![[Pasted image 20250110100046.png]] ## Breaking Down Each Section Let's take a closer look at each "floor" of our memory building, starting from the bottom. ### Text Segment (Code Segment) This is where all your program's actual instructions live. Think of it as the master recipe book that tells your program precisely what to do: - It's where the executable code hangs out. - Usually read-only (because who wants their instructions getting scrambled?) - Often shared between multiple copies of the same program (why waste space?) - Typically, it starts at a fixed address (though ASLR might shake things up a bit - want to know more about ASLR, have a read about it in [[The Stack]].) ```c // This code would end up in the text segment int add(int a, int b) { return a + b; } ``` ### Data Segment Think of this as your program's storage room split into two sections: #### Initialised Data (.data) - Home to global and static variables that start with specific values - Takes up space in your program file - Gets loaded into memory when your program kicks off ```c // These end up in the initialised data segment static int counter = 42; // Static variable with initial value char *message = "Hello World"; // Global string with initial value ``` #### Uninitialised Data (BSS) - Where variables that start as zero live - Cleverly doesn't waste space in your program file - Gets set up fresh when your program starts running ```c // These go in the BSS segment static int uninitialised; // Static variable without initial value char buffer[1024]; // Large buffer (automatically zeroed) ``` ### Heap > [!tip] Intrigued by how the heap actually manages all this dynamic memory? Hop over to [[The Heap]], where we dive deep into heap internals, common vulnerabilities, and why malware authors love targeting heap operations! This is your program's flexible workspace - like a craft room where you can grab more table space when you need it: - Grows upward in memory (reaching for the sky!) - Managed by malloc/free in C or new/delete in C++ - Can grow or shrink as your program runs - It can get a bit messy over time (like any workspace) ```c // Example of heap allocation char *dynamic_buffer = malloc(1024); // Allocates on the heap // ... use the buffer ... free(dynamic_buffer); // Returns memory to the heap ``` ### Stack We dove deep into this in [[The Stack]], but here's the quick version: - Grows downward in memory (like building a tower of blocks from the top down) - Handles function calls and local variables - Cleans up after itself automatically (nice!) - Super fast but has size limits ```c void function() { int local = 42; // Lives on the stack char buffer[512]; // Also calls the stack home } // Poof! Cleaned up automatically ``` ## Memory Management Units (MMU) >[!tip] If you're into malware analysis, understanding virtual memory is super important - lots of sneaky anti-debugging tricks mess around with memory permissions or try to spot when they're running in a virtual environment! Think of the MMU as your memory's security guard and personal assistant rolled into one. It's constantly: - Converting virtual addresses to physical ones (like a postal service for memory) - Enforcing memory protection (making sure everything stays where it should) - Handling memory hiccups and access violations Here's a simplified look at how virtual addressing works: <div style="font-family: monospace;"> <strong style="color: #6C83DB;">Virtual Address</strong><br> +----------------+----------------+<br> | <strong style="color: #A8B4F3;">Page Number</strong> | <strong style="color: #F2CF85;">Page Offset</strong> |<br> +----------------+----------------+<br> <span style="color: #DBB9F8;">↓</span> <span style="color: #DBB9F8;">↓</span><br> <strong style="color: #EA7268;">Page Table</strong> <strong style="color: #EA7268;">Physical Memory</strong><br> <span style="color: #DBB9F8;">↓</span> <span style="color: #DBB9F8;">↓</span><br> +----------------+----------------+<br> | <strong style="color: #A8B4F3;">Frame Number</strong> | <strong style="color: #F2CF85;">Frame Offset</strong> |<br> +----------------+----------------+<br> <strong style="color: #EA7268;">Physical Address</strong> </div> ## Common Memory Issues Let's look at some common memory problems you might encounter: ### Stack Overflow When your stack grows too big: ```c void recursive_disaster() { char huge_buffer[1024*1024]; // Big local array recursive_disaster(); // Recursion without exit } // 💥 Stack overflow! ``` ### Memory Leaks When you forget to free heap memory: ```c void leaky_function() { char *buffer = malloc(1024); // Oops, forgot to free(buffer)! } // Memory leak - that space is now lost ``` ### Use After Free Using memory after returning it to the heap: ```c char *ptr = malloc(10); free(ptr); ptr[0] = 'A'; // 💥 Accessing freed memory! ``` ## Memory Protection Techniques Modern systems use several techniques to protect memory: 1. **DEP (Data Execution Prevention)** - Prevents code execution from data pages - Marks memory regions as non-executable 2. **ASLR (Address Space Layout Randomisation)** - Randomises memory layout each time the program runs - Makes exploitation harder 3. **Stack Cookies/Canaries** - Places magic values to detect stack corruption - Checks values before function returns ## Practical Memory Analysis When analysing programs or debugging memory issues, these tools are invaluable: ```bash # Linux tools $ pmap <pid> # View process memory map $ /proc/<pid>/maps # Raw memory layout info $ valgrind # Memory leak detection # Windows tools > VMMap # SysInternals memory mapper > !address # WinDbg memory command > !heap # WinDbg heap analysis ``` ## Going Further Want to dive deeper? Check out these related topics: - [[CPU Registers Building Blocks]] - How CPU registers interact with memory - [[The Stack]] - Deep dive into stack operations - [[PE File Format Foundations]] - How programs are structured in memory - [[Windows API Basics]] - How programs interact with system memory Remember: understanding memory layout is crucial for both development and security analysis. Whether you're debugging a crash, analysing malware, or just trying to write more efficient code, knowing how memory works under the hood is invaluable!