Download as pdf or txt
Download as pdf or txt
You are on page 1of 11

‫סדנת מערכות הפעלה‬

‫‪ ,0X00‬מבוא‬

‫הכותרת "מערכות הפעלה" היא כותרת עצומה‪ ,‬ולא ניתן בסדנה אחת להכיר כל מה שקשור בפיתוח‬
‫בתחום זה‪ .‬לעומת זאת‪ ,‬מטרת הסדנה היא ליצור היכרות בסיסית עם כמה שיותר מרכיבים שקשורים‬
‫לפיתוח רכיבים הקשורים למערכת ההפעלה‪.‬‬
‫משיקולים שונים של נוחות או פרקטיות‪ ,‬בסדנה נפתח בסביבת לינוקס‪.‬‬
‫אחד היתרונות הגדולים בפיתוח ללינוקס הוא שכל הקוד של מערכת ההפעלה מפורסם ואפשר להיעזר‬
‫בו‪​ .‬כאן תמצאו את כל הקוד של לינוקס​‪.‬‬

‫מטרת הסדנה היא לתת בסיס לפיתוח רכיבים של מערכת ההפעלה )במקרה שלנו‪.(kernel module ,‬‬
‫בנוסף‪ ,‬בסדנה זו יש דגש על למידה עצמאית‪ ,‬מציאת מקורות מידע‪ ,‬ונגיעה במושגים שונים הקשורים‬
‫למערכות הפעלה כמו ‪ proc files, system calls‬ועוד‪.‬‬
‫בחלק הראשון של הסדנה נפתח רכיב של מערכת ההפעלה שעוקב אחרי פעולות קבצים שנעשות‬
‫ברחבי המחשב‪ ,‬ונותן ממשק נוח לקבל מידע זה‪.‬‬

‫חשוב לציין שרמת הפיתוח ו"אורך הקוד" הנדרש בסדנה הוא לא גבוה‪ ,‬ורוב האתגר הוא מחקרי ‪/‬‬
‫לימודי‪ .‬לכן‪ ,‬נסו להיכנס לעומק של כל נושא‪ .‬חקרו מה עושה כל פונקציה או קטע קוד ‪ -‬אין קופסאות‬
‫שחורות‪.‬‬

‫‪ ,0X01‬הכנות‬

‫ככלל‪ ,‬רצוי לפתח רכיבי מערכות הפעלה במכונה וירטואלית )‪ .(VM‬הסיבה לכך היא שקל מאוד לעשות‬
‫טעות קטנה ולגרום ל‪)​​kernel oops‬זכרו‪ ,‬בקרנל אין מי שיתפוס את האקספשנים שלנו וכל חריגה תהרוג‬
‫בדם קר את התהליך ואיתו כל מערכת ההפעלה(‪ ,‬או לטעון למערכת ההפעלה רכיב שגורם לה להפסיק‬
‫לעלות‪ .‬זה משהו שאתם פחות רוצים שיקרה ולכן נשתמש במכונה וירטואלית חדשה לכל הניסויים‬
‫המשוגעים שלנו‪.‬‬

‫ניתן להשתמש בכל תוכנת וירטואליזציה )‪ .(​​vmware​, ​virtualbox‬ניתן להתקין על המכונה ווירטואלית‬
‫)כמעט( כל הפצת לינוקס פופולרית‪ .‬אני בחרתי ב ‪ ,Ubuntu 16.04‬אך התהליך הוא זהה‪.‬‬
‫ברגע שיש לכם מכונה וירטואלית עם לינוקס מותקן עלייה‪ ,‬הצטיידו בעורך הטקסט האהוב עליכם‪ ,‬ואתם‬
‫מוכנים לצאת לדרך‪.‬‬

‫‪!0X02, Hello Kernel‬‬

‫כדי להדגיש‪ ,‬אזכיר שוב ​לא ​לעבוד על מערכת הפעלה אמתית אלא רק על מכונה וירטואלית‪ .‬בנוסף‪,‬‬
‫ברגע שהתקנתם לינוקס על המכונה הווירטואלית‪​ ,‬שמרו עותק )‪ ​(snapshot‬של המכונה כדי שלא‬
‫תצטרכו להתקין לינוקס מחדש אם )כאשר( משהו ישתבש‪.‬‬

‫מערכת ההפעלה מחולקת בגדול ל ‪ user space‬ו ‪) kernel space‬מומלץ לקרוא עוד בנושא ‪ -‬היעזרו‬
‫בחומרים של מערכות הפעלה משנים קודמות‪ ,‬אותם קיבלתם בתחילת השנה(‪ .‬המשתמש רץ ב ‪user‬‬
‫‪ ,space‬וכאשר הוא צריך לבצע פעולות שדורשות את התערבות מערכת ההפעלה )התנהלות עם זיכרון‪,‬‬
‫תקשורת‪ ,‬קבצים וכדומה‪ ,‬בעצם כל דבר‪ (...‬הוא מבקש ממערכת ההפעלה להריץ בשבילו פונקציות‬
‫)שרצות ב‪ .(kernel space‬בקשות אלו נקראות ‪.system calls‬‬

‫בשונה מתוכנה רגילה‪ ,‬אנו נכתוב קוד שרץ ב‪ .kernel space‬יש סיבות רבות לכתיבת קוד קרנל‪ ,‬כמו‬
‫ריצה בהרשאות גבוהות‪ ,‬שינוי דרך הפעולה של מערכת ההפעלה‪ ,‬גישה ישירה לזיכרון‪ ,‬חיסכון של‬
‫מעבר תכוף בין ‪ kernel space‬ל ‪ ,user space‬כתיבת תכנות המסייעות למערכת ההפעלה כמו‬
‫‪ drivers‬ועוד‪.‬‬

‫כמו הקוד של מערכת ההפעלה‪ ,‬גם הקוד שלנו יהיה כתוב בשפת ‪.C‬‬
‫כעת‪ ,‬אני מציג לפניכם את הגרסה של ה ‪ Linux Kernel‬לתוכנה הקלסית‪!Hello, world ,‬‬

‫‪​ :init_module‬פונקציית האתחול של המודול‪ ,‬מקביל ל ‪main‬‬


‫שימו לב שערך החזרה של הפונקציה מתאר הצלחה או כישלון‪ ,‬ולכן ‪ return 0‬הוא חובה‪ .‬ללא החזרת‬
‫הערך הנכון‪ ,‬האתחול יחשב ככישלון והמודול לא ייטען בהצלחה‪.‬‬

‫‪​ :cleanup_module‬פונקציית הניקיון של המודול‪.‬‬

‫‪​ :printk‬ה ‪ printf‬של הקרנל‪ .‬נחזור אליה בהמשך‪.‬‬

‫!‪0X03, Houston, we have a Makefile‬‬

‫מי מכם שבחיים לא שמע על ‪ ,Makefile‬מוזמן ללמוד עליהם ​כאן​‪.‬‬


‫מי שכן שמע על ‪ ,Makefile‬תשכחו ממה ששמעתם‪ ,‬כי כאן זה עובד מעט אחרת‪.‬‬

‫על תהליך הקמיפול והבניה של ‪ Kernel Module‬ניתן ללמוד ​כאן‪ ​.‬כדי לדעת את הבסיס כל מה שאתם‬
‫צריכים הוא לקרוא עד ‪ 4.1‬כולל )‪ .Kernel Includes‬ניתן לחפש מקורות מידע אחרים או יותר יפים‪ ,‬אבל‬
‫אל תסתבכו יותר מדי‪ ,‬כל המידע שצריך נמצא בקישור הזה‪.‬‬
‫הערה‪​ :‬לא להתחיל לעבוד ישר‪ .‬לקרוא את כל מה שרלוונטי ולחזור למסמך זה להערות נוספות‪.‬‬

‫הערות נוספות‪:‬‬
‫‪ .1‬לא ​להשתמש ב ‪ modules_install‬כ ‪ .target‬אנו רוצים רק לקמפל ולא להתקין שום דבר‪,‬‬
‫השתמשו ב ‪) modules‬חלק ‪(2.3‬‬
‫‪ .2‬אנו נעבוד בשיטת חלוקת הקבצים לשני קבצים נפרדים‪ Makefile ,‬ו ‪ ) Kbuild‬חלק ‪ ,3.2‬דוגמה‬
‫‪.(2‬‬
‫‪ .3‬הפרמטר ‪ C-‬של הפעולה ‪ make‬מקבל תיקייה של ‪ Kernel‬בנוי מראש כדי להשתמש במשאבים‬
‫שלו לבנות את המודול שלנו‪ ,‬אנו ניתן את הקרנל שאנו מריצים כרגע‪ ,‬שנמצא ב‪:path‬‬
‫‪/lib/​modules​/​$​(​shell uname ​-​r​)/​build‬‬
‫כאשר‬
‫)​‪$​(​shell uname ​-​r‬‬
‫מפעיל את הפקודה ‪ uname -r‬אשר מחזירה את השם המלא של הקרנל‪ ,‬ומכניס אותה‬
‫למחרוזת‪.‬‬
‫‪ .4‬בקובץ ‪ Kbuild‬נשתמש בפעולה ‪ obj-m‬כדי לבנות קובץ ‪ ko‬שניתן לטעון כמודול לקרנל‪.‬‬

‫‪0X04, Make it happen‬‬

‫עכשיו‪ ,‬כתבו תכנית ‪ Hello world‬משלכם‪ ,‬וכתבו לה קבצי ‪ Makefile‬ו ‪ Kbuild‬מתאימים‪.‬‬


‫קחו נשימה עמוקה‪ ,‬החזיקו אצבעות וכתבו את הפקודה ‪ make‬כדי להריץ את ה‪ Makefile‬שכתבתם‪.‬‬
‫במידה והתהליך הצליח תקבלו פלט מהפעולות ‪ make‬ו ‪ kbuild‬שאומרות שהכל בסדר‪ ,‬ובתיקיית‬
‫המקור שלכם )בנוסף להמון קבצי ביניים( תקבלו קובץ עם סיומת ‪ .ko‬זהו המודול שלכם ‪ -‬בהחלט סיבה‬
‫למסיבה!‬
‫במידה ומשהו כשל ולא קיבלתם קובץ ‪ ,ko‬חזרו לתיעוד של תהליך הבנייה‪ ,‬ולקוד ה ‪ hello world‬כדי‬
‫לבדוק מה השתבש‪.‬‬

‫‪ ,0X05‬הרצת המודול‬

‫שמחים ועליזים‪ ,‬עם מודול ביד‪ ,‬הגיע הזמן להכניס את המודול שלנו לרשימת המודולים ולהריץ אותו‬
‫כחלק ממערכת ההפעלה! לשם כך נשתמש בפקודה ‪ insmod‬כדי לטעון את המודול )הפקודה ‪ man‬ב‬
‫‪ terminal‬היא חבריכם הטוב ביותר(‪ .‬שימו לב שהפקודה ‪ insmod‬צריכה הרשאות ‪ root‬כדי לפעול‬
‫‪-‬השתמשו בפקודה ‪.sudo‬‬

‫במידה ואין שגיאות‪ ,‬ההכנסה עברה בהצלחה‪ .‬כמו קודם‪ ,‬במידה ויש שגיאות‪ ,‬הסתכלו בשלבים‬
‫הקודמים כדי לאתר בעיות‪.‬‬
‫אבל רגע‪ ,‬איפה ההדפסה שלנו?‬
‫כדי להבין זאת‪ ,‬נחזור לפונקציה ‪ .printk‬המטרה של פונקציה זו היא לא פלט למשתמש‪ ,‬אלא דרך‬
‫למודולים בקרנל לעשות ‪ log‬לפעולות שלהם‪ .‬כדי לצפות ב‪ log‬זה‪ ,‬ניתן להשתמש בפקודה ‪dmesg‬‬
‫הערה‪ :‬מטרת הפקודה ‪ tail‬היא להדפיס את סוף הקלט שלה )במקרה זה בחרתי להדפיס את ‪ 5‬השורות‬
‫האחרונות(‪ .‬יש הרבה מאוד מודולים שמדפיסים באמצעות ‪ printk‬ולכן נרצה רק את הסוף‪.‬‬
‫ניתן לראות שמספר מודולים אחרים כתבו ‪ ,log‬והרשומה האחרונה היא ההדפסה של המודול שלנו‪:‬‬
‫‪!Hello, Kernel‬‬
‫בנוסף‪ ,‬ניתן לראות שלינוקס כועס עלינו על ‪ kernel taint‬ברשומה למעלה‪ ,‬נגיע לזה בהמשך‪.‬‬

‫למעשה‪ ,‬המודול שלנו כרגע לא עושה יותר מדי‪ ,‬ונרצה לשלב זה להסיר אותו מהקרנל ) אין טעם‬
‫להשאיר סתם רכיבים שלא עושים כלום‪ .‬כדי להסיר את המודול שלנו‪ ,‬נשתמש בפעולה התאומה של‬
‫‪ insmod‬הנקראת ‪ .rmmod‬נפעיל שוב את הפעולה ‪:dmesg‬‬

‫ונראה שהפונקציה ‪ module_cleanup‬נקראה‪ ,‬והשורה ‪ Goodbye, Kernel‬הודפסה‪.‬‬

‫מסקנה‪ ​:‬בטעינת המודול נקראת הפונקציה ‪ ,init_module‬ובהסרת המודול נקראת הפונקציה‬


‫‪cleanup_module‬‬
‫הערה‪​ :‬ניתן לאתר שגיאות שונות שקרו בזמן ריצת‪/‬טעינת מודול באמצעות שימוש ב‪ dmesg‬באותה‬
‫צורה שראינו‪ .‬קראו עוד על ‪ dmesg‬ב ‪.man‬‬
‫‪ ,0X06‬מי נתן לך רישיון?‬

‫נזכר שבשלבים הקודמים‪ ,‬מערכת ההפעלה העירה לנו על משהו שנקרא ‪ .Kernel taint‬הבעיה היא‬
‫שלינוקס מתגאה ברישיון התוכנה החופשי שלה )‪ ,(open source‬ומכיוון שהוספנו רכיב חדש למערכת‬
‫ההפעלה‪ ,‬גם הוא צריך להיות בעל רישיון חופשי‪ .‬מכיוון שלא ציינו שום דבר לגבי רישיון התוכנה בקוד‬
‫שלנו‪ ,‬הקרנל לא מחשיב אותו כ ‪.open source‬‬
‫אז לפני שמפתחי לינוקס יבואו לדפוק אצלכם בדלת‪ ,‬מצאו דרך לתייג את הקוד שלכם להיות בעל רישיון‬
‫חופשי מסוג ‪GNU Public License‬‬

‫כדי לוודא שהצלחתם‪ ,‬הכניסו שוב את המודול בעזרת ‪ insmod‬ושימו לב שהפעם הקרנל שמח ומאושר‪,‬‬
‫ולא כותב שאתם מבצעים פשע נורא מסוג ‪.Kernel taint‬‬

‫‪0X07, The master plan‬‬

‫כעת‪ ,‬לאחר שלמדנו כיצד לכתוב ‪ Kernel module‬בסיסי‪ ,‬נחזור למטרה שלנו‪:‬‬
‫נרצה ליצור מערכת שמנטרת את פעולות המשתמש‪ .‬זאת נעשה באמצעות שיטה הנקראת ‪System‬‬
‫‪) .call hooking‬תזכורת על ‪ System calls‬ורשימה של קריאות מערכת ניתן למצוא ​כאן​(‪.‬‬

‫ניתן לראות שבהרבה פעולות בסיסיות של המשתמש )כתיבה וקריאה לקבצים‪ ,‬יצירת ‪ ,socket‬ועוד( יש‬
‫שימוש ב‪ .system calls‬במידה ונוכל להדפיס הודעה בכל פעם שיש שימוש בקריאת מערכת מסוימת )‬
‫‪ ,open‬לדוגמה(‪ ,‬נוכל בעצם לעקוב אחר פעולות שונות שהמשתמש עושה! )אם נחזור לאותה דוגמה‪,‬‬
‫נוכל להדפיס הודעה בכל פעם שמתבצעת פתיחת קובץ(‬

‫למזלנו‪ ,‬מערכת ההפעלה שומרת טבלה של פוינטרים לפונקציות קריאות המערכת‪ .‬שינוי פוינטרים אלה‬
‫לפונקציות משלנו יאפשר לנו לבצע פעולות מסוימות בכל פעם שמשתמש מנסה לבצע קריאת מערכת‬
‫)פתיחת קובץ לדוגמה(‪.‬‬

‫חשוב לזכור שאם נשנה את הפוינטרים לקריאות המערכת‪ ,‬הפונקציות המקוריות לא יקראו‪ .‬אם נחזור‬
‫לדוגמה של פתיחת הקובץ‪ ,‬שינוי הפוינטרים בטבלת ה ‪ system calls‬ייתן לנו את האפשרות להריץ קוד‬
‫משלנו‪ ,‬אך הקוד המקורי של פתיחת הקובץ לא ייקרא‪ ,‬והקובץ לא ייפתח‪.‬‬

‫כדי לפצות על בעיה זו‪ ,‬נשמור את הפוינטר המקורי של קריאת המערכת אותה אנו רוצים לשנות‪,‬‬
‫ובפונקציה שאנו יוצרים ​נקרא לפונקציה המקורית​ בנוסף לקוד שלנו כדי לבצע את הפעולה המקורית‬
‫)ובעצם לא לשבור את הפונקציונליות של מערכת ההפעלה(‪.‬‬

‫אם כך‪ ,‬שלבי הפעולה בקצרה הם‪:‬‬

‫‪ .1‬מציאת טבלת ה ‪system calls‬‬


‫‪ .2‬שמירת הפוינטר לפונקציה אותה אנו רוצים לשנות‪.‬‬
‫‪ .3‬נשנה את הפוינטר בטבלה כך שיצביע לפונקציה חדשה אותה נכתוב )במקרה שלנו‪ ,‬פונקציית‬
‫הדפסה(‬
‫‪ .4‬יש לוודא שהפונקציה החדשה )בנוסף לפעולות שלה( קוראת לקריאת המערכת המקורית‬
‫באמצעות הפוינטר ששמרנו‪.‬‬

‫‪ ,0X08‬אני מפה אני מפה‬


‫בגרסאות הישנות של לינוקס‪ ,‬היה ניתן לגשת ל ‪ syscall table‬באמצעות שם משתנה אשר מוגדר‬
‫בקובץ ‪ h‬כלשהו‪ .‬לעומת זאת‪ ,‬בגרסאות מודרניות של מערכת ההפעלה הטבלה אינה מיוצאת )‬
‫‪ .(exported‬המשמעות היא שהטבלה נמצאת בזיכרון אך לא ניתן לגשת אליה בצורה ישירה‪ .‬מטרתנו‬
‫בשלב זה היא למצוא את כתובת הטבלה‪.‬‬

‫למזלנו‪ ,‬ברוב ההפצות הפופולריות )ובוודאות ב‪ (Ubuntu‬ישנו קובץ הנקרא ‪ System map‬אשר מחזיק‬
‫את הכתובות למספר רב של משתנים‪ ,‬טבלאות‪ ,‬פונקציות )ועוד( במערכת ההפעלה‪ ,‬וביניהם גם טבלת‬
‫קריאות המערכת שלנו!‬

‫עוד על ‪) System map‬ואיך למצוא אותה( ניתן לקרוא ​כאן​‪.‬‬


‫לאחר שמצאתם את הטבלה‪ ,‬מצאו בתוכה את כתובת טבלת הקריאות‪ ,‬ושמרו אותה בצד‪.‬‬
‫?‪0X09, Got time for that‬‬

‫כדי ללמוד איך לעבוד עם ה ‪) syscall table‬ולוודא שהכל עד עכשיו עובד(‪ ,‬נכתוב מודול )או יותר נכון‪,‬‬
‫נרחיב את המודול שלנו( שמשתמש בקריאת המערכת ‪ time‬כדי לקבל ‪ ,unix time‬ולהדפיס אותו‬
‫באמצעות ‪.printk‬‬
‫חשוב להדגיש ​שלקרוא ל‪ system call‬בתוך הקרנל זה דבר ​לא נכון​‪ ,‬זה משהו שלא אמור לקרות‪,‬‬
‫והסיבה היחידה שאנחנו עושים את זה היא לוודא שאנחנו יודעים איך לעבוד עם הטבלה‪​ .‬אל ​תשתמשו‬
‫אף פעם בקריאות מערכת בתוך קוד שרץ בקרנל ‪ -‬אלו פונקציות שאמורות לתת שירות ל ‪.user space‬‬

‫קודם כל‪ ,‬נגדיר את טבלת קריאות המערכת באמצעות הכתובת שמצאנו ב‪System.map‬‬

‫)הכתובת היא מה שהיה רשום ב ‪ System.map‬שלי‪ ,‬לא בהכרח הכתובת שתהיה אצלכם(‪.‬‬

‫בטבלה זו נשתמש כמערך של פוינטרים לפונקציות קריאות המערכת‪ .‬כדי לגשת לפונקציה ספציפית‬
‫נשתמש ב‪ macros‬אשר מוגדרים ב ‪ ,asm/unistd.h‬ונראים כך‪:‬‬
‫‪__NR_syscallname‬‬
‫לדוגמה‪ ,‬הכתובת לקריאת המערכת ‪ write‬תימצא ב‬
‫]‪​table_address​[__NR_write‬‬

‫הערה‪​ :‬הקומפיילר לא ייתן לנו לקרוא לפונקציות ישירות מהטבלה ‪​ -‬הקוד הבא לא יתקמפל‪:‬‬
‫;)​‪err ​=​ table_address​[​__NR_write​](​fd​,​buffer​,​char_count‬‬

‫כדי להשתמש בטבלה‪ ,‬יש לשמור את כתובת הפונקציה בפוינטר לפונקציה‪ ,‬ולאחר מכן לקרוא לפונקציה‬
‫באמצעות הפוינטר ששמרנו‪) .‬על פוינטרים לפונקציות ב‪ C‬ניתן לקרוא כ​אן(‬

‫כעת‪ ,‬כתבו מודול אשר‪:‬‬


‫‪ .1‬בעת טעינתו מציין את הזמן שבו הוא נטען‬
‫‪ .2‬בעת הסרתו מציין את הזמן שבו הוא הוסר‬
‫את הזמן ציינו באמצעות ‪ unix time stamp‬אשר מוחזר מקריאת המערכת ‪time‬‬

‫כל הכבוד! כעת אתם יודעים כיצד לעבוד עם טבלת קריאות המערכת‪ ,‬אפשר להתקדם ‪.‬‬

‫‪ ,0X0A‬מכשול קטן בדרך‬

‫לפני שנוכל לעשות ‪ ,hook‬יש מכשול אחרון שנצטרך לפתור‪.‬‬


‫מגרסת לינוקס מסוימת‪ ,‬טבלת קריאות המערכת מוגדרת כמקטע זיכרון לקריאה בלבד‪ .‬לפני שנוכל‬
‫לערוך את הטבלה‪ ,‬נצטרך לבטל זאת‪.‬‬
‫ב ‪ ,user space‬מערכת ההפעלה מנהלת היררכיית משתמשים‪ ,‬וקובעת מה מותר בקבצים )קריאה‪,‬‬
‫כתיבה( עבור המשתמש הנוכחי‪ .‬המצב שלנו שונה‪ ,‬מכיוון שהזיכרון שאנחנו רוצים לשנות מוגדר לקריאה‬
‫בלבד גם עבור ה‪ .kernel‬כדי להשיג זאת‪ ,‬ישנו מצב שנקרא ‪ ,write protect‬שנקבע ע"י באוגר ‪ ​cr0‬של‬
‫המעבד‪ ,‬אשר מגביל את ההרשאות של הקרנל‪ .‬כדי לבטל את ה‪ ,write protect‬נכתוב ישירות לאוגר‬
‫‪ cr0‬ונשנה את הביט הזה‪.‬‬

‫כדי לבצע זאת‪ ,‬נשתמש בפונקציות ‪ write_cr0‬ו ‪ read_cr0‬שנמצאות בספרייה ‪,asm/cacheflush.h‬‬


‫כדי לשנות את ערכי האוגר‪.‬‬

‫כדי לבטל את מצב ‪ ,write protect‬נעשה פעולת ‪ BITWISE AND‬בין המצב הנוכחי של האוגר לבין‬
‫מספר בינארי שכולו ‪ 1‬חוץ מהביט של ‪) write protect‬הביט החמישי שערכו ‪ 16‬לפי ויקיפדיה(‪ .‬מכיוון‬
‫שאורך ה‪ cr0‬משתנה בין מעבדים‪ ,‬יש סיכוי שהקומפיילר יוסיף אפסים למספר שנכתוב‪ ,‬וכך נקבל מספר‬
‫שלא תכננו לכתוב‪ .‬לכן‪ ,‬נכתוב את המספר ההפוך )מלא באפסים( ונשתמש בפקודה ‪BITWISE NOT‬‬
‫)~( כדי להפוך את האפסים לאחדים‪ ,‬ולקבל את המספר שאנחנו רוצים‪.‬‬

‫כדי להפעיל חזרה את מצב ‪ ,write protect‬נעשה פעולת ‪ BITWISE OR‬בין המצב הנוכחי של האוגר‬
‫לבין מספר בינארי שכולו ‪ 0‬חוץ מהביט של ‪write protect‬‬

‫וודאו שאתם מבינים למה הפעולות משנות את הביט הספציפי של ‪ Write Protect‬אבל שומרות על שאר‬
‫המצב המקורי של האוגר ‪ -‬נכבה את ‪ write protect‬לפני שאנחנו משנים את טבלת קריאות המערכת‪,‬‬
‫ונדליק אותו בחזרה מיד אחרי השינוי כדי לשחזר את המצב של המעבד‪.‬‬

‫‪!0X0B, It's time‬‬


‫למדתם‪ ,‬עבדתם קשה‪ ,‬עכשיו הגיע הזמן סוף סוף לכתוב משהו שימושי‪.‬‬
‫תזכורת!‪ :‬לשמור ‪ snapshot‬של ה‪ vm‬לפני כל הרצה של המודול )‪ ,(Insmod‬קריסה עלולה לשבור‬
‫את המערכת‪ ,‬למחוק את ההתקדמות שלכם ולעשות שלל דברים רעים אחרים‪ .‬אם ‪ insmod‬מחזיר‬
‫שגיאה או ‪ ,killed‬תסגרו את ה‪ vm‬ותטענו את ‪ snapshot‬האחרון ששמרתם‪.‬‬
‫נחזור אחורה ונזכור את המטרה הסופית שלנו ‪ -‬ליצור מודול לקרנל שמנטר אחרי פעולות של המשתמש‬
‫באמצעות ‪ .system call hooking‬בפרק זה סוף סוף נעשה זאת! שימו לב שיש לכם הרבה חופש‬
‫בתרגיל הזה ‪ -‬אין מטרה אחת‪ ,‬ואתם רשאים לבחור לעקוב אחרי איזה פעולות של המשתמש שתבחרו‪.‬‬
‫עם זאת‪ ,‬מומלץ להשקיע ולחקור על כמה שיותר קריאות המערכת‪ ,‬ולממש כמה שיותר דרכי מעקב‪ .‬זו‬
‫הזדמנות מעולה לחקור על ‪ system calls‬וללמוד על רכיבים של מערכת ההפעלה‪ ,‬ולהתנסות בכתיבת‬
‫פרויקט משלכם כאשר הדבר היחיד שמפריד בין פרויקט מגניב עם פיצ'רים מגניבים לבין משהו בסיסי‬
‫ולא שלם היא המוטיבציה שלכם ‪ -‬שמרו על רוח גבוהה ותמשיכו לחקור!‬

‫‪ .1‬בחרו ‪ system call‬שמסמל פעולה של משתמש אחריה תרצו לעקוב ) מועמדים פופולריים הם‬
‫‪ , open, write, socket‬אך תוכלו לבחור מה שתרצו(‬

‫‪ .2‬שמרו את הכתובת של קריאת המערכת המקורית בפוינטר לפונקציה‪.‬‬

‫‪ .3‬שנו את הפוינטר בטבלה לפונקציה חדשה שתכתבו‪ ,‬שמדפיסה ל‪ dmesg‬את האירוע שקרה‬
‫ומידע עליו‪) .‬לא לשכוח לבטל ‪(write protect‬‬

‫‪ .4‬וודאו שבפונקציה החדשה אתם קוראים לפונקציה המקורית באמצעות הפוינטר ששמרתם ב‪.2‬‬

‫‪ .5‬שימו לב ש‪ system calls‬נקראות ברחבי המערכת גם ללא התערבות המשתמש‪ ,‬ומסך ה‬


‫‪ dmesg‬עלול להתמלא בזבל אם תעקבו אחרי קריאות כמו ‪ open‬או ‪ .write‬הגבילו את‬
‫הפונקציות שלכן כך שידפיסו רק דברים רלוונטיים לפי הפרמטרים של קריאת המערכת‬
‫)לדוגמה‪ :‬הגבלה למשתמש ספציפי או לתיקייה ספציפית‪ .‬חשבו בעצמכם מה ניתן להשמיט כך‬
‫שה‪ output‬יהיה אינפורמטיבי אך לא מוצף בזבל‪(.‬‬

‫‪ .6‬חשבו על עוד קריאות מערכת והוסיפו אותם לקוד שלכם‪ .‬נסו לעקוב אחרי כמה שיותר פעולות‬
‫של המשתמש וללמוד על פעולות של ‪ system calls‬שאתם לא מכירים‪.‬‬

‫מקורות נוספים‪:‬‬

‫מדריך מפורט לכתיבת ‪:kernel module‬‬


‫‪https://www.cs.bgu.ac.il/~csd162/wiki.files/lkmpg.pdf‬‬
‫דוגמא ל‪:hooking‬‬
‫‪https://github.com/ricardoteixas/hook‬‬
‫מחלקות ‪ h‬של ‪:syscalls‬‬
‫‪http://lxr.free-electrons.com/source/include/linux/syscalls.h‬‬
‫רשימת ‪:system calls‬‬
‫‪/http://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64‬‬

You might also like