วิธีเปลี่ยนเส้นทางไปยัง stdin ของ bash shell ที่กำลังทำงานอยู่


7

ตามทฤษฎีแล้วถ้าฉันรู้ pid ของ bash shell ที่กำลังรันอยู่ฉันสามารถรัน cat ที่ stdout ถูกเปลี่ยนทิศทางไปยัง stdin ของเชลล์นั้น ดูเหมือนว่าฉันจะพิมพ์บางอย่างบนเปลือกนั้น น่าเสียดายที่มีกระแสข้อมูลมาจาก cat แต่จะไม่ทำให้เชลล์ทำงานอย่างถูกต้อง (คำสั่งที่ป้อนจาก cat จะไม่ถูกดำเนินการโดย bash)

เปิดเทอร์มินัล:

ps -ef | grep bash
ymf       4906  4887  0 16:19 pts/0    00:00:00 /bin/bash

บนเทอร์มินัลอื่น:

cat 1> /proc/4906/fd/0
echo 'hello!'

ทำไม?


1
คุณส่งคีย์ 'Return' ด้วยหรือไม่ ตามที่จะต้องยุติคำสั่ง
boretom

@boretom แน่นอนฉันทำ
Determinant

ใช่ฉันเห็นแล้วคำถามที่น่าสนใจ อินพุทไปยัง bash นั้นจะถูกเปลี่ยนเส้นทางไปยัง stdout ลองใช้คำสั่งเช่น top และคุณจะเห็นว่า stdin เป็นเพียงการเพิ่มที่ใดที่หนึ่งไปยังเอาต์พุต ฉันเดาว่าเนื่องจากเชลล์เริ่มต้นเป็นเชลล์แบบโต้ตอบมันจะไม่ยอมรับคำสั่งจาก stdin แต่นั่นเป็นการเก็งกำไรที่บริสุทธิ์
boretom

ในขณะที่ฉันไม่มีกูรูที่นี่ฉันคิดว่าสิ่งที่คุณทำคือการเขียนไปยังเทอร์มินัลอีมูเลเตอร์และไม่ใช่กระบวนการที่เป็นปัญหา IE คุณเขียนไปยังทางแยกไปป์ไลน์ที่ถูกต้อง แต่มันหมุนไปในทางที่ผิดของสองท่อ
Eroen

@boretom ลอง ls -l /proc/PID/fd/. 0, 1, 2 ถูกเปลี่ยนเส้นทางทั้งหมดไปที่ /dev/pts/TERM_NUMER ไม่ว่าจะยอมรับคำสั่งจาก stdin หรือไม่ฉันแน่ใจว่า fd0 นั้นใช้สำหรับอินพุตและฉันได้เปลี่ยนเส้นทางการส่งออกของ cat ไปแล้ว
Determinant

คำตอบ:


7

ฉันเบื่อกับการ จำกัด "หนึ่งย่อหน้าเท่านั้น" ในความคิดเห็น =)

ถ้าคุณเริ่มเปลือก shและรับ pid $pid คุณสามารถค้นหาไฟล์ descriptors ตามที่คุณอธิบาย ตัวอย่าง:

$ ls -l /proc/29201/fd
total 0
lrwx------ 1 eroen users 64 Mar 22 15:52 0 -> /dev/pts/2
lrwx------ 1 eroen users 64 Mar 22 15:52 1 -> /dev/pts/2
lrwx------ 1 eroen users 64 Mar 22 15:52 2 -> /dev/pts/2
lrwx------ 1 eroen users 64 Mar 22 15:52 255 -> /dev/pts/2

คุณจะสังเกตได้ว่า 1, 2 และ 3 เป็น symlink ไป tty เดียวกัน (a chardev) กล่าวอีกนัยหนึ่งอินพุตไปยังกระบวนการถูกอ่านจากโหนดอุปกรณ์เดียวกันกับเอาต์พุตที่ถูกเขียนไป

เมื่อคุณพยายามที่จะเขียน (ในกระบวนการที่แตกต่าง) เพื่อ tty เดียวกัน (เช่นกัน /proc/$pid/fd/0 หรือ /dev/pts/? คุณทำสิ่งเดียวกันกับที่กระบวนการทำเมื่อมันเขียนข้อมูลลงในเอาต์พุต ข้อมูลจะปรากฏขึ้นในหน้าต่างเทอร์มินัล

การเปลี่ยนแปลงจริงที่จุด fd [0-2] หลังจากเริ่มกระบวนการมีความซับซ้อน แต่ไม่เป็นไปไม่ได้ Reptyr เป็นแอปพลิเคชั่นโอเพนซอร์สฟรีที่ปรับเปลี่ยนกระบวนการที่มีอยู่ดังนั้นมันจึง fd [0-2] ชี้ไปที่ tty อื่น (รวมถึงสิ่งอื่น ๆ ) นี่คือความสำเร็จผ่าน ptrace กรอบ. โพสต์ยังกล่าวถึงซอฟต์แวร์อื่น ๆ ที่ทำสิ่งเดียวกันและสามารถทำได้ผ่าน gdb .

คุณอาจพบว่า Reptyr หรือซอฟต์แวร์อื่นทำในสิ่งที่คุณต้องการทั้งนี้ขึ้นอยู่กับสิ่งที่คุณต้องการทำให้สำเร็จ มิฉะนั้นคุณสามารถดู / คัดลอก / ปรับเปลี่ยนซอร์สโค้ดและค้นหาวิธีที่พวกเขาทำเคล็ดลับ

ภาคผนวก:
นี้ มีไดอะแกรมแสดงตัวอย่างบางส่วนโดยเฉพาะ ที่สาม แผนผังจากด้านบน


1
ดังนั้น tty อ่านจากแป้นพิมพ์ด้วยวิธีที่มหัศจรรย์และการเขียนทุกอย่างไปยัง tty สามารถทำให้เกิดการแสดงข้อความเท่านั้น
Determinant

2
เวทมนตร์น้อยลงและมากขึ้น "ภายในเคอร์เนล" แต่ใช่
Eroen

5

ไปที่เทอร์มินัล A ประเภทใดก็ได้ tty

คุณจะได้รับเช่น "/ dev / pts / 0"

ทีนี้ไปที่อาคาร B แล้วพิมพ์ exec 0</dev/pts/0 (หรือสิ่งที่คำสั่ง tty ให้คุณ)

กลับไปที่เทอร์มินัล A และคำสั่งที่คุณป้อนจะทำงานบนเทอร์มินัลบี


2
ให้ฉันพูดถึงสิ่งนี้ว่าสร้าง น่าสนใจ สภาพการแข่งขันซึ่งในระบบของฉันทำให้มันดูเหมือนสุ่มที่เปลือกได้รับตัวละคร
Eroen

1

วิธีเปลี่ยนเส้นทางไปยัง stdin ของ bash shell ที่กำลังทำงานอยู่

ใช้ C ( https://stackoverflow.com/a/7370822 . ฉันยังไม่ได้ทดสอบ):

char* cmd="ls\n";
int fd = open (ptsname, O_RDWR);

while (*cmd)
{
    ioctl(fd, TIOCSTI, cmd++);
}

ใช้ Perl ( https://unix.stackexchange.com/a/48221 . ทำงานได้อย่างสมบูรณ์ แต่สำหรับเชลล์ปัจจุบันเท่านั้น):

require "sys/ioctl.ph";
ioctl(STDIN, &TIOCSTI, $_) for split "", join " ", @ARGV;

1
ใน superuser เรากำลังพูดถึงเชลล์ไม่ใช่ C หรือ perl
outoftime
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.