push ebp // save old frame ptr
// (1 byte instruction)
mov ebp, esp // set the top of
// the stack as the
// current frame ptr
// (2 byte inst)
sub esp, x // allocate x bytes on
// the stack for local
// variables (3 to 6
// byte instruction)
or
add esp, -x
add esp, x // dealloc. stack
// space, x bytes
// were allocated
// (3-6 byte inst)
pop ebp // restore caller's
// frame ptr (1 byte)
ret // return (1 byte)
mov esp, ebp // dealloc. stack
// space, any
// number of bytes
// allocated on the
// stack (2 byte
// instruction)
pop ebp // restore caller's
// frame ptr (1
// byte)
ret // return (1 byte)
leave // dealloc. stack
// frame & restores
// old frame ptr
// (1 byte)
ret // return (1 byte)
jne x
:
x: leave
ret
In this case, if we replace instructions prior to LEAVE, then the jump target x would be disturbed. From our experiences, the scenario of not being able to find 5 bytes worth of instructions at a function's epilogue does occur in practice but is relatively rare. For such a situation to occur in practice, two conditions need to be met:
goto label;
:
:
label:
return;