7.4 כלי Ghidra פתרון
פתרון תרגיל 1 - פתיחת בינארי בגידרה¶
-
גידרה תזהה פונקציות רבות - גם פונקציות פנימיות של libc וגם פונקציות של התוכנית. המספר המדויק תלוי בגרסת gcc ובמערכת, אבל בדרך כלל תראו כמה עשרות פונקציות (רובן פונקציות עזר של הריצה כמו
_start,__libc_csu_initוכו'). -
מציאת main: כיוון שעשינו strip, אין סימבולים. הדרך למצוא main:
- מצאו את
entry(נקודת הכניסה של ה-ELF) - ב-entry, מחפשים את הקריאה ל-
__libc_start_main - הפרמטר הראשון (שנמצא ב-rdi לפני הקריאה) הוא הכתובת של main
- לחצו כפול על הכתובת הזו - זו main
פתרון תרגיל 2 - קריאת הDecompiler¶
-
פלט ה-Decompiler של main ייראה בערך כך:
גידרה מראה שmain קוראת לאותה פונקציה פעמיים עם מחרוזות שונות. -
לשינוי שם: לחצו על
FUN_00401119ואז L, הקלידוgreet. -
בתוך greet, ה-Decompiler מראה:
לחצו עלparam_1, לחצו L, הקלידוname. -
להוספת הערה: לחצו ימני על שם הפונקציה -> Comment -> Set Plate Comment. כתבו: "Prints a greeting message with the given name".
פתרון תרגיל 3 - מציאת מחרוזות¶
-
אחרי פתיחה בגידרה, הולכים ל-Search -> For Strings.
-
ברשימת המחרוזות נראה:
"Enter password: ""s3cretP@ss""Access granted!""Access denied!"-
"%63s" -
הסיסמה היא
s3cretP@ss. מצאנו אותה פשוט על ידי חיפוש מחרוזות - היא מופיעה בטקסט גלוי בתוך הבינארי כי strcmp משווה ישירות למחרוזת. -
לחיצה כפולה על "Access granted!" מביאה אותנו לכתובת בsection של הdata. שם נראה XREF שמצביע לפונקציה check_password (או FUN_XXXXX אם אין סימבולים). לחצו כפול על ה-XREF כדי להגיע לפונקציה שמשתמשת במחרוזת.
פתרון תרגיל 4 - הבנת פונקציה¶
-
מוצאים את main כמו שלמדנו (דרך entry ו-
__libc_start_main). -
מ-main נראה קריאה לפונקציה עם שני ארגומנטים: 7 ו-5.
-
פלט ה-Decompiler של mystery ייראה בערך כך:
int FUN_00401136(int param_1, int param_2) { int local_c = 0; while (0 < param_2) { if ((param_2 & 1) != 0) { local_c = local_c + param_1; } param_1 = param_1 << 1; param_2 = param_2 >> 1; } return local_c; }
הפונקציה מבצעת כפל באמצעות אלגוריתם Russian Peasant Multiplication. היא בודקת כל ביט של param_2, ואם הוא דלוק - מוסיפה את param_1 לתוצאה. בכל איטרציה param_1 מוכפל ב-2 (shift שמאלה) ו-param_2 מחולק ב-2 (shift ימינה).
עבור 7 כפול 5:
- ביט 0 של 5 דלוק: result += 7 (result = 7)
- ביט 1 של 5 כבוי: לא מוסיפים
- ביט 2 של 5 דלוק: result += 28 (result = 35)
- התוצאה: 35 = 7 * 5
- שמות משמעותיים:
- הפונקציה:
multiply param_1->aparam_2->blocal_c->result
פתרון תרגיל 5 - ניתוח מלא¶
-
פותחים את הבינארי בגידרה ומוצאים את main.
-
ב-main נראה קריאות לשלוש פונקציות printf ולשתי פונקציות נוספות (encode ו-decode).
-
ה-Decompiler של encode יראה בערך:
void FUN_00401136(char *param_1, int param_2) { int local_c; for (local_c = 0; param_1[local_c] != '\0'; local_c++) { param_1[local_c] = param_1[local_c] ^ param_2; } }
הפונקציה עוברת על כל תו במחרוזת ומבצעת XOR עם המפתח (param_2). -
encode ו-decode הן אותו דבר כי XOR היא פעולה הפיכה:
- אם
a ^ key = b - אז
b ^ key = a - כלומר XOR פעמיים עם אותו מפתח מחזיר את הערך המקורי
בגידרה תראו ש-decode פשוט קוראת ל-encode - הן באמת אותה פונקציה.
- שמות מוצעים:
- הפונקציה הראשונה:
xor_encodeאוxor_cipher - הפרמטר הראשון:
str - הפרמטר השני:
key - המשתנה המקומי:
i(האינדקס בלולאה) - הפונקציה השנייה:
xor_decode(ולציין בהערה שהיא פשוט קוראת ל-encode) - ב-main:
secretלמערך התווים,keyלמפתח ה-XOR