我目前正在尝试编写(Python 2.7.3)一种 GDB 包装器,这将允许我从脚本输入动态切换到与 GDB 的交互式通信。
到目前为止我用
self.process = subprocess.Popen(["gdb vuln"], stdin = subprocess.PIPE, shell = True)
在我的脚本中启动 gdb。 (
vuln
是我要检查的二进制文件)
由于 gdb 的一个关键特性是暂停附加进程的执行并允许用户在接收到 SIGINT (STRG+C) 时检查寄存器和内存,我确实需要一些方法来将 SIGINT 信号传递给它。
都不是
self.process.send_signal(signal.SIGINT)
也不
os.kill(self.process.pid, signal.SIGINT)
或
os.killpg(self.process.pid, signal.SIGINT)
为我工作。
当我使用这些功能之一时,没有任何反应。我想这个问题是由
shell=True
的使用引起的。但是,在这一点上我真的没主意了。
这次连我的老朋友谷歌都帮不了我,所以也许你能帮我。提前致谢。
干杯,迈克
这对我有用:
import signal
import subprocess
try:
p = subprocess.Popen(...)
p.wait()
except KeyboardInterrupt:
p.send_signal(signal.SIGINT)
p.wait()
我深入研究了这个问题,发现了一些有趣的事情。也许这些发现会在未来帮助某人。
当使用 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 vuln
因此向进程发送 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 获取进程启动的 pid),请告诉我。
干杯,迈克
感谢Mark指出查看进程的ppid。 我设法使用以下方法缩小了 SIGINT 发送到的进程的范围:
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)
我过去做过类似下面的事情,如果我记得它似乎对我有用:
def detach_procesGroup():
os.setpgrp()
subprocess.Popen(command,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
preexec_fn=detach_processGroup)
@sirex 答案的修改,对我来说效果更好:
import signal
import subprocess
p = subprocess.Popen(...)
while True:
try:
p.wait()
exit(0)
except KeyboardInterrupt:
p.send_signal(signal.SIGINT)
原始代码将在第 2 次后中止
ctrl-C
.