Basic stuff part I : Memory organization

Intro:

It is very important to understand process memory organization when you are developing especially embedded and real-time softwares because of environment criticism such as resources limitation. This articles would allow readers to understand many compile errors, runtime bugs then to avoid them when programming.

Security threats could be present on your developed software by yourself, that sounds illogical but it is very common problem. Memory organization vulnerabilities and the way they are exploited by hackers must be taken in account when developing software.

Hope this article will be beneficial to persons seeking knowledge on this subject and will make it easier to understand!

 

Process memory organization:

To make a process running, Operating System shall load it in memory. Then it will allocate to each process a structure divided to five sections:

  • Data is readable and writable segments containing the static, global, initialized  data segments and variables.
  • BSS is readable and writable segments containing the static, global, un-initialized data segments and variables.
  • Stack is readable and writable segment, it is a data structure based on Last-In-First-Out ordering. It’s composed of frames that would be detailed later on this article. Items are pushed and popped from the top of the stack.
    Its processes are controlled directly by the CPU via some special instructions “PUSH” and “POP”.
  • Heap is a readable and writable segment, it stores dynamically allocated data. The allocator (malloc) and deallocator (free) are used to assign and free space for dynamic data inside heap memory.
  • Text is read-only segment  that contains the compiled executable code of the program.


Process memory organization

Stack elements : Frame!

The stack is composed of unitary elements called frames used to save routine’s data. These frames are pushed when calling a function and popped when returning. Frames are composed of several memory areas:

  • Return address:  when a subroutine is called, the location of the instruction to return to needs to be saved somewhere.
  • Local variables storage area: a function needs memory space for storing the values of local variables, whose are known only inside the active subroutine. These values are not retained after it returns.
  • Functions parameters: subroutines needs these values to be supplied to them by the caller.
  • Frame pointer: this filed contains the previous value of the frame pointer register, the value it had while the caller was executing.

    Stack frames structure

 

How do the stack works ?

To understand how stack works, you must keep in head basic information about executed process memory pointers :

  • Stack Pointer : it points always to the “top” of the stack. The stack is often accessed via  this register.
  • Frame Pointer : it always points to the “top” of the current frame. It is used to access memory within the current frame such as return address.
  • Instruction Pointer: this register contains the memory address of the next instruction to be executed.

Now to understand how the stack works, we will figure out a sample program, there is a main “caller” that calls a function “callee”.

void function (char * str)  {
    char buffer[8];
    strcpy(buffer, str);
}
void main () {
    char bug_tab[10] = "AAAAAAAAAA";
    function(bug_tab);
}

When this Program would be executed these steps would be performed:

  1. The “Caller” saves local and temporary variables, by pushing them onto the stack.
  2. The values of actual arguments are evaluated  by the “Caller”, and either pushed onto the stack or placed into registers.
  3. The actual call instruction, such as “Branch” and “Link”, is then executed to transfer control to the code of the target subroutine “function”.
  4. In the called subroutine “function”, the first code executed is the subroutine “prologue” which would be detailed below:

On most architecture, the function “prologue” typically does the following actions :

  • Pushes the current Instruction Pointer onto the stack, so it can be retrieved later when the current function terminates. This pointer refers to the last function.
  • Replaces the frame pointer with the current stack pointer, so it points now to the beginning of the new frame.
  • Moves the stack pointer further along the stack to point to the current frame, exactly to function’s local variable segment.

6.  Subroutine Instructions would be executed until it is ended or a return instruction is found.

5. When a subroutine is ready to return, it executes an “epilogue” that undoes the steps of the “prologue” :

Epilogue” reverses the actions of the “prologue” and returns control to the calling main function. It does the following actions :

  • Replaces the stack pointer with the current frame pointer, so the stack pointer is restored to its value before the “prologue”.
  • Pops the “Instruction Pointer” off the stack, so it is restored to its value before the “prologue”.
  • Returns to the Caller, by popping the previous frame’s program counter off the stack and jumping to it.

When main would call function the call stack will have the structure shown by the figure below:

Stack call structure

 

Stack vulnerabilities:

The stack layout has a major vulnerabilities which has led to security problems among past years. These vulnerabilities are “stack buffer over-flow” and “code injection”.

  • Stack buffer overflow:

In general, buffer overflow occurs when data written to a buffer, due to insufficient bounds checking, corrupts data values in memory address adjacent to the allocated buffer. It occurs while copying strings characters from one buffer to another.
This could cause an error such as a segmentation fault, and terminates the process.


Buffer overflow

 

In process running, a stack buffer overflow occurs when a program writes data outside of the intended data structure. This leads to corruption of adjacent data on the stack,  then will often cause program crash or to operate incorrectly.

Stack buffer overflow

  • injecting exploit:

An “exploit” is a program that injects a shell-code into a target process then will exploit a vulnerability to gain control over the “Instruction Pointer”. Shell-code could be injected by several means that are:

– Loading the shell-code in data sent over the network to the vulnerable process.

– Supplying it in a file that is read by the vulnerable process.

– Through command line or environment when exploit is local.

Exploit Injection happens when the “Instruction Pointer” is modified to point to injected shell-code, then would be executed and performs its malicious task. If the affected program is running with special privileges (e.g. the SUID bit set to run as the superuser), or accepts data from untrusted network hosts (e.g. a webserver) then the bug is a potential security vulnerability because the attacker would gain superuser privileges on the affected machine.

Shell-code injection

 

About Me

ELGAABEB Mohamed Ali is Research & Development software engineer, graduated from National Institut of Applied Science and Technologies (INSAT) in 2006. My first expierience was at “Euro Information” Tunisian field as Mainframe Engineer, then i’ve been hired by “Eurogiciel Tunisia”  as Research & Development software engineer to work on Aeronautical  Softwares  field.

My work fields concerns especially real-time and multithreading software development through C/C++ and Java languages, meanwhile i’m wide opened to learn any new technologies and programming languages to be uptodate.