Вызов функции во внедренной DLL?

Используя C ++, у меня есть приложение, которое создает удаленный процесс и внедряет в него DLL. Есть ли способ заставить удаленное приложение выполнить функцию, экспортированную из DLL, из приложения, которое ее создало? И возможно ли отправить параметры этой функции? Пожалуйста, обратите внимание, что я стараюсь не делать ничего внутри DllMain.

5

Решение

Замечания:
Для лучшего ответа, пожалуйста см. мое обновление опубликовано ниже!


Хорошо, вот как я смог это сделать:

BOOL RemoteLibraryFunction( HANDLE hProcess, LPCSTR lpModuleName, LPCSTR lpProcName, LPVOID lpParameters, SIZE_T dwParamSize, PVOID *ppReturn )
{
LPVOID lpRemoteParams = NULL;

LPVOID lpFunctionAddress = GetProcAddress(GetModuleHandleA(lpModuleName), lpProcName);
if( !lpFunctionAddress ) lpFunctionAddress = GetProcAddress(LoadLibraryA(lpModuleName), lpProcName);
if( !lpFunctionAddress ) goto ErrorHandler;

if( lpParameters )
{
lpRemoteParams = VirtualAllocEx( hProcess, NULL, dwParamSize, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE );
if( !lpRemoteParams ) goto ErrorHandler;

SIZE_T dwBytesWritten = 0;
BOOL result = WriteProcessMemory( hProcess, lpRemoteParams, lpParameters, dwParamSize, &dwBytesWritten);
if( !result || dwBytesWritten < 1 ) goto ErrorHandler;
}

HANDLE hThread = CreateRemoteThread( hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpFunctionAddress, lpRemoteParams, NULL, NULL );
if( !hThread ) goto ErrorHandler;

DWORD dwOut = 0;
while(GetExitCodeThread(hThread, &dwOut)) {
if(dwOut != STILL_ACTIVE) {
*ppReturn = (PVOID)dwOut;
break;
}
}

return TRUE;

ErrorHandler:
if( lpRemoteParams ) VirtualFreeEx( hProcess, lpRemoteParams, dwParamSize, MEM_RELEASE );
return FALSE;
}

//...
CStringA targetDll = "injected.dll"
// Inject the target library into the remote process
PVOID lpReturn = NULL;
RemoteLibraryFunction( hProcess, "kernel32.dll", "LoadLibraryA", targetDll.GetBuffer(MAX_PATH), targetDll.GetLength(), &lpReturn );
HMODULE hInjected = reinterpret_cast<HMODULE>( lpReturn );

// Call our exported function
lpReturn = NULL;
RemoteLibraryFunction( hProcess, targetDll, "Initialize", NULL, 0, &lpReturn );
BOOL RemoteInitialize = reinterpret_cast<BOOL>( lpReturn );

Это также может быть использовано для отправки параметров в удаленную функцию через указатель на структуру или объединение, и обходится без необходимости писать что-либо в DllMain.

6

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

Так что после некоторого сложного тестирования, кажется, мой предыдущий ответ не является надежным
(или даже на 100% функциональный, в этом отношении), и склонен к сбоям. Подумав, я решил использовать совершенно другой подход к этому … используя Межпроцессного взаимодействия.

Знать… этот метод использует код в DllMain,
Так что не идите за борт, и обязательно следовать безопасным практикам при этом, чтобы вы не оказались в тупик

В частности, Win32 API предлагает следующие полезные функции:

Используя их, мы можем просто сказать нашему процессу запуска, где именно находится наша функция удаленного запуска, прямо из введенной dll сам…


dllmain.cpp:

// Data struct to be shared between processes
struct TSharedData
{
DWORD dwOffset = 0;
HMODULE hModule = nullptr;
LPDWORD lpInit = nullptr;
};
// Name of the exported function you wish to call from the Launcher process
#define DLL_REMOTEINIT_FUNCNAME "RemoteInit"// Size (in bytes) of data to be shared
#define SHMEMSIZE sizeof(TSharedData)
// Name of the shared file map (NOTE: Global namespaces must have the SeCreateGlobalPrivilege privilege)
#define SHMEMNAME "Global\\InjectedDllName_SHMEM"static HANDLE hMapFile;
static LPVOID lpMemFile;

BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved )
{
TSharedData data;

switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hModule);

// Get a handle to our file map
hMapFile = CreateFileMappingA(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, SHMEMSIZE, SHMEMNAME);
if (hMapFile == nullptr) {
MessageBoxA(nullptr, "Failed to create file mapping!", "DLL_PROCESS_ATTACH", MB_OK | MB_ICONERROR);
return FALSE;
}

// Get our shared memory pointer
lpMemFile = MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (lpMemFile == nullptr) {
MessageBoxA(nullptr, "Failed to map shared memory!", "DLL_PROCESS_ATTACH", MB_OK | MB_ICONERROR);
return FALSE;
}

// Set shared memory to hold what our remote process needs
memset(lpMemFile, 0, SHMEMSIZE);
data.hModule = hModule;
data.lpInit = LPDWORD(GetProcAddress(hModule, DLL_REMOTEINIT_FUNCNAME));
data.dwOffset = DWORD(data.lpInit) - DWORD(data.hModule);
memcpy(lpMemFile, &data, sizeof(TSharedData));
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
// Tie up any loose ends
UnmapViewOfFile(lpMemFile);
CloseHandle(hMapFile);
break;
}
return TRUE;
UNREFERENCED_PARAMETER(lpReserved);
}

Затем, из нашего приложения Launcher, мы будем делать обычные CreateProcess + VirtualAllocEx + CreateRemoteThread трюк, чтобы ввести наш Dll, убедившись, что указатель на правильный SECURITY_DESCRIPTOR в качестве третьего параметра CreateProcess, а также передавая CREATE_SUSPENDED флаг в 6-м параметре.

Это сделано для того, чтобы гарантировать, что ваш дочерний процесс будет иметь надлежащие привилегии для чтения и записи в глобальное пространство имен совместно используемой памяти, хотя есть и другие способы достижения этого (или вы можете протестировать без глобального пути).

CREATE_SUSPENDED flag гарантирует, что функция точки входа dllmain закончила запись в нашу общую память до загружаются другие библиотеки, что позволяет в дальнейшем облегчать локальное подключение


Injector.cpp:

SECURITY_ATTRIBUTES SecAttr, *pSec = nullptr;
SECURITY_DESCRIPTOR SecDesc;

if (InitializeSecurityDescriptor(&SecDesc, SECURITY_DESCRIPTOR_REVISION) &&
SetSecurityDescriptorDacl(&SecDesc, TRUE, PACL(nullptr), FALSE))
{
SecAttr.nLength = sizeof(SecAttr);
SecAttr.lpSecurityDescriptor = &SecDesc;
SecAttr.bInheritHandle = TRUE;
pSec = &SecAttr;
}

CreateProcessA(szTargetExe, nullptr, pSec, nullptr, FALSE, CREATE_SUSPENDED, nullptr, nullptr, &si, &pi);

После внедрения DLL в целевой процесс все, что вам нужно сделать, это использовать тот же (более или менее) код сопоставления файлов из вашего проекта DLL в вашем проекте Launcher (за исключением той части, где вы, конечно, устанавливаете содержимое общей памяти) ,

Затем, вызов вашей удаленной функции — это просто вопрос:

// Copy from shared memory
TSharedData data;
memcpy(&data, lpMemFile, SHMEMSIZE);
// Clean up
UnmapViewOfFile(lpMemFile);
CloseHandle(hMapFile);
// Call the remote function
DWORD dwThreadId = 0;
auto hThread = CreateRemoteThread(hProcess, nullptr, 0, LPTHREAD_START_ROUTINE(data.lpInit), nullptr, 0, &dwThreadId);

Тогда ты можешь ResumeThread в главном потоке целевого процесса или из вашей удаленной функции.


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

Надеюсь, это поможет кому-то! знак равно

2

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