Desktop RE Writeup: Multi-Stage DLL Decryption

מאת שי מרדכי | 19 באפריל 2024

1. ניתוח סטטי (Static Analysis)

התוכנית טוענת בזמן ריצה את crack.dll אשר קורא לפונקציה BrainDamage, וטוענת DLL נוסף שקורא לפונקציה XorForever. בבחינת הייבוא (Imports), נצפו קריאות מחשידות ל-IsDebuggerPresent ו-RegOpenKeyExW. מאחר שפעולות מסוימות התרחשו עוד לפני ה-main, זה העלה חשד חזק לשימוש ב-TLS Callbacks כדי להקשות על הדיבוג.

2. חקירת הפונקציה TsCallBack וניתוב קוד (Control Flow Hijacking)

בתוך ה-Callback מתבצעת קריאה ל-StartAddress, העושה שימוש במחרוזת מוצפנת. מאנליזה דינמית, התוכנית תמיד נטתה לרוץ לענף הימני (Right Branch) ולפענח את המחרוזת ל-ava.dll או Java.dll. כדי לחשוף את ההתנהגות המלאה ולעקוף בדיקות מונעות דיבוג, ביצעתי Patching לפונקציה כך שתמיד תרוץ דרך הענף השמאלי (Left Branch) ותשחרר את הפיילוד (Payload).

3. שחזור ספרייה מתוך הזיכרון (DLL Reconstruction)

בסיום StartAddress, קריאות ל-fopen_s ו-fwrite יצרו קובץ בשם Java.dll. עם זאת, הקובץ שנוצר לא קיים את חוקי פורמט PE (ה-Headers שלו היו מוצפנים) ולא יכול היה להיטען לזיכרון.

מכיוון שאנו יודעים שקובץ PE חייב להתחיל בערכים מוגדרים היטב (כמו MZ ב-DOS Header), השתמשתי בטכניקת Known-Plaintext כדי לחשב את מפתחות ההצפנה ששימשו ב-Buffer המקורי (נמצא ששימשו המפתחות 0x81 ו-0x53 ברוטציה). כתבתי קוד C++ אוטומטי המבצע xorEncryptAndWrite על המערך המוצפן ושומר קובץ Java.dll תקין ובר-ריצה לדיסק.

4. פיענוח אלגוריתם XorForever והפקת ה-Flag

בטעינת Java.dll ל-IDA וניתוח באמצעות Hex-Rays Decompiler (המרת Assembly ל-C Pseudocode), חקרתי את הפונקציה XorForever. היא כללה לולאה שמחשבת סכום ASCII של קלט המשתמש, עם תנאי if (sum == 1337).

במקום לבצע Brute-force או לפצ'פץ' את התנאי בזיכרון, ניתחתי אנליטית את מערך המטרה (ArgList). גיליתי כי בהינתן שהבדיקה עוברת, הפונקציה מחליפה אינדקסים ספציפיים (0, 1, 2, 3, 6) מתוך מחרוזת קבועה "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".

הערכים הובילו ישירות למחרוזת 3TwB99f. יחד עם התחילית שהייתה בקוד, הופק ה-URL המלא של דגל הסיום: bit.ly/3TwB99f.