8

How could I hook anywhere but the beginning of a function? I'm trying to add features to a third party executable, and I need it to execute it's code completely, then pass its data onto my function. I can't quite conceive how to do this.

Is there an easy way to do this? I can't find any hooking engines that implement this. I can't find any information on it anywhere.

I saw someone saying that you could add an illegal opcode then catch the exception, but I do not know how to do that.

Example (pseudo-code):

int moveCharacter(int x, int y) {
    x += 5;
    y += 5;
    return 0;
}

Say I want to hook right before return 0, and pass the new x and y variables to my own function (in an injected DLL, or code-cave) that writes the variables to a log file. After my function, I want to return to the original function, so that it can return like normal.

3 Answers 3

8

The reason why there aren't engines to hook the end of a function is because it's hard to determine where that is, or if it even exists. A function has a single entry point, but it can have multiple exit points, including none at all (consider exit()). The exit point can have multiple types, too - return, throw(), longjmp(), C++EH, etc.

The general idea to hook after function completion is to detour the caller instead, but it's too late for what you need. Anyway, it's done this way: First, detour the function of interest, which hooks the start of execution. When you receive control, unhook the function and then read the return address from the stack (assuming that the function will actually return). Next, detour the return address (the caller), and then let the original function execute. When you receive control again, the function has completed its execution. You can unhook the return address, perform your additional operations, and then resume execution. Unfortunately, you'll lose access to local variables (which you seem to want, based on your description). One way to avoid that problem is to single-step through the function, by installing a Vectored Exception Handler to receive the single-step exception. That would allow you to examine the instruction that will be executed next (because the exception occurs after the previous instruction executed), and if it's the return instruction, then you can log the values.

As far as the exception method goes, you would install a Vectored Exception Handler to point to your code, and then place a breakpoint instruction at the place of interest. Again, the problem is to determine where that place is.

4

Microsoft Detours makes this very easy. You'd effectively write the following code (to be safe, you'd want to make other calls such as DetourUpdateThread() as well):

DetourTransactionBegin();
DetourAttach(&(PVOID&)OriginalFunction, Function);
DetourTransactionCommit();

And then have code such as the following as your hook:

int Function(int x)
{
   int r = OriginalFunction(x);

   // Handle r here

   return r;
}
3
  • I was under the impression that Detours could only be used for executing before the other function. Instead of making OriginalFunction the beginning of the function, I could make it anything? I added an example to my main post to try to explain what I want to do.
    – Sean Heiss
    Jul 14, 2013 at 0:53
  • Ah, you need access to the local stack variables. In that case, just patch the target function's ret instruction with a jmp to your hook function. Jul 14, 2013 at 0:58
  • Detours has a pretty restrictive EULA, though. Not suitable for a lot of purposes.
    – 0xC0000022L
    Aug 31, 2013 at 1:34
3

A much simpler approach is to identify the point at which the code has actually generated the data you need. When you find that location, replace the next several bytes with a call or an far call to your own code. Make careful note of the bytes that you are overwriting. (As an aside, I recommend a call or far call rather than a jmp so that I don't have to worry so much about code relocation; I can reference the original location to return to from the stack rather than having to worry about where I am relative to the original code.)

The very first thing that your code should do is preserve state. Perhaps a pusha/pushf? Now process away. Rather than execute a return, the last few bytes of your code should do the following:

  • Pop the flags and registers
  • copy in the bytes from the original code that you previously overwrite
  • Unwind the stack by adjusting SP to account for the call or far call
  • jmp or far jmp to the IP or CS:IP immediately below the current SP

This process is actually the primary way that traditional malware "hooks" into your code. You're creating a sort of detour.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.