这篇博客主要是一个终端的骚操作,没有什么知识点,都是一些经验之谈,表述上甚至可能有错误。

怎么在程序里强行让用户只能键盘输入

  在Linux的程序里(其实Windows里也差不多)一般能键盘输入的,就能用重定向输入,但是,有办法让人不能轻易用重定向代替键盘输入。
  最简单的,ssh这个工具本身不支持直接使用参数输入密码(当然可以通过sshpass之类的工具在参数输入密码),而且ssh虽然支持重定向输入,但是只能把命令重定向过去,而无法把密码重定向过去。
  类似ssh这样强制只能键盘输入的程序怎么实现呢?
  举个最简单的例子(先用shell写一个最简单的实现):

#!/bin/bashptsname="/dev/$(ps | awk "\$1==\"$$\"{print \$2}")"
exec 200<"$ptsname"
inputdata=""
read -u 200 inputdata
exec 200<&-echo "you input: $inputdata"

  运行一些看看效果:

  这样就写好了一个最简单的强制键盘输入的程序了,在使用echo "fu** you"重定向到这个shell脚本的时候,它并没有从标准输入读入,而是从终端读入,你可以看看ptsname变量的内容,就是当前终端的路径。
  这个shell脚本很简单,但是作为经验之谈,我稍微解释一下各行命令的作用:
  首先是ptsname="/dev/$(ps | awk "\$1==\"$$\"{print \$2}")"
  我们先看看ps的输出:

  可以看到,ps未使用任何参数的情况下可以获取到当前进程以及父进程的信息,在这张图片里,当前进程就是ps,父进程就是bash。而$$是代替当前进程号码,在这里也就是3158这个bash的进程号码(专业一点的说法是pid)。

有些老六会说$$是父进程的pid而不是当前进程的pid,其实不是,$$就是当前进程的pid,因为这些老六是这样用的:
echo "$$"
然后他就会说:“欸,获取到的是bash的pid而不是echo的pid”
我会说:“你在写命令行的时候,$$就被替换为当前进程的pid了,传入给echo命令的时候$$就是bash的pid,你让echo怎么搞才能输出echo的pid嘛。”

  然后重点关注3158   pts/0      00:00:00   bash这行,你看看第二个字符串,pts/0,这玩意就是当前进程使用的终端,具体可以通过ll /proc/$$/fd/看到,其中0就是标准输入,1是标准输出,2是标准错误,可以看到都是从终端读入的。
  你可能已经猜到了,当使用重定向时,0就不是指向/dev/pts/0了,可以写个简单的脚本看看:

#!/bin/bashls -l /proc/$$/fd/


  脚本内容很简单,正所谓大道至简。但是这个用法揭示了重定向的实质。
  一开始什么重定向都没用,直接调用脚本,看到fd很正常,都是终端。但是当使用管道重定向输入后,0就指向管道了(如果用的是文件重定向输入,0会指向那个文件,你可以试试)。用了管道重定向输出后,1就指向到cat的管道了,当使用了2>&1表示把标准错误也重定向到标准输出后,2也指向到cat的管道了。
  所以说,之所以能够用重定向代替键盘输入,是因为它把文件描述符指向了管道或文件了。所以如果要强行只能在键盘输入,那很简单,反过来通过打开表示终端的文件只读取键盘输入就可以了。
  后面的exec 200<"$ptsname"就是在当前进程以读的方式打开ptsname表示的tty终端并且设置描述符为200;后面的read -u 200 inputdata就是从文件描述符为200的文件里读入一行数据到inputdata变量里,200正好就是tty的描述符,所以就是从终端读入了,而不是从标准输入读入;再后面的exec 200<&-是关闭200文件描述符;最后就给用户输出刚刚键盘输入的内容。

对于强制键盘输入的程序可有破解之法

  必须有,哪里有压迫,哪里就有反抗。原理很简单,它不是要从键盘输入吗,好,我就模拟从键盘输入!要模拟键盘输入只需要模拟终端输入即可。那这个问题不是变得很简单了吗,直接用C创建一个终端,然后给发送内容即可。废话不多说,上代码(这个是一个没有任何判断输出逻辑的代码,如果想做出sshpass的效果,需要把子进程的输出也重定向到从终端,然后搞一个子线程来做判断逻辑):

#define _XOPEN_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <fcntl.h>// 参数为:
// 实际上要执行的程序 参数1 参数2 参数3 ...
int main(int argc, char *argv[])
{int master_fd = open("/dev/ptmx", O_RDWR | O_NOCTTY);   // 创建虚拟终端主终端char *slave_name;int slave;pid_t pid;char buf[65];ssize_t n;if (master_fd == -1) {return 1;}if (grantpt(master_fd) == -1) {close(master_fd);return 1;}if (unlockpt(master_fd) == -1) {close(master_fd);return 1;}slave_name = ptsname(master_fd);    // 获取从终端名字(也就是文件名/dev/pts/0之类的东西)if (slave_name == NULL) {close(master_fd);return 1;}pid = fork();if (pid < 0) {close(master_fd);return 1;}if (pid == 0) {    // 子进程,在这里执行从终端close(master_fd); // 从终端里不需要主终端的句柄if (setsid() == -1) {_exit(1);}slave = open(slave_name, O_RDWR);if (slave == -1) {_exit(1);}dup2(slave, STDIN_FILENO);execvp(argv[1], argv + 1);}// 下面父进程负责一直等待用户标准输入,并且把内容传给子进程while ((n = read(STDIN_FILENO, buf, sizeof(buf) - 1)) > 0) {   // 其实大小没必要-1,但是为了打日志不被坑加上buf[n] = '\0';   // 其实没必要,因为后面write的时候会明确长度,但是这样可以方便出问题时打日志不会被坑write(master_fd, buf, n);   // 把标准输入获取到的东西给虚拟终端传过去}write(master_fd, "\x04", 1);   // 发送键盘按下ctrl+d的控制符号,为什么是4可以看ANSI编码,4代表EOT(传输结束)wait(NULL);    // 给子进程收尸close(master_fd);return 0;
}

  稍微解释一下,master_fd是主终端句柄,slave是从终端句柄。这两个终端有一个特点,就是它们两可以通过这两个句柄交互:主终端往master_fd写东西,从终端就可以从slave读到;从终端往slave写东西,主终端就能从master_fd读到。所以dup2(slave, STDIN_FILENO)是把从终端读到主终端写到master_fd的内容重定向到从终端的标准输入。而我的逻辑是主终端获取到标准输入的时候,就写到master_fd。这样就相当于把这个程序的标准输入重定向到从终端的标准输入了。
  让我们试试威力(我把代码保存为pass.c):

  一开始是直接调用脚本,键盘输入hello后输出;
  第二次是用重定向想输入内容为xxx,但是失败了,还是要求键盘输入;
  第三次恼羞成怒,用这个代码编译了一个模拟终端输入的程序,然后就能重定向了。
  你可能已经发现了,这个代码不仅能解决我这个强制键盘输入脚本这个例子,通过不同的参数,可以解决不同的程序。比如ssh:

  第一次是没有用pass的对照,一回车就提示要键盘输入密码了;
  第二次是用了pass的效果。
  没错,就是这么简单的C代码,就可以模拟在键盘输入,从而达到模拟给ssh输入密码的效果(红色划掉的地方就是密码),因为ssh做了判断,不能在它显示能够root@127.0.0.1’s password:之前就输入密码,我这个程序没有写判断逻辑(感兴趣的话你可以自己加上,多不了几行代码,我这只是个最简单的例子),所以我通过sleep来粗略地控制流程。因为ssh默认是有回显的,所以你能看到在它下面的输出里也包含了模拟输入的命令内容。

Linux让终端只接受键盘输入相关推荐

  1. ubuntu下minicom不能接受键盘输入

    曾经使用设定Ctrl-A -> O -> Serial Port Setup -> Hardware flow control, 检查Hardware flow已经为No 但是,mi ...

  2. 解决set /p yn= 接受键盘输入导致ECHO 处于关闭状态的问题

    解决set /p yn= 接受键盘输入导致ECHO 处于关闭状态的问题 参考文章: (1)解决set /p yn= 接受键盘输入导致ECHO 处于关闭状态的问题 (2)https://www.cnbl ...

  3. Java复习:如何接受键盘输入的包含空格的字符串

    文章目录 package Remain;import java.io.BufferedReader; import java.io.IOException; import java.io.InputS ...

  4. shell接受键盘输入参数

    [root@localhost ~]$ read [选项][变量名] 选项:-a 后跟一个变量,该变量会被认为是个数组,然后给其赋值,默认是以空格为分割符.-p: "提示信息":在 ...

  5. 变量基础知识和如何接受键盘输入的值

    数值的命名规则 1.变量可以有字母,数字,下划线,美元符,人明币组成 2.变量不可以数字开头 3.正常以小写字母.下划线或美元符开头 4.人明币一般不使用 5.驼峰命名法: 多个单词,除去开头的,每个 ...

  6. 监控linux终端键盘输入,Linux内核实时监控键盘输入

    刚毕业那会儿,VC6学习MFC,总得来点儿好玩的东西才能继续下去,毕竟不是科班出身,得完全靠意义去驱动-那个时候认识了键盘钩子,鼠标钩子之类: https://blog.csdn.net/dog250 ...

  7. linux 控制台输入命令无效_解决linux下终端无法输入的假死问题

    有时在linux下shell终端中,会突然出现终端应用卡死,无法接受键盘输入, 但是其它分屏, 系统都是正常的.这本来是一个终端的很老的功能, 叫软件流控制(XON/XOFF flow control ...

  8. 解决linux下终端无法输入的假死问题

    有时在linux下shell终端中,会突然出现终端应用卡死,无法接受键盘输入, 但是其它分屏, 系统都是正常的.这本来是一个终端的很老的功能, 叫软件流控制(XON/XOFF flow control ...

  9. Linux内核实时监控键盘输入

    刚毕业那会儿,VC6学习MFC,总得来点儿好玩的东西才能继续下去,毕竟不是科班出身,得完全靠意义去驱动-那个时候认识了键盘钩子,鼠标钩子之类: https://blog.csdn.net/dog250 ...

最新文章

  1. 'module' object is not callable
  2. c语言解决函数变参数问题 va_list
  3. 【机器学习基础】Self-Supervised Learning入门介绍
  4. Open SAP 上 SAP Fiori Elements 公开课第一单元学习笔记
  5. Linux查看c语言组件进程,Linux下查看进程IO工具iopp
  6. leetcode1119. 删去字符串中的元音 小学难度
  7. Android开发之桌面快捷键使用细则(原创)
  8. php当前工作目录路径,Linux_Linux下使用Shell脚本改变当前工作路径,       She - phpStudy...
  9. 多线程之volatile关键字
  10. 计算机软件cae,各种CAE软件介绍
  11. Excel如何将xlsx后缀格式的文件转为xls格式?
  12. 基于bind搭建智能dns
  13. 设计模式六大原则详解
  14. 多进程与多线程的区别,和用途
  15. 一本通 P1486 【黑暗城堡】
  16. [体检]悲从中来,伤不起
  17. 【HNS】试着领一下 HandShake 为开源社区发放的 HNS Coin
  18. Oracle 行列转换函数pivot使用
  19. 润乾报表:怎样把不同数据库的数据放到一张报表里
  20. 科学家利用计算机模型,科学家开发出最详细计算机模型 揭示130亿年宇宙奥秘...

热门文章

  1. mes是怎样进行生产工艺管理的?
  2. 如何制作一个简易的计算器
  3. 2022金九银十工作潮,怎么样才能成功跳槽面试拿到高薪呢?
  4. ffmpeg教程java_ffmpeg Windows开发环境搭建
  5. Centos7.9安装GitLab
  6. 5G资费其实已经大幅下降,消费者不愿用5G在于信号太差了
  7. Ubuntu修改用户权限及修改文件夹所属用户
  8. sakura主题美化
  9. PBFT实用拜占庭容错算法深入详解
  10. centos安装goaccess 分析nginx日志