Flare ON Challenge #7

I was debating on whether or not I wanted to do a blog entry on my failed yet successful attempt at the FLARE On challenge (I only completed up to binary #10) and am still thinking it over. However, I am reading write ups and I see that my approach to #7 is a lot easier than most and I wanted to share it. Needless to say if you know me or my work, I was very excited this was a .NET binary!

The binary “YUSoMeta.exe” presents a nice message for us

I decided to throw the binary into one of my favorite .NET tools, Gray Wolf, which also does deobfuscation!

Throwing the binary in without deobfuscating reveals it is obfuscated..

So go and be rid of that!

Now looking at all of the source code I came across the main method that does the decryption of our key in System.Void ns0.Class1::Main(System.String[])

(code cut for brevity)

	Console.WriteLine(Encoding.ASCII.GetString(bytes));
	Console.Write(Encoding.ASCII.GetString(bytes2));
	string text = Console.ReadLine().Trim();
	string b = Class1.smethod_0(class2_, byte_2) + '_' + Class1.smethod_3();
	if (text == b)
	{
		Console.WriteLine(Encoding.ASCII.GetString(bytes4));
		Console.Write(Encoding.ASCII.GetString(bytes5));
		Console.WriteLine(Class1.smethod_1(text, byte_));
		return;
	}
	Console.WriteLine(Encoding.ASCII.GetString(bytes3));
}

So it needs us to input some string value and if it matches “b” it will decrypt our key. Notice the 3rd WriteLine is taking text and putting it through another routine with byte_. I thought this was the key and instantly traced Class1.smethod_1.

byte[] bytes = new Rfc2898DeriveBytes(string_0, byte_0.Length)
{
	Salt = byte_0
}.GetBytes(32);
rijndaelManaged.IV = new byte[16];
rijndaelManaged.Key = bytes;
[SNIP]

and saw it was doing crypto.. boring.

I then noticed Class1.smethod_0 was generating the “b” string which is compared to our string so I traced smethod_0.

static string smethod_0(Class2 class2_0, byte[] byte_0)
{
	byte[] array = Class1.smethod_2();
	string text = "";
	for (int i = 0; i < byte_0.Length; i++)
	{
		text += (char)(byte_0[i] ^ array[i % array.Length]);
	}
	return text;
}

and now we need to look at smethod_2 to see what this loop does

static byte[] smethod_2()
{
	return Assembly.GetExecutingAssembly().ManifestModule.ResolveMethod(100663297).GetMethodBody().GetILAsByteArray();
}

Ah! It is looking at some runtime information which is why it cannot be edited!

The line making string “b” also called into smethod_3() which also uses runtime information in the form of GetExecutingAssembly().

static string smethod_3()
{
	StringBuilder stringBuilder = new StringBuilder();
	MD5 mD = MD5.Create();
	foreach (CustomAttributeData current in CustomAttributeData.GetCustomAttributes(Assembly.GetExecutingAssembly()))
	{
		stringBuilder.Append(current.ToString());
	}
	byte[] bytes = Encoding.Unicode.GetBytes(stringBuilder.ToString());
	byte[] value = mD.ComputeHash(bytes);
	return BitConverter.ToString(value).Replace("-", "");
}

Well, this was all I needed and I started copy/pasting the logic into my own C# project.

Note that we need runtime information to perform smethod_2 and smethod_3… I just used reflection to load the binary in my project!

static byte[] smethod_2()
    {
        Assembly asm = System.Reflection.Assembly.Load(System.IO.File.ReadAllBytes("YUSoMeta.exe"));
        return asm.ManifestModule.ResolveMethod(100663297).GetMethodBody().GetILAsByteArray();
    }

and performed the same conversion for smethod_3()

static string smethod_3()
{
    StringBuilder stringBuilder = new StringBuilder();
    MD5 mD = MD5.Create();
    Assembly asm = System.Reflection.Assembly.Load(System.IO.File.ReadAllBytes("YUSoMeta.exe"));
    foreach (CustomAttributeData current in CustomAttributeData.GetCustomAttributes(asm))
    {
        stringBuilder.Append(current.ToString());
    }
    byte[] bytes = Encoding.Unicode.GetBytes(stringBuilder.ToString());
    byte[] value = mD.ComputeHash(bytes);
    return BitConverter.ToString(value).Replace("-", "");
}

Doing this and copying all of the other needed information reveals my new main() without any checking because I have all of the needed information already using reflection!

void mainRoutine()
{
    Console.WriteLine(Encoding.ASCII.GetString(bytes));
    Console.Write(Encoding.ASCII.GetString(bytes2));
    string b = smethod_0(byte_2) + '_' + smethod_3();
    Console.WriteLine(b);
    Console.WriteLine(Encoding.ASCII.GetString(bytes4));
    Console.Write(Encoding.ASCII.GetString(bytes5));
    Console.WriteLine(smethod_1(b, byte_));
    Console.WriteLine(Encoding.ASCII.GetString(bytes3));
}

Notice in the main I also replaced the call to smethod_1 with “b” instead of “text”, which is no longer in mine as the original main checked “if (text == b)” meaning they are the same!

Running this reveals the magic (and yes, I like to tamper so I left the last WriteLine which is the failed attempt)

and I not only read the source, but changed it!

Time permitting I hope to write the steps I took to solve the challenges I did! Like I said, while I may not have been “successful” at winning, I learned an awful lot from participating in FLARE ON!

Written on September 8, 2015