רציתי להמשיך עם כמה השלמות בענין ניתוב קלט/פלט
חשבתי להכניס את הכל בפוסט אחד אבל החלק הראשון כבר ארך יותר מדי... אז בינתיים נעלה אותו.
חלק זה הוא מידע תיאורטי שלא חייבים להבין כדי להשתמש בשורת הפקודה
השלמה בנושא File handles (המכונים גם File descriptors)
רקע
מטעמים מרובים זה לא פרקטי במערכות מדרניים לתת לכל תהליך לגשת ישירות לדיסק הקשיח ולעשות שם מה שהוא רוצה, ולכן אחת מהאחריות של מערכת ההפעלה היא להיות אמצעי בין התהליכים לבין קבצים, וכל גישה לקובץ נעשה דרך הגישור של מערכת ההפעלה.
בכל מערכות ההפעלה הנפוצות, פתיחה של קובץ גורם למערכת ההפעלה להקצות עבור התהליך "ידית" לקובץ (שהוא למעשה סה"כ מספר) כאשר הידית מייצגת את הקובץ ומועברת כפרמטר בכל פעולה שהתהליך רוצה לעשות עם הקובץ.
זה הרעיון של file handles.
מימוש בווינדוס ולינוקס
הזכרנו שלכל תהליך שה-shell מריץ קיימות בברירת מחדל 3 ידיות לקבצים. מספרי הידיות הם 0,1 ו-2 והם מייצגות את הקבצים של הקלט/פלט/ושגיאות.
במערכות מבוססות לינוקס מספרים אלו באמת מייצגות את הידית של מערכת ההפעלה. אפשר לראות את זה על ידי הפקודה:
lsof -a -p $$ -d0,1,2
זה מראה את הידיות 0,1,2 של ה-shell עצמו.
והתוצאה אמורה להיות משהו כמו זה:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
bash 16104 yossizahn 0u CHR 136,2 0t0 5 /dev/pts/2
bash 16104 yossizahn 1u CHR 136,2 0t0 5 /dev/pts/2
bash 16104 yossizahn 2u CHR 136,2 0t0 5 /dev/pts/2
הנתיב /dev/pts/2 מכיל את הקובץ שמייצג את חלון הטרמינל (ע"ע PTY)
ℹ הסבר הפקודה כאן; אגב, אתר מגניב, לא?
המשתנה $$ מייצגת את ה-PID של ה-shell עצמו
אם נבצע ניתוב פלט על ידי פקודה כזו:
exec 2> ~/error.log
נקבל טבלת ידיות כזה:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
bash 3460 yossizahn 0u CHR 136,2 0t0 5 /dev/pts/2
bash 3460 yossizahn 1u CHR 136,2 0t0 5 /dev/pts/2
bash 3460 yossizahn 2w REG 8,0 0 519201 /home/yossizahn/error.log
והנה הידית עם מזהה (FD = File Descriptor) 2 באמת פונה לקובץ error.log.
ℹ הפקודה exec עם ניתוב גורם לנתב את הפלט של ה-shell עצמו. עיין help exec.
פקודת help נותנת עזרה על פקודות "מובנות" או "פנימיות".
➕ בונוס: תלמדו את הייעוד של פקודת exec ותסבירו למה היא חייבת להיות פקודה מובנית/פנימית ולא פקודה חיצונית
בווינדוס כמו בווינדוס הדברים לא כל כך פשוטים.
א. לא כל תהליך מקבלת את הידיות האלו. רק אלה שמסומנים כאלה שמיועדים עבור שימוש בשורת הפקודה.
ב. מספרי הידיות שמערכת ההפעלה מקצה עבורם הם לא 0,1,2 אלא מספרים אחרים.
ניתן לראות את הידיות של תהליך בכלי הנפלא process hacker.
ככה נראה רשימת הידיות של תהליך CMD שהרצתי:
19a96ca7-bb06-4df1-a11b-afba86f99eb1-image.png
[סיננתי את הרשימה להראות רק ידיות מסוג File]
אפשר לראות שאין שם ידיות עם המספר 0,1,2. אז איפה הם?
התשובה היא שלשם תאימות עם מנגנון זה שמקובל בשורות פקודה של מערכות הפעלה, יש מטהדאטה נוסף שמוצמד לתהליך (ה-PEB) שכולל בתוכו את המידע שממפה ידיות ה-native-ים לידיות 0,1,2.
לא מצאתי בינתיים דרך פשוטה להסתכל במיפוי הזה.
אבל יש דרך לא פשוטה... 🙂
בא ננסה ביחד!
⚠ החלק הבא למתקדמים בלבד...
נפתח את תוכנת windbg ונבחר מתוך התפריט attach to process.
5c0510fb-8ca2-467f-b70d-fc664ca85f6c-image.png
ברשימת התהליכים נבחר את התהליך שנרצה לקבל מידע עליו.
9169c634-74b3-44a6-b4a9-4fd40742f448-image.png
[אפשר לסנן את הרשימה לפי שם התהליך]
עכשיו נריץ את הפקודה הבאה בחלון command:
dt _peb @$peb
ℹ פקודת dt מציג דאטה בצורה יפה (dump בלע"ז), הפרמטר _peb אומר להציג את זה כמבנה מסוג _peb. הפרמטר @$peb מתורגם לכתובת של מבנה ה-PEB.
נקבל dump של מבנה ה-PEB. מתוך זה נבחר את התת אובייקט: ProcessParameters.
למזלינו windbg מספיק חכם לדעת איך לתרגם את האובייקט הזה, והוא מציג אותו כקישור שבלחיצה עליו מורצת אוטומטית הפקודה שתעשה dump עליו:
48e63683-45e7-487d-9e6b-58e65808be3f-image.png
בפלט של הפקודה, סמוך לתחילת הרשימה נראה את המיפוי של הקלט,פלט,ופלט שגיאות:
c2d451a3-89ea-4846-834d-f4026af35990-image.png
כל שורה הוא סוג הפלט/קלט עם ערך של הידית שמשוייך אליו.
עכשיו אפשר לחזור ל-process hacker ולקבל את הנתיב של הקובץ לפי המזהה.
(נראה לי שבדיבוג ב-user mode אין דרך פשוטה לקבל את הנתיב של הקובץ מ-windbg, (רק בדיבוג קרנל אפשר) אבל יש דרך מסובכת מאוד, עיין כאן)
טוב, נראה לי שקצת נסחפתי... 🙂 בפוסט הבא נחזור שוב לנושאי שורת הפקודה