
तेज़ और मेमोरी-अनुकूल YARA नियम लिखने के तरीके पर एक मार्गदर्शिका
कुशल YARA नियम लिखना तेज़ और सटीक स्कैनिंग प्रदर्शन बनाए रखने के लिए आवश्यक है। यह मार्गदर्शिका आपके नियमों को अनुकूलित करने, अनावश्यक गणना कम करने और सामान्य गलतियों से बचने में मदद करने के लिए प्रमुख सिद्धांत और सर्वोत्तम अभ्यास प्रदान करती है। इसमें उद्योग विशेषज्ञों, जिनमें Victor M. Alvarez, WXS, और YARA समुदाय के योगदान शामिल हैं, की अंतर्दृष्टि शामिल है।
यह अनुभाग YARA प्रदर्शन सर्वोत्तम अभ्यासों का संक्षिप्त सारांश प्रदान करता है। विस्तृत स्पष्टीकरण और उदाहरणों के लिए, नीचे दिए गए पूर्ण मार्गदर्शिका देखें।
"YARA को दो-चरणीय प्रक्रिया के रूप में सोचें: पहले, स्ट्रिंग्स में सूचीबद्ध सभी पैटर्न की खोज करना, और दूसरे, कंडीशन का मूल्यांकन करना। आप खराब चुनी गई स्ट्रिंग्स की भरपाई के लिए सुव्यवस्थित कंडीशन का उपयोग नहीं कर सकते।"
— Wesley Shields
YARA फ़ाइल स्कैन करते समय चार मुख्य चरणों का पालन करता है:
YARA पहले स्ट्रिंग्स की खोज करता है, जिससे स्ट्रिंग चयन नियम दक्षता के लिए सबसे महत्वपूर्ण एकल कारक बन जाता है।
✅ स्ट्रिंग्स के लिए सर्वोत्तम अभ्यास:
\x00\x00\x00\x00 बहुत बार आता है।nocase का सावधानी से उपयोग करें – यह खोज भिन्नताओं को तेज़ी से बढ़ाता है।YARA कंडीशन का क्रमिक मूल्यांकन करता है और पहली विफलता पर रुक जाता है।
✅ कंडीशन के लिए सर्वोत्तम अभ्यास:
filesize < X) महंगी कंडीशन से पहले।for all i in (1..filesize) अक्षम है)।@) का उपयोग करें।⚠ ध्यान दें: रेगेक्स कंडीशन शॉर्ट-सर्किट नहीं होती हैं और हमेशा अंत में मूल्यांकित की जाती हैं।
pe, elf, या magic जैसे मॉड्यूल को मूल्यांकन से पहले पूरी फ़ाइल को पार्स करना चाहिए, जिससे स्कैन समय बढ़ता है।
✅ विकल्प:
pe.is_pe के बजाय, PE फ़ाइलों की पहचान करने के लिए uint16(0) == 0x5A4D का उपयोग करें।अत्यधिक मैच स्कैनिंग को धीमा कर देते हैं और "too many matches" त्रुटियाँ उत्पन्न कर सकते हैं।
✅ अक्षम मैचों को ठीक करना:
.*, .+, या {x,} से बचें।@herrcore ने इस प्रदर्शन मार्गदर्शिका में चर्चित विषयों को कवर करते हुए एक सहायक वीडियो ट्यूटोरियल बनाया है।
Introduction Into YARA - Writing Efficient YARA Rules
इस बात की बेहतर समझ पाने के लिए कि YARA प्रदर्शन को कहाँ और कैसे अनुकूलित किया जा सकता है, स्कैनिंग प्रक्रिया को समझना उपयोगी है। यह मूल रूप से 4 चरणों में विभाजित है, जिन्हें इस उदाहरण नियम का उपयोग करके बहुत सरल रूप से समझाया जाएगा:
import "math"
rule example_php_webshell_rule
{
meta:
description = "Just an example php webshell rule"
date = "2021/02/16"
strings:
$php_tag = "<?php"
$input1 = "GET"
$input2 = "POST"
$payload = /assert[\t ]{0,100}\(/
condition:
filesize < 20KB and
$php_tag and
$payload and
any of ( $input* ) and
math.entropy(500, filesize-500) >= 5
}
यह चरण वास्तविक स्कैन से पहले होता है। YARA Aho-Corasick ऑटोमेटन को फीड करने के लिए खोज स्ट्रिंग्स में तथाकथित एटम देखेगा। विवरण एटम अध्याय में समझाए गए हैं, लेकिन अभी के लिए यह जानना पर्याप्त है कि वे अधिकतम 4 बाइट लंबे होते हैं और YARA बहुत अधिक मैचों से बचने के लिए उन्हें काफी समझदारी से चुनता है। हमारे उदाहरण में YARA निम्नलिखित 4 एटम चुन सकता है:
<?phGETPOSTsser (assert में से)यहाँ स्कैन शुरू हो गया है। चरण 2.-4. सभी फ़ाइलों पर निष्पादित किए जाएंगे। YARA प्रत्येक फ़ाइल में ऊपर परिभाषित 4 एटम को Aho-Corasick ऑटोमेटन नामक प्रीफिक्स ट्री के साथ देखेगा। किसी भी मैच को बाइटकोड इंजन को सौंप दिया जाता है।
यदि, उदाहरण के लिए, sser पर मैच होता है, तो YARA जाँच करेगा कि क्या इसके पहले a था और फिर t के साथ आगे बढ़ता है। यदि यह सत्य है, तो यह रेगेक्स [\t ]{0,100}\( के साथ आगे बढ़ेगा। इस समझदार दृष्टिकोण से YARA धीमे रेगेक्स इंजन के साथ पूरी फ़ाइलों से गुजरने से बचता है और केवल कुछ विशेष भागों को चुनकर करीब से देखता है।
सभी पैटर्न मिलान पूरा होने के बाद, कंडीशन की जाँच की जाती है।
YARA के पास एक और अनुकूलन तंत्र है, जिससे हमारे उदाहरण नियम से केवल CPU-गहन math.entropy जाँच तभी की जाती है, जब उससे पहले की 4 कंडीशन संतुष्ट हों। इसके बारे में अधिक विवरण कंडीशन और शॉर्ट-सर्किट मूल्यांकन अध्याय में समझाया गया है।
यदि कंडीशन संतुष्ट होती हैं, तो मैच की सूचना दी जाती है। स्कैन चरण 2 में अगली फ़ाइल के साथ जारी रहता है।
YARA स्ट्रिंग्स से 4 बाइट तक लंबे छोटे सबस्ट्रिंग निकालता है जिन्हें "एटम" कहा जाता है। वे एटम स्ट्रिंग के किसी भी स्थान से निकाले जा सकते हैं, और YARA फ़ाइल स्कैन करते समय उन एटम को खोजता है, यदि उसे कोई एटम मिलता है तो वह सत्यापित करता है कि स्ट्रिंग वास्तव में मेल खाती है या नहीं।
उदाहरण के लिए, इन स्ट्रिंग्स पर विचार करें:
/abc.*cde/
=> संभावित एटम abc और cde हैं, उनमें से किसी एक का उपयोग किया जा सकता है। वर्तमान में abc एटम को प्राथमिकता दी जाती है क्योंकि उनकी गुणवत्ता समान है और यह दोनों में से पहला है।
/(one|two)three/
=> संभावित एटम one, two, thre और hree हैं, हम केवल thre (या hree) खोज सकते हैं, या one और two दोनों खोज सकते हैं। एटम thre को प्राथमिकता दी जाती है क्योंकि यह one और two (जो छोटे हैं) की तुलना में कम संभावित मैच लाएगा और इसमें दोहरा e नहीं है (अक्षर जितना अधिक अद्वितीय, उतना बेहतर)।
YARA प्रत्येक स्ट्रिंग से सर्वोत्तम एटम चुनने का पूरा प्रयास करता है, उदाहरण के लिए:
{ 00 00 00 00 [1-4] 01 02 03 04 }
=> यहाँ YARA एटम 01 02 03 04 का उपयोग करता है, क्योंकि 00 00 00 00 बहुत सामान्य है
{ 01 02 [1-4] 01 02 03 04 }
=> 01 02 03 04 को 01 02 पर प्राथमिकता दी जाती है क्योंकि यह लंबा है
इसलिए, महत्वपूर्ण बिंदु यह है कि स्ट्रिंग्स में अच्छे एटम होने चाहिए। ये खराब स्ट्रिंग्स हैं क्योंकि इनमें या तो बहुत छोटे या बहुत सामान्य एटम होते हैं:
{00 00 00 00 [1-2] FF FF [1-2] 00 00 00 00}
{AB [1-2] 03 21 [1-2] 01 02}
/a.*b/
/a(c|d)/
सबसे खराब स्ट्रिंग्स वे हैं जिनमें कोई भी एटम नहीं होता, जैसे:
/\w.*\d/
/[0-9]+\n/
इस रेगेक्स में कोई भी निश्चित सबस्ट्रिंग नहीं है जिसे एटम के रूप में उपयोग किया जा सके, इसलिए यह देखने के लिए कि क्या यह वहाँ मेल खाता है, फ़ाइल के हर ऑफसेट पर इसका मूल्यांकन किया जाना चाहिए।
एक और अच्छी अनुशंसा यह है कि लूप में बहुत अधिक पुनरावृत्तियों से बचें, विशेष रूप से यदि लूप के भीतर का कथन बहुत जटिल है, उदाहरण के लिए:
strings:
$a = {00 00}
condition:
for all i in (1..#a) : (@a[i] < 10000)