.

Trying to understand i686 architecture

<<

jacksmash

Newbie
Newbie

Posts: 14

Joined: Wed Feb 24, 2010 10:22 am

Post Wed Feb 24, 2010 10:24 am

Trying to understand i686 architecture

Hi,

I'm hoping someone can help me with this.

The command `uname -r` gives the following output on my machine:

  Code:
Linux ***-ubuntu 2.6.31-14-generic #48-Ubuntu SMP Fri Oct 16 14:04:26 UTC 2009 i686 GNU/Linux


(Note: I am running Ubuntu 9.04 on VirtualBox)

Here is some code that I am trying to run:

  Code:
#include <stdio.h>

void function(int a, int b, int c) {
  char buffer1[5];
  char buffer2[10];
  int *ret;

  ret = (int *)buffer1 + 16;
  (*ret) += 7; // have checked to make sure we need 7 bytes to skip x=1;
}

void main() {
  int x;

  x = 0;
  function(1,2,3);
  x = 1;
  printf("%d\n",x);
}



The goal of the above code is to skip the instruction `x = 1;`, and so the output of the printf statement should be "0".

However, in order to do that I need to know precisely how much to increment the return pointer in "function". This is where I'm a bit stuck.

I have been reading an article that has been somewhat helpful:

http://www.ethicalhacker.net/content/view/122/2/

It has helped me to understand that the `(*ret) += 7;` statement is likely correct.

Here is an assembly dump of the main function:

  Code:
(gdb) disassemble main
Dump of assembler code for function main:
0x08048404 <main+0>:   push   %ebp
0x08048405 <main+1>:   mov    %esp,%ebp
0x08048407 <main+3>:   sub    $0x10,%esp
0x0804840a <main+6>:   movl   $0x0,-0x4(%ebp)
0x08048411 <main+13>:   movl   $0x3,0x8(%esp)
0x08048419 <main+21>:   movl   $0x2,0x4(%esp)
0x08048421 <main+29>:   movl   $0x1,(%esp)
0x08048428 <main+36>:   call   0x80483e4 <function>
[B]0x0804842d <main+41>:   movl   $0x1,-0x4(%ebp)[/B] <-- [I]the instruction to skip[/I]
0x08048434 <main+48>:   mov    $0x8048510,%eax
0x08048439 <main+53>:   mov    -0x4(%ebp),%edx
0x0804843c <main+56>:   mov    %edx,0x4(%esp)
0x08048440 <main+60>:   mov    %eax,(%esp)
0x08048443 <main+63>:   call   0x804831c <printf@plt>
0x08048448 <main+68>:   leave 
0x08048449 <main+69>:   ret   
End of assembler dump.


Since we want to skip the statement at 0x0804842d and get to 0x08048434, we can calculate the difference to by 7 bytes easily enough. Hence, that's why I know it's correct to increment the ret pointer by 7.

What I can't figure out for the life of me is how many bytes have been allocated on the stack.

The memory layout should be like this:

  Code:
bottom of                                                                                    top of
memory                                                                                       memory
                              buffer2     buffer1     sfp     ret
<------                    [            ][           ][     ][     ]

top of                                                                                        bottom of
stack                                                                                         stack


My best guess is from this line:

  Code:
0x08048407 <main+3>:   sub    $0x10,%esp


... which suggests 16 bytes have been allocated, hence: `ret = (int *)buffer1 + 16;`

But, compiling and executing the program does not result in skipping the x=1 command.

So, I'm not asking anyone to tell me what the answer is (believe it or not). in terms of what the right number is. Rather, I'm hoping that someone can point me in the right direction so I can understand the stack layout on the machine.

Hope this makes sense. Thanks for any advice!!
<<

zeroflaw

User avatar

Full Member
Full Member

Posts: 208

Joined: Fri Feb 12, 2010 10:41 am

Location: Holland, Den Helder

Post Wed Feb 24, 2010 10:55 am

Re: Trying to understand i686 architecture

What exactly are you doing to change the return address? How are you actually changing the stack? The function doesn't return to the address in your ret variable, it returns to the return value that's placed on the stack.

Also, did you keep in mind that the function arguments are also placed on the stack? The return address is placed between the saved frame pointer (or local variables) and function arguments.

Hope this helps.

ZF
Last edited by zeroflaw on Wed Feb 24, 2010 10:59 am, edited 1 time in total.
ZF
<<

jacksmash

Newbie
Newbie

Posts: 14

Joined: Wed Feb 24, 2010 10:22 am

Post Wed Feb 24, 2010 11:02 am

Re: Trying to understand i686 architecture

Yes, you are correct about the function variables. I should have drawn the stack like this:
  Code:
bottom of                                                                                             top of
memory                                                                                                memory
               buffer2    buffer1       Slack    sfp      ret   a      b       c
<------    [            ][            ][       ][     ][     ][     ][     ][     ]

top of                                                                                                    bottom of
stack                                                                                                     stack


As for the return address, I'm trying to point "ret" to the return address of function, and then increment that address so it skips the x=1 instruction in the main function.
<<

zeroflaw

User avatar

Full Member
Full Member

Posts: 208

Joined: Fri Feb 12, 2010 10:41 am

Location: Holland, Den Helder

Post Wed Feb 24, 2010 11:43 am

Re: Trying to understand i686 architecture

Excuse me for my ignorance. I didn't read the first post properly. You were actually changing the return address by pointing to it's location and then incrementing it, doh! That should work. :P

The problem lies in this piece of code;

ret = (int *)buffer1 + 16;

You need to take the the sum of buffer1 and 16 together en then cast it to an int pointer. So it goes like this;

ret = (int *)(buffer1 + 16);

This should do the trick assuming the rest of your math is correct.

ZF
ZF
<<

jacksmash

Newbie
Newbie

Posts: 14

Joined: Wed Feb 24, 2010 10:22 am

Post Wed Feb 24, 2010 11:54 am

Re: Trying to understand i686 architecture

Ok, thanks. At least now I'm getting a segmentation fault. Now back to my original question. How do I figure out how much space there is between buffer1 and ret (on the stack)?

Thanks for your patience!
<<

zeroflaw

User avatar

Full Member
Full Member

Posts: 208

Joined: Fri Feb 12, 2010 10:41 am

Location: Holland, Den Helder

Post Wed Feb 24, 2010 12:51 pm

Re: Trying to understand i686 architecture

You have to keep in mind that the bytes are aligned on the stack with 4 byte values.

So let's say we have a 22 byte local buffer filled with a's. The bottom part of your stack looks like these.

----------------------------------------------------------------------

0    a a a a
4    a a a a
8    a a a a
12   a a a a
16   a a a a
20   a a 0 0  <- The compiler puts some padding to keep things properly aligned.
24   %%%% <- sfp
28       %%%% <- eip/ret

----------------------------------------------------------------------

When you you picture it like this, the math should be easy enough ;)

ZF
Last edited by zeroflaw on Wed Feb 24, 2010 1:02 pm, edited 1 time in total.
ZF
<<

jacksmash

Newbie
Newbie

Posts: 14

Joined: Wed Feb 24, 2010 10:22 am

Post Wed Feb 24, 2010 12:59 pm

Re: Trying to understand i686 architecture

Ok, so let's see if I understand this then.

buffer1's size is 10 bytes. So that's going to be 12 bytes on the bottom of the stack.

The sfp's size is 4 bytes, so that's going to be a total of 16 bytes to move the ret pointer to eip/ret

Does that make sense? There must be something I'm missing though, because incrementing by 16 bytes, and then by 7 bytes (as previously explained) just causes a seg fault.

Thanks for your help with this.
<<

zeroflaw

User avatar

Full Member
Full Member

Posts: 208

Joined: Fri Feb 12, 2010 10:41 am

Location: Holland, Den Helder

Post Wed Feb 24, 2010 1:42 pm

Re: Trying to understand i686 architecture

Correct, you need to move it 16 bytes to get to eip. Now there's something wrong with the value you're adding. You made an error in your calculation. You're almost there!

ZF
ZF
<<

jacksmash

Newbie
Newbie

Posts: 14

Joined: Wed Feb 24, 2010 10:22 am

Post Wed Feb 24, 2010 1:50 pm

Re: Trying to understand i686 architecture

Do you mean there's an error when I add '7' ??

The only thing I can think of at this point is I need to add another 4 bytes to get it past eip. Is that what you mean? Because I think the 7 is correct, because that's how many bytes I need to get past the 'x=1' statement.

Cheers.
<<

zeroflaw

User avatar

Full Member
Full Member

Posts: 208

Joined: Fri Feb 12, 2010 10:41 am

Location: Holland, Den Helder

Post Wed Feb 24, 2010 2:15 pm

Re: Trying to understand i686 architecture

The 7 is unfortunately incorrect. It's not enough for the whole jump. Check your math again.

ZF
ZF
<<

jacksmash

Newbie
Newbie

Posts: 14

Joined: Wed Feb 24, 2010 10:22 am

Post Wed Feb 24, 2010 2:20 pm

Re: Trying to understand i686 architecture

Ok.

Instead of just guessing, I'm obviously not understanding something.

If we consider this assembly breakdown:

  Code:
0x0804842d <main+41>:   movl   $0x1,-0x4(%ebp)[/B] <-- [i]the instruction to skip[/i]
0x08048434 <main+48>:   mov    $0x8048510,%eax


The first instruction is where "1" gets assigned to "x". Now, I want to move past this instruction to the next one, do I not? That's where I'm getting the '7' from.
<<

zeroflaw

User avatar

Full Member
Full Member

Posts: 208

Joined: Fri Feb 12, 2010 10:41 am

Location: Holland, Den Helder

Post Wed Feb 24, 2010 5:15 pm

Re: Trying to understand i686 architecture

I've been messing around with this for a while, and I'm guessing it also has something to do with alignment. I'm not 100% sure of this, and I will look into it. 7 seems correct, but maybe the layout of your stack is different. I compiled it with Visual C++ and I need to add 10 for it to work. I feel stupid for providing you with the wrong information. I assumed the memory layout would be the same.

Edit: Apparently it is about the compiler and alignment. I also found this article which explains it.

http://www.ethicalhacker.net/content/view/122/2/

Hope this solves your problem!

ZF
Last edited by zeroflaw on Thu Feb 25, 2010 8:12 am, edited 1 time in total.
ZF
<<

jacksmash

Newbie
Newbie

Posts: 14

Joined: Wed Feb 24, 2010 10:22 am

Post Thu Feb 25, 2010 10:11 am

Re: Trying to understand i686 architecture

Don't feel stupid. I appreciate your willingness to work through this with me.

I already included a link to the article you mentioned... so it helps to a point, but I'm obviously still missing something.
<<

zeroflaw

User avatar

Full Member
Full Member

Posts: 208

Joined: Fri Feb 12, 2010 10:41 am

Location: Holland, Den Helder

Post Thu Feb 25, 2010 11:54 am

Re: Trying to understand i686 architecture

I found the solution, when I decided to debug the whole thing on Ubuntu. If you inspect the stack layout, you will see the compiler put some extra space. The article describes this as "slack".

Run GDB, set a breakpoint at buffer1. And Inspect the stack memory for buffer1 with the command "x/8 buffer1", you will actually see the return address and some slack space. I disassembled main to be sure that it's the right address.

I'll show you some of the output to clear things up.

-----------------------------------------------------------------
(gdb) list function
1 void function(int a, int b, int c) {
2 char buffer1[5];
3 char buffer2[10];
4 int *ret;
5
6 ret = (int*)(buffer1 + 12);
7 (*ret) += 7;
8 }
9
10 void main() {
(gdb) break 2
Breakpoint 1 at 0x804837a: file ret.c, line 2.
(gdb) run
Starting program: /home/zeroflaw/Desktop/ret

Breakpoint 1, function (a=1, b=2, c=3) at ret.c:6
6 ret = (int*)(buffer1 + 12);
(gdb) x/8 buffer1
0xbffff7e0: 0xb7f9f729 0xb7fd6ff4 0xbffff818 0x08048419
0xbffff7f0: 0xb7fd6ff4 0xbffff8ac 0xbffff818 0x080483c5
(gdb) disas main
Dump of assembler code for function main:
0x08048392 <main+0>: push %ebp
0x08048393 <main+1>: mov %esp,%ebp
0x08048395 <main+3>: sub $0x18,%esp
0x08048398 <main+6>: and $0xfffffff0,%esp
0x0804839b <main+9>: mov $0x0,%eax
0x080483a0 <main+14>: sub %eax,%esp
0x080483a2 <main+16>: movl $0x0,0xfffffffc(%ebp)
0x080483a9 <main+23>: movl $0x3,0x8(%esp)
0x080483b1 <main+31>: movl $0x2,0x4(%esp)
0x080483b9 <main+39>: movl $0x1,(%esp)
0x080483c0 <main+46>: call 0x8048374 <function>
0x080483c5 <main+51>: movl $0x1,0xfffffffc(%ebp) <-- Skipping this instruction.
0x080483cc <main+58>: mov 0xfffffffc(%ebp),%eax
0x080483cf <main+61>: mov %eax,0x4(%esp)
0x080483d3 <main+65>: movl $0x80484c4,(%esp)
0x080483da <main+72>: call 0x80482a0 <printf@plt>
0x080483df <main+77>: leave
0x080483e0 <main+78>: ret
End of assembler dump.

-----------------------------------------------------------------

You can see buffer1 starts at address 0xbffff7e0 and the return address is at 0xbffff7fc. 0xbffff7fc - bffff7e0 = 28. The correct value in this case is 28!

I guess it's important to keep in mind what the compiler does. Also not every stack uses a saved frame pointer! So it's important to always dive into the assembly instructions and inspect memory carefully.

I also learned a lot from this, so thanks for posting your question :D

ZF
ZF
<<

jacksmash

Newbie
Newbie

Posts: 14

Joined: Wed Feb 24, 2010 10:22 am

Post Thu Feb 25, 2010 12:11 pm

Re: Trying to understand i686 architecture

Ok, two things:

1. When you say the return address is at 0xbffff7fc, where did you get that from? Did you mean 0xbffff7f0??

2. How are you compiling ret.c? When I run 'x/8 buffer1', I get this weird output:

0xbffff467: 75784192 -751608 -751425 75770815
0xbffff477: 264 512 768 0

which isn't very helpful to me!

THanks :)
Next

Return to Network Pen Testing

Who is online

Users browsing this forum: No registered users and 2 guests

.
Powered by phpBB® Forum Software © phpBB Group.
Designed by ST Software