ConfuserEx Deep Analysis ~ AntiDump

Selamlar, bu yazımda ConfuserEx adlı “obfuscate” yazılımının içerisindeki AntiDump korumasının derin analizini yapacağım.

Bu Yazı Neler İçeriyor?

Bu yazı ve “ConfuserEx Deep Analysis” başlığı altında açılan yazılar genel olarak şu başlıklardan oluşacak :

ConfuserEx Nedir?

ConfuserEx is an free, open-source protector for .NET applications. It is the successor of Confuser project.

.NET Uygulamaları için bedava, açık kaynaklı bir koruma. “Confuser” projesinin varisidir.

AntiDump Nedir?

AntiDump, bellekten alınmak istenen dökümü bozan, engelleyen bir yapı. (?)

ConfuserEx AntiDump Çalışma Prensibi

ConfuserEx korumasının AntiDump’ının çalışma prensibini inceleyebilmek için kodlarını Github sayfasından alalım.

https://github.com/yck1509/ConfuserEx/blob/master/Confuser.Runtime/AntiDump.cs

Şundan da bahsetmeliyim ki ConfuserEx, Runtime çalışabilen korumalardan oluşuyor. Yani AntiTamper, AntiDebugger, AntiDump gibi korumalar için Runtime şekilde çalışabilecek korumalar üretiyor ve daha sonrasında seçilen .NET dosyanın içine bunu enjekte edip Rename işlemine sokuyor. Örneğin linkini yukarda verdiğim AntiDump.cs dosyası Runtime çalışan (.NET Kütüphaneleri dışında farklı bir kütüphaneye ihtiyaç duymuyor(DLL) ) bir kod parçası.

https://github.com/yck1509/ConfuserEx/blob/master/Confuser.Protections/AntiDumpProtection.cs

Bu kısımda gördüğümüz kısım, Runtime çalışan class’ı içerisine enjekte eden kısım :

 protected override void Execute(ConfuserContext context, ProtectionParameters parameters) {
			TypeDef rtType = context.Registry.GetService<IRuntimeService>().GetRuntimeType("Confuser.Runtime.AntiDump");

			var marker = context.Registry.GetService<IMarkerService>();
			var name = context.Registry.GetService<INameService>();

			foreach (ModuleDef module in parameters.Targets.OfType<ModuleDef>()) {
				IEnumerable<IDnlibDef> members = InjectHelper.Inject(rtType, module.GlobalType, module);

			MethodDef cctor = module.GlobalType.FindStaticConstructor();
			var init = (MethodDef)members.Single(method => method.Name == "Initialize");
			cctor.Body.Instructions.Insert(0, Instruction.Create(OpCodes.Call, init));

			foreach (IDnlibDef member in members)
				name.MarkHelper(member, marker, (Protection)Parent);
}

Runtime çalışan class’ın DLL Import kısmına bakalım.

[DllImport("kernel32.dll")]
static extern unsafe bool VirtualProtect(byte* lpAddress, int dwSize, uint flNewProtect, out uint lpflOldProtect);

Bu kısımda kernel32.dll ‘i içerisinde bulunan VirtualProtect apisi “VirtualProtect” ismi ile class’a dahil ediliyor.

VirtualProtect ?
BOOL VirtualProtect(
  LPVOID lpAddress,
  SIZE_T dwSize,
  DWORD  flNewProtect,
  PDWORD lpflOldProtect
);

Changes the protection on a region of committed pages in the virtual address space of the calling process.

Çağrılan işlemin sanal adres alanındaki korumayı değiştirir.

https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualprotect

VirtualProtect üstünden de basitçe geçtiğimize göre şimdi kodları inceleyelim.

Initalize method’u içerisindeki kısım yani en başından başlıyoruz.

uint old; //1
Module module = typeof(AntiDump).Module; //2
var bas = (byte*)Marshal.GetHINSTANCE(module); //3
//Bunun gerisi memory üzerinde istenilen yerin hesaplanması.
byte* ptr = bas + 0x3c; // 3c = 60
byte* ptr2;
ptr = ptr2 = bas + *(uint*)ptr;
ptr += 0x6;
ushort sectNum = *(ushort*)ptr;
ptr += 14;
ushort optSize = *(ushort*)ptr;
ptr = ptr2 = ptr + 0x4 + optSize;

Screenshot_9 Bu kısım… ptr2 adresinin tuttuğu alana gittiğimizde Section Headers’ları göreceğiz.

for (int k = 0; k < (int)num; k++)
{
	<Module>.VirtualProtect(ptr2, 8, 64U, ref num3); //8 baytlık alan ayırmasının sebebi section isimleri 8 bayttan oluşuyor.
	Marshal.Copy(new byte[8], 0, (IntPtr)((void*)ptr2), 8); //Silme işlemini tam olarak bu kısımda yapıyor.
	ptr2 += 40; //Bu kısımda birinde işini bitirdikten sonra 40 bayt ekleyerek diğer bayt'a geçiyor hepsi arasında 40 bayt var.
}

Bu kod parçası sectionlar içerisinde dolaşarak hepsinin ismini siliyor.

Screenshot_10 Bu kısımda BSJB flag’inin hesaplanmasını yapıp 4 byte’lık alan ayırıp onu siliyor. BSJB, meta veri tablosundaki ilk girdidir (Meta veri motorunda çalışan 4 adamın adlarının ilk 4 harfinin birleşimidir) evet, biraz saçma bir detay oldu :D.

AntiDump korumamız bu kısımları sildikten sonra dnSpy içerisindeki modules sekmesi ile dump alalım. aaa Gördüğünüz gibi bütün flagler silindiği için ve section isimleri silindiği için okunamıyor.

Basit Bir AntiDump Geliştirelim.

Başında uyarayım bu sadece bir sürü yöntemi olduğunu gösterme amaçlı bir antidump olacak yani o kadar stabil çalışmıyor.

internal unsafe static void AntiDumpFunction()
{
	uint num3 = 0U;
        Module module = typeof(Program).Module;
        byte* ptr = (byte*)((void*)Marshal.GetHINSTANCE(module));
        VirtualProtectFunc(ptr, 128, 64U, ref num3);
        Marshal.Copy(new byte[128], 0, (IntPtr)((void*)ptr), 128);
}

Runtime MZ Header Erase işlemi yapan bir kod parçacığı. Bu programı dump aldığımız zaman şöyle bir görüntü ile karşılaşıyoruz : bbbb

Anti-AntiDump

AntiDump olan bir .NET uygulamasından nasıl dump alırız? Bunun iki yöntemi veya birçok yöntemi olabilir.

1) JITFreezer (Bunun kodlarını inceleyelim) 2) x0rz’s antidump fixer tool ( BackBox üstadıma selamlar o7 ) x0rz bunun kodlarını obfuscate etmiş yani incelenmesini istemediği için mi o kısmı tam olarak bilmediğim için istemiyordur diye kodlarını deobfuscate etmeye gerek yoktur diye düşünüyorum.

JITFreezer

Çalışma prensibi çook basit.

try
{
	string fileName = args[0];
	Process process = new Process();
	process.StartInfo.FileName = fileName;
	process.StartInfo.CreateNoWindow = true;
	process.StartInfo.UseShellExecute = false;
	process.Start();
	int id = process.Id;
	for (;;)
	{
		if (Utils.GetCLRModule(id))
		{
			Utils.SuspendT(id);
			Utils.PrintLogo();
			Console.WriteLine("[!] .NET has been loaded.\n");
			Console.WriteLine("[»] Manually dump it (Ex: MegaDumper / Scylla / ExtremeDumper).");
			Console.WriteLine("\n[!] Press Enter to kill the process.");
			Console.ReadLine();
			process.Kill();
		}
	}
}
catch (Exception ex)
{
	Console.Clear();
	string str = "[x] Error: \n";
	Exception ex2 = ex;
	Console.WriteLine(str + ((ex2 != null) ? ex2.ToString() : null));
}

//(...)

public static bool GetCLRModule(int pID)
{
	ProcessModuleCollection modules = Process.GetProcessById(pID).Modules;
	for (int i = 0; i < modules.Count; i++)
	{
		if (modules[i].ModuleName.ToLower() == "clr.dll")
		{
			return true;
		}
	}
	return false;
}

clr.dll yüklendiği sırada uygulamaya suspend atıyor yani duraklatıyor tek işlevi bu. Suspend attığı sırada daha uygulama tam olarak yüklenmemiş olacağı için hiçbir fonksiyon çalışmamış olacak. Bu sırada dump alırsak AntiDump hiç devreye girmemiş olacak.

KULLANILABİLECEK MUHTEŞEM ÖTESİ KAYNAKLAR

https://www.codeproject.com/Articles/5841/Inside-the-NET-Application https://ring0.info/posts/pe-dosya-formatina-dalis