7.4 כלי Ghidra הרצאה
בהרצאה הזו נלמד על Ghidra - כלי הנדסה הפוכה חינמי וקוד פתוח שפותח על ידי ה-NSA.
גידרה היא אחד הכלים החזקים ביותר בתחום, והיא כוללת disassembler ו-decompiler מלאים - כלומר, היא לא רק מראה לנו אסמבלי, אלא גם ממירה את האסמבלי בחזרה לקוד דמוי C שקריא בהרבה.
למה Ghidra?¶
עד עכשיו השתמשנו ב-objdump וב-GDB כדי לנתח קוד. הכלים האלו מצוינים, אבל כשמנתחים תוכנה גדולה עם מאות או אלפי פונקציות, צריך כלי שנותן תמונה רחבה יותר.
גידרה נותנת לנו:
- תצוגת disassembly מסודרת עם שמות, תיוגים, והפניות צולבות
- decompiler שממיר אסמבלי בחזרה לקוד C קריא - זו התכונה החזקה ביותר!
- ניווט קל בין פונקציות, מחרוזות, ייבואים ויצואים
- יכולת לשנות שמות, להוסיף הערות, ולהגדיר טיפוסים
- תצוגה גרפית של זרימת בקרה
התקנה והגדרה¶
גידרה דורשת Java (גרסה 17 ומעלה). התקינו JDK:
הורידו את Ghidra מהאתר הרשמי:
חלצו את הקובץ והריצו:
בפתיחה הראשונה Ghidra תבקש מכם להגדיר את ה-JDK path. בדרך כלל היא מוצאת אותו אוטומטית.
יצירת פרויקט וייבוא קובץ בינארי¶
בגידרה, כל עבודה מאורגנת בתוך פרויקט - project. פרויקט הוא תיקייה שמכילה את כל הקבצים הבינאריים שאתם מנתחים, יחד עם כל ההערות, השמות, והמידע שהוספתם.
יצירת פרויקט חדש:¶
- פתחו את Ghidra
- בחרו File -> New Project
- בחרו Non-Shared Project (לעבודה מקומית)
- תנו שם לפרויקט ובחרו תיקייה
ייבוא קובץ בינארי:¶
- גררו קובץ בינארי לתוך חלון הפרויקט, או בחרו File -> Import File
- גידרה תזהה אוטומטית את סוג הקובץ (ELF, PE, Mach-O וכו')
- לחצו OK ואז לחצו כפול על הקובץ כדי לפתוח אותו ב-CodeBrowser
- גידרה תשאל אם לנתח את הקובץ (Analyze) - אישרו. הניתוח האוטומטי מזהה פונקציות, מחרוזות, הפניות צולבות ועוד.
החלונות הראשיים - main windows¶
כשפותחים קובץ בינארי ב-CodeBrowser, מופיעים כמה חלונות חשובים:
חלון הListing - תצוגת disassembly¶
זהו החלון המרכזי. הוא מציג את קוד האסמבלי של התוכנית, עם:
- כתובות זיכרון בצד שמאל
- שמות פונקציות ותיוגים (labels)
- הפניות צולבות (cross-references) - מי קורא לפונקציה הזו? לאן היא קופצת?
- הערות אוטומטיות שגידרה מוסיפה
זה דומה לפלט של objdump, אבל הרבה יותר מסודר ואינטראקטיבי.
חלון הDecompiler¶
כאן קורה הקסם. כשאתם לוחצים על פונקציה ב-Listing, ה-Decompiler מציג את קוד C מתורגם של אותה פונקציה.
למשל, אם באסמבלי יש לנו:
push rbp
mov rbp, rsp
sub rsp, 0x10
mov dword ptr [rbp-0x4], edi
mov eax, dword ptr [rbp-0x4]
imul eax, eax
leave
ret
ה-Decompiler יציג משהו כזה:
הרבה יותר קריא! אבל שימו לב - השמות אוטומטיים (FUN_00401000, param_1). חלק מהעבודה שלנו כחוקרים הוא לשנות את השמות למשהו משמעותי.
עץ הסמלים - Symbol Tree¶
חלון שמראה את כל הסמלים בתוכנית, מאורגנים לפי קטגוריות:
- פונקציות - Functions: כל הפונקציות שגידרה זיהתה
- תיוגים - Labels: כתובות עם שמות
- ייבואים - Imports: פונקציות מספריות חיצוניות (כמו printf, malloc מ-libc)
- יצואים - Exports: פונקציות שהתוכנית חושפת החוצה
מנהל טיפוסי הנתונים - Data Type Manager¶
כאן מגדירים ומנהלים struct-ים, enum-ים, typedef-ים וטיפוסים אחרים. כשאנחנו מבינים שפוינטר מצביע על struct מסוים, אנחנו מגדירים אותו כאן ומחילים אותו - וה-Decompiler מתעדכן בהתאם.
גרף הפונקציה - Function Graph¶
תצוגה גרפית של זרימת הבקרה בפונקציה. כל בלוק (basic block) מוצג כריבוע, וחיצים מראים את הקפיצות המותנות ולולאות. זה עוזר מאוד להבין לוגיקה מורכבת - if-ים מסועפים, לולאות מקוננות, וכו'.
אפשר לעבור לתצוגה הגרפית דרך Window -> Function Graph.
ניווט בגידרה - navigation¶
לחיצה כפולה¶
לחצו כפול על כל שם פונקציה, כתובת, או הפניה - וגידרה תקפוץ לשם. זו הדרך הכי טבעית לנווט בקוד.
מקש G - מעבר לכתובת - Go to address¶
לחצו G ותוכלו להקליד כתובת זיכרון ולקפוץ ישירות אליה.
מקש L - שינוי שם - Label¶
לחצו L על פונקציה, משתנה, או כתובת כדי לשנות את השם שלה. זו פעולה שתעשו המון - ככל שאתם מבינים יותר את הקוד, אתם נותנים שמות משמעותיים.
מקש T - שינוי טיפוס - reTtype¶
לחצו T על משתנה כדי לשנות את הטיפוס שלו. למשל, אם גידרה חושבת שמשהו הוא int אבל אתם יודעים שזה char * - שנו אותו.
חזרה אחורה וקדימה¶
כמו בדפדפן - הכפתורים Back/Forward (או Alt+Left/Right) מחזירים אתכם למקום הקודם.
הDecompiler - הבנת הפלט¶
ה-Decompiler הוא הכלי החזק ביותר בגידרה. הוא ממיר אסמבלי לקוד דמוי C. אבל חשוב להבין כמה דברים:
הוא לא מושלם¶
הפלט הוא קירוב של הקוד המקורי, לא עותק מדויק. שמות משתנים הם אוטומטיים:
- local_10 - משתנה מקומי ב-offset 0x10 מ-rbp
- param_1 - הפרמטר הראשון לפונקציה
- iVar1 - משתנה int שגידרה יצרה
- uVar2 - משתנה unsigned שגידרה יצרה
אתם צריכים לשנות את השמות ככל שאתם מבינים את הקוד. לחצו על שם משתנה ב-Decompiler ולחצו L כדי לשנות שם, או T כדי לשנות טיפוס.
לפעמים הטיפוסים שגויים¶
ה-Decompiler מנחש טיפוסים. לפעמים הוא מנחש לא נכון. אם אתם רואים קוד שנראה מוזר, נסו לשנות את הטיפוס של משתנה - זה יכול לשפר את הקריאות בצורה דרמטית.
למשל, אם גידרה מציגה:
ואתם יודעים ש-local_10 הוא מצביע ל-struct, תוכלו להגדיר את ה-struct ב-Data Type Manager, לשנות את הטיפוס של local_10, ופתאום הקוד יראה ככה:
שחזור struct-ים¶
תהליך חשוב: כשרואים גישה לoffset-ים קבועים מתוך מצביע, סביר שמדובר ב-struct.
1. פתחו את Data Type Manager
2. צרו struct חדש
3. הגדירו את השדות לפי ה-offset-ים שראיתם
4. חזרו לDecompiler ושנו את הטיפוס של המצביע ל-struct החדש
הפניות צולבות - Cross-References (XREF)¶
זו אחת התכונות החזקות ביותר להבנת זרימת הקוד. הפניות צולבות עונות על השאלות:
- מאיפה קוראים לפונקציה הזו? - מי משתמש בה?
- איפה משתמשים במחרוזת הזו? - איזו פונקציה מדפיסה את ההודעה הזו?
- לאן קופצים מהכתובת הזו? - מה קורה אחרי הif?
איך למצוא הפניות:¶
- לחצו ימני על פונקציה/משתנה/מחרוזת -> References -> Find references to
- או פשוט הסתכלו על ההערות בצד - גידרה מציגה XREF אוטומטית ליד כל פונקציה
למשל, אם רואים:
זה אומר שהפונקציה נקראת משני מקומות - מ-main ומ-check_input.
הפניות צולבות הן הדרך הכי יעילה לעקוב אחרי זרימת הקוד בתוכנית גדולה.
שינוי שמות והוספת הערות - annotating¶
ככל שאתם מנתחים יותר, הקוד צריך להפוך ליותר קריא. הנה הכלים:
שינוי שם פונקציה¶
לחצו על שם הפונקציה ולחצו L. שנו מ-FUN_00401000 ל-check_password כשאתם מבינים מה היא עושה.
שינוי שם משתנה בDecompiler¶
לחצו על משתנה ב-Decompiler ולחצו L. שנו מ-local_10 ל-user_input.
הוספת הערות¶
לחצו ; (נקודה פסיק) או לחצו ימני -> Comment. אפשר להוסיף הערות ב:
- EOL Comment - הערה בסוף שורה
- Pre Comment - הערה לפני שורה
- Post Comment - הערה אחרי שורה
- Plate Comment - הערה גדולה בראש פונקציה
שינוי טיפוסים¶
לחצו T על משתנה כדי לשנות את הטיפוס שלו. זה משפיע ישירות על איכות הפלט של ה-Decompiler.
חיפוש - searching¶
חיפוש מחרוזות - Search for Strings¶
בחרו Search -> For Strings. גידרה תמצא את כל המחרוזות בקובץ הבינארי.
זה מאוד שימושי! מחרוזות כמו הודעות שגיאה, URL-ים, שמות קבצים, וכו' נותנות רמזים חשובים על מה התוכנית עושה. מ-Search -> For Strings אפשר ללחוץ כפול על מחרוזת, ואז להשתמש בXREF כדי למצוא איזו פונקציה משתמשת בה.
חיפוש בזיכרון - Search for bytes¶
בחרו Search -> Memory. מאפשר לחפש רצף בתים ספציפי בכל הקובץ.
חיפוש פונקציות¶
השתמשו ב-Symbol Tree או ב-Search -> For Address Tables.
סקריפטים בגידרה - Ghidra scripting¶
גידרה תומכת בסקריפטים ב-Python וב-Java. אפשר לכתוב סקריפטים שמבצעים אוטומציה של משימות שחוזרות על עצמן:
- שינוי שמות אוטומטי לפי דפוסים
- חיפוש דפוסי קוד חשודים
- ייצוא מידע לקבצי טקסט
הכניסה לסקריפטים דרך Window -> Script Manager. לא ניכנס לעומק של הנושא הזה כרגע, אבל דעו שהאפשרות קיימת.
עבודה מעשית - walkthrough¶
בואו נעבור על תהליך עבודה טיפוסי עם גידרה:
שלב 1 - ייבוא וניתוח¶
- פתחו פרויקט חדש
- ייבאו את הבינארי
- תנו לגידרה לנתח אותו (Auto Analysis)
שלב 2 - סקירה ראשונית¶
- בדקו את רשימת הפונקציות ב-Symbol Tree
- חפשו מחרוזות מעניינות (Search -> For Strings)
- מצאו את main (או את נקודת הכניסה) ולחצו עליה
שלב 3 - ניתוח הDecompiler¶
- קראו את הקוד בDecompiler
- התחילו לשנות שמות של פונקציות ומשתנים
- שנו טיפוסים כשצריך
שלב 4 - מעקב אחר זרימת הקוד¶
- השתמשו ב-XREF כדי לעקוב אחרי קריאות לפונקציות
- לחצו כפול כדי לנווט
- הוסיפו הערות במקומות חשובים
שלב 5 - תיעוד¶
- וודאו שכל הפונקציות החשובות קיבלו שמות משמעותיים
- הוסיפו Plate Comments לפונקציות מרכזיות
- שמרו את הפרויקט
השוואה - Ghidra מול כלים אחרים¶
| תכונה | Ghidra | IDA Pro | radare2/Cutter |
|---|---|---|---|
| מחיר | חינם (קוד פתוח) | מסחרי (אלפי דולרים) | חינם (קוד פתוח) |
| ממשק | גרפי (Java) | גרפי (Qt) | שורת פקודה / גרפי |
| דיקומפיילר | כלול | תוסף נפרד (Hex-Rays) | כלול (r2ghidra) |
| ארכיטקטורות | המון | המון | המון |
| סקריפטים | Python / Java | Python / IDC | Python / r2pipe |
| קהילה | גדלה במהירות | ותיקה ומבוססת | פעילה |
גידרה מצוינת כנקודת התחלה - היא חינמית, כוללת decompiler, ויש לה קהילה גדלה. IDA Pro נחשבת לסטנדרט בתעשייה אבל עולה הרבה כסף. radare2 (ו-Cutter הממשק הגרפי שלה) היא אלטרנטיבה חינמית שעובדת גם משורת הפקודה - שימושית מאוד לאוטומציה.
לצורך הקורס שלנו, נתמקד בגידרה.
סיכום¶
גידרה היא כלי חזק שמשלב disassembler, decompiler, וסביבת ניתוח מלאה. הדבר הכי חשוב לזכור:
- ה-Decompiler ממיר אסמבלי לקוד C קריא - זה חוסך המון זמן
- הפניות צולבות (XREF) הן הדרך לעקוב אחרי זרימת הקוד
- שינוי שמות הוא חלק מהותי מתהליך הניתוח - ככל שאתם מבינים יותר, אתם משנים שמות ומשפרים את הקריאות
- חיפוש מחרוזות הוא בדרך כלל הצעד הראשון בניתוח - מחרוזות נותנות רמזים חשובים
בשילוב עם GDB שלמדנו בנושאים הקודמים, יש לנו כלים חזקים מאוד לניתוח סטטי (Ghidra) ודינמי (GDB) של תוכנות.