Home > Programming, Reversing, Windows > Preventing Recursion in API Hooks

Preventing Recursion in API Hooks

I’m sure many have ran across the same issue I did recently, and that is that when doing API hooking of low-level functions (e.g. the NT API) code that is inserted into the hook function (e.g. logging code) will end up calling the same function and cause a stack overflow.

Greyman had a good idea which I’ve used, and put together an example for. Credits to Greyman for the idea.

Basically, you use TLS to hold a flag so that the offending code (the code causing the infinite recursion)  is only executed once per call. The following code should work under all major Windows compilers, but is using a nonstandard compiler extension so may not work cross-platform (which is not a concern for a low level project anyway). Using LdrGetProcedureAddress as an example because using any of the standard output functions will cause the recursive call (printf, std::cout, etc):

NTSTATUS NTAPI APIHook::LdrGetProcedureAddress_Hook( IN HMODULE ModuleHandle,

IN PANSI_STRING FunctionName OPTIONAL, IN WORD Ordinal OPTIONAL,

OUT PVOID *FunctionAddress )

{

// Use TLS to prevent recursive function calls when logging

static __declspec(thread) bool Logging = false;

// Get the true address of the function

NTSTATUS RetVal =

((tLdrGetProcedureAddress)(PROC)(sm_LdrGetProcedureAddress))

(ModuleHandle,FunctionName,Ordinal,FunctionAddress);

// Don’t call function recursively when logging

if (Logging)

return RetVal;

// Start logging wrapper

Logging = true;

// Function pointer

PVOID pFunc = (FunctionAddress ? *FunctionAddress : 0);

// Log API call

if (Config::Get()->ShouldLogFunctions())

{

try

{

// Guard against structured exceptions

SehGuard Guard;

// Create string from c-style string

// Note: Will thrown an access violation if c-style string isn’t a

// valid pointer

std::string FunctionNameTemp(FunctionName->Buffer);

// If we get to this point the string is valid so log it.

DBGPRNT(boost::str(boost::format(”LdrGetProcedureAddress: Module”

” = %p, Name = %s. Return = %p.\n”) %ModuleHandle

%FunctionNameTemp %pFunc).c_str());

}

catch (const SehException& /*e*/)

{

// If we get here the string is invalid so we assume it’s an

// ordinal and log it as such

DBGPRNT(boost::str(boost::format(”LdrGetProcedureAddress: Module”

” = %p,  Ordinal = %u. Return = %p.\n”) %ModuleHandle %Ordinal

%pFunc).c_str());

}

}

// End logging wrapper

Logging = false;

// Check we got a valid pointer back

if (!FunctionAddress)

return RetVal;

// Dereference pointer and get actual function pointer

FARPROC pfn = (FARPROC)(*FunctionAddress);

// Is it one of the functions that we want hooked?

APIHook* p = sm_pHead;

for (; (pfn != NULL) && (p != NULL); p = p->m_pNext)

{

if (pfn == p->m_pOrig)

{

// The address to return matches an address we want to hook

// Return the hook function address instead

pfn = p->m_pHook;

break;

}

}

return RetVal;

}

In the above code DBGPRNT is just a macro used to call ‘printf’ if a certain compiler flag is enabled, or omit the code entirely if the flag is disabled. Implemented that way for performance reasons. Irrelevant details aside though, its easy to see how the implementation and how simple it is to use. Obviously thread-safe due to the variable being thread-local so it shouldn’t interfere with anything, I’ve yet to have any problems with it. Tested on both IA-32 and AMD64.

  1. No comments yet.
  1. No trackbacks yet.