hideinpILainsight

נכתב על ידי naweiss

hideinpILainsight

התקבל מהאתגר קובץ בשם wabbalubbadubdub.exe, בתיאור האתגר נכתב שמדובר בקוד של .NET לכן השתמשנו ב ILSpy וקיבלנו את הקוד הבא:

using System;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;

public class Sanchez
{
    public static void Main(string[] args)
    {
        if (Debugger.IsAttached)
        {
            Console.WriteLine("Sometimes science is a lot more art than science. A lot of people don't get that.");
            Console.ReadKey();
        }
        else if (new Random(Guid.NewGuid().GetHashCode()).Next(312) >= 312)
        {
            byte[] il = new byte[125] { /*some 125 bytes*/ };
            byte[] array = new byte[33] { /*some 33 bytes*/ };
            byte[] iLAsByteArray = Assembly.GetExecutingAssembly().GetTypes()[0].GetMethods()[0].GetMethodBody().GetILAsByteArray();
            AssemblyName assemblyName = new AssemblyName();
            assemblyName.Name = "CitadelOfRicks";
            AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
            AppDomain.CurrentDomain.UnhandledException += delegate
            {
                Console.WriteLine("Arrrrgh This is an unrecoverable exception, I need to remove this code somehow");
            };
            TypeBuilder typeBuilder = assemblyBuilder.DefineDynamicModule("DoofusRick").DefineType("J19Zeta7");
            MethodBuilder methodBuilder = typeBuilder.DefineMethod("gimmedeflag", MethodAttributes.FamANDAssem | MethodAttributes.Family | MethodAttributes.Static | MethodAttributes.HideBySig, CallingConventions.Standard, typeof(byte[]), new Type[2]
            {
                typeof(byte[]),
                typeof(byte[])
            });
            SignatureHelper localVarSigHelper = SignatureHelper.GetLocalVarSigHelper();
            for (int i = 0; i < 8; i++)
            {
                localVarSigHelper.AddArgument(typeof(uint));
            }
            localVarSigHelper.AddArgument(typeof(int));
            localVarSigHelper.AddArgument(typeof(byte));
            methodBuilder.SetMethodBody(il, 4, localVarSigHelper.GetSignature(), null, null);
            object obj = typeBuilder.CreateType().GetMethods()[0].Invoke(null, new object[2]
            {
                array,
                iLAsByteArray
            });
            Console.WriteLine(Encoding.ASCII.GetString((byte[])obj));
            Console.ReadKey();
        }
    }
}

יש שני מכשולים קטנים שצריך לעבור כדי להגיע לחלק המעניין:

  1. הקוד בודק האם אנו משתמשים ב-Debugger, אם כן הוא פשוט מדפיס Sometimes science is a lot more art than science. A lot of people don't get that.
  2. אחרת, הוא מג'נרט מספר ראנדומאלי בין 0 ל-312 לא כולל ובודק האם הוא גדול שווה מ-312. כלומר if (false)

נתעלם לרגע משני המכשולים ונמשיך הלאה.

הקוד יוצר dll תוך כדי ריצה עם מודל מסוים שבתוכו פונקציה בשם gimmedeflag, מעניין.

הפונקציה מקבלת שני פרמטרים מטיפוס byte[] ומחזירה byte[].

אחר כך מוגדרים כל הטיפוסים של המשתנים המקומיים בפונקציה ומוגדר שקוד ה-IL (byte-code) של הפונקציה יהיה התוכן של המערך il.

לאחר מכן הפונקציה gimmedeflag מופעלת עם 2 פרמטרים:

ניקח את הקוד הרלוונטי נשים בפרויקט C# חדש נריץ ב-Debug ונדלג מעל שני המכשולים.

הפונקציה gimmedeflag זורקת error, מוזר.

אנחנו לא יודעים מה באמת קורה בפונקציה gimmedeflag אבל נתון לנו קוד ה-IL שלה, ננסה להיעזר בזה.

הדרך הנוחה ביותר הייתה פשוט לשמור את כל ה-dll שנוצר תוך כדי ריצה בקובץ נפרד, ואז נוכל לעשות לו decompile. וכך יהיה לנו את קוד ה-C# של gimmedeflag.

כמה שינויים קטנים בקוד ונקבל את ה-dll:

AssemblyName assemblyName = new AssemblyName();
assemblyName.Name = "CitadelOfRicks";
AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
AppDomain.CurrentDomain.UnhandledException += delegate
{
    Console.WriteLine("Arrrrgh This is an unrecoverable exception, I need to remove this code somehow");
};
TypeBuilder typeBuilder = assemblyBuilder.DefineDynamicModule("DoofusRick", "CitadelOfRicks.dll").DefineType("J19Zeta7");
MethodBuilder methodBuilder = typeBuilder.DefineMethod("gimmedeflag", MethodAttributes.FamANDAssem | MethodAttributes.Family | MethodAttributes.Static | MethodAttributes.HideBySig, CallingConventions.Standard, typeof(byte[]), new Type[2]
{
    typeof(byte[]),
    typeof(byte[])
    });
SignatureHelper localVarSigHelper = SignatureHelper.GetLocalVarSigHelper();
for (int i = 0; i < 8; i++) {
    localVarSigHelper.AddArgument(typeof(uint));
}
localVarSigHelper.AddArgument(typeof(int));
localVarSigHelper.AddArgument(typeof(byte));
methodBuilder.SetMethodBody(il, 4, localVarSigHelper.GetSignature(), null, null);
typeBuilder.CreateType();
assemblyBuilder.Save("CitadelOfRicks.dll");

נשתמש ב-ILSpy שוב ונקבל:

public static byte[] gimmedeflag(byte[] P_0, byte[] P_1)
{
    uint num = 2135247942u;
    uint num2 = 0u;
    uint num3 = 0u;
    uint num4 = 33570304u;
    uint num5 = 16777216u;
    uint num6 = 278528u;
    uint num7 = 0u;
    uint num8 = 33620224u;
    for (int i = 0; i < P_0.Length; i++)
    {
        byte b = (i > 11) ? P_1[i % P_1.Length] : ((byte)(P_1[i % P_1.Length] + P_1.Length));
        P_0[i] = (byte)(P_0[i] ^ b);
    }
    if (num > num2 && num4 > num3 && num5 > num6 && num8 > num7)
    {
        throw null;
    }
    return P_0;
}

נשים לב שהקוד יזרוק null תמיד בלא קשר ל-input.

נסכם מה שראינו, הקוד יצר dll שאותו שמרנו לקובץ, קראנו את הפונקציה gimmedeflag ושמנו לב שהיא זורקת שגיאה.

ננסה ליצור פרויקט חדש ונשים בו את הפונקציה gimmedeflag ללא ה-throw null.

כמו שהזכרנו, הפונקציה מקבלת 2 פרמטרים. מערך קבוע והקוד של ה-Main מה-exe הנ"ל.

הדבר היחיד שחסר לנו זה הקוד של ה-Main, נוציא אותו עם הקוד:

Assembly asm = Assembly.LoadFile(@"FULL_PATH\wabbalubbadubdub.exe");
byte[] iLAsByteArray = asm.GetTypes()[0].GetMethods()[0].GetMethodBody().GetILAsByteArray();

זהו, נריץ את הקוד עם הפרמטרים הנ"ל ונקבל את הדגל: BSidesTLV{Look, Rick, I know IL!}

הערה: הפרמטר המוחזר היה מטיפוס byte[] נמיר אותו ל-string כך: Encoding.Default.GetString(flag)

Success