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 ?
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:
See function GetRemoteFuncAddress.