在注入的DLL中调用函数? [英] Calling a function in an injected DLL?

查看:195
本文介绍了在注入的DLL中调用函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Using C++, I have an application which creates a remote process and injects a DLL into it. Is there a way to get the remote application to execute a function exported from the DLL, from the application which created it? And is it possible to send parameters to that function? Please note that I am trying to stay away from doing anything within DllMain.

推荐答案

经过一些精心的测试,似乎我以前的答案是万无一失的(甚至100%的功能,在这个问题上),并且容易发生崩溃。在给出了一些想法之后,我已经决定采取一种完全不同的方法来使用进程间通信

So after some elaborate testing, it would seem that my previous answer is anything but foolproof
(or even 100% functional, for that matter), and is prone to crashes. After giving it some thought, I've decided to take an entirely different approach to this... using Interprocess Communication.

请注意 ...此方法利用代码在 DllMain

所以不要超越,请确保遵循安全措施,这样做,所以你最终不会在死锁 ...

Be aware... this method utilizes code in DllMain.
So don't go overboard, and be sure to follow safe practices when doing this, so that you don't end up in a deadlock...

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

Most notably, the Win32 API offers the following two functions that will prove useful:

  • CreateFileMapping
  • MapViewOfFile
  • OpenFileMapping

使用这些,我们可以简单地告诉我们的Launcher进程,我们的远程init函数所在的位置,直接从注入的dll 本身...


With the use of these, we can simply tell our Launcher process exactly where our remote init function resides, straight from the injected dll itself...


// 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 标志。


Then, from our Launcher application, we will do the usual CreateProcess + VirtualAllocEx + CreateRemoteThread trick to inject our Dll, making sure to pass in a pointer to a proper SECURITY_DESCRIPTOR as the 3rd parameter to CreateProcess, as well as passing the CREATE_SUSPENDED flag in the 6th parameter.

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

This is to help ensure that your child process will have the proper privileges to read and write to a global shared memory namespace, though there are also other ways to achieve this (or you could test without the global path altogether).

CREATE_SUSPENDED 标志将确保dllmain入口点函数将在其他库加载之前完成写入我们的共享内存,这样可以更容易地在本地挂起。


The CREATE_SUSPENDED flag will ensure that the dllmain entry point function would have finished writing to our shared memory before other libraries are loaded, which allows easier local hooking later on...


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注入目标进程后, do将使用与您的DLL项目相同的(或多或少)文件映射代码到您的Launcher项目(当然,您设置共享内存的内容除外)。


After injecting the DLL into the target process, all you need to do is use the same (more or less) file mapping code from your DLL project into your Launcher project (except for the part where you set the shared memory's contents, of course).

然后,调用远程函数只是一个简单的问题:

Then, calling your remote function is just a simple matter of:

// 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 中做太多,如果可能的话,只需使用你的远程init函数(它也是安全地使用命名互斥体,例如)创建一个单独的共享内存映射,并从那里继续通信。

Then you can ResumeThread on the target process's main thread, or from your remote function.


As an added bonus... Using this form of communication can also open up several doors for our Launcher process, as it can now directly communicate with the target process.
But again, be sure that you don't do too much in DllMain and, if at all possible, simply use your remote init function (where it is also safe to use named mutexes, for example) to create a separate shared memory map and continue communication from there.

这篇关于在注入的DLL中调用函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆