【问题标题】:How to pass handle to child process如何将句柄传递给子进程
【发布时间】:2011-09-14 17:34:05
【问题描述】:

我正在尝试通过命令行或任何其他方式将互斥体句柄传递给子进程。

我该怎么做? 如何访问孩子的互斥锁?

这就是我创建子进程的方式:

HANDLE ghMutex;

     if( !CreateProcess( _T("C:\\Users\\Kumppler\\Documents\\Visual Studio 2010\\Projects\\teste3\\Debug\\teste3.exe"),   // No module name (use command line)
                aux2,                              // Command line
                NULL,                              // Process handle not inheritable
                NULL,                              // Thread handle not inheritable
                TRUE,                              // Set handle inheritance to TRUE
                STARTF_USESTDHANDLES,              // inherit the standard input, standard output, and standard error handles
                NULL,                              // Use parent's environment block
                NULL,                              // Use parent's starting directory 
                &si[j],                            // Pointer to STARTUPINFO structure
                &pi[j] )                           // Pointer to PROCESS_INFORMATION structure
            )                     

编辑:

我需要为多个子进程使用互斥锁,可以吗?

这就是我现在正在做的事情:

HANDLE ghMutex;
int mutex;
char mutexstring[7];

mutex=(int)ghMutex;
itoa(mutexValue,mutexString,10);

我将通过命令行传递 mutexString,然后在子进程中将其转换回:

mutexValue=atoi(argv[2]);

Mutex=(HANDLE)mutexValue;

我的问题,可以进行 (HANDLE) 投射吗??

【问题讨论】:

    标签: c winapi


    【解决方案1】:

    两种选择:

    1. 您可以使用命名对象。进程 A 使用名称创建互斥体,然后生成进程 B。进程 B 然后调用具有相同名称的 OpenMutex 或 CreateMutex,它将获得同一个互斥体的句柄。

      缺点在于名称选择。如果您有名称冲突,您可能会得到不可预知的结果。攻击者可以创建同名互斥体并造成拒绝服务情况。处理此问题的一种方法是随机生成名称。例如,进程 A 可以为名称生成一个 GUID,然后在命令行上将该 GUID(作为字符串)传递给进程 B。

    2. 您可以使用inheritance。子进程可以从父进程继承许多类型的句柄,包括互斥句柄。在 CreateProcess 命令中设置 bInheritHandles 参数(您的示例已经这样做了),并将命令行上的句柄值(作为字符串)传递给子进程。然后子进程可以将命令行字符串转换回一个值并开始使用它。两个进程的值相同。

    这种技术与命名对象技术没有相同的缺点。

    继承的工作示例(省略了错误检查):

    #include <cstddef>
    #include <iostream>
    #include <string>
    #include <sstream>
    #include <windows.h>
    
    void DoParentWork() {
      std::wcout << L"Parent:  Creating an inheritable event..." << std::endl;
      SECURITY_ATTRIBUTES security = {
        sizeof(security), nullptr, /* bInheritHandle = */ TRUE
      };
      HANDLE hEvent = ::CreateEventW(&security, /* bManualReset = */ TRUE,
                                     /* bInitialState = */ FALSE, nullptr);
    
      std::wstringstream ssCommand;
      ssCommand << L"foo.exe " << reinterpret_cast<std::size_t>(hEvent);
      std::wstring strCmd = ssCommand.str();;
    
      std::wcout << L"Parent:  Starting child process..." << std::endl;
      STARTUPINFO start_info = {sizeof(start_info)};
      PROCESS_INFORMATION proc_info = {0};
      ::CreateProcessW(L"foo.exe", &strCmd[0], nullptr, nullptr,
                       /* bInheritHandles = */ TRUE, 0, nullptr, nullptr,
                       &start_info, &proc_info);
      ::CloseHandle(proc_info.hThread);
      ::CloseHandle(proc_info.hProcess);
    
      std::wcout << L"Parent:  Waiting for the child to signal the event."
                 << std::endl;
      if (::WaitForSingleObject(hEvent, 10*1000) == WAIT_OBJECT_0) {
        std::wcout << L"Parent:  The event was signaled." << std::endl;
      } else {
        std::wcout << L"Parent:  Timed out waiting for the event."
                   << std::endl;
      }
      ::CloseHandle(hEvent);
    }
    
    void DoChildWork(const char *pszEvent) {
      std::stringstream ss(pszEvent);
      UINT_PTR iEvent;
      ss >> iEvent;
      HANDLE hEvent = reinterpret_cast<HANDLE>(iEvent);
      std::cout << "Child:  Event handle "
                << reinterpret_cast<std::size_t>(hEvent) << std::endl;
      ::Sleep(2000);
      std::cout << "Child:  Signalling the event." << std::endl;
      ::SetEvent(hEvent);
    }
    
    int main(int cArgs, char *ppszArgs[]) {
      if (cArgs > 1) DoChildWork(ppszArgs[1]);
      else DoParentWork();
      return 0;
    }
    

    【讨论】:

    • +1 用于命名互斥锁。它们是显而易见的解决方案。通过命令行传递 GUID 以避免冲突是多余的:只需在每个程序中对其进行硬编码:无论如何它们都是独一无二的。
    • "子进程然后可以将命令行字符串转换回一个值并简单地开始使用它" 你的意思是把它转换成一个字符串?
    • @Serge - appTranslator:硬编码名称有两个问题。 (1) 它将您限制为应用程序的单个实例。 (2) 如果攻击者在您之前创建互斥锁,则会出现拒绝服务漏洞(如我的回答中所述)。
    • @Caio:我不确定你在问什么。我相信我说的是我的意思。
    • @Adrian McCarthy:我会试着解释一下。你的意思是我必须将 argv[i] 转换回互斥变量的值(地址)?
    【解决方案2】:

    在创建子进程之前创建互斥体并使其可继承(在 CreateMutex 的 lpMutexAttributes 参数中将 bInheritHandle 设置为 TRUE)。这样就可以在命令行中传递句柄了。

    或者使用 DuplicateHandle 并通过其他机制传递句柄(例如,使用管道作为子进程的 STDIN)。

    【讨论】:

    • 这不起作用。您不能将 HANDLE 序列化为字符串并将其传递给孩子。我试过这样做,但它不起作用。随意用一个工作示例证明我错了。
    • @jcoffland 当然可以,但是根据答案,您确实需要复制它
    猜你喜欢
    • 2013-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-11
    • 2014-11-13
    • 2014-06-22
    • 2018-09-17
    相关资源
    最近更新 更多