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.