前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Windows中如何在父子进程间传递SOCKET句柄

Windows中如何在父子进程间传递SOCKET句柄

作者头像
drunkdream
发布2024-05-17 09:44:58
1000
发布2024-05-17 09:44:58
举报
文章被收录于专栏:醉梦轩醉梦轩

0x00 背景

Linux由于一切皆文件,不管是文件、管道,还是socket,都可以轻易在父子进程间传递;而Windows上会复杂很多。最近有个需求,需要进行父子进程间的通信,常见的方案是在创建子进程时通过stdinstdoutstderr这三个句柄来传递管道句柄,从而达到父子进程间通信的目的。但这种方式最大的问题是:对子进程需要单独处理stdout和stderr,使用上有些限制。

经过调研之后,放弃了管道这种方式,因为匿名管道不支持异步读写,不符合我们的使用场景。然后,考虑将SOCKET句柄传递给子进程,进而进行通信。

0x01 复制句柄

Windows中有一个复制句柄的API:DuplicateHandle

代码语言:javascript
复制
BOOL DuplicateHandle(
  [in]  HANDLE   hSourceProcessHandle,
  [in]  HANDLE   hSourceHandle,
  [in]  HANDLE   hTargetProcessHandle,
  [out] LPHANDLE lpTargetHandle,
  [in]  DWORD    dwDesiredAccess,
  [in]  BOOL     bInheritHandle,
  [in]  DWORD    dwOptions
);

参数含义如下:

  • hSourceProcessHandle —— 源进程句柄
  • hSourceHandle —— 源句柄
  • hTargetProcessHandle —— 目标进程句柄
  • lpTargetHandle —— 新句柄指针
  • dwDesiredAccess —— 新句柄访问权限
  • bInheritHandle —— 句柄是否可继承
  • dwOptions —— 可选行为,取值为:DUPLICATE_CLOSE_SOURCEDUPLICATE_SAME_ACCESS

使用这个函数,我们可以将当前进程的某个句柄复制到其它进程中,也可以将其它进程的某个句柄复制到当前进程中。因此,我们可以在父进程中创建一个socket对象,然后将句柄的id通过命令行参数传递给子进程;然后子进程将该句柄真正复制到当前进程,并转换成socket对象即可。

0x02 具体代码

父进程

代码语言:javascript
复制
import socket
import subprocess

sock = socket.create_connection(('www.qq.com', 80))
print(sock)


child_process = subprocess.Popen(
    ["python", "child.py", str(sock.fileno())],
)

child_process.wait()

子进程

代码语言:javascript
复制
import _winapi
import os
import socket

def steal_handle(source_pid, handle):
    '''Steal a handle from process identified by source_pid.'''
    source_process_handle = _winapi.OpenProcess(
        _winapi.PROCESS_DUP_HANDLE, False, source_pid)
    try:
        return _winapi.DuplicateHandle(
            source_process_handle, handle,
            _winapi.GetCurrentProcess(), 0, False,
            _winapi.DUPLICATE_SAME_ACCESS | _winapi.DUPLICATE_CLOSE_SOURCE)
    finally:
        _winapi.CloseHandle(source_process_handle)


handle = steal_handle(os.getppid(), int(sys.argv[1]))
print(sys.argv[1], "=>", handle)

socks = socket.fromfd(handle, socket.AF_INET, socket.SOCK_STREAM)

print(socks)

socks.send(b'GET / HTTP/1.1\r\n\r\n')
data = socks.recv(1024)
print("Received data:", data)

steal_handle函数代码是从multiprocessing模块中复制过来的,它也是用了类似的原理进行句柄的传递。

socket.fromfd是Windows端python 3.5以上提供的内置方法,也可以直接用socks = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0, handle)代替,差别只是没有再复制一个句柄出来。

0x03 总结

利用DuplicateHandle函数,可以实现一些特殊的效果

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-05-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 0x00 背景
  • 0x01 复制句柄
  • 0x02 具体代码
    • 父进程
      • 子进程
      • 0x03 总结
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档