
विंडोज यूज़र-मोड शेलकोड विकास ढांचा (WUMSDF)
v1.1SILVERPICK परियोजना एक Windows User-Mode Shellcode Development Framework (WUMSDF) है, जिसका एकमात्र उद्देश्य क्षमता डेवलपर्स को C/C++ का उपयोग करके Windows x64 के लिए Position Independent Code (PIC) ब्लॉब्स को आसान तरीके से बनाने में सक्षम बनाना है, ताकि इस तरह के प्रयास की विकास लागत को कम किया जा सके।
यह WILDBEAST परियोजना से व्युत्पन्न है और, इस प्रकार, निम्नलिखित का लाभ उठाता है:
Visual Studio Code को कोड संपादक के रूप मेंMinGW-w64 टूलचेन को कंपाइलर टूलचेन के रूप मेंGNU Make को बिल्ड सिस्टम के रूप मेंआप सेटअप निर्देश यहाँ पा सकते हैं: GCC-Clang-Setup-Windows
कृपया ध्यान दें कि यह परियोजना MSYS2 का उपयोग कर रही है।
उच्च-स्तरीय प्रोग्रामिंग भाषाओं में शेलकोड लिखना कोई नई बात नहीं है, और 2010 से इसी विषय पर असंख्य ब्लॉग पोस्ट और शोध पत्र प्रकाशित हो चुके हैं। तो, SILVERPICK में नया क्या है?
खैर, मुझे खुशी है कि आपने पूछा।
SILVERPICK की आस्तीन में कई बेहतरीन ट्रिक्स छिपी हुई हैं, लेकिन सबसे बढ़कर, यह इस विषय पर मेरा अपना दृष्टिकोण है।
तो, बिना किसी देरी के, मैं आपके सामने अपनी पहली ट्रिक प्रस्तुत करता हूँ।
जब से मैट ग्रेबर ने C में शेलकोड लिखने को लोकप्रिय बनाया, अधिकतर लोग उनके Assembly भाषा में लिखे गए 16-बाइट स्टैक संरेखण स्टब का उपयोग कर रहे हैं।
हालाँकि यह कोई समस्या नहीं है, फिर भी चूँकि हम IKEA नहीं हैं, असेंबली आवश्यक नहीं होनी चाहिए, और वास्तव में यह आवश्यक नहीं है।
एक GCC फ़ंक्शन एट्रिब्यूट मौजूद है जो आपके लिए स्टैक संरेखण स्टब उत्पन्न कर देगा।
मिलिए force_align_arg_pointer फ़ंक्शन एट्रिब्यूट से, जो एक सहायक ALIGN_STACK मैक्रो के रूप में है, और निम्नलिखित असेंबली उत्पन्न करता है:
Disassembly of section .init:
<PicEntry>:
push rbp
mov rbp,rsp
and rsp,0xfffffffffffffff0
sub rsp,0x20
call <PicEntry+0x11> IMAGE_REL_AMD64_REL32 .text$payload
leave
ret
.init अनुभाग क्या है, आप पूछेंगे? खैर, यह मेरी दूसरी ट्रिक की ओर एक अच्छा संक्रमण प्रदान करता है।
हो सकता है कि मैट ग्रेबर ने किसी समय C में शेलकोड लिखने को लोकप्रिय बनाया हो, लेकिन वास्तव में, पॉल उनगुर ने Stardust के साथ इस ब्लैक आर्ट को पुनर्जीवित किया।
अब, Stardust फ़ंक्शनों और डेटा के स्थान को सही क्रम में उचित PE अनुभाग में नियंत्रित करने के लिए एक Binutils linker script का उपयोग करता है। यह तकनीक स्वयं ऑस्टिन हडसन के कार्य से व्युत्पन्न है, और कई लोग उनकी लिंकर स्क्रिप्ट के एक रूप का उपयोग करते हैं।
जहाँ लिंकर स्क्रिप्ट लिंकर अनुभाग क्रम के लिए बेहतरीन हैं, वहीं यदि आपको केवल किसी विशेष फ़ंक्शन को कोड अनुभाग की शुरुआत में रखना है, तो वे अनावश्यक हैं।
अब आता है section फ़ंक्शन एट्रिब्यूट, जिसमें .init नामक एक विशेष अनुभाग नाम होता है, जो लिंकर को संकेत देता है कि फ़ंक्शन में main() से पहले का रनटाइम प्रारंभिकरण कोड है और इसे लिंक क्रम में पहले होना चाहिए।
इसी उद्देश्य से, CODE_BEGIN मैक्रो बनाया गया है।
अपनी तीसरी ट्रिक के लिए, मैं आपके सामने STACK_STRING मैक्रो प्रस्तुत करता हूँ।
C में, आप स्ट्रिंग लिटरल को ANSI वर्णों की एक सरणी के रूप में घोषित करके एक स्टैक स्ट्रिंग (एक स्ट्रिंग जो स्टैक पर गतिशील रूप से निर्मित होती है) बना सकते हैं:
char charrHelloKitty[] = { 'H', 'e', 'l', 'l', 'o', 'K', 'i', 't', 't', 'y', '\0' };
C++ में, आप केवल एक char सरणी को constexpr के रूप में चिह्नित करके एक स्टैक स्ट्रिंग बना सकते हैं:
constexpr char charrHelloKitty[]{ "HelloKitty" };
हालाँकि, ये दोनों तकनीकें कंपाइलर ऑप्टिमाइज़ेशन के सामने तब बेकार हो जाती हैं यदि स्ट्रिंग लिटरल पर्याप्त रूप से बड़े हों, हमारे समाधान के विपरीत, जो कैन बोलुक की बदौलत कुछ चतुर C++ टेम्पलेट मेटाप्रोग्रामिंग हैक के कारण स्ट्रिंग लंबाई और कंपाइलर ऑप्टिमाइज़ेशन के स्तर की परवाह किए बिना काम करेगा।
इस मैक्रो का उपयोग काफी सीधा है:
STACK_STRING(sstrText, "an extra long hello world!");
STACK_STRING(sstrCaption, "Demo");
MessageBoxA(nullptr, sstrText.data(), sstrCaption.data(), MB_OK);
यह निम्नलिखित असेंबली उत्पन्न करेगा:
mov [rsp+58h+var_23], 61h ; 'a'
mov [rsp+58h+var_22], 6Eh ; 'n'
mov [rsp+58h+var_21], 20h ; ' '
mov [rsp+58h+var_20], 65h ; 'e'
mov [rsp+58h+var_1F], 78h ; 'x'
mov [rsp+58h+var_1E], 74h ; 't'
mov [rsp+58h+var_1D], 72h ; 'r'
mov [rsp+58h+var_1C], 61h ; 'a'
mov [rsp+58h+var_1B], 20h ; ' '
mov [rsp+58h+var_1A], 6Ch ; 'l'
mov [rsp+58h+var_19], 6Fh ; 'o'
mov [rsp+58h+var_18], 6Eh ; 'n'
mov [rsp+58h+var_17], 67h ; 'g'
mov [rsp+58h+var_16], 20h ; ' '
mov [rsp+58h+var_15], 68h ; 'h'
mov [rsp+58h+var_14], 65h ; 'e'
mov [rsp+58h+var_13], 6Ch ; 'l'
mov [rsp+58h+var_12], 6Ch ; 'l'
mov [rsp+58h+var_11], 6Fh ; 'o'
mov [rsp+58h+var_10], 20h ; ' '
mov [rsp+58h+var_2F], 0
mov [rsp+58h+var_F], 77h ; 'w'
mov [rsp+58h+var_E], 6Fh ; 'o'
mov [rsp+58h+var_D], 72h ; 'r'
mov [rsp+58h+var_C], 6Ch ; 'l'
mov [rsp+58h+var_B], 64h ; 'd'
mov [rsp+58h+var_A], 21h ; '!'
mov [rsp+58h+var_33], 44h ; 'D'
mov [rsp+58h+var_32], 65h ; 'e'
mov [rsp+58h+var_31], 6Dh ; 'm'
mov [rsp+58h+var_30], 6Fh ; 'o'
C++ की बात करते हुए, मैं अपनी चौथी ट्रिक के रूप में कंपाइल-टाइम स्ट्रिंग हैशिंग प्रस्तुत करता हूँ।
हालाँकि यह एक नई अवधारणा नहीं है, SILVERPICK मौजूदा सार्वजनिक कार्यान्वयनों पर कुछ सुधार प्रदान करता है।
पहले, हम सफल हैश टकराव हमले की संभावना को कम करने के लिए लोकप्रिय FNV-1a गैर-क्रिप्टोग्राफिक हैश फ़ंक्शन के 64-बिट प्रकार का उपयोग करते हैं।
दूसरे, हम पूर्व-गणना की गई हैश तालिका लुकअप, जैसे HashDB, से बचाव के लिए हैश फ़ंक्शन के लिए एक संशोधित पैरामीटर का उपयोग करते हैं। महत्वपूर्ण बात यह है कि यह हैश फ़ंक्शन के गुणों को नहीं बदलता है।
रन टाइम पर एक छोटी स्ट्रिंग को हैश करने के लिए, बस HASH_STRING_RUN_TIME मैक्रो का उपयोग करें।
कंपाइल टाइम पर एक छोटे स्ट्रिंग लिटरल को हैश करने के लिए, बस HASH_STRING_COMPILE_TIME मैक्रो का उपयोग करें। केवल कंपाइल-टाइम मूल्यांकन consteval के माध्यम से सुनिश्चित किया जाता है।
यह पता चलता है कि आप x86 स्ट्रिंग निर्देशों का उपयोग करके काफी कुछ C Runtime Library (CRT) फ़ंक्शन लागू कर सकते हैं। इसलिए, निश्चित रूप से, मुझे उन्हें कंपाइलर इंट्रिन्सिक्स और इनलाइन असेंबली के मिश्रण का उपयोग करके लागू करना था।
क्या आप अपने कोड में msvcrt!memset फ़ंक्शन का उपयोग करना चाहते हैं? इसके बजाय ZERO_MEMORY मैक्रो का उपयोग करें, जो कंपाइलर इंट्रिन्सिक के माध्यम से उत्सर्जित rep stosb निर्देश का उपयोग करता है।
msvcrt!memcpy फ़ंक्शन या msvcrt!memmove फ़ंक्शन के बारे में क्या, आप पूछेंगे? प्रतिस्थापन के रूप में COPY_MEMORY मैक्रो से मिलिए, जो कंपाइलर इंट्रिन्सिक के माध्यम से उत्सर्जित rep movsb निर्देश का उपयोग करता है।
लेकिन msvcrt!memcmp फ़ंक्शन के विकल्प के बारे में क्या? यह पता चलता है कि repe cmpsb निर्देश को उत्सर्जित करने के लिए वास्तव में कोई कंपाइलर इंट्रिन्सिक उपलब्ध नहीं है। इसलिए, हम इसके बजाय इनलाइन असेंबली का उपयोग करके एक compare_memory फ़ंक्शन लिखते हैं।