使用 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 useful functions:
通过使用这些,我们可以简单地告诉我们的 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);
}
CreateProcess
+ VirtualAllocEx
+ CreateRemoteThread
技巧来注入我们的 Dll,确保传入一个指向适当的 SECURITY_DESCRIPTOR
的指针作为 CreateProcess
的第三个参数,并在第 6 个参数中传递 CREATE_SUSPENDED
标志.
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);
那么,调用你的远程函数只是一个简单的事情:
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
.
DllMain
中做太多事情,并且如果可能的话,只需使用您的远程 init 函数(在那里 使用命名互斥体,例如)创建一个单独的共享内存映射并从那里继续通信.
Then you can ResumeThread
on the target process's main thread, or from your remote function.
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 中调用函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!