Kendall Weihe
Kendall Weihe

Reputation: 111

How to execute machine instructions placed on the stack

I have a return value in my previous stack frame that points towards a buffer in my subsequent stack frame. How can I get machine instructions, placed in the buffer, to execute?

Is this even possible? From what I understand about the stack this is nonsensical. Since, of course, the stack is a last in-first out structure. In other words once the PC reaches the return address, the buffer will have already been popped off.

Any ideas?

the <test> function (below) calls the <getbuf> function (also below):

08048c53 <test>:
 8048c53:   55                      push   %ebp
 8048c54:   89 e5                   mov    %esp,%ebp
 8048c56:   83 ec 28                sub    $0x28,%esp
 8048c59:   e8 63 04 00 00          call   80490c1 <uniqueval>
 8048c5e:   89 45 f0                mov    %eax,-0x10(%ebp)
 8048c61:   e8 5f 00 00 00          call   8048cc5 <getbuf>
 8048c66:   89 45 f4                mov    %eax,-0xc(%ebp)
 8048c69:   e8 53 04 00 00          call   80490c1 <uniqueval>
 8048c6e:   8b 55 f0                mov    -0x10(%ebp),%edx
 8048c71:   39 d0                   cmp    %edx,%eax
 8048c73:   74 0e                   je     8048c83 <test+0x30>
 8048c75:   c7 04 24 f0 a3 04 08    movl   $0x804a3f0,(%esp)
 8048c7c:   e8 9f fc ff ff          call   8048920 <puts@plt>
 8048c81:   eb 40                   jmp    8048cc3 <test+0x70>
 8048c83:   8b 55 f4                mov    -0xc(%ebp),%edx
 8048c86:   a1 20 e1 04 08          mov    0x804e120,%eax
 8048c8b:   39 c2                   cmp    %eax,%edx
 8048c8d:   75 21                   jne    8048cb0 <test+0x5d>
 8048c8f:   8b 45 f4                mov    -0xc(%ebp),%eax
 8048c92:   89 44 24 04             mov    %eax,0x4(%esp)
 8048c96:   c7 04 24 19 a4 04 08    movl   $0x804a419,(%esp)
 8048c9d:   e8 ae fb ff ff          call   8048850 <printf@plt>
 8048ca2:   c7 04 24 03 00 00 00    movl   $0x3,(%esp)
 8048ca9:   e8 a0 07 00 00          call   804944e <validate>
 8048cae:   eb 13                   jmp    8048cc3 <test+0x70>
 8048cb0:   8b 45 f4                mov    -0xc(%ebp),%eax
 8048cb3:   89 44 24 04             mov    %eax,0x4(%esp)
 8048cb7:   c7 04 24 36 a4 04 08    movl   $0x804a436,(%esp)
 8048cbe:   e8 8d fb ff ff          call   8048850 <printf@plt>
 8048cc3:   c9                      leave
 8048cc4:   c3                      ret

08048cc5 <getbuf>:
 8048cc5:   55                      push   %ebp
 8048cc6:   89 e5                   mov    %esp,%ebp
 8048cc8:   83 ec 38                sub    $0x38,%esp
 8048ccb:   8d 45 d8                lea    -0x28(%ebp),%eax
 8048cce:   89 04 24                mov    %eax,(%esp)
 8048cd1:   e8 32 01 00 00          call   8048e08 <Gets>
 8048cd6:   b8 01 00 00 00          mov    $0x1,%eax
 8048cdb:   c9                      leave
 8048cdc:   c3                      ret

Upvotes: 3

Views: 196

Answers (2)

JimmyB
JimmyB

Reputation: 12610

Is this even possible?

Not if the Data Execution Prevention is in action.

the buffer will have already been popped off

POP/RET does not alter any data on the stack. It only changes the stack pointer SP while the data remains where it was until replaced by a PUSH or CALL.

That's why bugs like

int* foo() {
  int i = 123;
  return &i;
}

may seem to work for a while before the error shows. The data is still there for an indeterminate time before it's location on the stack actually gets overwritten.

Upvotes: 3

mksteve
mksteve

Reputation: 13073

Yes it was possible pre Data Execution Prevention.

A piece of code would fill out a buffer with more than it was expected, which would drift onto the stack. At that point, you have 2 mechanisms available.

1) wikipedia: return into libc

2) wikipedia: stack buffer overflow

return into libc

Here you overwrite the stack with a set of calls into functions (usually pre-existing in the program). This allows you to build up further code, and execute what you are after.

stack buffer overflow

This the overwrite modifies the saved frame pointer, or the return address on the stack. These are changed to the expected location of the function on the stack. This is somewhat hit-and-miss, so normally a buffer (nop-slide) will be added to increase reliability.

wikipedia : address space layout randomization makes this harder from outside the program, as you can't predict where important functions and data are.

Data execution and Address space layout randomization help mitigate these issues, as they are not normally desired. I would strongly recommend avoiding this form of dynamic programming, as it would be easy to exploit by some malicious entity.

Upvotes: 1

Related Questions