5

I know that a program stack looks somewhat like this (from high to low):

   EIP   |   EBP   |   local variables

But where could I find %eax, and the other general registers? Is it possible to overwrite them using a buffer overflow?

Update: In the end, I did not even have to overwrite %eax, because it turned out that the program pointed %eax to the user input at some point.

LonelyWebCrawler
  • 2,866
  • 4
  • 37
  • 57
  • 2
    This depends on the calling convention in use, and possibly on the compiler's optimization decisions. – Mark Nov 03 '14 at 10:27
  • 1
    A better title for your question might be "Is it possible to overwrite a register using a buffer overflow?" because as stated, it assumes a false premise, strictly (though incidentally, it happens to be true in at least one context) – codenheim Nov 03 '14 at 19:38
  • You're right, I changed it. – LonelyWebCrawler Nov 04 '14 at 00:37

3 Answers3

7

A register, by definition, is not in RAM. Registers are in the CPU and do not have addresses, so you cannot overwrite them with a buffer overflow. However, there are very few registers, so the compiler really uses them as a kind of cache for the most used stack elements. This means that while you cannot overflow into registers stricto sensu, values overwritten in RAM will sooner or later be loaded into registers.

(In Sparc CPU, the registers-as-stack-cache policy is even hardwired.)

In your schema, EIP and EBP are not on the stack; the corresponding slots on the stack are areas from which these two registers will be reloaded (upon function exit). EAX, on the other hand, is a general purpose register that the code will use here and there, without a strict convention.

Thomas Pornin
  • 72,986
  • 14
  • 147
  • 189
2

EAX will probably never appear on the stack. For most x86 compilers EAX is the 32-bit return-value register, and is never saved on the stack nor restored from the stack (RAX in 64-bit systems).

This is not to say that a buffer overflow cannot be used to alter the contents of EAX by putting executable code on the stack; if code execution on the stack has not been disabled by the OS, this can be done, or you can force a bogus return address on the stack which transfers control to a code sequence that loads a value into EAX, but these are quite difficult to pull off. Similarly, if the value returned by a function is known to be stored in a local variable, a stack smash that altered that variable would change the value copied to EAX, but optimizing compilers can change stack layout on a whim, so an exploit that works on one version may fail completely on a new release or hotfix.

flounder
  • 141
  • 6
  • Thanks for the details. It all makes sense, except this: "For most x86 compilers EAX is the 32-bit return-value register". I thought EAX was just a general register. Aren't the return values stored elsewhere? – LonelyWebCrawler Nov 03 '14 at 17:09
  • 1
    Different operating systems have different calling conventions, but I've never seen one that hasn't used EAX (or AX or RAX) to note the return value from a function. After the CALL is executed you will usually see the value in EAX being checked or stored. – Jason Goemaat Nov 04 '14 at 00:53
2

See Thomas Pornin (+1) and flouder's (+1) answers, they are good. I want to add a supplementary answer that may have been alluded to but not specifically stated, and that is register spilling.

Though the "where" of the original question (at least as worded) appears to be based on the false premise that %eax is on the stack, and being a register, it isn't part of the stack on x86 (though you can emulate any hardware register set on a stack, and some architectures actually do this, but that isn't relevant), incidentally, registers are spilled/filled from the stack frequently. So it is possible to smash the value of a register with a stack overflow if the register has been spilled to the stack. This would require you to know the spilling mechanism of the particular compiler, and for that function call, you would need to know that %eax had been spilled, where it had been spilled to, and stomp that stack location, and when it is next filled from its memory copy, it gets the new value. As unlikely as this seems, these attacks are usually inspired by reading source code, and knowing something about the compiler in question, so it isn't really that far fetched.

See this for more reading on register spilling

gcc argument register spilling on x86-64

https://software.intel.com/en-us/articles/dont-spill-that-register-ensuring-optimal-performance-from-intrinsics

Community
  • 1
  • 1
codenheim
  • 20,467
  • 1
  • 59
  • 80