Перехват API, который вступает в силу для всего процесса - как EXE, так и DLL - PullRequest
4 голосов
/ 28 июня 2011

У меня приложение состоит из одного EXE и нескольких DLL. После прочтения Windows через C / C ++ я пытаюсь выполнить функцию Sleep перехвата в одной из DLL, и ожидаю, что перехват будет работать как для EXE, так и для всех DLL. Обратите внимание, что CAPIHook код поступает из Windows через образец кода C / C ++

В проекте DLL

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;
}

В проекте EXE

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();
}

Это вывод, который я получаю

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

Что заставляет меня чувствовать себя странно, так это то, что я ожидаю, что CAPIHook будет действовать во всем отдельном процессе. Поскольку EXE и DLL принадлежат одному и тому же процессу, оба должны иметь возможность достигать MySleep. Тем не менее, я заметил, что только вызов из EXE достигнет MySleep, но не DLL.

Я могу найти образец кода прямо здесь CAPIHook-doesnt-have-effect-in-entire-process.zip , он содержит dll и exe проектов.

Я тоже однажды заменил CHookAPI на код в apihijack . Та же проблема все еще случается. Эффект зацепления не будет распространяться на весь процесс.

Есть что-то, что я пропустил? Пожалуйста, не предлагайте мне использовать EasyHook, Detours, ..., поскольку я просто хочу знать, почему приведенный выше код не будет работать, и как я могу это исправить.

1 Ответ

4 голосов
/ 28 июня 2011

Это потому, что оригинальный CAPIHook не заменяет локальный IAT (в вашем случае проект DLL, который содержит двоичные файлы для CAPIHook).

Причина этого состояла в том, чтобы защитить себя от бесконечной рекурсии, которая приводит к stackoverflow (который пользователи также опубликуют в SO: D).

Чтобы гарантировать, что все последующие загруженные модули будут импортировать «правильную» функцию,
поиск CAPIHook и перенаправление LoadLibrary и GetProcAddress после строительства.

Однако эти функции используются и самим CAPIHook, поэтому замена локального IAT на прокси-функцию (CAPIHook :: LoadLibrary или CAPIHook :: GetProcAddress) вызовет бесконечную рекурсию, поскольку прокси-серверы непреднамеренно вызывали себя при попытке вызвать API-интерфейс ОС!


Один из способов решить эту проблему - изменить CAPIHook, чтобы проверить, можно ли заменить локальный IAT.

1.) Новый атрибут m_bIncludeLocalIAT добавлен в CAPIHook, а ctor / dtor изменены соответствующим образом.

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.) В статическую функцию добавлен новый параметр 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.) Обновление статических экземпляров CAPIHook

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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...