hideinpILainsight
נכתב על ידי naweiss
התקבל מהאתגר קובץ בשם 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();
}
}
}
יש שני מכשולים קטנים שצריך לעבור כדי להגיע לחלק המעניין:
- הקוד בודק האם אנו משתמשים ב-Debugger, אם כן הוא פשוט מדפיס
Sometimes science is a lot more art than science. A lot of people don't get that.
- אחרת, הוא מג'נרט מספר ראנדומאלי בין 0 ל-312 לא כולל ובודק האם הוא גדול שווה מ-312. כלומר
if (false)
נתעלם לרגע משני המכשולים ונמשיך הלאה.
הקוד יוצר dll תוך כדי ריצה עם מודל מסוים שבתוכו פונקציה בשם gimmedeflag
, מעניין.
הפונקציה מקבלת שני פרמטרים מטיפוס byte[]
ומחזירה byte[]
.
אחר כך מוגדרים כל הטיפוסים של המשתנים המקומיים בפונקציה ומוגדר שקוד ה-IL (byte-code)
של הפונקציה יהיה התוכן של המערך il
.
לאחר מכן הפונקציה gimmedeflag
מופעלת עם 2 פרמטרים:
- המערך הקבוע array.
- קוד ה-IL של ה-Main מה-exe עצמו, לכן כל שינוי בקוד יגרור שינוי בתוכן המערך .
ניקח את הקוד הרלוונטי נשים בפרויקט 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)