מדריך שורת הפקודה - File handles

חלק שמיני בסדרת מדריך שורת הפקודה

Authors
  • Name
    YossiZ
    Published on
    Twitter

רציתי להמשיך עם כמה השלמות בענין ניתוב קלט/פלט
חשבתי להכניס את הכל בפוסט אחד אבל החלק הראשון יצא כבר יותר מדי ארוך... אז בינתיים נעלה אותו.

חלק זה הוא מידע תיאורטי שלא חייבים להבין על מנת להשתמש בשורת הפקודה

השלמה בנושא 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 שהרצתי:
1612383637900-19a96ca7-bb06-4df1-a11b-afba86f99eb1-image.png

[סיננתי את הרשימה כדי להציג רק ידיות מסוג File]

אפשר לראות שאין שם ידיות עם המספר 0,1,2. אז איפה הם?

התשובה היא שלשם תאימות עם מנגנון זה שמקובל בשורות פקודה של מערכות הפעלה, יש מטהדאטה נוסף שמוצמד לתהליך (ה-PEB) שכולל בתוכו את המידע שממפה ידיות ה-native-ים לידיות 0,1,2.

לא מצאתי בינתיים דרך פשוטה להסתכל במיפוי הזה.

אבל יש דרך לא פשוטה... 🙂

בואו וננסה ביחד!
החלק הבא למתקדמים בלבד...

  • נפתח את תוכנת windbg ונבחר מתוך התפריט attach to process.
    1612384486695-5c0510fb-8ca2-467f-b70d-fc664ca85f6c-image.png
  • ברשימת התהליכים נבחר את התהליך שנרצה לקבל מידע עליו.
    1612384552299-9169c634-74b3-44a6-b4a9-4fd40742f448-image.png

[אפשר לסנן את הרשימה לפי שם התהליך]

  • עכשיו נריץ את הפקודה הבאה בחלון command:
dt _peb @$peb

ℹ פקודת dt מציג דאטה בצורה יפה (dump בלע"ז), הפרמטר ‎_peb אומר להציג את זה כמבנה מסוג ‎_peb. הפרמטר ‎@$peb מתורגם לכתובת של מבנה ה-PEB.

  • נקבל dump של מבנה ה-PEB. מתוך זה נבחר את התת אובייקט: ProcessParameters.
    למזלינו windbg מספיק חכם לדעת איך לתרגם את האובייקט הזה, והוא מציג אותו כקישור שבלחיצה עליו מורצת אוטומטית הפקודה שתעשה dump עליו:

1612385295150-48e63683-45e7-487d-9e6b-58e65808be3f-image.png

  • בפלט של הפקודה, סמוך לתחילת הרשימה נראה את המיפוי של הקלט, פלט, ופלט שגיאות:

1612385384129-c2d451a3-89ea-4846-834d-f4026af35990-image.png

כל שורה היא סוג הפלט/קלט עם ערך של הידית שמשוייך אליו.

עכשיו אפשר לחזור ל-process hacker ולקבל את הנתיב של הקובץ לפי המזהה.

(נראה לי שבדיבוג ב-user mode אין דרך פשוטה לקבל את הנתיב של הקובץ מ-windbg, (רק בדיבוג קרנל אפשר) אבל יש דרך מסובכת מאוד, עיין כאן)

טוב, נראה לי שקצת נסחפתי... 🙂 בפוסט הבא נחזור שוב לנושאי שורת הפקודה.