This is the first in a short series of articles I’m going to write about the way MockItNow works. I’m going to start off with something pretty meaty: How does MockItNow intercept the function calls and redirect them?
I tried a few ways of intercepting function calls and recording their parameters, and maybe one day I’ll explain ways not to do it, but for now, read on if you’re interested in how it works at the moment.
How Does MockItNow Intercept Function Calls and Redirect Them?
The short answer to that question is:
MockItNow uses a compiler flag to hook a call to a naked function at the beginning of every function call, before the prologue. This hook function jumps to a predetermined interceptor function and manipulates the stack pointer to cause the program to return back two levels in the stack when the interceptor function returns.
If I’d read this eight months ago then I’d be pretty confused right now. I knew roughly what a stack frame is, but special hooks? Prologues? Naked functions? Manipulating the stack pointer? That was all mumbo jumbo to me. If some or all of those are also mumbo jumbo to you, then you might want to read on. I’m going to explain what these things are, and why I needed to learn about them.
First Things First
I think it’s going to help to start off with an idea of what’s going on with the program when the mocker is intercepting and redirecting function calls. In the following scenario, we are calling a function Bar from a function Foo. Bar is going to get intercepted by the mocker and redirected to a replay function.
- Foo calls Bar.
- Bar calls compiler hook function _penter.
- _penter locates the replay function address and sets it into a variable jumpAddress.
- _penter moves the stack pointer.
- _penter jumps to Replay.
- Replay makes a note of the function call and returns
- Program flow returns back to Foo
Below I’ve written out a simplified view of the assembly code that this scenario would generate. I’ve interleaved the instructions to illustrate the program flow through the various functions. To help out with identifying which function is which, I’ve colored them all differently.
The important thing for the MockItNow is that we must never execute the body of Bar, which is highlighted in the second green section. If you’re smart and like this kind of thing, you might be able to work out why the body of Bar will never be called. If not, don’t worry – I’m about to explain.
There are a few important things to note here:
1. The call to _penter occurs before the prologue of Bar executes.
2. _penter adds four bytes to the stack pointer in its epilogue.
3. Instead of calling ret at the end of the _penter, it uses jmp to jump to Replay.
In the next few sections, I’m going to explain some details behind why these points are important. I’m also going to fill in a little bit of background knowledge that I had to learn in order to work this out.
Stack Frames, Prologues and Epilogues
If the assembly listing didn’t put you off, you may be wondering at this point, what is a prologue? Well, as you can see in the assembly above, each function performs the exact same two operations at the start of the function:
push ebp mov ebp,esp
This is the prologue! Note that if a function has any local variables then there will be another line in the prologue to allocate space for them, but in this case we don’t have any, so I’ll ignore it.
So what’s going on here? The point of the prologue is set up the current stack frame. The stack frame basically stores all the information about the current function we are in. It is here that your stack variables get stored, along with any other context the program needs to call and pass arguments to other functions, and to restore the previous stack frame.
All the prologue does is to store the previous stack frame location (ebp) by pushing it onto the stack and sets ebp to store the current stack frame location (esp).
You’ll probably also notice that apart from the _penter function, all the functions do the exact same thing at the end:
mov esp,ebp pop ebp ret
This is called the epilogue, and it just moves the stack pointer back to where the old base pointer is stored in the stack frame, and then pops the base pointer, which restores it. One important thing to remember here is that when you call pop, it restores whatever is at the current stack pointer location into the register provided, and moves the stack pointer.
I suspect that most programmers aren’t even aware of prologues and epilogues because the compiler automatically generates a standard prologue and epilogue for each function you write. It even works out the size of all your stack variables so that it can make the stack frame big enough. I certainly never had to deal with it until I started looking into MockItNow.
There is, however, one type of function for which the compiler won’t auto-generate prologues and epilogues. These functions are called naked functions. You can declare your function as naked using __declspec(naked) before the function name.
You’ll almost never want to use a naked function unless, of course, you need to customize either the prologue or epilogue. This is exactly what needs to happen in the _penter function in order to divert the function call.
Manipulating the Instruction Pointer
There are a couple more things I need to explain before I can go through an example of how MockItNow actually works: I need to explain what happens to the stack when the call and ret instructions are encountered, and also difference between call and jmp.
I’ll start my explanations with a quick introduction to the instruction pointer register (eip) and how it is changes as a program runs. The instruction pointer stores the address of the instruction that the program is currently executing. Normally when an instruction is executed, the instruction pointer is moved to the address of the next instruction. The call, ret and jmp instructions are all exceptions to this rule though, since their sole purpose is to manipulate instruction pointer in very specific ways.
When you call a function, the instruction pointer moves to the next instruction as usual. The value of the instruction pointer register then gets pushed onto the stack, and the program sets the register to the address of the first instruction in the function you are calling. This means that the next instruction to get executed is the first instruction of the function you have called.
So how does the program know which address to copy into the instruction pointer register when you call a function? For most calls, the answer is easy: The linker tells it! If you take a look at the disassembly for a function call, you’ll normally see something like this:
call Foo (123456h)
The number in brackets is the address that the instruction pointer is going to jump to when the call instruction is processed. Sometimes you may see the program make a function call using a register like eax. This happens if you are calling a virtual function because the function address wasn’t known at link time.
Beware that if you have incremental linking turned on then address you see in the call instruction probably isn’t the address of the actual function, but actually the address inside the incremental link table. This descrepency between the real function address and the call address is why MockItNow doesn’t work when incremental linking is turned on.
I suspect that you’ve guessed by now that the reason the call instruction pushed the old instruction pointer register onto the stack is so that the ret instruction can pop it back off. This is exactly what it does to return program flow back to the caller function.
You’ve probably also guessed that the difference between call and jmp is that jmp doesn’t push the instruction pointer onto the stack before changing it. We’re going to exploit this difference in a bit.
Putting it All Together
Hopefully everything I outlined above is clear, because now I’m going to show a simplified view of the state of the stack as the program in the scenario above executes, and we’ll see why the body of Bar never gets executed.
Remember, the contents of the stack are based on the address of stack pointer, so if you change the stack pointer, you change the contents of the stack. Also, ebp is the base pointer for that function’s stack frame, and eip is the next instruction to execute within the function.
I’m going to assume that Foo is called directly from the Test function, so the first thing that gets pushed onto the stack is the Test function return address and base pointer. The stack is represented by the table below each significant event. The top of the stack is the top of the table.
There’s nothing out of the ordinary here so far. This is what you’d expect to see for a function call to Bar. It just pushed the return address for the instruction pointer onto the stack.
Now things are looking a bit interesting. We have the return address for Bar on top of the return address for Foo. We’re going to manipulate this in a bit.
There’s nothing out of the ordinary here so far for _penter. It has done the standard prologue, and it has done the first two instructions of the standard epliogue.
Finally, this is the part where the good stuff happens! The stack pointer was incremented by four bytes, which basically removes the return address for Bar without restoring the instruction pointer. There is no trace left in the stack that Bar was ever called! The program now uses the jmp instruction to move program exectution to the Replay function. It uses jmp rather than call so that the instruction pointer register doesn’t get stored onto the stack.
This function has the standard prologue and epilogue, but before the ret instruction is executed, I wanted to highlight the fact that the address on the the top of the stack is an address inside Foo.
We have now jumped up two levels in the stack. I write ‘two levels’ because we were never really in Bar. Instead of returning back _penter, or to Bar, we have returned Foo. This is really important since the Replay function may be returning a value, and the next instructions in Foo will retrieve that return value.
The rest is just some cleanup!
I hope that you can see how manipulating the stack caused the instruction pointer to return back from Replay to Foo. The body of Bar was never executed.
If Bar has a return value, we return a preset value from Replay, and Foo never knows that Bar was intercepted! As long as Replay has the same calling convention as Bar, you don’t have to worry about how the return values are propagated back.
Looking back to the beginning of the article, I highlighted three important points. I hope you have a better understanding now I highlighted these points in particular.
1. Bar never gets the chance to change the state of the stack. This means we don’t have to worry about removing the stack frame when we return from _penter.
2. Adding four bytes to the stack pointer removes the return address back into Bar from the stack without changing the instruction pointer. This makes it appear as though _penter was called directly from Foo.
3. Because the call instruction wasn’t used to enter the Record function from _penter, the instruction pointer was never saved to the stack, so the return address still points back to Foo.
I hope this was informative and perhaps even a little bit interesting. Next time I’m going to write about some of the the challenges I encountered when working out how to store function arguments and return values.