דילוג לתוכן
New

DeepSeek V4.1 Flash free for 7 days: 10M tokens a day after a top-up of $10 or more. Until Nov 30.

How it works

מהי הנדסה לאחור? שימושים, מגבלות ויסודות משפטיים

מה קומפילציה מאבדת, במה דיסאסמבלר שונה מדקומפיילר, והמגבלות המשפטיות שכדאי להכיר לפני ניתוח של בינארי.

מתחילים7 דקות קריאהמאת NotHoly

בהנדסה לאחור מבינים איך משהו נבנה מתוך בחינת הדבר המוגמר. בתוכנה, הדבר המוגמר הוא בדרך כלל תוכנית מקומפלת: קובץ הרצה, ספרייה משותפת או תמונת קושחה. קוד המקור חסר או שמעולם לא פורסם, ולכן מתחילים מקוד מכונה ועובדים לאחור אל מה שהתוכנית עושה ולמה.

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

מה קומפילציה מאבדת

קומפיילר הופך קוד מקור קריא לאדם להוראות שמעבד יכול להריץ. הפלט נכון עבור המכונה ואומר מעט על הכוונה. כמה דברים נעלמים בדרך:

  • הערות ועיצוב. הם אף פעם לא מגיעים לפלט.
  • שמות. שמות של משתנים מקומיים ושל פונקציות רבות נשמטים, אלא אם ה-build שומר סמלי דיבוג או שהקובץ מגיע עם טבלת סמלים.
  • טיפוסים. מספר שלם של 32 ביט, דגל וכתובת זיכרון הם כולם רק ביטים באוגר או במחסנית.
  • מבנה בקרה. לולאת for הופכת להשוואה ולקפיצה. if הופך לקפיצה מותנית למקום אחר בקובץ.
  • הפריסה המקורית. אופטימייזרים מסדרים מחדש, ממזגים ועושים inlining לקוד, כך שפונקציה אחת שכתבת לא בהכרח תמופה לבלוק אחד בבינארי.

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

אפשר לראות גרסה קטנה של זה עם Python 3.12. הדוגמה למטה היא פונקציה של שלוש שורות עם הערה. bytecode של Python הוא לא קוד מכונה native, ולכן זו אנלוגיה ולא מודל של פלט C. עדיין, היא ממחישה את הנקודה.

python
# Teaching constant, not real access control.
def check_pin(user_pin):
    training_pin = 2468  # the comment never reaches the bytecode
    return user_pin == training_pin

מקמפלים ועושים דיסאסמבלי עם הפקודות האלה:

bash
python -c "import py_compile; py_compile.compile('check_pin.py', cfile='check_pin.pyc', doraise=True)"
python -c "import marshal, dis; data = open('check_pin.pyc','rb').read()[16:]; code = marshal.loads(data); fn = [c for c in code.co_consts if hasattr(c,'co_code')][0]; print('name:', fn.co_name, '| constants:', fn.co_consts, '| locals:', fn.co_varnames); dis.dis(fn)"

על המחשב שבו נבדק המאמר, הפלט היה:

text
name: check_pin | constants: (None, 2468) | locals: ('user_pin', 'training_pin')
  2           0 RESUME                   0

  3           2 LOAD_CONST               1 (2468)
              4 STORE_FAST               1 (training_pin)

  4           6 LOAD_FAST                0 (user_pin)
              8 LOAD_FAST                1 (training_pin)
             10 COMPARE_OP              40 (==)
             14 RETURN_VALUE

שני דברים בולטים. ההערה נעלמה: חיפוש של הטקסט שלה בקובץ המקומפל לא מוצא כלום. השמות נשמרו, כי Python מחזיק אותם באובייקט הקוד. תוכנית C מקומפלת לרוב לא שומרת אף אחד מהם, ולכן אותו תרגיל על בינארי native קשה יותר. זה מודל חשיבה, ולא הבטחה לגבי כל שפה.

ניתוח סטטי ודינמי

שיטות הנדסה לאחור מתחלקות לשתי קבוצות רחבות.

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

ניתוח דינמי מריץ את התוכנית תחת מעקב. דיבאגר עוצר אותה בנקודות עצירה כדי לקרוא אוגרים וזיכרון. tracer רושם קריאות מערכת, גישה לקבצים או חיבורי רשת. ארגז חול (sandbox) רושם מה משתנה בדיסק. עבודה דינמית מראה התנהגות אמיתית, כולל ערכים שקיימים רק בזמן ריצה, אבל היא מחייבת להריץ קוד שאולי אין סיבה לסמוך עליו. עושים אותה במכונה וירטואלית חד־פעמית בלי חשבונות אמיתיים, בלי תיקיות משותפות ובלי נתונים רגישים, ובאופן אידיאלי בלי גישה לרשת.

רוב העבודה האמיתית משלבת את השתיים. מעבר סטטי מוצא את הפונקציה שבודקת סיסמה. הרצה בדיבאגר מראה מה באמת הקלט והפלט.

דיסאסמבלרים ודקומפיילרים

דיסאסמבלר ממיר בתים להוראות assembly של ארכיטקטורת מעבד מסוימת. התרגום מכני: תבנית בתים הופכת למנמוניק כמו mov, ‏cmp או jne, עם האופרנדים שלו. התוצאה תואמת למכונה בדיוק, אבל נשארת ברמה נמוכה. קריאה של אלפי הוראות כדי להבין יכולת אחת לוקחת זמן רב.

דקומפיילר הולך רחוק יותר. הוא מנסה להפיק מאותם בתים פסאודו־קוד ברמה גבוהה יותר, בדרך כלל דמוי C. הוא משחזר גבולות פונקציות, זרימת בקרה כמו if או while, וטיפוסי נתונים בקירוב. הפלט שלו הוא פרשנות, ולא עותק של קוד המקור. הוא יכול לטעות בטיפוסים, למזג דברים שהיו נפרדים או להמציא מבנה שמעולם לא היה קיים. הרגל טוב הוא לקרוא את פלט הדקומפיילר ליד הדיסאסמבלי ולסמוך על ה-assembly כשהם לא מסכימים.

Ghidra הוא אחד הכלים החינמיים הנפוצים ביותר שעושים את שניהם. זו מסגרת להנדסה לאחור של תוכנה ש-Research Directorate של U.S. National Security Agency יצר ומתחזק, ברישיון Apache-2.0, והיא רצה על Windows, macOS ו-Linux. היא תומכת בארכיטקטורות מעבד ובפורמטי קבצים רבים, ואפשר להרחיב אותה ב-Java או ב-Python. ה-README שלה דורש JDK 25 (64-bit) כדי להריץ גרסה רשמית. קיימים כלים אחרים, מסחריים ופתוחים, והרעיונות במאמר הזה חלים על כולם.

לשם מה משתמשים בזה

להנדסה לאחור יש כמה שימושים לגיטימיים.

יכולת פעולה הדדית (interoperability). התוכנה שלך צריכה להחליף נתונים עם תוכנית או פורמט סגורים, והספק לא מפרסם את הפרטים. האיחוד האירופי מטפל במקרה הזה ישירות, כפי שהסעיף המשפטי מסביר.

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

ניתוח נוזקות. מגינים מפרקים קובץ חשוד כדי ללמוד מה הוא עושה, באילו מערכות הוא נוגע ואיך לזהות אותו. חלק גדול מהידע הציבורי על איומים מגיע מהעבודה הזאת.

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

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

התמונה המשפטית, במבט על

זו סקירה כללית ולא ייעוץ משפטי. חוקים שונים ממדינה למדינה, וחוזים יכולים להוסיף תנאים שחלים בכל מקום. שלוש שכבות חשובות במיוחד.

1. תנאי רישיון. רוב רישיונות התוכנה המסחריים אוסרים הנדסה לאחור אלא במקום שהחוק מתיר. רישיונות קוד פתוח עובדים אחרת ולעיתים קרובות מתירים קריאה ושינוי של קוד, אבל גם להם יש תנאים. קריאת מקור שקיבלת שונה מהנדסה לאחור של בינארי, ושניהם שונים מפריצה לשירות. לפני ניתוח של מוצר שלא כתבת, קוראים את הרישיון שלו.

2. האיחוד האירופי. Directive 2009/24/EC בדבר ההגנה המשפטית על תוכנות מחשב כולל חריג של יכולת פעולה הדדית ב-Article 6. בקצרה, משתמש חוקי, או מי שפועל מטעמו, רשאי לבצע דקומפילציה לתוכנית כשזה הכרחי להשגת המידע הדרוש כדי שתוכנית שנוצרה באופן עצמאי תעבוד עם אחרות. חלים תנאים. המידע לא יכול להיות זמין כבר בקלות, העבודה מוגבלת לחלקי התוכנית שנחוצים ליכולת פעולה הדדית, והמידע לא ישמש למטרות אחרות ולא יועבר מעבר למה שיכולת פעולה הדדית דורשת. אסור להשתמש בו לפיתוח תוכנית דומה במהותה, והחריג לא יכול לפגוע באופן בלתי סביר באינטרסים הלגיטימיים של בעל הזכויות. Article 6 עוסק ביכולת פעולה הדדית ולא בסקרנות כללית.

3. ארצות הברית. Section 1201 של Digital Millennium Copyright Act אוסר לעקוף אמצעים טכנולוגיים ששולטים בגישה ליצירות מוגנות בזכויות יוצרים. האיסור הזה נפרד מהפרת זכויות יוצרים, כך שאדם יכול לעבור על הכלל בלי להעתיק דבר. החוק כולל חריגים, ביניהם section 1201(j), שמכסה בדיקות אבטחה מסוימות בתנאים שנקבעו. ה-Copyright Office גם מקיים הליך קביעת תקנות כל שלוש שנים שיכול להוסיף חריגים זמניים. הדף שלו על section 1201, שמקושר במקורות, מתאר את התהליך. בזמן הבדיקה ההליך העשירי כבר החל, וחריגים שחודשו בו תקפים לשלוש שנים, מאוקטובר 2027 עד אוקטובר 2030. לפני הסתמכות על חריג כלשהו קוראים את החוק ואת התקנות הנוכחיות. הטקסט הוא שקובע, לא סיכום.

למדינות אחרות יש כללים משלהן. שלוש השכבות שלמעלה הן דוגמאות לאופן שבו השאלות מנוסחות, ולא מפה של תחום השיפוט שלך.

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

מתחילים מבינאריים שכתבת בעצמך

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

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

טעויות נפוצות

  • התייחסות לפלט של דקומפיילר כאל קוד המקור. זו פרשנות. צריך להשוות אותה לדיסאסמבלי.
  • הנחה שבבינארי שעבר strip לא נשאר כלום. מחרוזות, ייבואים, קבועים והתנהגות בדרך כלל נשארים. strip מסיר שמות, לא הכול.
  • התחלה עם דוגמה לא מוכרת על מחשב יומיומי. עובדים במכונה וירטואלית מבודדת עם snapshots.
  • החלת החוק של מדינה אחת בכל מקום. תחום השיפוט משנה, וכך גם החוזים.
  • בלבול בין ניתוח לגישה. בחינת קובץ שנמצא אצלך שונה משימוש בשירות חי שאינו בשליטתך.
  • פרסום ממצאים לפני גילוי. משתפים פרטים בתהליך של הספק לפני שכותבים עליהם בפומבי.

איך ממשיכים

לומדים את המעבד שבודקים, בדרך כלל x86-64 או ARM64 במחשבים מודרניים, ואיך מערכת ההפעלה מעבירה ארגומנטים לפונקציות. מקמפלים את אותו קובץ C קטן פעמיים עם קומפיילר C מהימן, פעם עם מידע דיבוג ופעם אחרי strip, ומשווים מה נשאר. קוראים את התיעוד של Ghidra ואת ה-README של הפרויקט. אחר כך ממשיכים למאמר המעשי שבא אחרי זה.

מקורות

מקורות

  1. Ghidra project site
  2. Directive 2009/24/EC on the legal protection of computer programs (EUR-Lex)
  3. U.S. Copyright Office: section 1201 rulemaking
  4. NSA Ghidra repository on GitHub

עוד בנושא הנדסה לאחור

הנדסה לאחור

למה להשתמש ב-NotHoly להנדסה הפוכה

השאירו את Ghidra, radare2 או IDA. הדביקו את פלט ה-decompiler והמודל מסביר אותו וכותב את הסקריפט, בלי לסרב. triage סטטי למבט ראשון.

ביניים2 דקות קריאה

הנדסה לאחור

מבוא ל-Ghidra עם בינארי תמים שמקמפלים לבד

לקמפל בדיקת רישיון לדוגמה ב-C בשתי דרכים, ואז למצוא ב-Ghidra את המחרוזת, לעקוב אחרי ההפניות ולהשוות את הדקומפיילר לקוד המקור.

ביניים11 דקות קריאה