macOS Universal binaries & Mach-O Format
Last updated
Last updated
AWS हैकिंग सीखें और अभ्यास करें:HackTricks प्रशिक्षण AWS रेड टीम विशेषज्ञ (ARTE) GCP हैकिंग सीखें और अभ्यास करें: HackTricks प्रशिक्षण GCP रेड टीम विशेषज्ञ (GRTE)
Mac OS बाइनरीज आम तौर पर यूनिवर्सल बाइनरीज के रूप में कॉम्पाइल की जाती हैं। एक यूनिवर्सल बाइनरी में एक ही फ़ाइल में कई विश्वकर्माओं का समर्थन कर सकती है।
ये बाइनरीज Mach-O संरचना का पालन करती हैं जो मुख्य रूप से निम्नलिखित से बना होता है:
हेडर
लोड कमांड्स
डेटा
फ़ाइल को खोजें: mdfind fat.h | grep -i mach-o | grep -E "fat.h$"
हेडर में मैजिक बाइट्स होते हैं जिनके बाद फ़ाइल में मौजूद विश्वकर्माओं की संख्या (nfat_arch
) होती है और प्रत्येक विश्वकर्म के पास fat_arch
संरचना होती है।
इसे इस प्रकार देखें:
या Mach-O View उपकरण का उपयोग करके:
जैसा कि आप सोच रहे होंगे, आम तौर पर 2 विश्वकर्मों के लिए कॉम्पाइल किया गया यूनिवर्सल बाइनरी एक विश्वकर्म के लिए कॉम्पाइल किए जाने वाले बाइनरी के आकार को दोगुना कर देता है।
हेडर में फ़ाइल के बारे में मूल जानकारी होती है, जैसे जादू बाइट्स जिससे इसे एक Mach-O फ़ाइल के रूप में पहचाना जा सकता है और लक्षित विश्वकर्म के बारे में जानकारी। आप इसे यहाँ पा सकते हैं: mdfind loader.h | grep -i mach-o | grep -E "loader.h$"
विभिन्न फ़ाइल प्रकार हैं, आप उन्हें उदाहरण के लिए यहाँ पर परिभाषित पा सकते हैं। सबसे महत्वपूर्ण वाले इस प्रकार हैं:
MH_OBJECT
: स्थानांतरणीय ऑब्जेक्ट फ़ाइल (कॉम्पाइलेशन के बीच के उत्पाद, अभी तक क्रियाशील नहीं)।
MH_EXECUTE
: क्रियाशील फ़ाइलें।
MH_FVMLIB
: स्थिर VM पुस्तकालय फ़ाइल।
MH_CORE
: कोड डंप्स
MH_PRELOAD
: पूर्व-लोड क्रियाशील फ़ाइल (अब XNU में समर्थित नहीं)
MH_DYLIB
: डायनामिक पुस्तकालयें
MH_DYLINKER
: डायनामिक लिंकर
MH_BUNDLE
: "प्लगइन फ़ाइलें"। -bundle का उपयोग करके जनरेट किया जाता है और NSBundle
या dlopen
द्वारा स्पष्ट रूप से लोड किया जाता है।
MH_DYSM
: सहायक .dSym
फ़ाइल (डीबगिंग के लिए प्रतीक वाली फ़ाइल)।
MH_KEXT_BUNDLE
: कर्नेल एक्सटेंशन्स।
या Mach-O View का उपयोग करें:
स्रोत कोड भी कई ध्वजों को परिभाषित करता है जो पुस्तकालयों को लोड करने के लिए उपयोगी हैं:
MH_NOUNDEFS
: कोई अपरिभाषित संदर्भ नहीं (पूरी तरह से लिंक किया गया)
MH_DYLDLINK
: Dyld लिंकिंग
MH_PREBOUND
: डायनामिक संदर्भ पूर्वबंधित।
MH_SPLIT_SEGS
: फ़ाइल आर / ओ और आर / डब्ल्यू सेगमेंट को विभाजित करती है।
MH_WEAK_DEFINES
: बाइनरी में कमजोर परिभाषित प्रतीक हैं
MH_BINDS_TO_WEAK
: बाइनरी कमजोर प्रतीक का उपयोग करती है
MH_ALLOW_STACK_EXECUTION
: स्टैक को क्रियाशील बनाएं
MH_NO_REEXPORTED_DYLIBS
: पुस्तकालय LC_REEXPORT कमांड नहीं
MH_PIE
: स्थान स्वतंत्र कार्यक्षम
MH_HAS_TLV_DESCRIPTORS
: धागे से धागे स्थानीय चर के साथ एक खंड है
MH_NO_HEAP_EXECUTION
: हीप / डेटा पृष्ठों के लिए कोई क्रियान्वयन नहीं
MH_HAS_OBJC
: बाइनरी में ओब्जेक्ट-सी खंड हैं
MH_SIM_SUPPORT
: सिम्युलेटर समर्थन
MH_DYLIB_IN_CACHE
: साझा पुस्तकालय कैश में डायलिब्स / फ़्रेमवर्क पर उपयोग किया जाता है।
मेमोरी में फ़ाइल का खाका यहाँ निर्दिष्ट किया गया है, मुख्य धागे की स्थान, क्रियान्वयन प्रारंभ पर मुख्य धागे का संदर्भ, और आवश्यक साझा पुस्तकालय। निर्देश दिए गए हैं डायनामिक लोडर (dyld) को मेमोरी में बाइनरी के लोडिंग प्रक्रिया पर।
उपयोग करता है load_command संरचना, उल्लिखित loader.h
में परिभाषित:
व्यवस्था को विभिन्न प्रकार के लोड कमांड का सामना करना है। सबसे सामान्य लोड कमांड हैं: LC_SEGMENT_64
, LC_LOAD_DYLINKER
, LC_MAIN
, LC_LOAD_DYLIB
, और LC_CODE_SIGNATURE
।
मुख्य रूप से, यह प्रकार का लोड कमांड कैसे __TEXT (कार्यात्मक कोड) और __DATA (प्रक्रिया के लिए डेटा) सेगमेंट को डेटा खंड में दिखाए गए ऑफसेट के अनुसार बाइनरी को निष्पादित किया जाता है।
ये कमांड सेगमेंट को परिभाषित करते हैं जो एक प्रक्रिया के वर्चुअल मेमोरी स्पेस में मैप किए जाते हैं जब यह निष्पादित होता है।
इनमें विभिन्न प्रकार के सेगमेंट होते हैं, जैसे __TEXT सेगमेंट, जो किसी प्रोग्राम के कार्यात्मक कोड को धारित करता है, और __DATA सेगमेंट, जो प्रक्रिया द्वारा उपयोग किए जाने वाले डेटा को समेतता है। ये सेगमेंट डेटा सेक्शन में स्थित होते हैं मैक-ओ फ़ाइल में।
प्रत्येक सेगमेंट को और अधिक सेक्शनों में विभाजित किया जा सकता है। लोड कमांड संरचना में जानकारी होती है इन सेगमेंट के भीतर के सेक्शनों के बारे में।
हेडर में पहले आपको सेगमेंट हेडर मिलता है:
सेगमेंट हेडर का उदाहरण:
यह हेडर उन सेक्शनों की संख्या को परिभाषित करता है जिनके हेडर इसके बाद दिखाई देते हैं:
उदाहरण का खंड शीर्षक:
यदि आप खंड ऑफसेट (0x37DC) + ऑफसेट जहां आर्क शुरू होता है, इस मामले में 0x18000
जोड़ें --> 0x37DC + 0x18000 = 0x1B7DC
यह भी संभव है कि हेडर्स जानकारी को कमांड लाइन से प्राप्त किया जा सके:
इस cmd द्वारा लोड किए जाने वाले सामान्य सेगमेंट:
__PAGEZERO
: यह कर्नेल को पता देता है कि एड्रेस जीरो को पढ़ा नहीं जा सकता, लिखा नहीं जा सकता, या नहीं चलाया जा सकता। संरचना में maxprot और minprot चर मान शून्य पर सेट किए जाते हैं जिससे इस पृष्ठ पर कोई पढ़ने-लिखने-चलाने का अधिकार नहीं हो।
यह आवंटन NULL प्वाइंटर डिफरेंस वल्नरेबिलिटी को कम करने के लिए महत्वपूर्ण है। यह इसलिए है क्योंकि XNU एक हार्ड पेज जीरो को प्रयोग करता है जो सुनिश्चित करता है कि मेमोरी का पहला पेज (केवल पहला) अप्राप्य है (केवल i386 में)। एक बाइनरी इस आवश्यकता को पूरा कर सकता है एक छोटा __PAGEZERO (का उपयोग करके -pagezero_size
) बनाकर पहले 4k को कवर करना और बाकी 32बिट मेमोरी को उपयोगकर्ता और कर्नेल मोड में दोनों के लिए पहुंचने योग्य बनाने के लिए।
__TEXT
: पाठ्यक्रियात्मक कोड को पढ़ने और चलाने की अनुमति है (कोई लेखन नहीं)। इस सेगमेंट के सामान्य खंड:
__text
: कंपाइल किया गया बाइनरी कोड
__const
: स्थिर डेटा (केवल पढ़ने के लिए)
__[c/u/os_log]string
: C, यूनिकोड या os लॉग स्ट्रिंग स्थिर
__stubs
और __stubs_helper
: डायनामिक लाइब्रेरी लोडिंग प्रक्रिया के दौरान संलग्न
__unwind_info
: स्टैक अनवाइंड डेटा।
ध्यान दें कि यह सभी सामग्री साइन की गई है लेकिन इसे भी चलाया जा सकता है (जो इस विशेषाधिकार की आवश्यकता नहीं है, जैसे स्ट्रिंग समर्पित खंडों के शोषण के विकल्पों के लिए और अधिक विकसित करने के लिए)।
__DATA
: डेटा को शामिल करता है जो पढ़ने योग्य और लिखने योग्य है (कोई चलाया नहीं)।
__got:
ग्लोबल ऑफसेट टेबल
__nl_symbol_ptr
: नॉन लेजी (लोड पर बाइंड) सिम्बल पॉइंटर
__la_symbol_ptr
: लेजी (उपयोग पर बाइंड) सिम्बल पॉइंटर
__const
: केवल पढ़ने योग्य डेटा (वास्तव में नहीं)
__cfstring
: कोर फाउंडेशन स्ट्रिंग्स
__data
: ग्लोबल वेरिएबल्स (जिन्होंने प्रारंभ किया गया है)
__bss
: स्टेटिक वेरिएबल्स (जिन्होंने प्रारंभ नहीं किया गया है)
__objc_*
(__objc_classlist, __objc_protolist, आदि): ऑब्जेक्टिव-सी रनटाइम द्वारा उपयोग किया जाने वाली जानकारी
__DATA_CONST
: __DATA.__const को स्थिर माना नहीं जाता है (लेखन अनुमतियाँ), न ही अन्य पॉइंटर्स और गॉट। इस खंड ने mprotect
का उपयोग करके __const
, कुछ प्रारंभकर्ताओं और गॉट टेबल (एक बार सुलझाया गया) को केवल पढ़ने योग्य बनाया है।
__LINKEDIT
: लिंकर (डायल्ड) के लिए जानकारी शामिल करता है जैसे, सिम्बल, स्ट्रिंग, और स्थानांतरण तालिका प्रविष्टियाँ। यह __TEXT
या __DATA
में नहीं है और इसकी सामग्री को अन्य लोड कमांड्स में वर्णित किया गया है।
डायल्ड जानकारी: Rebase, Non-lazy/lazy/weak बाइंडिंग ऑपकोड और निर्यात जानकारी
फ़ंक्शन शुरू होते हैं: फ़ंक्शन के प्रारंभ पतों की शुरुआत की तालिका
कोड में डेटा: __text में डेटा आइलैंड्स
सिम्बल टेबल: बाइनरी में सिम्बल्स
इंडायरेक्ट सिम्बल टेबल: पॉइंटर/स्टब सिम्बल्स
स्ट्रिंग टेबल
कोड हस्ताक्षर
__OBJC
: ऑब्जेक्टिव-सी रनटाइम द्वारा उपयोग की जाने वाली जानकारी शामिल करता है। हालांकि यह जानकारी __DATA सेगमेंट में भी पाई जा सकती है, विभिन्न __objc_* खंडों में।
__RESTRICT
: एक सेगमेंट जिसमें सामग्री नहीं है जिसे __restrict
कहा जाता है (भी खाली) जो सुनिश्चित करता है कि बाइनरी को चलाते समय, यह DYLD पर्यावरणीय चरों को नजरअंदाज करेगा।
जैसा कि कोड में देखा जा सका, सेगमेंट भी झंडे समर्थन करते हैं (हालांकि वे बहुत अधिक उपयोग नहीं होते):
SG_HIGHVM
: केवल कोर (उपयोग नहीं होता)
SG_FVMLIB
: उपयोग नहीं होता
SG_NORELOC
: सेगमेंट में कोई स्थानांतरण नहीं है
SG_PROTECTED_VERSION_1
: एन्क्रिप्शन। उदाहरण के लिए फाइंडर द्वारा पाठ को एन्क्रिप्ट करने के लिए __TEXT
सेगमेंट का उपयोग किया जाता है।
LC_UNIXTHREAD/LC_MAIN
LC_MAIN
में entryoff विशेषता में प्रवेश बिंदु होता है। लोड समय पर, dyld बस के (मेमोरी में) बाइनरी के आधार में इस मान को जोड़ता है, फिर इस निर्देशिका पर जाकर बाइनरी के कोड का निष्पादन शुरू करने के लिए उछलता है।
LC_UNIXTHREAD
में रजिस्टर के मान शामिल होते हैं जब मुख्य धागा शुरू होता है। यह पहले से ही प्रायोगिक हो गया था लेकिन dyld
अब भी इसका उपयोग करता है। इसके साथ इस द्वारा सेट किए गए रजिस्टरों के मान देखना संभव है:
LC_CODE_SIGNATURE
में Macho-O फ़ाइल के कोड हस्ताक्षर के बारे में जानकारी होती है। यह केवल एक ओफ़्सेट शामिल करता है जो हस्ताक्षर ब्लॉब की ओर पहुंचता है। यह आम तौर पर फ़ाइल के अंत में होता है। हालांकि, आप इस खंड के बारे में कुछ जानकारी इस ब्लॉग पोस्ट और इस गिस्ट में पा सकते हैं।
LC_ENCRYPTION_INFO[_64]
बाइनरी एन्क्रिप्शन का समर्थन। हालांकि, यदि कोई हमलावर प्रक्रिया को कंप्रमाइज करने में सफल होता है, तो वह यादृच्छिक रूप से मेमोरी को अनएन्क्रिप्ट कर सकेगा।
LC_LOAD_DYLINKER
डायनामिक लिंकर एक्जीक्यूटेबल का पथ शामिल होता है जो साझा लाइब्रेरी को प्रक्रिया पता स्थान में मैप करता है। मान हमेशा /usr/lib/dyld
पर सेट किया जाता है। यह महत्वपूर्ण है कि macOS में dylib मैपिंग उपयोगकर्ता मोड में होती है, कर्नेल मोड में नहीं।
LC_IDENT
पुराना है लेकिन जब पैनिक पर डंप जेनरेट करने के लिए कॉन्फ़िगर किया जाता है, तो एक Mach-O कोर डंप बनाया जाता है और कर्नेल संस्करण LC_IDENT
कमांड में सेट किया जाता है।
LC_UUID
रैंडम UUID। यह किसी काम के लिए सीधे उपयोगी नहीं है लेकिन XNU इसे प्रक्रिया जानकारी के बाकी साथ कैश करता है। यह क्रैश रिपोर्ट में उपयोग किया जा सकता है।
LC_DYLD_ENVIRONMENT
प्रक्रिया को निष्पादित होने से पहले dyld को वातावरण चरों को सूचित करने की अनुमति देता है। यह बहुत ही खतरनाक हो सकता है क्योंकि यह प्रक्रिया के अंदर विचारहीन कोड निष्पादित करने की अनुमति दे सकता है, इसलिए यह लोड कमांड केवल #define SUPPORT_LC_DYLD_ENVIRONMENT
के साथ डायल्ड बिल्ड में उपयोग किया जाता है और आगे संविदान केवल DYLD_..._PATH
रूप के चरों को निर्दिष्ट करने के लिए प्रसंस्करण को प्रतिबंधित करता है।
LC_LOAD_DYLIB
यह लोड कमांड एक डायनामिक लाइब्रेरी आवश्यकता का वर्णन करता है जो लोडर (dyld) को उस लाइब्रेरी को लोड और लिंक करने के लिए निर्देशित करता है। Mach-O बाइनरी के प्रत्येक लाइब्रेरी के लिए एक LC_LOAD_DYLIB
लोड कमांड होता है।
यह लोड कमांड एक प्रकार की संरचना है dylib_command
(जिसमें वास्तविक निर्भर डायनामिक लाइब्रेरी का वर्णन करने वाला स्ट्रक्ट dylib होता है):
आप इस जानकारी को क्लाइंट लाइन से भी प्राप्त कर सकते हैं:
कुछ संभावित मैलवेयर संबंधित लाइब्रेरी हैं:
DiskArbitration: USB ड्राइव की मॉनिटरिंग
AVFoundation: ऑडियो और वीडियो कैप्चर
CoreWLAN: वाईफाई स्कैन।
एक Mach-O बाइनरी में एक या एक से अधिक निर्माताओं को शामिल किया जा सकता है, जो LC_MAIN में निर्दिष्ट पते से पहले क्रियान्वित होंगे। किसी भी निर्माताओं के ऑफसेट __DATA_CONST सेगमेंट के __mod_init_func खंड में रखे जाते हैं।
फ़ाइल के मूल में डेटा क्षेत्र है, जो लोड-कमांड्स क्षेत्र में परिभाषित कई सेगमेंटों से बना होता है। प्रत्येक सेगमेंट में कई डेटा खंड हो सकते हैं, हर खंड कोड या डेटा विशेष एक प्रकार के के लिए होता है।
डेटा मुख्य रूप से उस सभी जानकारी को समेत करता है जो लोड कमांड्स LC_SEGMENTS_64 द्वारा लोड की जाती है।
इसमें शामिल हैं:
कार्य सारणी: जो कार्य के बारे में जानकारी रखती है।
प्रतीक सारणी: जो बाइनरी द्वारा उपयोग की गई बाह्य कार्य के बारे में जानकारी रखती है
यह आंतरिक कार्य, चर नामों को भी शामिल कर सकता है और अधिक।
इसे जांचने के लिए आप Mach-O View टूल का उपयोग कर सकते हैं:
या CLI से:
__TEXT
सेगमेंट (r-x) में:
__objc_classname
: कक्षा के नाम (स्ट्रिंग्स)
__objc_methname
: मेथड के नाम (स्ट्रिंग्स)
__objc_methtype
: मेथड के प्रकार (स्ट्रिंग्स)
__DATA
सेगमेंट (rw-) में:
__objc_classlist
: सभी Objective-C कक्षाओं के पॉइंटर
__objc_nlclslist
: Non-Lazy Objective-C कक्षाओं के पॉइंटर
__objc_catlist
: श्रेणियों के लिए पॉइंटर
__objc_nlcatlist
: Non-Lazy श्रेणियों के लिए पॉइंटर
__objc_protolist
: प्रोटोकॉल सूची
__objc_const
: स्थिर डेटा
__objc_imageinfo
, __objc_selrefs
, objc__protorefs
...
_swift_typeref
, _swift3_capture
, _swift3_assocty
, _swift3_types, _swift3_proto
, _swift3_fieldmd
, _swift3_builtin
, _swift3_reflstr