
फज़िंग के लिए एक हाइपरवाइज़र जो WHVP और Bochs के साथ निर्मित है
नमस्ते! applepie में आपका स्वागत है! यह एक उपकरण है जो फ़ज़िंग, अंतर्दर्शन और बग ढूंढने के लिए डिज़ाइन किया गया है! यह Windows Hypervisor Platform API का उपयोग करने वाला एक हाइपरवाइज़र है जो Windows के हाल के संस्करणों में मौजूद है (विशेष रूप से इसे Windows 10 17763 पर विकसित और परीक्षण किया गया था)। Bochs का उपयोग गहन अंतर्दर्शन और उपकरण अनुकरण के लिए किया जाता है।
Windows Hypervisor Platform API (WHVP) Hyper-V की हाइपरवाइज़र क्षमताओं तक पहुँचने के लिए एक API सेट है। यह API हमारे लिए उपयोगकर्ता-स्थान में बिना किसी विशेष ड्राइवर या अनुमति की आवश्यकता के एक वर्चुअल मशीन को लागू करना आसान बनाता है।
यह एक तेज़ी से विकसित होने वाली परियोजना है। जब नई सुविधाएँ दस्तावेज़ीकृत होने से पहले आती हैं, तो मैं संभवतः ट्वीट करूँगा।
मुझे अपनी परियोजनाओं के लिए भौतिक चीज़ें रखना पसंद है:
यह एक उपकरण है जो सुरक्षा अनुसंधान के दौरान फ़ज़िंग और अंतर्दर्शन के लिए डिज़ाइन किया गया है। एक हाइपरवाइज़र का उपयोग करके सामान्य फ़ज़िंग तकनीकों को किसी भी लक्ष्य, कर्नेल या उपयोगकर्ता स्थान पर लागू किया जा सकता है। यह वातावरण स्रोत की आवश्यकता के बिना पूरे सिस्टम के फ़ज़िंग की अनुमति देता है। हाइपरवाइज़र स्तर पर कोड कवरेज एकत्र किया जा सकता है, और यदि आवश्यक हो तो Bochs अनुकरण का उपयोग अनुकरण वातावरण में मनमाना अंतर्दर्शन प्रदान करने के लिए किया जा सकता है। इस कवरेज जानकारी का उपयोग फ़ज़ मामलों की प्रभावशीलता का पता लगाने के लिए किया जा सकता है। एक फ़ज़ मामला जिसने कवरेज में वृद्धि की, उसे एक दिलचस्प मामला मानकर सहेजा जा सकता है। इस इनपुट का उपयोग बाद में नए भ्रष्टाचारों द्वारा निर्मित किया जा सकता है।
स्नैपशॉट फ़ज़िंग इस उपकरण का प्राथमिक उपयोग है। जहाँ आप एक निश्चित अवस्था में सिस्टम का स्नैपशॉट लेते हैं और उसे सहेज लेते हैं। इस स्नैपशॉट को फिर फ़ज़िंग के लिए लोड किया जा सकता है, जहाँ एक फ़ज़ मामला इंजेक्ट किया जाता है, और इसे फिर से शुरू किया जाता है। चूँकि VM को बहुत सस्ते में रीसेट किया जा सकता है, VM को बार-बार रीसेट किया जा सकता है। यदि Word को बूट होने में 5 सेकंड लगते हैं, लेकिन आप इसे ठीक उस समय स्नैपशॉट कर सकते हैं जब वह आपकी फ़ाइल पढ़ता है, तो आप फ़ज़ मामले को केवल उसी तक सीमित कर सकते हैं जो एक इनपुट के लिए प्रासंगिक है। यह स्रोत तक पहुँच की आवश्यकता के बिना फ़ज़िंग के एक बहुत ही कड़े लूप की अनुमति देता है। चूँकि VM पूरी तरह से अलग सिस्टम हैं, कई को समानांतर में चलाया जा सकता है ताकि सभी कोर तक स्केलिंग की जा सके।
वर्तमान में यह उपकरण केवल कोड कवरेज एकत्र करने, Windows के लिए गतिशील प्रतीक डाउनलोड करने, और Windows लक्ष्यों के लिए प्रतीक/मॉड्यूल पार्सिंग का समर्थन करता है। फ़ज़िंग समर्थन जोड़ना जल्द ही होगा।
यह देखते हुए कि मैंने यहाँ लगभग सभी सुविधाएँ पहले लिखी हैं (कवरेज, फ़ज़िंग, तेज़ रीसेट, आदि)। मुझे उम्मीद है कि यह परियोजना जल्द ही फ़ज़िंग के लिए तैयार हो जाएगी, जब तक कि मैं विचलित न हो जाऊं :D
मैं जनवरी के अंत तक कवरेज (हो गया!), फीडबैक, मॉड्यूल सूची (हो गया!), प्रक्रिया सूची, तेज़ रीसेट, और प्रतीक समर्थन (हो गया!) का लक्ष्य रख रहा हूँ। जो इसे एक बहुत ही सक्षम फ़ज़र बना देगा।
मुख्य समर्थित लक्ष्य आधुनिक Windows 10 है। Windows लक्ष्यों में प्रतीक स्टोर से प्रतीक डाउनलोड करने की सुविधा है। यह Windows लक्ष्यों में बॉक्स से बाहर प्रतीकात्मक कवरेज की अनुमति देता है। हालाँकि, कोड इस तरह लिखा गया है कि Linux enlightenment को आसानी से जोड़ा जा सकता है।
बिना किसी enlightenment के, कोई भी OS जो बूट होता है, उसे फ़ज़ किया जा सकता है और बुनियादी कवरेज एकत्र किया जा सकता है।
OS समर्थन समस्याओं की रिपोर्ट करने से पहले कृपया यह सत्यापित करें कि समस्या हाइपरवाइज़र/Bochs में किए गए परिवर्तनों में है, बिना हाइपरवाइज़र के मानक पूर्व-निर्मित Bochs का उपयोग करके अपने लक्ष्य को बूट करने का प्रयास करके। Bochs का आमतौर पर उपयोग नहीं किया जाता है और इसमें Linux बूट करने जैसी सामान्य चीजों के लिए भी ब्रेकिंग बग हो सकते हैं। विशेष रूप से OS में Spectre/Meltdown mitigations के साथ CPUID/MSR उपयोगों में तेज़ आंतरिक परिवर्तनों के कारण।
मुद्दों की सूची के लिए Github पर issues पृष्ठ देखें। मैंने इसमें पहले से कुछ बीज बो दिए हैं। फ़ज़िंग विकास शुरू होने से पहले इनमें से कुछ को जल्दी से संबोधित करने की आवश्यकता है।
इसे बनाने के लिए आपको कुछ चीज़ों की आवश्यकता है:
Visual Studio 2017 स्थापित करें और सुनिश्चित करें कि यह अपडेट है। हम यहाँ कुछ ब्लीडिंग एज APIs, हेडर और लाइब्रेरी का उपयोग कर रहे हैं।
मैं cl.exe संस्करण: Microsoft (R) C/C++ Optimizing Compiler Version 19.16.27025.1 for x64 का उपयोग कर रहा था
और SDK संस्करण 10.0.17763.0
Rust को https://rustup.rs/ के माध्यम से स्थापित करें। मैंने rustc 1.32.0-nightly (b3af09205 2018-12-04) का उपयोग किया
सुनिश्चित करें कि आप x86_64-pc-windows-msvc टूलचेन स्थापित करते हैं क्योंकि इस परियोजना के लिए केवल 64-बिट समर्थित है।
सुनिश्चित करें कि cargo आपके PATH में है। यह डिफ़ॉल्ट होना चाहिए।
python https://www.python.org/ से प्राप्त करें और सुनिश्चित करें कि यह आपके PATH में इस प्रकार है कि python को आमंत्रित किया जा सके।
64-बिट Cygwin (https://www.cygwin.com/setup-x86_64.exe) को विशेष रूप से C:\cygwin64 पर स्थापित करें। Cygwin स्थापित करते समय सुनिश्चित करें कि आप autoconf और make पैकेज स्थापित करते हैं।
"Turn Windows features on or off" में जाएं और "Hyper-V" और "Windows Hypervisor Platform" के बगल में चेकबॉक्स को चिह्नित करें। इसके लिए निश्चित रूप से आवश्यक है कि आपका कंप्यूटर Hyper-V का समर्थन करता हो।
यह स्थापना प्रक्रिया गाइड निम्नलिखित पर सत्यापित की गई थी:
Clean install of Windows 10, Build 17763
rustc 1.33.0-nightly (8e2063d02 2019-01-07)
Microsoft (R) C/C++ Optimizing Compiler Version 19.16.27025.1 for x64
Visual Studio Community 2017 version 15.9.4
applepie commit `f84c084feb487e2e7f31f9052a4ab0addd2c4cf9`
Python 3.7.2 x64
git version 2.20.1.windows.1



autoconf पैकेज)make पैकेज)git clone https://github.com/gamozolabs/applepie के माध्यम से applepie चेकआउट करेंpython build.py चलाएँ
यह प्रारंभिक निर्माण प्रक्रिया लगभग 2 मिनट ले सकती है, एक आधुनिक मशीन पर यह शायद 20-30 सेकंड है।
बस इस परियोजना की रूट डायरेक्टरी से python build.py चलाएँ। इसे वातावरण की समझदारी की जाँच करनी चाहिए और सब कुछ "बस काम करना चाहिए"।
Bochs और Rust बाइनरी को साफ करने के लिए python build.py clean चलाएँ।
सभी Bochs और Rust बाइनरी को पूरी तरह से हटाने के लिए python build.py deepclean चलाएँ, यह Bochs के लिए सभी कॉन्फ़िगरेशन को भी हटा देता है। यदि आप किसी तरह से Bochs को पुन: कॉन्फ़िगर करते हैं तो इसका उपयोग करें।
अपने वातावरण को स्थापित करने का तरीका जानने के लिए Bochs कॉन्फ़िगरेशन पढ़ें। हमारी कुछ आवश्यकताएँ हैं, जैसे sync=none, ips=1000000, और वर्तमान में केवल एकल प्रोसेसर समर्थन। ये कोड के अंदर ही लागू किए जाते हैं ताकि आप अपने पैर में गोली न मारें।
शामिल bochservisor_test\bochsrc.bxrc और bochservisor_test_real\bochsrc.bxrc कॉन्फ़िगरेशन को उदाहरण के रूप में उपयोग करें। bochservisor_test_real संभवतः सबसे अद्यतित कॉन्फ़िग है जिसे आपको संदर्भ के रूप में देखना चाहिए।
Windows लक्ष्यों में मॉड्यूल सूची enlightenment होती है, जो हमें उस संदर्भ में सभी मॉड्यूल की सूची देखने की अनुमति देती है जिसमें हम चल रहे हैं। इसके साथ हम निर्देश पतों को मॉड्यूल + ऑफसेट में बदल सकते हैं। यह मॉड्यूल + ऑफसेट ASLR स्थिति बदलने पर फ़ज़ मामलों के बीच कवरेज जानकारी रखने में मदद करता है। यह IDA जैसे टूल में मॉड्यूल को रंगीन करने की अनुमति भी देता है ताकि यह देखा जा सके कि कौन सा कोड हिट हुआ है।
Windows लक्ष्यों के लिए, आपके _NT_SYMBOL_PATH और symchk का उपयोग करके प्रतीकों को गतिशील रूप से प्रतीक स्टोर से डाउनलोड किया जाएगा। PATH में symchk के बिना यह चुपचाप विफल हो जाएगा। प्रतीकों के साथ कवरेज का एक अच्छा मानव-पठनीय संस्करण देखने के लिए सहेजा जा सकता है। इसके अलावा, निजी प्रतीकों के साथ कवरेज को स्रोत:पंक्ति में परिवर्तित किया जा सकता है ताकि स्रोत कोड को रंगीन किया जा सके।
ठीक है, वास्तव में परीक्षण नहीं हैं, लेकिन एक bochservisor_test है जो एक छोटा OS है जो केवल यह सत्यापित करता है कि हाइपरवाइज़र के साथ सब कुछ बूट होता है।
फिर bochservisor_test_real है जो एक कॉन्फ़िगरेशन है जिसका उपयोग मैं Windows/Linux जैसी चीजों के लिए करता हूँ। यह वह है जो संभवतः सबसे अधिक बार अपडेट होगा।
यह कोडबेस Bochs में थोड़ी मात्रा में कोड पेश करता है ताकि CPU संदर्भ, गेस्ट फिजिकल से उनके बैकिंग मेमोरी, और डिवाइस और CPU स्थिति दोनों को स्टेप करने के लिए मॉड्यूलर एक्सेस की अनुमति मिल सके।
मुख्य कोड जिसे आप देखना चाहते हैं वह bochservisor Rust प्रोजेक्ट में lib.rs में है।
Bochs के मुख्य CPU लूप में हम इसके बजाय LoadLibrary() का उपयोग करके bochservisor DLL लोड करते हैं। यह DLL एक रूटीन निर्यात करता है जो Rust CPU लूप है जिसे आमंत्रित किया जाएगा।
Bochs इस bochs_cpu_loop रूटीन को एक संरचना पास करेगा जिसमें Bochs से जानकारी प्राप्त करने और उसमें डिवाइस और CPU स्थिति को स्टेप करने के लिए फंक्शन पॉइंटर होंगे।
जब MMIO या I/O होता है, तो हाइपरवाइज़र मेमोरी फॉल्ट या I/O निर्देश फॉल्ट के साथ बाहर निकलता है। जबकि WHVP एक अनुकरण API प्रदान करता है, यह वास्तव में कमी है और पर्याप्त नहीं है।
बल्कि हम Bochs का उपयोग करते हैं जो पहले से मौजूद है और कुछ निर्देशों के माध्यम से कदम बढ़ाते हैं। हाइपरवाइज़र CPU स्थिति को Bochs के साथ सिंक में रखकर हम किसी भी समय हाइपरवाइज़र और अनुकरण के बीच गतिशील रूप से स्विच कर सकते हैं (या कम से कम हमें सक्षम होना चाहिए)।
इसका अर्थ है कि पूर्ण हाइपरवाइज़र स्थिति हमेशा Bochs के साथ सिंक में होती है और इस प्रकार Bochs स्नैपशॉट जैसी चीज़ें सामान्य रूप से काम करनी चाहिए और हाइपरवाइज़र के बिना बूट की जा सकती हैं (शायद कुछ CPUID स्थिति को छोड़कर जिसे स्नैपशॉट जानकारी में संग्रहीत करने की आवश्यकता है)।
जब MMIO या I/O होता है तो हम सिर्फ एक का अनुकरण करने के बजाय अनुकरण के तहत निर्देशों की एक निश्चित संख्या चलाते हैं। हाइपरवाइज़र में प्रवेश करने और बाहर निकलने की API लागत, और समान MMIO संचालन के एक-दूसरे के बगल में होने की संभावना के कारण, हम कुछ निर्देशों पर कदम बढ़ाते हैं। यह API के ओवरहेड को कम करने की अनुमति देता है और VMEXIT आवृत्ति को कम करता है। यह एक समायोज्य संख्या है लेकिन कोडबेस में जो है वह शायद एक कारण से है।
इंटरप्ट्स को हम वास्तव में दिलचस्प तरीके से संभालते हैं। हाइपरवाइज़र को इंटरप्ट्स शेड्यूल करने के बजाय हम सभी इंटरप्ट्स को Bochs अनुकरण में ही संभालते हैं। एक्सेप्शन जैसी चीज़ें जो पूरी तरह से हाइपरवाइज़र के अंदर होती हैं, निश्चित रूप से Bochs द्वारा संभाली नहीं जाती हैं।
यह हमें ऐसी सुविधाएँ भी देता है जो WHVP समर्थन नहीं करता, जैसे SMIs (SMM के लिए)। Bochs का BIOS डिफ़ॉल्ट रूप से SMM का उपयोग करता है और SMI समर्थन के बिना एक कस्टम BIOS बनाने की आवश्यकता होती है। मैंने अपने पहले पुनरावृत्ति में ऐसा किया था... अनुशंसा नहीं करता।
यह परियोजना फ़ज़िंग के लिए डिज़ाइन की गई है, हालाँकि यह इतनी नई है (केवल कुछ दिन पुरानी) कि इसमें इनमें से कोई भी सुविधा नहीं है।
आने वाली कुछ पहली चीज़ें होंगी:
हम संभावित रूप से Bochs डिवाइस सामान को एक थ्रेड में रीयल-टाइम में लूप में चला सकते हैं, और दूसरे थ्रेड में हाइपरवाइज़र चला सकते हैं। Async ईवेंट IPC के माध्यम से संचारित होंगे और निष्पादन गेस्ट में होने पर उपकरणों को अपडेट करने की अनुमति देंगे।
वर्तमान में सब कुछ एक थ्रेड में होता है जिसका अर्थ है कि हाइपरवाइज़र को यह सुनिश्चित करने के लिए एक अंतराल पर बाहर निकलना होगा कि हम उपकरणों को कदम बढ़ा सकें। ऐसा लगता है जैसे हमने अपना स्वयं का शेड्यूलर लिखा हो।
यह थोड़ा तेज़ हो सकता है, लेकिन यह जटिलता भी बढ़ाता है और रेस की समस्याओं की संभावना बढ़ाता है। यह कहना मुश्किल है कि क्या ऐसा कभी होगा।
मुझे यकीन नहीं है कि मैं कोड कवरेज एकत्र करने के लिए किस विधि का उपयोग करूंगा, लेकिन कम से कम कुछ विकल्प होंगे। सटीक से लेकर तेज़ तक, आदि। ये सभी कवरेज तंत्र सिस्टम स्तर के होंगे और लक्ष्यों के स्रोत या प्रतीकों की आवश्यकता नहीं होगी।
OS संरचनाओं का पार्सिंग करके प्रक्रिया सूची, मॉड्यूल सूची आदि जैसी प्रारंभिक जानकारी प्राप्त करना। फिर इसका उपयोग प्रतीक जानकारी प्राप्त करने के लिए PDBs से क्वेरी करने के लिए किया जाएगा।
क्रैश को किसी सार्थक तरीके से रिपोर्ट करना। आदर्श रूप से मिनीडंप अच्छे होंगे क्योंकि उन्हें WinDbg में लोड और प्रोसेस किया जा सकता है। यह काफी आसान हो सकता है क्योंकि DMP केवल भौतिक मेमोरी और प्रोसेसर संदर्भ हैं, जो हमारे पास पहले से हैं।
मेरे पास बग्स के मूल कारण का पता लगाने के लिए कुछ मजेदार तकनीकें हैं जो ऐतिहासिक रूप से सफल रही हैं। मैं उन्हें यहाँ लाने की योजना बना रहा हूँ।
गंदे पृष्ठों को ट्रैक करके और केवल संशोधित चीज़ों को पुनर्स्थापित करके हम VMs को बहुत जल्दी रीसेट करने में सक्षम होना चाहिए। यह हमें सिस्टम लक्ष्य के सभी कोर पर अधिकतम गति से फ़ज़ करने की क्षमता देता है। यह वैसा ही है जैसा मैंने falkervisor में किया था, इसलिए यह पहले से ही सोचा और डिज़ाइन किया गया है। इसे बस यहाँ पोर्ट करने की आवश्यकता है।
अत्यंत तेज़ फ़ज़िंग जो MMIO या I/O होने पर निष्पादन रद्द कर देती है। यह सभी CPU समय को हाइपरवाइज़र में बिताने की अनुमति देता है और कोई अनुकरण समय नहीं। इसका एक नकारात्मक पक्ष यह है कि फ़ज़ मामले के दौरान डिस्क I/O जैसी चीज़ों का समर्थन नहीं करता, लेकिन यह अच्छा है।
इस परियोजना की कुछ मुख्य अवधारणाएँ Bochs में न्यूनतम संशोधन हैं। यह हमें इस रिपॉजिटरी के Bochs भाग को अद्यतित रखने की अनुमति देता है।
लक्ष्य जितना संभव हो उतना कोड को Rust और dlls में स्थानांतरित करना है ताकि सिस्टम को अधिक मॉड्यूलर और सुरक्षित बनाया जा सके। यह उम्मीद है कि हाइपरवाइज़र में ही मूर्खतापूर्ण भ्रष्टाचार बग बनाने की संभावनाओं को कम करेगा, जिससे अमान्य फ़ज़ परिणाम होते हैं।
वर्तमान में हाइपरवाइज़र एक DLL है और Bochs में परिवर्तन के बिना बदला जा सकता है (जब तक कि FFI API न बदले)।
Bochs में आगे के परिवर्तनों को स्पष्ट रूप से प्रलेखित किया जाना चाहिए, और मैं जल्द ही उसके लिए एक दस्तावेज़ बनाऊंगा ताकि Bochs में उन परिवर्तनों को ट्रैक किया जा सके जिन्हें Bochs अपडेट के साथ पोर्ट और पुन: मूल्यांकन किया जाना चाहिए।