C程序和子进程
我编写了这个简单的 c 程序来解释具有相同特征的更困难的问题。
#include <stdio.h>
int main(int argc, char *argv[])
{
int n;
while (1){
scanf("%d", &n);
printf("%d\n", n);
}
return 0;
}
它按预期工作。
我还编写了一个子进程脚本来与该程序交互:
from subprocess import popen, pipe, stdout
process = popen("./a.out", stdin=pipe, stdout=pipe, stderr=stdout)
# sending a byte
process.stdin.write(b'3')
process.stdin.flush()
# reading the echo of the number
print(process.stdout.readline())
process.stdin.close()
问题是,如果我运行 python 脚本,执行会在 readline()
上冻结。事实上,如果我中断脚本,我会得到:
/tmp » python script.py
^ctraceback (most recent call last):
file "/tmp/script.py", line 10, in <module>
print(process.stdout.readline())
^^^^^^^^^^^^^^^^^^^^^^^^^
keyboardinterrupt
如果我更改我的 python 脚本:
from subprocess import popen, pipe, stdout
process = popen("./a.out", stdin=pipe, stdout=pipe, stderr=stdout)
with process.stdin as pipe:
pipe.write(b"3")
pipe.flush()
# reading the echo of the number
print(process.stdout.readline())
# sending another num:
pipe.write(b"4")
pipe.flush()
process.stdin.close()
我得到了这个输出:
» python script.py
b'3\n'
Traceback (most recent call last):
File "/tmp/script.py", line 13, in <module>
pipe.write(b"4")
ValueError: write to closed file
这意味着第一个输入已正确发送,并且读取已完成。
我真的找不到解释这种行为的东西;有人可以帮助我理解吗? 提前致谢
[编辑]:由于有很多要点需要澄清,所以我添加了此编辑。我正在使用 rop
技术进行缓冲区溢出漏洞利用的培训,并且我正在编写一个 python 脚本来实现这一目标。为了利用这个漏洞,由于aslr,我需要发现libc
地址并使程序重新启动而不终止。由于脚本将在目标机器上执行,我不知道哪些库可用,那么我将使用 subprocess,因为它是内置于 python 中的。不详细说明,攻击在第一个 scanf
上发送一系列字节,目的是泄漏 libc
基地址并重新启动程序;然后发送第二个有效负载以获得一个 shell,我将通过它以交互模式进行通信。
这就是为什么:
- 我只能使用内置库
- 我必须发送字节并且无法附加结尾
\n
:我的有效负载将无法对齐或可能导致失败 - 我需要保持
stdin
打开 - 我无法更改 c 代码
正确答案
更改这些:
在 c 程序读取的数字之间发送分隔符。 scanf(3) 接受任何非数字字节作为分隔符。为了最简单的缓冲,请从 python 发送换行符(例如
.write(b'42\n')
)。如果没有分隔符,scanf(3) 将无限期地等待更多数字。每次写入(c 和 python 中)后,刷新输出。
这对我有用:
#include <stdio.h>
int main(int argc, char *argv[])
{
int n;
while (1){
scanf("%d", &n);
printf("%d\n", n);
fflush(stdout);
}
return 0;
}
import subprocess
p = subprocess.popen(
('./a.out',), stdin=subprocess.pipe, stdout=subprocess.pipe)
try:
print('a'); p.stdin.write(b'42 '); p.stdin.flush()
print('b'); print(repr(p.stdout.readline()));
print('c'); p.stdin.write(b'43\n'); p.stdin.flush()
print('d'); print(repr(p.stdout.readline()));
finally:
print('e'); print(p.kill())
原始 c 程序在终端窗口中交互运行时能够正常工作的原因是,在 c 中,当将换行符 (\n
) 写入终端时,输出会自动刷新。因此 printf("%d\n", n);
最后会隐式执行 fflush(stdout);
。
当使用 subprocess
从 python 运行时,原始 c 程序无法工作的原因是它将输出写入管道(而不是终端),并且没有自动刷新到管道。发生的情况是,python 程序正在等待字节,而 c 程序不会将这些字节写入管道,但它正在等待更多字节(在下一个 scanf
中),因此两个程序都在无限期地等待对方。 (但是,在输出几 kib(通常为 8192 字节)后,将会出现部分自动刷新。但是单个十进制数太短,无法触发该操作。)
如果无法更改 c 程序,那么您应该使用终端设备而不是管道来在 c 和 python 程序之间进行通信。 pty
python 模块可以创建终端设备,这对我来说适用于你的原始 c 程序:
import os, pty, subprocess
master_fd, slave_fd = pty.openpty()
p = subprocess.popen(
('./a.out',), stdin=slave_fd, stdout=slave_fd,
preexec_fn=lambda: os.close(master_fd))
try:
os.close(slave_fd)
master = os.fdopen(master_fd, 'rb+', buffering=0)
print('a'); master.write(b'42\n'); master.flush()
print('b'); print(repr(master.readline()));
print('c'); master.write(b'43\n'); master.flush()
print('d'); print(repr(master.readline()));
finally:
print('e'); print(p.kill())
如果你不想从python发送换行符,这里有一个没有换行符的解决方案,它对我有用:
import os, pty, subprocess, termios
master_fd, slave_fd = pty.openpty()
ts = termios.tcgetattr(master_fd)
ts[3] &= ~(termios.ICANON | termios.ECHO)
termios.tcsetattr(master_fd, termios.TCSANOW, ts)
p = subprocess.Popen(
('./a.out',), stdin=slave_fd, stdout=slave_fd,
preexec_fn=lambda: os.close(master_fd))
try:
os.close(slave_fd)
master = os.fdopen(master_fd, 'rb+', buffering=0)
print('A'); master.write(b'42 '); master.flush()
print('B'); print(repr(master.readline()));
print('C'); master.write(b'43\t'); master.flush()
print('D'); print(repr(master.readline()));
finally:
print('E'); print(p.kill())
以上就是C程序和子进程的详细内容,更多请关注编程网其它相关文章!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
C程序和子进程
下载Word文档到电脑,方便收藏和打印~