I looked at the basics of buffer overflow vulnerabilities and tried to understand how the stack is working. For that I wanted to write a simple program which changes the address of the return address to some value. Can anybody help me with figuring out the size of the base pointer to get the offset from the first argument?
void foo(void)
{
char ret;
char *ptr;
ptr = &ret; //add some offset value here
*ptr = 0x00;
}
int main(int argc, char **argv)
{
foo();
return 1;
}
The generated assembler code looks as follows:
.file "test.c"
.text
.globl foo
.type foo, @function
foo:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
leaq -9(%rbp), %rax
movq %rax, -8(%rbp)
movq -8(%rbp), %rax
movb $0, (%rax)
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size foo, .-foo
.globl main
.type main, @function
main:
.LFB1:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl %edi, -4(%rbp)
movq %rsi, -16(%rbp)
call foo
movl $1, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE1:
.size main, .-main
.ident "GCC: (GNU) 4.7.1 20120721 (prerelease)"
.section .note.GNU-stack,"",@progbits
The relevant part of the foo frame segment should look like this:
[char ret] [base pointer] [return address]
I have the position of the first one which is only 1 byte in size. Is it only 1 byte further to the base pointer or the size of a word as mentioned in http://insecure.org/stf/smashstack.html? And how do I get to know the size of the base pointer?
Every time a CALL instruction is executed, its return address is pushed onto the stack. Every time a RETURN instruction enters the pipeline, the next address is popped off the stack and the processor continues fetching from the associated address seamlessly.
Return address contains the address of the instruction to return to. It's not otherwise stored anywhere else. Frame pointer is generally the previous stack pointers. The return address is the previous instruction pointer.
Functions of the call stack. As noted above, the primary purpose of a call stack is to store the return addresses. When a subroutine is called, the location (address) of the instruction at which the calling routine can later resume needs to be saved somewhere.
In machine code, the return address, $ra for MIPS, is effectively a parameter to the subroutine — it tells the subroutine where to resume execution in the caller, where to return to. There are several ways to set the $ra register with a meaningful return address, though of course jal is by far the most common way.
You're not going to be able to do this in vanilla C, you don't have control of how the compiler lays out the stack frame.
In x86-64, the return address should be at %rbp + 8
. You could use some inline assembly to get that (gcc syntax):
uint64_t returnaddr;
asm("mov 8(%%rbp),%0" : "=r"(returnaddr) : : );
Similarly for setting it.
Even that is a bit sketchy, as you don't know whether the compiler is going to set up %rbp
or not. YMMV.
Your basepointer is most likely just a pointer, so it has the size sizeof(int*).
But there is also another value in between your variable ret
and the base pointer.
I would assume its value of a register (eax?). This would lead to something like the following, if you want an endless loop:
void foo(void)
{
char ret;
char *ptr;
ptr = (char*)(&ret) + (sizeof(ret) + 2*sizeof(int*)) ;
*(int*)ptr -= 0x0c;
}
The return target which is modified assuming it has the size of a pointer (could differ for other instruction sets). By decrementing it, the return target is set to a point before the calling point of foo
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With