4

I have this function:

int vulnerableFunc(char *input)
{
    char buffer[256];

    memcpy(buffer, input, 1024);
    return 1;
}

When I call it with 2000 "A" and dissassemble it with ollydbg on a 32 bit windows XP machine, I get the following addresses on the stack:

22FB6C Ret Addr             |
22FB68 Old EBP              |       |
                            | 268   |
                            |       | 264
22FA60 Buffer for Writing A |       |

22FA5C ?? RETURN from ntdll.7c92755D to ntdll.7C927553                      |
22FA58 1024                                                                 |
22FA54 SRC - Ptr to 22FBB0 (22FBB0 = A * 2000 (Original Arg to Func))       | 16
22FA50 DEST - Ptr to 22FA60 (Copy is Inc From 22FA60)                       |
22FA4C local var end (last local var 22FA50)    

Q1) I have only allocated 256 bytes of local variable and yet I get 264 bytes from "Buffer for Writing A" until "Old EBP", why is that?

Q2) What is "RETURN from ntdll.7c92755D to ntdll.7C927553" at address 22FA5C? Shouldn't there only be 12 bytes arguments to memcpy?

enter image description here

nrz
  • 10,435
  • 4
  • 39
  • 71
user962460
  • 153
  • 1
  • 8
  • 2
    The /GS compile option creates a stack canary that detects stack frame corruption, the kind you are exercising here. /RTC also creates extra space to detect bugs. – Hans Passant Dec 21 '13 at 12:13
  • I think the answer for Q1 might be because char[] is the same as char* and that in itself is 8 bytes on a 64-bit system + the 256 bytes you allocated. Then again, I don't know.. – Brandon Dec 21 '13 at 12:14
  • @ CantChooseUsernames The OS is 32 bit, sorry for not stating earlier – user962460 Dec 21 '13 at 12:35
  • @CantChooseUsernames: No, they're not the same. – MSalters Dec 21 '13 at 12:36
  • @Hans Passant What about Q2? Is "RETURN from ntdll.7c92755D to ntdll.7C927553" just garbage because of /GS? – user962460 Dec 21 '13 at 12:37
  • @Hans Passant Ignore the last comment to you. What about Q2? Is "RETURN from ntdll.7c92755D to ntdll.7C927553" a canary value? – user962460 Dec 21 '13 at 12:43

1 Answers1

1

To imagine the full picture you should realize that memory is currently cheap, compared to execution time, at least for non-embedded environment. So gaps in stack usage can be caused simply by mis-taking a care to fill them. Particularly for this case, I'm not familiar with the MSVC habits, but the following is obviously seen that a gap start is aligned to 16-byte boundary. Such boundary is useful for cache access optimization and is required for many ABIs (e.g. AMD x86-64 ABI; and GCC does this now even for 32-bit environment). I guess this is the first reason to skip a few bytes but reach some more execution speed.

The second factor is that, if a called function follows C-style convention (like __cdecl) and doesn't clear stack after it, the stack pointer is moved after function call by its argument size. If it's important than caller should move SP back immediately; but it seems again less important than an extra CPU instruction. I've been seeing object code examples after GCC when a function chain was called without SP returning, so it was moved more than 100 bytes left to its initial position. It's also a trade-off issue and could be very depending on optimization level, target CPU tuning, etc.

So my suggestion is just to stop worrying on that unless you are developing for a rather limited resource case (embedded, system startup, etc.)

Netch
  • 4,171
  • 1
  • 19
  • 31