2012-07-21 25 views
6

Quiero conectar funciones que se invocan desde una DLL cargada en tiempo de ejecución, utilicé la clase CAPIHook del libro "Windows Vía C/C++" (la inyección de DLL mediante el sistema de instalación Gancho ancho y El enganche mediante Modificar IAT), pero este código solo funciona si el nombre/símbolos DLL existen en el IAT en el archivo ejecutable. (Es decir, para Implícito DLL Linking)Cómo modificar la tabla de direcciones de importación para el DLL cargado en tiempo de ejecución

este es el código DLL:

CAPIHook::CAPIHook(PSTR pszCalleeModName, PSTR pszFuncName, PROC pfnHook) { 

    // Note: the function can be hooked only if the exporting module 
    //  is already loaded. A solution could be to store the function 
    //  name as a member; then, in the hooked LoadLibrary* handlers, parse 
    //  the list of CAPIHook instances, check if pszCalleeModName 
    //  is the name of the loaded module to hook its export table and 
    //  re-hook the import tables of all loaded modules. 

    m_pNext = sm_pHead; // The next node was at the head 
    sm_pHead = this;  // This node is now at the head 

    // Save information about this hooked function 
    m_pszCalleeModName = pszCalleeModName; 
    m_pszFuncName  = pszFuncName; 
    m_pfnHook   = pfnHook; 
    m_pfnOrig   = GetProcAddressRaw(GetModuleHandleA(pszCalleeModName), m_pszFuncName); 

    // If function does not exit,... bye bye 
    // This happens when the module is not already loaded 
    if (m_pfnOrig == NULL) 
    { 
     wchar_t szPathname[MAX_PATH]; 
     GetModuleFileNameW(NULL, szPathname, _countof(szPathname)); 
     wchar_t sz[1024]; 
     StringCchPrintfW(sz, _countof(sz), 
     TEXT("[%4u - %s] impossible to find %S\r\n"), 
     GetCurrentProcessId(), szPathname, pszFuncName); 
     OutputDebugString(sz); 
     return; 
    } 

    // Hook this function in all currently loaded modules 
    ReplaceIATEntryInAllMods(m_pszCalleeModName, m_pfnOrig, m_pfnHook); 
} 

esto es las funciones de gancho:

HMODULE WINAPI CAPIHook::LoadLibraryA(PCSTR pszModulePath) { 

    HMODULE hmod = ::LoadLibraryA(pszModulePath); 
    FixupNewlyLoadedModule(hmod, 0); 
    return(hmod); 
} 

HMODULE WINAPI CAPIHook::LoadLibraryW(PCWSTR pszModulePath) { 

    HMODULE hmod = ::LoadLibraryW(pszModulePath); 
    FixupNewlyLoadedModule(hmod, 0); 
    return(hmod); 
} 

HMODULE WINAPI CAPIHook::LoadLibraryExA(PCSTR pszModulePath, 
    HANDLE hFile, DWORD dwFlags) { 

    HMODULE hmod = ::LoadLibraryExA(pszModulePath, hFile, dwFlags); 
    FixupNewlyLoadedModule(hmod, dwFlags); 
    return(hmod); 
} 

HMODULE WINAPI CAPIHook::LoadLibraryExW(PCWSTR pszModulePath, 
    HANDLE hFile, DWORD dwFlags) { 

    HMODULE hmod = ::LoadLibraryExW(pszModulePath, hFile, dwFlags); 
    FixupNewlyLoadedModule(hmod, dwFlags); 
    return(hmod); 
} 

el método para la sustitución de IAT:

void CAPIHook::ReplaceIATEntryInOneMod(PCSTR pszCalleeModName, 
    PROC pfnCurrent, PROC pfnNew, HMODULE hmodCaller) { 

    // Get the address of the module's import section 
    ULONG ulSize; 

    // An exception was triggered by Explorer (when browsing the content of 
    // a folder) into imagehlp.dll. It looks like one module was unloaded... 
    // Maybe some threading problem: the list of modules from Toolhelp might 
    // not be accurate if FreeLibrary is called during the enumeration. 
    PIMAGE_IMPORT_DESCRIPTOR pImportDesc = NULL; 
    __try { 
     pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR) ImageDirectoryEntryToData(
     hmodCaller, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ulSize); 
    } 
    __except (InvalidReadExceptionFilter(GetExceptionInformation())) { 
     // Nothing to do in here, thread continues to run normally 
     // with NULL for pImportDesc 
    } 

    if (pImportDesc == NULL) 
     return; // This module has no import section or is no longer loaded 


    // Find the import descriptor containing references to callee's functions 
    for (; pImportDesc->Name; pImportDesc++) { 
     PSTR pszModName = (PSTR) ((PBYTE) hmodCaller + pImportDesc->Name); 
     if (lstrcmpiA(pszModName, pszCalleeModName) == 0) { 

     // Get caller's import address table (IAT) for the callee's functions 
     PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA) 
      ((PBYTE) hmodCaller + pImportDesc->FirstThunk); 

     // Replace current function address with new function address 
     for (; pThunk->u1.Function; pThunk++) { 

      // Get the address of the function address 
      PROC* ppfn = (PROC*) &pThunk->u1.Function; 

      // Is this the function we're looking for? 
      BOOL bFound = (*ppfn == pfnCurrent); 
      if (bFound) { 
       if (!WriteProcessMemory(GetCurrentProcess(), ppfn, &pfnNew, 
        sizeof(pfnNew), NULL) && (ERROR_NOACCESS == GetLastError())) { 
        DWORD dwOldProtect; 
        if (VirtualProtect(ppfn, sizeof(pfnNew), PAGE_WRITECOPY, 
        &dwOldProtect)) { 

        WriteProcessMemory(GetCurrentProcess(), ppfn, &pfnNew, 
         sizeof(pfnNew), NULL); 
        VirtualProtect(ppfn, sizeof(pfnNew), dwOldProtect, 
         &dwOldProtect); 
        } 
       } 
       return; // We did it, get out 
      } 
     } 
     } // Each import section is parsed until the right entry is found and patched 
    } 
} 

la el autor agregó comentarios para agregar esta funcionalidad, pero no estoy seguro de cómo hacerlo

Nota: la función solo se puede enganchar si el módulo de exportación ya está cargado. Una solución podría ser almacenar el nombre de la función como miembro; luego, en los manejadores LoadLibrary * enganchados, analice la lista de instancias de CAPIHook, compruebe si pszCalleeModName es el nombre del módulo cargado para enganchar su tabla de exportación y vuelva a conectar las tablas de importación de todos los módulos cargados.

también escribir esto en el libro, pero de nuevo no sé qué hacer

Una posible solución es utilizar el LoadLibrary enganchado * funciones a detectar cuando un módulo está exportando una sin parchear función enganchado y continuación, ejecutar dos acciones:

gancho de nuevo la tabla de importación del módulo ya cargado porque es ahora es posible llamar a GetProcAddress y obtener un puntero a la original aplicación de la función para enganchar. Observe que el nombre de la función debe almacenarse como un miembro de clase y establecerse en el constructor .

Actualice directamente esta función enganchada en Exportar tabla de direcciones del módulo de exportación como se muestra mediante la implementación de la función ReplaceEATEntryInOneMod. De esta manera, todos los nuevos módulos que llaman la función de gancho llamarán a nuestro manejador

intento de modificar el IAT después de cargar el archivo DLL, pero mi función de enganche no se llama

HMODULE WINAPI CAPIHook::LoadLibraryW(PCWSTR pszModulePath) { 

    HMODULE hmod = ::LoadLibraryW(pszModulePath); 

    if (StrCmpIW(pszModulePath, myDLLUnicodeName.c_str()) == 0) { 
     PROC proc = GetProcAddressRaw(GetModuleHandleA(myDLLName.c_str()), myFunctionName.c_str()); 

     if (proc != NULL) { 
      for (CAPIHook* p = sm_pHead; p != NULL; p = p->m_pNext) { 
       if (StrCmpIA(p->m_pszCalleeModName, myDLLName.c_str()) == 0) { 
        MessageBox(NULL, L"This is the New Dynamic DLL", L"Test!", 0); 
        ReplaceIATEntryInAllMods(p->m_pszCalleeModName, proc , p->m_pfnHook); 
       } 
      } 
     } 
    } 

    FixupNewlyLoadedModule(hmod, 0); 
    return(hmod); 
} 

es así, cómo modificar este código para manejar el caso de carga dinámica?

+0

¿Está tratando de bloquear la inyección dll? Debido a que un simple 'JNZ' puede omitir todo –

+0

Cambie el' ReplaceIATEntryInOneMod' para devolver un código de error para que sepa si la entrada se ha reemplazado satisfactoriamente o no, o si incluso se encuentra la entrada. – Jay

Respuesta

8

He hecho esto antes. Lo que desea es enganchar EAT en lugar de IAT. Además, enganche la API :: LoadLibrary para que sepa cuándo se carga la DLL y enganche la API solicitada de la DLL después de que se cargue.

Hay algunos ejemplos en Internet sobre cómo hacer esto.Aquí hay uno que encontré hace un momento: http://board.cheat-project.com/showthread.php?t=10633

+0

¿Podría explicar lo que quiere decir sobre conectar el EAT en lugar de IAT? – mox

+4

Significa escribir en la tabla de direcciones de exportación de la DLL importada en lugar de escribir en la tabla de direcciones de importación de su propio módulo. Si está cargando un dll dinámicamente y llamando a algo de él, la función que está llamando no tendrá entrada en el IAT de su módulo. Sin embargo, estará presente en su propio DLL EAT. – EddieBytes

+2

Desafortunadamente, el enlace que ha proporcionado ya no funciona, ¿tal vez podría reemplazarlo por otro que sí lo haga (o incorporar parte del código en su respuesta)? –

Cuestiones relacionadas