Reputation: 42642
I have an application consists of a single EXE and multiple DLLs. After reading Windows via C/C++, I try to perform hook on Sleep
function in one of the DLL, and expecting the hook will work across both EXE and all DLLs. Note that, CAPIHook
code is getting from Windows via C/C++'s sample code
In DLL Project
void WINAPI MySleep( DWORD dwMilliseconds );
CAPIHook g_Sleep("Kernel32.dll", "Sleep", (PROC)MySleep);
typedef void (WINAPI *Sleep_Type)( DWORD dwMilliseconds );
// Hook function.
void WINAPI MySleep( DWORD dwMilliseconds )
{
printf ("-------> In MySleep\n");
((Sleep_Type)(PROC)g_Sleep)(dwMilliseconds);
}
// This is an example of an exported function.
DLL_API int dll_function_which_is_going_to_call_sleep(void)
{
printf ("DLL function being called\n");
printf ("Call Sleep in DLL function\n");
Sleep(100);
return 42;
}
In EXE Project
void CexeDlg::OnBnClickedButton1()
{
// TODO: Add your control notification handler code here
printf ("Button being clicked\n");
printf ("Call Sleep in EXE function\n");
Sleep(100);
dll_function_which_is_going_to_call_sleep();
printf ("Call Sleep in EXE function\n");
Sleep(100);
dll_function_which_is_going_to_call_sleep();
}
This is the output I am getting
Button being clicked
Call Sleep in EXE function
-------> In MySleep
DLL function being called
Call Sleep in DLL function
Call Sleep in EXE function
-------> In MySleep
DLL function being called
Call Sleep in DLL function
What make me feel strange is that, I am expecting CAPIHook
will take effect across entire single process. Since EXE and DLLs belong to a same process, both should be able to reach MySleep
. However, my observation is that, only call from EXE will reach MySleep
, but not DLL.
I locate sample code right here CAPIHook-doesnt-have-effect-in-entire-process.zip, it contains dll
and exe
projects.
I also once drop in replace CHookAPI
with code in apihijack. Same problem still happen. The hooking effect will not spread across entire process.
Is there anything I had missed out? Please do not suggest me to use EasyHook, Detours, ..., as I just want to know why the above code won't work, and how I can fix it.
Upvotes: 4
Views: 3280
Reputation: 3208
This is because the original CAPIHook does not replace local IAT (in your case, the DLL project which contains binaries for CAPIHook).
The reason behind this was to protect itself from infinite recursion which lead to stackoverflow (which the users will also post question in SO :D).
To ensure that any subsequent modules loaded will be importing the "correct" function,
CAPIHook search and re-direct LoadLibrary and GetProcAddress upon construction.
However, these function are used by CAPIHook itself too, so changing local IAT to proxy function (CAPIHook::LoadLibrary or CAPIHook::GetProcAddress) will cause infinite recursion as the proxies unintentionally called itself while trying to call underlying OS API !
One way to solve this is by modifying CAPIHook to check whether it is alright to replace local IAT.
1.) New attribute m_bIncludeLocalIAT added to CAPIHook and ctor/dtor modified accordingly.
class CAPIHook
{
...
CAPIHook(PSTR pszCalleeModName, PSTR pszFuncName,
PROC pfnHook, BOOL bIncludeLocalIAT = TRUE);
...
BOOL m_bIncludeLocalIAT;
...
};
CAPIHook::CAPIHook( PSTR pszCalleeModName, PSTR pszFuncName,
PROC pfnHook, BOOL bIncludeLocalIAT) {
...
m_bIncludeLocalIAT = bIncludeLocalIAT;
...
ReplaceIATEntryInAllMods(m_pszCalleeModName, m_pfnOrig, m_pfnHook, m_bIncludeLocalIAT);
}
CAPIHook::~CAPIHook() {
ReplaceIATEntryInAllMods(m_pszCalleeModName, m_pfnHook, m_pfnOrig, m_bIncludeLocalIAT);
...
}
2.) New parameter added to the static function CAPIHook::ReplaceIATEntryInAllMods.
static void WINAPI ReplaceIATEntryInAllMods(PCSTR pszCalleeModName,
PROC pfnOrig, PROC pfnHook, BOOL bReplaceLocalIAT){
HMODULE hmodThisMod = ExcludeAPIHookMod
? ModuleFromAddress(ReplaceIATEntryInAllMods) : NULL;
// Get the list of modules in this process
CToolhelp th(TH32CS_SNAPMODULE, GetCurrentProcessId());
MODULEENTRY32 me = { sizeof(me) };
for (BOOL bOk = th.ModuleFirst(&me); bOk; bOk = th.ModuleNext(&me)) {
if (bReplaceLocalIAT || (me.hModule != hmodThisMod)) {
// Hook this function in this module
ReplaceIATEntryInOneMod(
pszCalleeModName, pfnCurrent, pfnNew, me.hModule);
}
}
}
3.) Update the static CAPIHook instances
CAPIHook CAPIHook::sm_LoadLibraryA ("Kernel32.dll", "LoadLibraryA",
(PROC) CAPIHook::LoadLibraryA, FALSE);
CAPIHook CAPIHook::sm_LoadLibraryW ("Kernel32.dll", "LoadLibraryW",
(PROC) CAPIHook::LoadLibraryW, FALSE);
CAPIHook CAPIHook::sm_LoadLibraryExA("Kernel32.dll", "LoadLibraryExA",
(PROC) CAPIHook::LoadLibraryExA, FALSE);
CAPIHook CAPIHook::sm_LoadLibraryExW("Kernel32.dll", "LoadLibraryExW",
(PROC) CAPIHook::LoadLibraryExW, FALSE);
CAPIHook CAPIHook::sm_GetProcAddress("Kernel32.dll", "GetProcAddress",
(PROC) CAPIHook::GetProcAddress, FALSE);
Upvotes: 4