macOS Universal binaries & Mach-O Format
Last updated
Last updated
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (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
: "प्लगइन फ़ाइलें"। gcc में -bundle का उपयोग करके उत्पन्न और NSBundle
या dlopen
द्वारा स्पष्ट रूप से लोड की गई।
MH_DYSM
: साथी .dSym
फ़ाइल (डिबगिंग के लिए प्रतीकों के साथ फ़ाइल)।
MH_KEXT_BUNDLE
: कर्नेल एक्सटेंशन।
Or using Mach-O View:
स्रोत कोड कई ध्वजों को परिभाषित करता है जो पुस्तकालयों को लोड करने के लिए उपयोगी हैं:
MH_NOUNDEFS
: कोई अपरिभाषित संदर्भ नहीं (पूर्ण रूप से लिंक किया गया)
MH_DYLDLINK
: Dyld लिंकिंग
MH_PREBOUND
: गतिशील संदर्भ पूर्व बंधित।
MH_SPLIT_SEGS
: फ़ाइल r/o और r/w खंडों में विभाजित होती है।
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
: बाइनरी में oBject-C अनुभाग हैं
MH_SIM_SUPPORT
: सिम्युलेटर समर्थन
MH_DYLIB_IN_CACHE
: साझा पुस्तकालय कैश में dylibs/फ्रेमवर्क पर उपयोग किया गया।
फाइल का लेआउट मेमोरी में यहाँ निर्दिष्ट किया गया है, जो प्रतीक तालिका के स्थान, निष्पादन प्रारंभ पर मुख्य थ्रेड का संदर्भ, और आवश्यक साझा पुस्तकालयों का विवरण देता है। गतिशील लोडर (dyld) को बाइनरी के मेमोरी में लोडिंग प्रक्रिया के लिए निर्देश दिए जाते हैं।
यह load_command संरचना का उपयोग करता है, जिसे उल्लेखित loader.h
में परिभाषित किया गया है:
There are about 50 different types of load commands that the system handles differently. The most common ones are: LC_SEGMENT_64
, LC_LOAD_DYLINKER
, LC_MAIN
, LC_LOAD_DYLIB
, and LC_CODE_SIGNATURE
.
बुनियादी रूप से, इस प्रकार के लोड कमांड कैसे __TEXT (कार्यकारी कोड) और __DATA (प्रक्रिया के लिए डेटा) सेगमेंट को लोड करना है यह परिभाषित करते हैं, जो बाइनरी के निष्पादन के समय डेटा अनुभाग में निर्दिष्ट ऑफ़सेट के अनुसार होता है।
ये कमांड सेगमेंट को परिभाषित करते हैं जो प्रक्रिया के निष्पादन के समय इसके आभासी मेमोरी स्पेस में मैप होते हैं।
सेगमेंट के विभिन्न प्रकार होते हैं, जैसे कि __TEXT सेगमेंट, जो एक प्रोग्राम के कार्यकारी कोड को रखता है, और __DATA सेगमेंट, जो प्रक्रिया द्वारा उपयोग किए जाने वाले डेटा को शामिल करता है। ये सेगमेंट Mach-O फ़ाइल के डेटा अनुभाग में स्थित होते हैं।
प्रत्येक सेगमेंट को आगे कई अनुभागों में विभाजित किया जा सकता है। लोड कमांड संरचना में इन अनुभागों के बारे में जानकारी होती है जो संबंधित सेगमेंट के भीतर होती है।
हेडर में पहले आपको सेगमेंट हेडर मिलता है:
Example of segment header:
This header defines the number of sections whose headers appear after it:
उदाहरण अनुभाग शीर्षक का:
यदि आप अनुभाग ऑफ़सेट (0x37DC) + ऑफ़सेट जहां आर्क शुरू होता है, इस मामले में 0x18000
--> 0x37DC + 0x18000 = 0x1B7DC
जोड़ते हैं
यह कमांड लाइन से हेडर जानकारी प्राप्त करना भी संभव है:
Common segments loaded by this 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 को स्थायी होने की गारंटी नहीं है (लिखने की अनुमति), न ही अन्य पॉइंटर्स और GOT। यह अनुभाग __const
, कुछ प्रारंभिक और GOT तालिका (एक बार हल होने पर) को केवल पढ़ने योग्य बनाता है mprotect
का उपयोग करके।
__LINKEDIT
: इसमें लिंकर्स (dyld) के लिए जानकारी होती है जैसे, प्रतीक, स्ट्रिंग, और पुनर्स्थापन तालिका प्रविष्टियाँ। यह __TEXT
या __DATA
में न होने वाली सामग्री के लिए एक सामान्य कंटेनर है और इसकी सामग्री अन्य लोड कमांड में वर्णित है।
dyld जानकारी: रीबेस, गैर-आलसी/आलसी/कमजोर बाइंडिंग ऑपकोड और निर्यात जानकारी
फ़ंक्शंस प्रारंभ: फ़ंक्शंस के प्रारंभ पते की तालिका
कोड में डेटा: __text में डेटा द्वीप
प्रतीक तालिका: बाइनरी में प्रतीक
अप्रत्यक्ष प्रतीक तालिका: पॉइंटर/स्टब प्रतीक
स्ट्रिंग तालिका
कोड सिग्नेचर
__OBJC
: इसमें ऑब्जेक्टिव-सी रनटाइम द्वारा उपयोग की जाने वाली जानकारी होती है। हालांकि यह जानकारी __DATA खंड में भी पाई जा सकती है, विभिन्न __objc_* अनुभागों के भीतर।
__RESTRICT
: एक ऐसा खंड जिसमें सामग्री नहीं होती है जिसमें एकल अनुभाग होता है जिसे __restrict
(भी खाली) कहा जाता है जो सुनिश्चित करता है कि बाइनरी चलाते समय, यह DYLD पर्यावरणीय चर को अनदेखा करेगा।
जैसा कि कोड में देखा जा सकता है, खंड भी फ़्लैग का समर्थन करते हैं (हालांकि उनका बहुत अधिक उपयोग नहीं किया जाता):
SG_HIGHVM
: केवल कोर (उपयोग नहीं किया गया)
SG_FVMLIB
: उपयोग नहीं किया गया
SG_NORELOC
: खंड में कोई पुनर्स्थापन नहीं है
SG_PROTECTED_VERSION_1
: एन्क्रिप्शन। उदाहरण के लिए Finder द्वारा __TEXT
खंड के पाठ को एन्क्रिप्ट करने के लिए उपयोग किया जाता है।
LC_UNIXTHREAD/LC_MAIN
LC_MAIN
में entryoff विशेषता में प्रवेश बिंदु होता है। लोड समय पर, dyld बस इस मान को (मेमोरी में) बाइनरी के आधार में जोड़ता है, फिर इस निर्देश पर कूदता है ताकि बाइनरी के कोड का निष्पादन शुरू हो सके।
LC_UNIXTHREAD
में वे मान होते हैं जो रजिस्टर को मुख्य धागा शुरू करते समय होना चाहिए। इसे पहले ही अमान्य कर दिया गया था लेकिन dyld
अभी भी इसका उपयोग करता है। इसके द्वारा सेट किए गए रजिस्टर के मानों को देखना संभव है:
LC_CODE_SIGNATURE
इसमें Macho-O फ़ाइल के कोड सिग्नेचर के बारे में जानकारी होती है। इसमें केवल एक ऑफसेट होता है जो सिग्नेचर ब्लॉब की ओर संकेत करता है। यह आमतौर पर फ़ाइल के अंत में होता है। हालांकि, आप इस अनुभाग के बारे में कुछ जानकारी इस ब्लॉग पोस्ट और इस gists में पा सकते हैं।
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 निर्माण में उपयोग किया जाता है और केवल DYLD_..._PATH
के रूप के चर को लोड पथ निर्दिष्ट करने के लिए आगे संसाधित करता है।
LC_LOAD_DYLIB
यह लोड कमांड एक डायनामिक लाइब्रेरी निर्भरता का वर्णन करता है जो लोडर (dyld) को कहा गया लाइब्रेरी लोड और लिंक करने के लिए निर्देश देता है। Mach-O बाइनरी के लिए आवश्यक प्रत्येक लाइब्रेरी के लिए एक LC_LOAD_DYLIB
लोड कमांड होता है।
यह लोड कमांड dylib_command
प्रकार की संरचना है (जिसमें एक संरचना dylib होती है, जो वास्तविक निर्भर डायनामिक लाइब्रेरी का वर्णन करती है):
आप इस जानकारी को CLI से भी प्राप्त कर सकते हैं:
कुछ संभावित मैलवेयर से संबंधित पुस्तकालय हैं:
DiskArbitration: USB ड्राइव की निगरानी
AVFoundation: ऑडियो और वीडियो कैप्चर
CoreWLAN: वाईफाई स्कैन।
एक Mach-O बाइनरी में एक या अधिक कंस्ट्रक्टर्स हो सकते हैं, जिन्हें LC_MAIN में निर्दिष्ट पते से पहले निष्पादित किया जाएगा। किसी भी कंस्ट्रक्टर के ऑफसेट __mod_init_func अनुभाग में __DATA_CONST खंड में रखे जाते हैं।
फाइल के मूल में डेटा क्षेत्र है, जो लोड-कमांड क्षेत्र में परिभाषित कई खंडों से बना है। प्रत्येक खंड के भीतर विभिन्न प्रकार के डेटा अनुभाग हो सकते हैं, प्रत्येक अनुभाग में कोड या डेटा होता है जो एक प्रकार के लिए विशिष्ट होता है।
डेटा मूल रूप से उस भाग को संदर्भित करता है जिसमें सभी जानकारी होती है जो लोड कमांड LC_SEGMENTS_64 द्वारा लोड की जाती है।
इसमें शामिल हैं:
फंक्शन टेबल: जो प्रोग्राम फंक्शंस के बारे में जानकारी रखती है।
सिंबॉल टेबल: जो बाइनरी द्वारा उपयोग किए जाने वाले बाहरी फंक्शन के बारे में जानकारी रखती है
इसमें आंतरिक फंक्शन, वेरिएबल नाम भी हो सकते हैं और भी बहुत कुछ।
इसे जांचने के लिए आप Mach-O View टूल का उपयोग कर सकते हैं:
या CLI से:
In __TEXT
segment (r-x):
__objc_classname
: क्लास नाम (स्ट्रिंग)
__objc_methname
: मेथड नाम (स्ट्रिंग)
__objc_methtype
: मेथड प्रकार (स्ट्रिंग)
In __DATA
segment (rw-):
__objc_classlist
: सभी Objetive-C क्लासेस के लिए पॉइंटर्स
__objc_nlclslist
: नॉन-लेज़ी ऑब्जेक्टिव-C क्लासेस के लिए पॉइंटर्स
__objc_catlist
: श्रेणियों के लिए पॉइंटर
__objc_nlcatlist
: नॉन-लेज़ी श्रेणियों के लिए पॉइंटर
__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
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)