Computer Emergency Response Center

YARA (Yet Another Recursive Acronym) qaydaları

Yara

YARA (Yet Another Recursive Acronym) mətn və ya binar faylı təsnif etmək üçün istifadə olunan alətdir. YARA hazırlanması üçün xüsusi şablon (pattern) və şərtlər (condition) istifadə olunur. Bu alət Virustotal sisteminin yaradıcılarından biri olan Viktor Alvarez tərəfindən hazırlanıb. Alətin hazırlanmasında əsas məqsən zərərli proqram təminatının növünü və ya təsnifatını təyin etmək üçün nəzərdə tutulub. YARA qaydaları Regex ilə müqayisə edilə bilər, lakin Regex əsasən mətn axtarışında, YARA isə zərərli proqramların aşkarlanması və təhlili üçün istifadə olunur.

YARA qaydaları necə yaradılır? Hər bir qayda   başlığ (header), metadata (istəyə bağlı), strings və şərt bölmələrindən ibarətdir. Fayl daxilində xüsusi sətirlə uyğun gələn sadə YARA qaydası nümunəsinə baxaq.

rule example_rule
{
    strings:
        $my_string = "example string"

    condition:
        $my_string
}

Göstərilən nümunədə “example_rule” qaydanın başlığıdır. Gövdə hissəsində “strings” bölməsi $my_string adlı dəyişənə “example string” dəyəri mənimsədilib. Şərt bölməsi faylda $my_string sətrinin tapıldığı halda qaydanın uyğun olmasını müəyyən edir. Daha kompleks misala nəzər salaq.

rule complex_rule
{
    meta:
        description = "Complex YARA rule example"

    strings:
        $string1 = "pattern1"
        $string2 = "pattern2"
        $regex1 = /abc[a-z]{3}xyz/

    condition:
        $string1 and ($string2 or $regex1)
}

Bu qaydanı təsvir etmək üçün metadata bölməsini meta açar sözü ilə əlavə etdik. Strings bölməsində 3 ayrı dəyişən elan edildi: $string1 və $string2 adi sətir, $regex1 regular expression. Şərt bölməsi müəyyən edir ki, əgər $string1 tapılarsa və $string2 və ya $regex1 tapılarsa qaydaya uyğun olmalıdır. YARAnın üstün cəhətlərindən biri onaltılıq (hex) sətirlərin axtarışını apara bilməsidir. Məsələn “salam” sözünün əvəzinə “73 61 6C 61 6D” sətrini axtara bilərik. Onaltılıq sətirlərin axtarışını daha effektiv etmək üçün “wildcard” xüsusiyyətindən istifadə etmək olar. Bəzi baytlar dəyişsə belə “wildcard” xüsusiyyəti bizə onları təyin etməyə kömək edir. Yenə “salam” sözünü nümunə gətirərək “73 61 ?? 61 6D” sətiri ilə axtarış edə bilərik, bu halda 3cü baytın nə olduğu bizim üçün əhəmiyyət daşımır və baytların qalan hissəsi uyğun gəlirsə YARA nəticəni göstərir. Digər “wildcard” xüsusiyyəti naməlum bayt diapazonunu müəyyən etməyə imkan verir. “73 61 [1-3] 6C 61 6D” istifadə edərək “sa” və “lam” arasında 1 və ya 3 bayt ölçüsündə məlumat yerləşsədə, bu uyğundur. Zərərli proqramların axtarışını asanlaşdırmaq üçün bu xüsusiyyətlər çox faydalıdır.

Yaddaşda zərərvericinin axtarışı

Məqalənin bu hissəsində proses yaddaşında YARA qaydaları istifadə edərək zərərli kod nümunələrinin axtarışını həyata keçirəcəyik. Proses başlayanda Windows əməliyyat sistemi proqram təminatına lazım olan qədər yaddaşda yer ayırır. Lakin istifadəçi rejimində (user mode) bu ayrılan yaddaş “bütöv blok” şəklində olmur, mövcud boş yaddaşı ayırmağa çalışır.

Bu ünvanları tapmaq üçün bir necə funksiyalardan istifadə olunacaq. İlk öncə istifadəçi rejimi üçün əməliyyat sistemi tərəfindən yaddaşa ayrılan aşağı və yuxarı sərhədlari müəyyən etmək lazımdır. Bunun üçün GetSystemInfo() funksiyasından istifadə olunacaq. Bu funksiya mövcud sistem haqqında məlumatları alır və SYSTEM_INFO strukturunda saxlayır. Bu struktur içərisində lpMinimumApplicationAddresslpMaximumApplicationAddress atributları müvafiq olaraq user rejimi üçün ayrılmış yaddaşın aşağı və yuxarı sərhədlərini göstərir. VirtualQueryEx funksiyası ilə hədəf prosesə aid olan adresləri təyin edib, ReadProcessMemory funksiyası ilə yaddaş dəyərlərini əldə etmiş olacayıq. Yuxarıda qeyd olunan funksiyaları praktikada tətbiq edək. Test üçün icra olunan zərərlinin SHA256 xeşi: c5b6985cc8e63c04d1ee674684e6362353c00002fdfaff33e15affae9c005b00. Faylı yükləmək üçün ünvan: https://bazaar.abuse.ch/sample/c5b6985cc8e63c04d1ee674684e6362353c00002fdfaff33e15affae9c005b00. Qeyd: göstərilən eksperiment izolasiya olunmuş sistemdə aparılıb. Zərərverici C# proqramlaşdırma dilində hazırlanıb.

şəkildə mavi düzbucaqlının içində opkodlar, qırmızı düzbucaqlının içində opkod arqumentlər, sarı düzbucaqlıda isə opkodun adları yerləşir. Nəzərə almaq lazımdır ki bəzi opkodlar 2 bayt həcmində ola bilər. Məsələn “ceq” opkkodu onaltılıq say sistemində “FE 01” kimi təsvir olunur. YARA qaydalar yazılan zaman zərərli proqramın statik və ya sərt (hard) kodlu hissələrdən istifadə etmək daha uyğundur.  Bizim analiz etdiyimiz kodda 5ci şəkildə 1141-1147ci sətrlərin YARA qaydaları yazılacaq.

$pattern = { 7B [4] 72 [4] 6F [4] 02 22 [4] 22 }

Bütün deyilənləri birləşdirib yekun axtarış kodunu yazaq.

sys_info = SYSTEM_INFO()
GetSystemInfo(byref(sys_info))

proc_min_address = sys_info.lpMinimumApplicationAddress
proc_max_address = sys_info.lpMaximumApplicationAddress

bytes_read = c_ulong(0)
proc_min_address_l = proc_min_address
proc_max_address_l = proc_max_address

rules = yara.compile(source="rule find_pattern { strings: $pattern = { 7B [4] 72 [4] 6F [4] 02 22 [4] 22 } condition: $pattern }")

while (proc_min_address_l < proc_max_address_l):
	mem_basic_info = MEMORY_BASIC_INFORMATION()
	res = VirtualQueryEx(processHandle, proc_min_address, byref(mem_basic_info), sizeof(MEMORY_BASIC_INFORMATION))

	if (mem_basic_info.Protect == PAGE_READWRITE and mem_basic_info.State == MEM_COMMIT):
		buf = create_string_buffer(mem_basic_info.RegionSize)
		ReadProcessMemory(processHandle, c_void_p(mem_basic_info.BaseAddress), buf, mem_basic_info.RegionSize, byref(bytes_read))
		matches = rules.match(data=buf.raw)

		if len(matches) != 0:
			print("Found {0} matches!".format(len(matches[0].strings[0].instances)))

    proc_min_address_l += mem_basic_info.RegionSize
    proc_min_address = c_void_p(proc_min_address_l)

Kod icra olunduqdan aşağıda göstərilən nəticəni görürük:

 

 

 

İstinadlar

[1] https://yara.readthedocs.io/en/stable/index.html

Press ESC to close