无法使用 termios.TIOCSTI 伪造终端输入
Unable to fake terminal input with termios.TIOCSTI
大部分code samples I've seen are trying to read from stdin without local echo. To do this they modify the "local modes" flag to remove the setting to "Echo input characters". I thought I could just modify the "input modes" flag to TIOCSTI
which is for "Insert the given byte in the input queue.". However, even though I run the script as root, it has no effect. anything I write to the fd seems to go to the terminal output, rather than the terminal input. Basically what I want to do is this exact thing,但纯python。
"""
termfake.py
Usage: sudo python termfake.py /dev/ttys002
Get the tty device path of a different local termimal by running `tty`
in that terminal.
"""
import sys
import termios
fd = open(sys.argv[1], 'w')
fdno = fd.fileno()
# Returns [iflag, oflag, cflag, lflag, ispeed, ospeed, cc]
tatters = termios.tcgetattr(fdno)
print('original', tatters)
tatters[0] = termios.TIOCSTI
print('TIOCSTI', termios.TIOCSTI)
# Set iflag
termios.tcsetattr(fdno, termios.TCSANOW, tatters)
# Verify setting change
with open('/dev/ttys002', 'w') as fd2:
print('modified', termios.tcgetattr(fd2.fileno()))
fd.write('This is test\n')
fd.close()
TIOCSTI
是一个 ioctl(记录在 tty_ioctl(4)
中),不是终端设置,所以你不能使用 tcsetattr()
-- 你需要输入假的每个字符输入 ioctl()
代替。以前从来不需要从 Python 执行 ioctl,但以下似乎适用于不同终端中的 运行 和 ls
(指定为参数,例如 /dev/pts/13) 那是 运行 Bash:
import fcntl
import sys
import termios
with open(sys.argv[1], 'w') as fd:
for c in "ls\n":
fcntl.ioctl(fd, termios.TIOCSTI, c)
顺便说一下,TIOCSTI
需要 root 权限(或 CAP_SYS_ADMIN
更具体,但实际上通常是相同的)——参见 capabilities(7)
.
我从@Ulfalizer 那里得到了答案并将其扩展为一个完整且可用的应用程序。
import sys
import fcntl
import termios
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('tty', type=argparse.FileType('w'),
help='full tty path as given by the tty command')
group = parser.add_mutually_exclusive_group()
group.add_argument('-n', action='store_true',
help='prevent sending a trailing newline character')
group.add_argument('--stdin', action='store_true',
help='read input from stdin')
group = parser.add_argument_group()
group.add_argument('cmd', nargs='?',
help='command to run (required if not using --stdin)')
group.add_argument('args', nargs='*',
help='arguments to command')
args = parser.parse_known_args()
if args.stdin:
data = sys.stdin.read()
else:
data = ' '.join([args.cmd] + args.args)
for c in data:
fcntl.ioctl(args.tty, termios.TIOCSTI, c)
if not args.n and data[-1][-1] != '\n':
fcntl.ioctl(args.tty, termios.TIOCSTI, '\n')
以下是您的使用方法:
1 号航站楼: 做...
$ tty > /tmp/t1
2 号航站楼: 做...
$ sudo python termfake.py $(cat /tmp/t1) date +%s
1 号航站楼: 观察...
$ tty > /tmp/t1
$ date +%s
1487276400
大部分code samples I've seen are trying to read from stdin without local echo. To do this they modify the "local modes" flag to remove the setting to "Echo input characters". I thought I could just modify the "input modes" flag to TIOCSTI
which is for "Insert the given byte in the input queue.". However, even though I run the script as root, it has no effect. anything I write to the fd seems to go to the terminal output, rather than the terminal input. Basically what I want to do is this exact thing,但纯python。
"""
termfake.py
Usage: sudo python termfake.py /dev/ttys002
Get the tty device path of a different local termimal by running `tty`
in that terminal.
"""
import sys
import termios
fd = open(sys.argv[1], 'w')
fdno = fd.fileno()
# Returns [iflag, oflag, cflag, lflag, ispeed, ospeed, cc]
tatters = termios.tcgetattr(fdno)
print('original', tatters)
tatters[0] = termios.TIOCSTI
print('TIOCSTI', termios.TIOCSTI)
# Set iflag
termios.tcsetattr(fdno, termios.TCSANOW, tatters)
# Verify setting change
with open('/dev/ttys002', 'w') as fd2:
print('modified', termios.tcgetattr(fd2.fileno()))
fd.write('This is test\n')
fd.close()
TIOCSTI
是一个 ioctl(记录在 tty_ioctl(4)
中),不是终端设置,所以你不能使用 tcsetattr()
-- 你需要输入假的每个字符输入 ioctl()
代替。以前从来不需要从 Python 执行 ioctl,但以下似乎适用于不同终端中的 运行 和 ls
(指定为参数,例如 /dev/pts/13) 那是 运行 Bash:
import fcntl
import sys
import termios
with open(sys.argv[1], 'w') as fd:
for c in "ls\n":
fcntl.ioctl(fd, termios.TIOCSTI, c)
顺便说一下,TIOCSTI
需要 root 权限(或 CAP_SYS_ADMIN
更具体,但实际上通常是相同的)——参见 capabilities(7)
.
我从@Ulfalizer 那里得到了答案并将其扩展为一个完整且可用的应用程序。
import sys
import fcntl
import termios
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('tty', type=argparse.FileType('w'),
help='full tty path as given by the tty command')
group = parser.add_mutually_exclusive_group()
group.add_argument('-n', action='store_true',
help='prevent sending a trailing newline character')
group.add_argument('--stdin', action='store_true',
help='read input from stdin')
group = parser.add_argument_group()
group.add_argument('cmd', nargs='?',
help='command to run (required if not using --stdin)')
group.add_argument('args', nargs='*',
help='arguments to command')
args = parser.parse_known_args()
if args.stdin:
data = sys.stdin.read()
else:
data = ' '.join([args.cmd] + args.args)
for c in data:
fcntl.ioctl(args.tty, termios.TIOCSTI, c)
if not args.n and data[-1][-1] != '\n':
fcntl.ioctl(args.tty, termios.TIOCSTI, '\n')
以下是您的使用方法:
1 号航站楼: 做...
$ tty > /tmp/t1
2 号航站楼: 做...
$ sudo python termfake.py $(cat /tmp/t1) date +%s
1 号航站楼: 观察...
$ tty > /tmp/t1
$ date +%s
1487276400