如何通过使用shell = true的Python subprocess.Popen()将SIGINT传递给子进程 [英] How to pass SIGINT to child process with Python subprocess.Popen() using shell = true

查看:165
本文介绍了如何通过使用shell = true的Python subprocess.Popen()将SIGINT传递给子进程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在尝试为GDB编写(Python 2.7.3)封装器,这将允许我从脚本输入动态切换到与GDB交互式通信。



到目前为止,我使用

pre $ self.process = subprocess.Popen([gdb vuln],stdin = subprocess。 PIPE,shell = True)

在我的脚本中启动gdb。 ( vuln 是我想要检查的二进制文件)



由于gdb的一个关键特性是暂停执行附加的过程,并允许用户在接收SIGINT(STRG + C)时检查寄存器和内存。我确实需要某种方式将SIGINT信号传递给它。



/ p>

  self.process.send_signal(signal.SIGINT)

也没有

  os.kill(self.process.pid,signal.SIGINT )

  os.killpg(self.process.pid,signal.SIGINT)

我。

当我使用这些函数时,没有任何回应。我想这个问题来自于使用 shell = True 。然而,在这一点上,我真的没有想法。
即使我的老朋友谷歌这次也无法帮助我,所以也许你可以帮助我。



干杯,麦克

解决方案

进入问题并发现一些有趣的事情。使用suprocess.Popen()调用 gdb vuln 时,它确实可以帮助别人在将来帮助别人。

实际上创建了三个进程,其中pid返回的是 sh (5180)。

  ps -a 
5180 pts / 0 00:00:00 sh
5181 pts / 0 00:00:00 gdb
5183 pts / 0 00:00:00因此,向进程发送SIGINT实际上会将SIGINT发送到 sh 。



另外,我继续寻找答案,并且偶然发现了这篇文章
https://bugzilla.kernel.org/show_bug.cgi?id=9039



为了保持简短,提到了以下内容:

当在定期使用gdb的同时按下STRG + C时,SIGINT实际上被发送给被检查程序(在这种情况下 vuln ),然后ptrace会拦截它并将它传递给gdb。
这意味着什么,如果我使用 self.process.send_signal(signal.SIGINT),它实际上永远不会以这种方式到达gdb。



临时解决方法:



我设法解决了这个问题,只需调用 subprocess.popen() 如下:

subprocess.Popen(killall -s INT+ self.binary,shell = True)



这只不过是第一种解决方法。当多个同名的应用程序正在运行时可能会造成一些严重的损害。此外,如果未设置 shell = True ,它会以某种方式失败。
如果有人有更好的解决方法(例如,如何通过gdb获得进程startet的pid),请告诉我。


Cheers,Mike p>

编辑:



感谢Mark指出看看过程的微妙之处。
我设法缩小了SIGINT使用以下方法发送的进程:

  out = subprocess.check_output (['ps','-Aefj'])
为out.splitlines()中的行:
如果self.binary在行中:
l = line.split()
whilein l:
l.remove()
#获取子进程的sid和pgid(/ bin / sh)
sid = os.getsid(self.process .pid)
pgid = os.getpgid(self.process.pid)
#only对目标进程为真
如果l [4] == str(sid)和l [3]! = str(pgid):
os.kill(pid,signal.SIGINT)


I am currently trying to write (Python 2.7.3) kind of a wrapper for GDB, which will allow me to dynamically switch from scripted input to interactive communication with GDB.

So far I use

self.process = subprocess.Popen(["gdb vuln"], stdin = subprocess.PIPE,  shell = True)

to start gdb within my script. (vuln is the binary I want to examine)

Since a key feature of gdb is to pause the execution of the attached process and allow the user to inspect registers and memory on receiving SIGINT (STRG+C) I do need some way to pass a SIGINT signal to it.

Neither

self.process.send_signal(signal.SIGINT)

nor

os.kill(self.process.pid, signal.SIGINT)

or

os.killpg(self.process.pid, signal.SIGINT)

work for me.

When I use one of these functions there is no response. I suppose this problem arises from the use of shell=True. However, at this point I am really out of ideas. Even my old friend Google couldn't really help me out this time, so maybe you can help me. Thank's in advance.

Cheers, Mike

解决方案

I looked deeper into the problem and found some interesting things. Maybe these findings will help someone in the future.

When calling gdb vuln using suprocess.Popen() it does in fact create three processes, where the pid returned is the one of sh (5180).

ps -a
 5180 pts/0    00:00:00 sh
 5181 pts/0    00:00:00 gdb
 5183 pts/0    00:00:00 vuln

Consequently sending a SIGINT to the process will in fact send SIGINT to sh.

Besides, I continued looking for an answer and stumbled upon this post https://bugzilla.kernel.org/show_bug.cgi?id=9039

To keep it short, what is mentioned there is the following:

When pressing STRG+C while using gdb regularly SIGINT is in fact sent to the examined program (in this case vuln), then ptrace will intercept it and pass it to gdb. What this means is, that if I use self.process.send_signal(signal.SIGINT) it will in fact never reach gdb this way.

Temporary Workaround:

I managed to work around this problem by simply calling subprocess.popen() as follows:

subprocess.Popen("killall -s INT " + self.binary, shell = True)

This is nothing more than a first workaround. When multiple applications with the same name are running might do some serious damage. Besides, it somehow fails, if shell=True is not set. If someone has a better fix (e.g. how to get the pid of the process startet by gdb), please let me know.

Cheers, Mike

EDIT:

Thanks to Mark for pointing out to look at the ppid of the process. I managed to narrow down the process's to which SIGINT is sent using the following approach:

out = subprocess.check_output(['ps', '-Aefj'])
for line in out.splitlines():
    if self.binary in line:
        l = line.split(" ")
        while "" in l:
            l.remove("")
        # Get sid and pgid of child process (/bin/sh)
        sid = os.getsid(self.process.pid)
        pgid  = os.getpgid(self.process.pid)
        #only true for target process
        if l[4] == str(sid) and l[3] != str(pgid):
            os.kill(pid, signal.SIGINT)

这篇关于如何通过使用shell = true的Python subprocess.Popen()将SIGINT传递给子进程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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