c++hookipcopenprocess

Executing function in remote process using code injection


I'm using advanced code injection code to start up .dll on remote process. You can find how this works / code snipet for example from here:

https://sourceforge.net/p/diagnostic/svn/HEAD/tree/src/RemoteInit.cpp

I've noticed that with some applications this approach does not work - it crashes host application. Main problem seems to be special kind 3-rd party software like ConEmuHk64.dll which intercepts kernel32.dll GetProcAddress by providing it's own hook function - after that I'm getting function pointer like this:

*((FARPROC*) &info.pfuncGetProcAddress) = GetProcAddress(hKernel32, "GetProcAddress");

But instead I'm getting pointer to function located in ConEmuHk64.dll.

In my own process calling that function is acceptable, but when trying to do the same in remote process - it crashes, since ConEmuHk64.dll is not necessarily available there.

I've figure out mechanism how to auto-probe correct address of that function by manually walking in DOS/NE other header - here is code snippet:

//
//  We use GetProcAddress as a base function, with exception to when GetProcAddress itself is hooked by 3-rd party 
//  software and pointer to function returned to us is incorrect - then we try to locate function manually by
//  ourselfes.
//
FARPROC GetProcAddress2( HMODULE hDll, char* funcName )
{
    FARPROC p = GetProcAddress( hDll, funcName );

    if( !p )
        return NULL;

    IMAGE_DOS_HEADER* pDosHeader = (IMAGE_DOS_HEADER *) hDll;

    if ( pDosHeader->e_magic != IMAGE_DOS_SIGNATURE )
        return p;

    IMAGE_NT_HEADERS* pNtHeaders = (IMAGE_NT_HEADERS *) (((char*) pDosHeader) + pDosHeader->e_lfanew);

    if ( pNtHeaders->Signature != IMAGE_NT_SIGNATURE )
        return p;

    IMAGE_OPTIONAL_HEADER* pOptionalHeader = &pNtHeaders->OptionalHeader;

    if( (char*) p >= (char*)hDll && (char*) p <= ((char*)hDll) + pOptionalHeader->SizeOfCode )
        // Sounds like valid address.
        return p;

    // Does not sounds right, may be someone hooked given function ? (ConEmuHk64.dll or ConEmuHk.dll)
    IMAGE_DATA_DIRECTORY* pDataDirectory = &pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
    IMAGE_EXPORT_DIRECTORY* pExp = (IMAGE_EXPORT_DIRECTORY *) ((size_t) pDosHeader + pDataDirectory->VirtualAddress);

    ULONG* addrofnames = (ULONG *) ((BYTE*) hDll + pExp->AddressOfNames);
    ULONG* funcaddr = (ULONG*) ((BYTE*) hDll + pExp->AddressOfFunctions);

    for ( DWORD i = 0; i < pExp->NumberOfNames; i++ )
    {
        char* funcname = (char*) ((BYTE*) hDll + addrofnames[i]);

        if ( strcmp( funcname, funcName ) == 0 )
        {
            void* p2 = (void*) ((BYTE*) hDll + funcaddr[i]);
            return (FARPROC) p2;
        }
    } //for

    return p;
} //GetProcAddress2

This seems to be working for GetProcAddress - I can detect hooked function and override it's behavior. However - this approach is not generic. I have tried similar function calls for other methods, for example for FreeLibrary/AddDllDirectory/RemoveDllDirectory - and those function pointers pinpoints out of dll boundary - GetProcAddress returns address before DOS header.

I suspect that comparison by dll / code size range is not correct one:

    if( (char*) p >= (char*)hDll && (char*) p <= ((char*)hDll) + pOptionalHeader->SizeOfCode )

But don't have a clue how formula can be improved.

Can you recommend me how to make this fix fully - so any 3-rd party software can intercept any function, and I can survive from it without crashes ?


Solution

  • Function pointer resolving is incorrect in case if "Exported function forward" is used (Can be googled by that term).

    A proper function resolving can be written like this: (What you see above is some copy-pasted function from some forum).

    //
    //  We use GetProcAddress as a base function, with exception to when GetProcAddress itself is hooked by 3-rd party 
    //  software and pointer to function returned to us is incorrect - then we try to locate function manually by
    //  ourselfes.
    //
    FARPROC GetProcAddress2( HMODULE hDll, char* funcName )
    {
        FARPROC p = GetProcAddress( hDll, funcName );
    
        if( !p )
            return NULL;
    
        IMAGE_DOS_HEADER* pDosHeader = (IMAGE_DOS_HEADER *) hDll;
    
        if ( pDosHeader->e_magic != IMAGE_DOS_SIGNATURE )
            return p;
    
        IMAGE_NT_HEADERS* pNtHeaders = (IMAGE_NT_HEADERS *) (((char*) pDosHeader) + pDosHeader->e_lfanew);
    
        if ( pNtHeaders->Signature != IMAGE_NT_SIGNATURE )
            return p;
    
        IMAGE_OPTIONAL_HEADER* pOptionalHeader = &pNtHeaders->OptionalHeader;
    
        if( (char*) p >= (char*)hDll && (char*) p <= ((char*)hDll) + pOptionalHeader->SizeOfCode )
            // Sounds like valid address.
            return p;
    
        // Does not sounds right, may be someone hooked given function ? (ConEmuHk64.dll or ConEmuHk.dll)
        IMAGE_DATA_DIRECTORY* pDataDirectory = &pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
        IMAGE_EXPORT_DIRECTORY* pExp = (IMAGE_EXPORT_DIRECTORY *) ((size_t) pDosHeader + pDataDirectory->VirtualAddress);
    
        ULONG* addrofnames = (ULONG *) ((BYTE*) hDll + pExp->AddressOfNames);
        ULONG* funcaddr = (ULONG*) ((BYTE*) hDll + pExp->AddressOfFunctions);
    
        for ( DWORD i = 0; i < pExp->NumberOfNames; i++ )
        {
            char* funcname = (char*) ((BYTE*) hDll + addrofnames[i]);
    
            if ( strcmp( funcname, funcName ) == 0 )
            {
                ULONG addressOfFunction = funcaddr[i];
                void* p2 = (void*) ((BYTE*) hDll + addressOfFunction);
    
                if( addressOfFunction >= pDataDirectory->VirtualAddress && addressOfFunction < pDataDirectory->VirtualAddress + pDataDirectory->Size )
                {
                    // "Exported function forward" - address of function can be found in another module.
                    // Actually for example AddDllDirectory is truly located in KernelBase.dll (alias api-ms-win-core-libraryloader-l1-1-0.dll ?)
                    char* dll_func = (char*) p2;
                    char* pdot = strchr(dll_func, '.');
                    if( !pdot ) pdot = dll_func + strlen( dll_func );
                    CStringA dllName(dll_func, (int)(pdot - dll_func));
                    dllName += ".dll";
    
                    HMODULE hDll2 = GetModuleHandleA(dllName);
                    if( hDll2 == NULL )
                        return p;
    
                    return GetProcAddress2( hDll2, pdot + 1 );
                }
    
                return (FARPROC) p2;
            }
        } //for
    
        return p;
    } //GetProcAddress2
    

    Besides this it's possible still to get .dll to be loaded at different address, but this does not happen with kernel32.dll or kernelbase.dll.

    But if .dll rebasing comes as a problem - one approach to solve is to use EasyHook approach - can be located here:

    https://github.com/EasyHook/EasyHook/blob/b8b2e37cfe1c269eea7042420bde305eb127c973/EasyHookDll/RemoteHook/thread.c

    See function GetRemoteFuncAddress.