繁体   English   中英

在注入的DLL中调用函数?

[英]Calling a function in an injected DLL?

使用C ++,我有一个应用程序,它创建一个远程进程并向其中注入一个DLL。 有没有办法让远程应用程序执行从DLL导出的函数,从创建它的应用程序? 是否可以向该功能发送参数? 请注意,我正试图远离在DllMain中做任何事情。

注意:
如需更好的答案,请参阅下面发布的更新


好的,这就是我能够做到这一点的方式:

 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中编写任何内容。

因此经过一些精心的测试后,我的回答似乎不是万无一失
(或者甚至是100%功能性的),并且容易发生崩溃。 在考虑之后,我决定采用完全不同的方法......使用进程间通信

请注意 ......此方法使用DllMain代码。
因此,不要过火,并确保在执行此操作遵循安全的做法 ,这样您就不会陷入僵局 ......

最值得注意的是,Win32 API提供以下有用功能:

通过使用这些,我们可以直接告诉我们的Launcher进程我们的远程init函数所在的位置, 直接来自注入的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的第3个参数传递,并在其中传递CREATE_SUSPENDED标志。第六个参数。

这有助于确保您的子进程具有读取和写入全局共享内存命名空间的适当权限,尽管还有其他方法可以实现此目的(或者您可以在没有全局路径的情况下进行测试)。

CREATE_SUSPENDED标志将确保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


作为一个额外的好处......使用这种形式的通信也可以为我们的Launcher进程打开几扇门,因为它现在可以直接与目标进程通信。
但同样,请确保您在DllMain没有做太多,并且,如果可能的话,只需使用远程初始化函数(例如, 使用命名互斥锁也是安全的)来创建单独的共享内存映射,从那里继续沟通。

希望这有助于某人! =)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM