Finding return address of stack - c

I have this simple code:
#include <sys/types.h>
#include <netinet/in.h>
#include <stdio.h>
#include <ctype.h>
main(argc, argv)
char *argv[];
{
char line[512];
gets(line);
}
my goal is to find the distance between the end of the buffer and the return address of the stack.
So if my buffer (line) is 512 bytes, I could find the starting address, and add 512 and know where the start of that distance would be.. but how would I find the return address of the stack?
Basically I am just trying to figure out how to find the return address of the stack and the buffers start address.. I couldn't find it when disassembling main

#include <stdio.h>
int main()
{
long l, k;
asm("mov %%rsp,%0" : "=r"(l));
asm("mov %%rbp,%0" : "=r"(k));
printf("Stack pointer: 0x%16.16lX\n", l);
printf("Stack frame base: 0x0%16.16lX\n", k);
printf("Distance to return address: %ld\n", k-l);
}
snow ~ $ ./test
Stack pointer: 0x00007FFC95B793C0
Stack frame base: 0x000007FFC95B793D0
Distance to return address: 16
Obviously this is not portable, I'm assuming x64 and gcc here.
Caveat: BP isn't always going to point to the return address. Sometimes it's not used as a stack frame pointer, and some functions may not return their values on the stack. Register optimizations will break it. Local variables may break it. Variable word alignments may break it. Basically, don't count on it working. (I believe depending on the compiler/compile-time options you may need to add a constant offset to this, as well.)
I do really wonder if there isn't a better way to do whatever it is that you are trying to do... =)

Related

Dynamic expansion of the Linux stack

I've noticed the Linux stack starts small and expands with page faults caused by recursion/pushes/vlas up to size getrlimit(RLIMIT_STACK,...), give or take (defaults to 8MiB on my system).
Curiously though, if I cause page faults by addressing bytes directly, within the limit, Linux will just regularly segfault without expanding the page mapping (no segfault though, if I do it after I had e.g., alloca, cause the stack expansion).
Example program:
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <stdlib.h>
#define CMD "grep stack /proc/XXXXXXXXXXXXXXXX/maps"
#define CMDP "grep stack /proc/%ld/maps"
void vla(size_t Sz)
{
char b[Sz];
b[0]='y';
b[1]='\0';
puts(b);
}
#define OFFSET (sizeof(char)<<12)
int main(int C, char **V)
{
char cmd[sizeof CMD]; sprintf(cmd,CMDP,(long)getpid());
if(system(cmd)) return 1;
for(int i=0; ; i++){
printf("%d\n", i);
char *ptr = (char*)(((uintptr_t)&ptr)-i*OFFSET);
if(C>1) vla(i*OFFSET); //pass an argument to the executable to turn this on
ptr[0] = 'x';
ptr[1] = '\0';
if(system(cmd)) return 1;
puts(ptr);
}
}
What kernel code is doing this? How does it differentiate between natural stack growth and me poking around in the address space?
The linux kernel takes the content of the stack pointer as the limit (within reasonable boundaries). Accessing the stack below the stack pointer minus 65536 and the size for 32 unsigned longs is causing a segmentation violation. So, if you access the memory down the stack you have to make sure, that the stack pointer somehow decreases with the accesses to have the linux kernel enlarge the segment. See this snippet from /arch/x86/mm/fault.c:
if (sw_error_code & X86_PF_USER) {
/*
* Accessing the stack below %sp is always a bug.
* The large cushion allows instructions like enter
* and pusha to work. ("enter $65535, $31" pushes
* 32 pointers and then decrements %sp by 65535.)
*/
if (unlikely(address + 65536 + 32 * sizeof(unsigned long) < regs->sp)) {
bad_area(regs, sw_error_code, address);
return;
}
}
The value of the stack pointer register is key here!

Why is function pointer 12 bytes long?

I've been inspecting the heap memory when executing the following code:
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
struct data {
char name[64];
};
struct fp {
int (*fp)();
};
void winner()
{
printf("level passed\n");
}
void nowinner()
{
printf("level has not been passed\n");
}
int main(int argc, char **argv)
{
struct data *d;
struct fp *f;
d = malloc(sizeof(struct data));
f = malloc(sizeof(struct fp));
f->fp = nowinner;
printf("data is at %p, fp is at %p\n", d, f);
strcpy(d->name, argv[1]);
f->fp();
}
The code is compiled like this:
gcc winner.c -w -g -fno-stack-protector -z norelro -z execstack -o winner
(More code will be added later on so tags like fno-stack-protector are there)
I executed the project with argument "HELLO" and I set a break point on f->fp() and inspect the heap memory:
Everything after the first malloc() makes sense but I'm kinda puzzled about what happened after the second malloc(). The second chunk should only request 4 bytes of memory to store the function pointer but instead it took 12 bytes, which reflects on what is stored on the address 0x804a04c (4 bytes of metadata + 12 bytes of requested memory + status bit 1 = 17 => 0x00000011).
And as you can see, the function pointer did only take up four bytes on 0x804a050 with the address of nowinner (0x080484a1).
I read up on this SO post and this article but it seems it still can't explain why.
Your initial question can be answered very easily by printing sizeof of your pointer. You will not see a 12 here.
The answer to your question "Why is function pointer 12 bytes long?" is simply: "It's not!"
But your question describes a different underlying question:
"Why does allocating 4 bytes take 12 bytes on the heap?"
You are under the wrong impression that memory allocation only takes exactly what is needed to store the user data.
This is wrong.
Memory management also needs to store some management data for each allocation.
When you call free the runtime library needs to know the size of the allocated block.
Therefore you can take it as granted that every allocation consumes more memory than the requested amount.
Depending on the implementation of the heap this can be within the heap itself or in a separate area.
You can also not rely on taking the same amount of overhead for each allocation. There are weird implementation out there.
Some implementations take the requested amount and add fixed length of management data.
Some implementations use a buddy system and follow a sequence of fibonacci numbers to determine smallest suitable block size.

how virtual addresses assigned?

Take this C code for example
#include <stdio.h>
#include <stdlib.h>
int main() {
int x;
int* y = (int *) malloc(10*sizeof(int));
printf("%p\n",&x);
printf("%p\n",y);
printf("%p\n",&(y[1]));
while(1);
return 0;
}
Which will print virtual addresses that look something like this
0x7ffd4e96d214
0x908010
0x908014
The virtual addresses will be different every time you run the binary file which made me think how the virtual address are actually decided for a program ?
This is - probably - the effect of ASLR.
The decision should - as the name Address Space Layout Randomization tells - be random.

"Visualization" of dangling pointer

While learning pointers I tried pointer declarations/dereferenciations.
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
int *call() {
int a = 3;
return &a;
}
int main() {
printf("call* is: %d\n", *call());
printf("call is: %p\n", call());
Sleep(2000);
printf("call* is: %d\n", *call());
printf("call is: %p\n", call());
Sleep(2000);
printf("call* is: %d\n", *call());
printf("call is: %p\n", call());
return 0;
}
So "obviously" the "a" is a local variable.
But my problem is,
when I'm reading out the address of "a", it's always the same address.
Why is that like this?
PS: I'm running a prime-number-calculator in the background to fill up as much memory as possible and I put in the "Sleep" to make the program wait, but still the address of "a" is always the same.
a is located on the stack of the current thread : every time the function call() is run, it "allocates" 4 bytes on the stack to stock a, return the address and then "frees" the space it uses on stack (it is not actually allocating/freeing anything, just offsetting the stack pointer).
So if you call it several times in a row, the state of the stack on input of the function will be exactly the same, so the actual address of a on the stack the same every time (please note that this address is invalid as soon as you exit the function).
You should do something like
int * call2(){
int a = 0;
int *b = call();
printf("%d",a);
return b;
}
and then
int *a = call();
int *b = call2();
You will see a and b will be different (the printf is there to make sure the compiler does not optimise anything away)
Since the stack is local to the current thread (not influenced by other processes/threads), your prime number calculator and Sleep are to no use at all.
"call" is to return a pointer to a variable? The problem here is that "a" is not statically allocated, but is on the stack. You can return its address at the moment (which may or may not be the same address, depending on whether "call" is invoked at the same depth each time), but there's no guarantee of what that address is pointing to once you return from "call". You put a 3 in it during the call, and that may be overwritten by something else by the time you get around to looking at the contents of that address.

Accessing specific memory locations in C

In assembly language we have instructions like:
movl ax, [1000]
This allows us to access specific memory locations.
But in C can we do something similar to this?
I know inline assembly code using asm() will allow you to do this,
but I would like to know about some C specific technique to achieve this.
I tried the following code and got segmentation error:
int *ptr=0xFE1DB124;
*ptr;
This again was confusing as the memory location was identified by the code given below:
int var;
printf("\nThe Address is %x",&var);
So the memory location is available, but I am still getting a segmentation fault.
Why?
Common C compilers will allow you to set a pointer from an integer and to access memory with that, and they will give you the expected results. However, this is an extension beyond the C standard, so you should check your compiler documentation to ensure it supports it. This feature is not uncommonly used in kernel code that must access memory at specific addresses. It is generally not useful in user programs.
As comments have mentioned, one problem you may be having is that your operating system loads programs into a randomized location each time a program is loaded. Therefore, the address you discover on one run will not be the address used in another run. Also, changing the source and recompiling may yield different addresses.
To demonstrate that you can use a pointer to access an address specified numerically, you can retrieve the address and use it within a single program execution:
#include <inttypes.h>
#include <stdio.h>
#include <stdint.h>
int main(void)
{
// Create an int.
int x = 0;
// Find its address.
char buf[100];
sprintf(buf, "%" PRIuPTR, (uintptr_t) &x);
printf("The address of x is %s.\n", buf);
// Read the address.
uintptr_t u;
sscanf(buf, "%" SCNuPTR, &u);
// Convert the integer value to an address.
int *p = (int *) u;
// Modify the int through the new pointer.
*p = 123;
// Display the int.
printf("x = %d\n", x);
return 0;
}
Obviously, this is not useful in a normal program; it is just a demonstration. You would use this sort of behavior only when you have a special need to access certain addresses.
For accessing Specific memory from user space, we have to map the memory Address to Programs Virtual Address using mmap(), the below C code shows the implementation:
Take a file "test_file" containing "ABCDEFGHIJ".
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
int main(void)
{
char *map_base_addr; // Maping Base address for file
int fd; // File descriptor for open file
int size = 10;
fd= open("test_file", O_RDWR); //open the file for reading and writing
map_base_addr= mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);// Maping file into memory
char *ch= map_base_addr;
int i;
/*Printing first 10 char*/
for(i=0; i<size; i++)
fputc(*(ch+i),stdout);
printf("\n");
*(ch+1) = 'b';
*(ch+4) = 'z';
*(ch+7) = 'x';
/*Printing char after modification*/
for(i=0; i<size; i++)
fputc(*(ch+i),stdout);
printf("\n");
/* Finally unmap the file. This will flush out any changes. */
munmap(map_base_addr, size);
exit(0);
}
The output will be:
ABCDEFGHIJ
AbCDzFGxIJ
It works for me:
#include <stdio.h>
int main(int argc, char**argv) {
int var = 7456;
printf("Adress of var = %x, var=%d\n", &var, var);
int *ptr = (int*)0x22cd28;
printf(" ptr points to %x\n", ptr);
*ptr = 123;
printf("New value of var=%d\n", var);
return 0;
}
Program output:
Adress of var = 22cd28, var=7456
ptr points to 22cd28
New value of var=123
Note:
The address is usually not the same on every execution. When I tried my example I had to run it three times before I got the address to match.
char* can point to any adress (because sizeof (char) = 1). Pointers to larger objects must often be aligned on even adresses (usually one divisible by 4).
Your question doesn't really make much sense if you are running on linux/windows/mac/whatever
http://en.wikipedia.org/wiki/Virtual_memory
You can do that only if you are programming a device without virtual memory, or if you are programming the operating system itself.
Otherwise the addresses you see are not the "real" addresses on the RAM, the operating system translates them to real addresses and if there is not a map to translate your virtual address to a real one, then you can get a segmentation fault. Keep in mind that there are other reasons that can cause a segmentation fault.

Resources