View Full Version : gcc error: -mpreferred-stack-boundary=2 is not between 4 and 12

11-09-2012, 03:53 AM
Hi guys,

I'm just starting to learn a bit of c and assembly to learn about buffer overflows (so go easy on me, this is my first dive into programming :)

At this point I'm really mostly following along with some training videos online and trying to get a grasp. The videos use an x32 system, what I'm doing it trying to learn it in both 32 and 64 bit at the same time so I have two virtual machines I compile similar code on (I replace syscall codes as needed for x64, etc). I'm learning about buffer overflows right now.

This tiny script is to force a return value of 20 after the program runs.

Anyway, so there is this code that on x32 I'm supposed to compile this way:

gcc -ggdb -mpreferred-stack-boundary=2 -o Code Code.c

This compiles fine. This is the code:


char shellcode[] = "\xbb\x14\x00\x00\x00"
main() {

int *ret;
ret = (int *)&ret +2;
(*ret) = (int)shellcode;

on x32 it works the same as the video, which is after it runs, if I check the return code, it shows as 20:

# echo $?

On the 64-bit machine, if I try to compile with the exact same command, I get error:

$ gcc -ggdb -mpreferred-stack-boundary=2 -o ShellCode ShellCode.c
ShellCode.c:1: error: -mpreferred-stack-boundary=2 is not between 4 and 12

Instead of -mpreferred-stack-boundary=2, I tested compiling with a setting of 4, and also all even numbers up to 12, and I also tested leaving that switch out completely I don't get an error at compile time when I test 4-12 or leaving this switch out, but I'm not getting a return code of 20 that I'm supposed to get if this script is working right. In fact I seem to get random return codes each time I run it.

On the 32-bit machine, I get a 20 every time.

I don't yet have a good handle of the math involved, so this could have to do with the +2 in the script too, I'm not sure.

Does anyone have any ideas about this error and what the significance of this switch actually is?


11-09-2012, 04:34 AM
That program isn't actually returning a value though. Or did you omit some of the code?

That gcc flag is telling the compiler to keep the stack word aligned if you set it to 2. In 64-bit when the flag is set to 4, the stack is double word aligned. (see: http://gcc.gnu.org/onlinedocs/gcc-4.5.0/gcc/i386-and-x86_002d64-Options.html)

While the code you posted is confusing since it seems like some of it is missing, changing the +2 to a +4 might fix the problem.

However also keep in mind that when compiling for 64-bit the compiler is going to do some very different things because by default it can utilize a lot more advanced features of the processor.

In normal development it would be extremely rare that you would want to set the stack alignment boundary, for things like that it is best to let the compiler decide. Also keep in mind that as the GCC manual says, just because you tell it 2 or 4 doesn't mean it actually will. The compiler will ultimately decide what to do.

11-14-2012, 02:25 AM
Thanks for the replies.

I got some help from another resource, including the solution here in case this helps anyone else in the future:

1) on 64 bit Linux, size of int is 4 bytes. we're playing with the stack here so we need a 64 bit integer: the long type.

2) according to this resource: http://blog.markloiseau.com/2012/06/64-bit-linux-shellcode/

"you can no more define the shell code as a char array, because the shellcode[] character array is stored in the explicitly non-executable .rodata section of the ELF file" causing a segfault.

you have to insert it directly into the body of the main function.

3) the opcodes for x64 are different from those for x86.
the exit syscall is called differently.
the assembly for your shellcode on x64 would be:

mov rdi, 20
mov rax, 60

11-18-2012, 02:48 PM
Wow. I wrote a response and then deleted it because I figured out what you're trying to do.

You're trying to overwrite the return address on the stack with an address to the array, which contains hand-coded op-codes. Right?

Of course, this is very compiler-specific and platform-specific, so you would never do this in a real program. But I realize you are just poking around to try to understand what's going on.

On problem: The size of a pointer is probably 32-bits on a 32-bit machine and 64 bits on a 64-bit machine, but the size of int is probably 32 bits on both machines. So you're only writing half an address. (I say probably because there are no guarantees for compiler-specific details.)

And since you're also using the size of int to navigate the stack, that's likely to be wrong also. I've never investigated this, but gcc may document somewhere what size if pushed on the stack--I would guess sizeof(long *). If it's documented, you could use that type instead of int and at least remove one error.

As for making the op-codes executable, I don't know how you would do that in C. But you could probably use some in-line assembly code.