Выполнение функции в удаленном процессе с использованием внедрения кода

Я использую расширенный код внедрения кода для запуска .dll на удаленном процессе.
Вы можете найти, как это работает / фрагмент кода, например, здесь:

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

Я заметил, что в некоторых приложениях этот подход не работает — он приводит к сбою хост-приложения. Похоже, что основной проблемой является специальное программное обеспечение сторонних производителей, такое как ConEmuHk64.dll который перехватывает kernel32.dll GetProcAddress предоставляя свою собственную функцию ловушки — после этого я получаю указатель на функцию следующим образом:

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

Но вместо этого я получаю указатель на функцию, расположенную в ConEmuHk64.dll.

В моем собственном процессе вызов этой функции приемлем, но при попытке сделать то же самое в удаленном процессе — происходит сбой, так как ConEmuHk64.dll не обязательно доступен там.

Я выяснил механизм автоматического определения правильного адреса этой функции путем ручного перехода в другой заголовок DOS / NE — вот фрагмент кода:

//
//  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

Кажется, это работает для GetProcAddress — Я могу обнаружить подключенную функцию и переопределить ее поведение. Однако этот подход не является общим. Я пробовал аналогичные вызовы функций для других методов, например для FreeLibrary/AddDllDirectory/RemoveDllDirectory — и эти указатели на функции указывают вне границы DLL — GetProcAddress возвращает адрес перед заголовком DOS.

Я подозреваю, что сравнение по диапазону размера DLL / кода не является правильным:

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

Но не имею понятия, как можно улучшить формулу.

Можете ли вы порекомендовать мне, как сделать это исправление полностью — чтобы любое стороннее программное обеспечение могло перехватить любую функцию, и я мог бы выжить без сбоев?

0

Решение

Неправильное разрешение указателя функции в случае, если используется «Экспортированная функция вперед» (может быть введено с помощью этого термина).

Правильное разрешение функции может быть написано так: (То, что вы видите выше, это некоторая скопированная функция с какого-то форума).

//
//  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

Кроме того, все еще можно загрузить .dll для загрузки по другому адресу, но этого не происходит с kernel32.dll или kernelbase.dll.

Но если проблема с перебазированием .dll — один из подходов, который нужно решить, это использование подхода EasyHook — можно найти здесь:

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

Смотрите функцию GetRemoteFuncAddress.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]