macOS Universal binaries & Mach-O Format
मूल जानकारी
Mac OS बाइनरीज आम तौर पर यूनिवर्सल बाइनरीज के रूप में कॉम्पाइल की जाती हैं। एक यूनिवर्सल बाइनरी में एक ही फ़ाइल में कई विश्वकर्माओं का समर्थन कर सकता है।
ये बाइनरीज Mach-O संरचना का पालन करती हैं जो मुख्य रूप से निम्नलिखित से बनी होती है:
हेडर
लोड कमांड्स
डेटा
फैट हेडर
फ़ाइल को खोजें: mdfind fat.h | grep -i mach-o | grep -E "fat.h$"
हेडर में मैजिक बाइट्स होते हैं जिनके बाद फ़ाइल में मौजूद विश्वकर्मों की संख्या (nfat_arch
) होती है और प्रत्येक विश्वकर्म के पास fat_arch
संरचना होती है।
इसे इस प्रकार देखें:
या Mach-O View उपकरण का उपयोग करके:
जैसा कि आप सोच रहे होंगे, आम तौर पर 2 विश्वकर्मों के लिए कॉम्पाइल किया गया यूनिवर्सल बाइनरी एक केवल 1 विश्वकर्म के लिए कॉम्पाइल किए गए बाइनरी के आकार को दोगुना कर देता है।
Mach-O हेडर
हेडर में फ़ाइल के बारे में मूल जानकारी होती है, जैसे यह किसी Mach-O फ़ाइल के रूप में पहचानने के लिए मैजिक बाइट्स और लक्ष्य विश्वकर्म के बारे में जानकारी होती है। आप इसे यहाँ पा सकते हैं: mdfind loader.h | grep -i mach-o | grep -E "loader.h$"
Mach-O फ़ाइल प्रकार
विभिन्न फ़ाइल प्रकार हैं, आप उन्हें उदाहरण के लिए यहाँ परिभाषित पा सकते हैं. सबसे महत्वपूर्ण शामिल हैं:
MH_OBJECT
: स्थानांतरणीय ऑब्जेक्ट फ़ाइल (कॉम्पाइलेशन के बीच के उत्पाद, अभी तक क्रियाशील नहीं).MH_EXECUTE
: क्रियाशील फ़ाइलें।MH_FVMLIB
: स्थिर VM लाइब्रेरी फ़ाइल।MH_CORE
: कोड डंप्सMH_PRELOAD
: पूर्व-लोड क्रियाशील फ़ाइल (अब XNU में समर्थित नहीं)MH_DYLIB
: डायनामिक लाइब्रेरीज़MH_DYLINKER
: डायनामिक लिंकरMH_BUNDLE
: "प्लगइन फ़ाइलें". -bundle का उपयोग करके gcc में उत्पन्न की गई औरNSBundle
याdlopen
द्वारा स्पष्ट रूप से लोड की गई।MH_DYSM
: सहायक.dSym
फ़ाइल (डीबगिंग के लिए प्रतीक वाली फ़ाइल)।MH_KEXT_BUNDLE
: कर्नेल एक्सटेंशन्स।
या Mach-O View का उपयोग करें:
Mach-O ध्वज
स्रोत कोड भी कई ध्वजों को परिभाषित करता है जो पुस्तकालयों को लोड करने के लिए उपयोगी हैं:
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
: साझा पुस्तकालय कैश में डायलिब्स / फ्रेमवर्क पर उपयोग किया जाता है।
Mach-O लोड कमांड्स
फ़ाइल का लेआउट मेमोरी में यहाँ निर्दिष्ट किया गया है, मुख्य धागे की स्थानिकी, क्रियान्वयन प्रारंभ पर मुख्य धागे का संदर्भ, और आवश्यक साझा पुस्तकालय। निर्देश दिए गए हैं डायनामिक लोडर (dyld) को मेमोरी में बाइनरी के लोडिंग प्रक्रिया पर।
उपयोग करता है load_command संरचना, जो उल्लिखित loader.h
में परिभाषित किया गया है:
व्यवस्था विभिन्न प्रकार के लोड कमांड को सामान्य रूप से अलग-अलग संभालती है। सबसे सामान्य लोड कमांड हैं: LC_SEGMENT_64
, LC_LOAD_DYLINKER
, LC_MAIN
, LC_LOAD_DYLIB
, और LC_CODE_SIGNATURE
।
LC_SEGMENT/LC_SEGMENT_64
मूल रूप से, इस प्रकार के लोड कमांड कैसे __TEXT (कार्यात्मक कोड) और __DATA (प्रक्रिया के लिए डेटा) सेगमेंट को डेटा सेक्शन में दिखाए गए ऑफसेट के अनुसार बाइनरी को निष्पादित किया जाएगा।
ये कमांड सेगमेंट को परिभाषित करते हैं जो एक प्रक्रिया के वर्चुअल मेमोरी स्पेस में मैप किए जाते हैं जब यह निष्पादित होता है।
विभिन्न प्रकार के सेगमेंट होते हैं, जैसे __TEXT सेगमेंट, जो किसी प्रोग्राम के कार्यात्मक कोड को धारित करता है, और __DATA सेगमेंट, जो प्रक्रिया द्वारा उपयोग किए जाने वाले डेटा को समेतता है। ये सेगमेंट डेटा सेक्शन में स्थित होते हैं Mach-O फ़ाइल में।
प्रत्येक सेगमेंट को और भी विभाजित किया जा सकता है मल्टीपल सेक्शन में। लोड कमांड संरचना में जानकारी होती है इन सेक्शन्स के बारे में अपने संबंधित सेगमेंट के भीतर।
हेडर में पहले आपको सेगमेंट हेडर मिलता है:
सेगमेंट हेडर का उदाहरण:
यह हेडर उन सेक्शनों की संख्या को परिभाषित करता है जिनके हेडर इसके बाद दिखाई देते हैं:
उदाहरण का खंड शीर्षक:
यदि आप खंड ऑफसेट (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 को स्थिर नहीं माना जाता है (लेखन अनुमतियाँ), न ही अन्य पॉइंटर और गोट। यह खंड__const
, कुछ प्रारंभकर्ताओं और गोट टेबल (एक बार सुलझाया गया) को केवल पढ़ने योग्य बनाने के लिएmprotect
का उपयोग करता है।__LINKEDIT
: लिंकर (डायल्ड) के लिए जानकारी शामिल है जैसे, सिम्बल, स्ट्रिंग, और स्थानांतरण तालिका प्रविष्टियाँ। यह__TEXT
या__DATA
में नहीं है और इसकी सामग्री को अन्य लोड कमांड में वर्णित किया गया है।डायल्ड जानकारी: Rebase, Non-lazy/lazy/weak binding opcodes और export info
फ़ंक्शन शुरू होते हैं: फ़ंक्शनों के प्रारंभ पतों की तालिका
कोड में डेटा: __text में डेटा आइलैंड्स
सिम्बल टेबल: बाइनरी में सिम्बल्स
इंडायरेक्ट सिम्बल टेबल: पॉइंटर/स्टब सिम्बल्स
स्ट्रिंग टेबल
कोड हस्ताक्षर
__OBJC
: वस्तु-सी रनटाइम द्वारा उपयोग की जाने वाली जानकारी शामिल है। हालांकि यह जानकारी __DATA सेगमेंट में भी पाई जा सकती है, विभिन्न __objc_* खंडों में।__RESTRICT
: एक सेगमेंट जिसमें सामग्री नहीं है और एक ही खंड है जिसका नाम है__restrict
(भी खाली) जो सुनिश्चित करता है कि बाइनरी को चलाते समय, यह DYLD पर्यावरणीय चरों को नजरअंदाज करेगा।
जैसा कि कोड में देखा जा सका, सेगमेंट भी ध्वज समर्थन करते हैं (हालांकि वे बहुत अधिक उपयोग नहीं होते):
SG_HIGHVM
: केवल कोर (उपयोग नहीं होता)SG_FVMLIB
: उपयोग नहीं होताSG_NORELOC
: सेगमेंट में कोई स्थानांतरण नहीं हैSG_PROTECTED_VERSION_1
: एन्क्रिप्शन। उदाहरण के लिए Finder द्वारा पाठ__TEXT
सेगमेंट को एन्क्रिप्ट करने के लिए उपयोग किया जाता है।
LC_UNIXTHREAD/LC_MAIN
LC_UNIXTHREAD/LC_MAIN
LC_MAIN
में entryoff विशेषता में प्रवेश बिंदु होता है। लोड समय पर, dyld बस (मेमोरी में) के बेस में इस मान को जोड़ता है, फिर इस निर्देशिका पर जाकर बाइनरी कोड का निष्पादन शुरू करने के लिए उछलता है।
LC_UNIXTHREAD
में मान होते हैं जिन्हें प्रमुख धागा शुरू करते समय रजिस्टरों में होना चाहिए। यह पहले से ही प्रायोगिक हो गया है लेकिन dyld
अभी भी इसका उपयोग करता है। इसके साथ इस द्वारा सेट किए गए रजिस्टरों के मानों को देखना संभव है:
LC_CODE_SIGNATURE
LC_CODE_SIGNATURE
में Macho-O फ़ाइल के कोड हस्ताक्षर के बारे में जानकारी होती है। यह केवल एक ओफ़्सेट शामिल करता है जो हस्ताक्षर ब्लॉब की ओर पहुंचता है। यह आम तौर पर फ़ाइल के अंत में होता है। हालांकि, आप इस खंड के बारे में कुछ जानकारी इस ब्लॉग पोस्ट और इस गिस्ट में पा सकते हैं।
LC_ENCRYPTION_INFO[_64]
LC_ENCRYPTION_INFO[_64]
बाइनरी एन्क्रिप्शन का समर्थन। हालांकि, यदि कोई हमलावर प्रक्रिया को कंप्रमाइज करने में सफल होता है, तो वह यादृच्छिक रूप से मेमोरी को अनएन्क्रिप्ट कर सकेगा।
LC_LOAD_DYLINKER
LC_LOAD_DYLINKER
डायनामिक लिंकर एक्जीक्यूटेबल का पथ शामिल है जो साझा लाइब्रेरी को प्रक्रिया पता स्थान में मैप करता है। मान हमेशा /usr/lib/dyld
पर सेट किया जाता है। यह महत्वपूर्ण है कि macOS में, dylib मैपिंग उपयोगकर्ता मोड में होती है, कर्नेल मोड में नहीं।
LC_IDENT
LC_IDENT
पुराना है लेकिन जब पैनिक पर डंप जेनरेट करने के लिए कॉन्फ़िगर किया जाता है, तो एक Mach-O कोर डंप बनाया जाता है और कर्नेल संस्करण LC_IDENT
कमांड में सेट किया जाता है।
LC_UUID
LC_UUID
रैंडम UUID। यह किसी काम के लिए सीधे उपयोगी नहीं है लेकिन XNU इसे प्रक्रिया जानकारी के बाकी साथ कैश करता है। यह क्रैश रिपोर्ट में उपयोग किया जा सकता है।
LC_DYLD_ENVIRONMENT
LC_DYLD_ENVIRONMENT
प्रक्रिया के ठीक पहले dyld को पर्यावरण चरों को सूचित करने की अनुमति देता है। यह बहुत ही खतरनाक हो सकता है क्योंकि यह प्रक्रिया के अंदर विचारशील कोड को निष्पादित करने की अनुमति दे सकता है, इसलिए यह लोड कमांड केवल #define SUPPORT_LC_DYLD_ENVIRONMENT
के साथ डायल्ड बिल्ड में उपयोग किया जाता है और आगे संविदान केवल DYLD_..._PATH
रूप के चरों के लिए प्रसंस्करण को प्रतिबंधित करता है।
LC_LOAD_DYLIB
LC_LOAD_DYLIB
यह लोड कमांड एक डायनामिक लाइब्रेरी आवश्यकता का वर्णन करता है जो लोडर (dyld) को उस लाइब्रेरी को लोड और लिंक करने के लिए निर्देशित करता है। Mach-O बाइनरी के प्रत्येक लाइब्रेरी के लिए एक LC_LOAD_DYLIB
लोड कमांड होता है।
यह लोड कमांड एक प्रकार की संरचना है
dylib_command
(जिसमें वास्तविक निर्भर डायनामिक लाइब्रेरी का वर्णन करने वाला संरचना dylib होता है):
आप इस जानकारी को cli से भी प्राप्त कर सकते हैं:
कुछ संभावित मैलवेयर संबंधित लाइब्रेरीज हैं:
DiskArbitration: USB ड्राइव की मॉनिटरिंग
AVFoundation: ऑडियो और वीडियो कैप्चर
CoreWLAN: वाईफाई स्कैन।
एक Mach-O बाइनरी में एक या एक से अधिक निर्माताओं हो सकते हैं, जो LC_MAIN में निर्दिष्ट पते से पहले क्रियान्वित होंगे। किसी भी निर्माताओं के offsets को __DATA_CONST सेगमेंट के __mod_init_func खंड में रखा जाता है।
Mach-O डेटा
फ़ाइल के मूल में डेटा क्षेत्र है, जो लोड-कमांड्स क्षेत्र में परिभाषित कई सेगमेंटों से बना होता है। प्रत्येक सेगमेंट में कई डेटा खंड हो सकते हैं, हर खंड कोड या डेटा विशिष्ट एक प्रकार के होता है।
डेटा मुख्य रूप से उस सभी जानकारी को समेटता है जो लोड कमांड्स LC_SEGMENTS_64 द्वारा लोड की जाती है।
इसमें शामिल हैं:
कार्य सारणी: जो कार्य के बारे में जानकारी रखती है।
प्रतीक सारणी: जो बाइनरी द्वारा उपयोग की गई बाह्य कार्य के बारे में जानकारी रखती है
यह आंतरिक कार्य, चर नामों को भी शामिल कर सकता है और अधिक।
इसे जांचने के लिए आप Mach-O View टूल का उपयोग कर सकते हैं:
या CLI से:
Last updated