Executing function in remote process using code injection

1k Views Asked by At

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 ?

1

There are 1 best solutions below

0
TarmoPikaro On BEST ANSWER

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.