hideinpILainsight

By naweiss

hideinpILainsight

We got the file wabbalubbadubdub.exe from the challenge, in the challenges description it says it's .NET code therefore we used 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();
        }
    }
}

There are two small obstacles for us to overcome:

  1. The code checks if we are using a debugger, if we are it just prints Sometimes science is a lot more art than science. A lot of people don't get that.
  2. Otherwise it generates a random number between 0 to 312 non inclusive and checks if it is larger than or equals to 312 i.e. if (false)

We'll ignore these obstacles for now and come back to them later.

The code creates a dll during runtime with a module that has a function called gimmedeflag, interesting.

The function gets two byte[] parameters and returns a byte[] parameter.

After that all the types of the functions local variables are defined. And the content of the array il is set to be the IL (byte-code) of the function.

Next the function gimmedeflag is called with two parameter:

We'll take the relevant code and put it in a new C# project and we'll debug it skipping over the two obstacles described earlier.

We don't really know what is going on inside the function gimmedeflag but we have its IL code, we'll try to learn from that.

The easiest way was to just save the entire dll that was created during runtime to a new file, and then we could decompile that. We did this and got gimmedeflag's C# code.

A few little changes in the code and we get the 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");

We'll use ILSpy again and get:

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;
}

We noticed that the code throws null no matter what input we give.

To summarize what we saw, the code created a dll which we saved to a new file, we read the function gimmedeflag and noticed it throws an error.

We'll create a new project and put gimmedeflag's code without throw null.

As we mentioned earlier, the function get two parameters: A set array and the Main functions's code from the exe.

The last thing we are missing is the code from the main, we'll extract it with the following code:

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

That's all, we'll run the code with the described parameters, and get the flag: BSidesTLV{Look, Rick, I know IL!}

Success