
Rusty Hell's Gate / Halo's Gate / Tartarus' Gate / FreshyCalls / Syswhispers2 लाइब्रेरी
मैंने इस प्रोजेक्ट का नाम Mordor रखा है क्योंकि Hell's Gate / Halo's Gate / Tartarus' Gate किसी अजीब कारण से मुझे The Lord of the Rings में Mordor के Black Gate की याद दिलाते हैं, हाहा, और प्रोजेक्ट को एक शानदार नाम चाहिए तो क्यों न यही रखा जाए?
Middle-earth: Shadow of War Wiki को श्रेय
Hooking एक तकनीक है जिसका उपयोग पहले से मौजूद फ़ंक्शंस के कॉल्स को इंटरसेप्ट करने या किसी वैध API के निष्पादन प्रवाह को मेमोरी में किसी अन्य स्थान पर रीडायरेक्ट करने के लिए किया जाता है। यह मेमोरी स्थान किसी हमलावर, एंटी-वायरस (AV), एंड-पॉइंट डिटेक्शन एंड रिस्पॉन्स (EDR), या एंटी-चीट (AC) के नियंत्रण में हो सकता है।
Inline Hooking: यह हमें लक्षित फ़ंक्शन के पहले कुछ बाइट्स (assembly निर्देश) को एक jump निर्देश से बदलने की अनुमति देता है ताकि निष्पादन प्रवाह को मेमोरी में किसी अन्य स्थान पर रीडायरेक्ट किया जा सके।
Import Address Table Hooking (IAT hooking): Import Address table DLLs या executables से आयातित फ़ंक्शंस के लिए फ़ंक्शन पॉइंटर्स की एक लुकअप टेबल है। IAT hooking हमें प्रोग्राम के निष्पादन प्रवाह को रीडायरेक्ट करने के लिए Import Address Table में फ़ंक्शन पते को किसी अन्य से बदलने की अनुमति देता है।
Kyle Mistele को श्रेय
Hell's Gate एक प्रोसेस इंजेक्शन तकनीक है जो हमें ntdll.dll मॉड्यूल से syscall stub नामक कुछ बाइट्स को खोजने की अनुमति देती है ताकि सिस्टम कॉल नंबर निकाले जा सकें और उन्हें एक समर्पित मेमोरी टेबल में सहेजा जा सके, जिसका उपयोग फिर सिस्टम APIs को सीधे कॉल करने के लिए किया जाता है। हालाँकि, Hell's Gate की सीमा यह है कि यदि फ़ंक्शंस hooked हैं तो इसे एक साफ़ ntdll.dll मॉड्यूल तक पहुँच की आवश्यकता होती है। अन्यथा, यह आवश्यक syscall नंबरों को populate नहीं कर सकता और अंततः native API कॉल्स देने में विफल हो जाता है। इस समस्या के समाधान के लिए, Halo's Gate नामक एक जुड़वाँ बहन का जन्म हुआ, जो Hell's Gate के लिए एक बहुत ही सरल अवलोकन पर आधारित पैच मात्र है।
जब किसी फ़ंक्शन पर hook (jmp <address>) लगाया जाता है तो हम syscall नंबरों को गतिशील रूप से प्राप्त नहीं कर पाएंगे, इसलिए इस समस्या के समाधान के लिए हम पड़ोसी फ़ंक्शंस के सिस्टम कॉल नंबरों को देख सकते हैं और अपना सिस्टम कॉल नंबर प्राप्त करने के लिए गणनाओं को तदनुसार समायोजित कर सकते हैं, क्योंकि syscall stub में syscall ID एक के बाद एक क्रमिक रूप से आते हैं।
Hell's Gate केवल बाइट्स के अनुक्रम 4c8bd1b8 को निम्नलिखित क्रम में जाँचता है, जो assembly में इस तरह दिखता है:
mov r10, rcx
mov eax, <syscall>
Halo's Gate वही करता है जो Hell's Gate करता है, लेकिन इसमें एक अतिरिक्त जाँच होती है कि कहीं कोई हुक लगा हुआ है या नहीं, यह देखकर कि export का पहला बाइट e9 (jmp) है या नहीं, और यदि कोई हुक लगा हुआ है तो Halo's Gate आस-पास के फ़ंक्शन्स को देखना शुरू करता है और तदनुसार गणनाओं को समायोजित करता है ताकि हमें अपना system call नंबर मिल सके, क्योंकि syscall stub में syscall ID एक-दूसरे के बाद क्रमिक रूप से आती है।
हालाँकि, सभी EDRs एक ही स्थान पर (फ़ंक्शन के आरंभ में) हुक नहीं लगाते। क्या होगा यदि EDRs ठीक mov r10, rcx (4c8bd1) के बाद हुक लगाते हैं? इससे हमारा कोड टूट जाएगा।
Tartarus' Gate इस समस्या को Halo's Gate में एक अतिरिक्त जाँच जोड़कर हल करता है, जिसमें इन बाइट्स को क्रमिक रूप से 4c8bd1e9 के रूप में भी खोजा जाता है, जो assembly में ऐसा दिखता है।
mov r10, rcx
jmp <address>
हालाँकि, यदि सभी फ़ंक्शन हुक किए गए हैं तो हम पहले वाले को ढूंढ सकते हैं और कॉल ID 0 से शुरू करके एक-एक करके सभी को अनहुक कर सकते हैं। इस विधि को SEKTOR7 पर Veles' Reek कहा जाता है।
FreshyCalls तकनीक Export Directory में Nt से शुरू होने वाले फ़ंक्शन खोजती है (Ntdll को छोड़कर) और उन्हें पतों के अनुसार क्रमबद्ध करती है। आश्चर्यजनक रूप से सबसे कम पता syscall संख्या 0 है और अगला syscall संख्या 1 और 2 और 3 होगा... आप इसे स्वयं x64 dbg या Windbg में सत्यापित कर सकते हैं।
Syswhispers2 भी यही काम करता है लेकिन ntdll.dll की export directory के अंदर Nt फ़ंक्शन खोजने के बजाय यह Zw से शुरू होने वाले फ़ंक्शन खोजता है। आश्चर्यजनक रूप से Zw फ़ंक्शन और Nt फ़ंक्शन समान syscall stubs की ओर इंगित करते हैं और उनकी syscall संख्या समान होगी।
यहाँ हम इसे सत्यापित कर सकते हैं:
Zw और Nt फ़ंक्शन के बीच के अंतर को Microsoft ने यहाँ समझाया है:
"*Windows native operating system services API को उन रूटीन के एक सेट के रूप में लागू किया गया है जो kernel mode में चलते हैं। इन रूटीन के नाम Nt या Zw उपसर्ग से शुरू होते हैं। Kernel-mode ड्राइवर इन रूटीन को सीधे कॉल कर सकते हैं। User-mode एप्लिकेशन syscalls का उपयोग करके इन रूटीन तक पहुँच सकते हैं।
कुछ अपवादों के साथ, प्रत्येक native system services रूटीन के दो थोड़े भिन्न संस्करण होते हैं जिनके नाम समान लेकिन उपसर्ग भिन्न होते हैं। उदाहरण के लिए, NtCreateFile और ZwCreateFile के कॉल समान ऑपरेशन करते हैं और वास्तव में, एक ही kernel-mode system रूटीन द्वारा सेवित होते हैं।
User mode से syscalls के लिए, किसी रूटीन के Nt और Zw संस्करण समान रूप से व्यवहार करते हैं। Kernel-mode ड्राइवर से कॉल के लिए, किसी रूटीन के Nt और Zw संस्करण इस बात में भिन्न होते हैं कि वे कॉलर द्वारा रूटीन को पास किए गए पैरामीटर मानों को कैसे संभालते हैं।
एक kernel-mode ड्राइवर native system services रूटीन के Zw संस्करण को कॉल करता है ताकि रूटीन को सूचित किया जा सके कि पैरामीटर एक विश्वसनीय, kernel-mode स्रोत से आए हैं। इस स्थिति में, रूटीन मानता है कि यह पैरामीटर को पहले सत्यापित किए बिना सुरक्षित रूप से उपयोग कर सकता है। हालाँकि, यदि पैरामीटर user-mode स्रोत या kernel-mode स्रोत से हो सकते हैं, तो ड्राइवर इसके बजाय रूटीन के Nt संस्करण को कॉल करता है, जो कॉलिंग थ्रेड के इतिहास के आधार पर निर्धारित करता है कि पैरामीटर user mode से उत्पन्न हुए हैं या kernel mode से*"
Hell's Gate: यह syscall stub (4c8bd1b8) का प्रारंभ खोजने के लिए ntdll.dll को पार्स करेगा और फिर syscall ID प्राप्त करेगा। हालाँकि, यदि syscall stub हुक किया गया है तो हमारा कोड टूट जाएगा।
Halo's Gate: Hell's Gate के समान, लेकिन यह जाँचने के लिए एक अतिरिक्त जाँच जोड़ता है कि क्या पहले हुक लगे हुए हैं, यह देखकर कि क्या पहला बाइट e9 (jmp) है और यदि कोई हुक लगा हुआ है तो Halo's gate पड़ोसी फ़ंक्शन को देखना शुरू करता है और तदनुसार गणना समायोजित करता है ताकि हमें हमारी syscall संख्या मिल सके, क्योंकि syscall stub में syscall ID एक-दूसरे के बाद क्रमिक रूप से आते हैं।
Tartarus' Gate: Halo's Gate के समान लेकिन यह जाँचने के लिए एक अतिरिक्त जाँच जोड़ता है कि क्या syscall stub दूसरी पंक्ति में हुक किया गया है, असेंबली निर्देशों mov r10, rcx के बाद, बाइट्स के निम्नलिखित अनुक्रम को खोजकर: 4c8bd1e9.
FreshyCalls: यह Export Directory में Nt से शुरू होने वाले फ़ंक्शन खोजेगा और उन्हें पतों के अनुसार क्रमबद्ध करेगा और सबसे कम पता syscall पहचानकर्ता 0 है।
SysWhispers1: सही syscall संख्या चुनने के लिए OS संस्करण जानकारी का उपयोग करता है।
Syswhispers2: FreshyCalls के समान, लेकिन यह Export Directory में Zw फ़ंक्शन खोजेगा और Zw को Nt से बदलकर नाम संग्रहीत करेगा।