
macOS डिबगर एंटाइटलमेंट्स और DYLD_INSERT_LIBRARIES का दुरुपयोग करके किसी चालू प्रक्रिया की मेमोरी को डंप या खोजता है, साथ ही EDR एट्रिब्यूशन को हस्ताक्षरित हेल्पर बाइनरी पर स्थानांतरित करता है।
memdumper किसी चल रही macOS प्रक्रिया की मेमोरी को किसी अन्य हस्ताक्षरित बाइनरी के डिबगर एन्टाइटलमेंट के अंतर्गत पढ़ता है। उद्देश्य यह है कि task_for_pid और ptrace उस एन्टाइटल्ड बाइनरी के रूप में चलें, ताकि EDR उसे रिकॉर्ड करे, न कि memdumper को।
द्वारा cenobyte [email protected] 2026
https://github.com/cenobyte-vincit/memdumper
memdumper एक एन्टाइटल्ड बाइनरी चलाता है जिसमें com.apple.security.cs.debugger और वे दो एन्टाइटलमेंट होते हैं जो DYLD_INSERT_LIBRARIES इंसर्ट की अनुमति देते हैं। इसका उपयोग root के रूप में किसी अन्य प्रक्रिया की मेमोरी खोजने और डंप करने के लिए करें। OpenJDK का jspawnhelper एक आम मिलने वाला बाइनरी है, खासकर डेवलपर मशीनों पर।
attach.sh को एक टारगेट PID और एन्टाइटल्ड बाइनरी दें। dylib कंस्ट्रक्टर उस बाइनरी के main से पहले चलता है, टारगेट पढ़ता है, फिर _exit करता है। एन्टाइटल्ड बाइनरी कभी main तक नहीं पहुँचती, इसलिए jspawnhelper जैसा हेल्पर अपना उपयोग बैनर नहीं छापता। एन्टाइटल्ड बाइनरी के बाद के अतिरिक्त तर्क कमांड लाइन पर बने रहते हैं, जिसे EDR रिकॉर्ड करता है। -s के बिना dylib प्रत्येक पठनीय क्षेत्र की शुरुआत का हेक्स-डंप करता है। -s के साथ वह उन क्षेत्रों में स्ट्रिंग खोजता है। टारगेट एड्रेस स्पेस में कुछ नहीं लिखा जाता। ptrace अटैच टारगेट को संक्षेप में रोक सकता है।
डंप की स्थिति मर्ज किए गए आउटपुट पर [RESULT] लाइन होती है। सफल इंसर्ट के बाद कंस्ट्रक्टर समाप्त होते ही एग्ज़िट 0 होता है।
com.apple.security.cs.debugger, com.apple.security.cs.allow-dyld-environment-variables और com.apple.security.cs.disable-library-validation (उदाहरण के लिए OpenJDK का jspawnhelper)clangmakeattach.sh और टेस्ट स्क्रिप्ट्स के लिए (brew install shellcheck)brew install cppcheck)बिल्ड होस्ट पर:
make
यह memdumper.dylib बनाता है। यदि मशीनें अलग हैं तो attach.sh और memdumper.dylib को टारगेट पर कॉपी करें।
memdumper.dylib वाली निर्देशिका से root के रूप में attach.sh चलाएँ। गैर-root कॉलर को एन्टाइटल्ड बाइनरी शुरू होने से पहले ही अस्वीकार कर दिया जाता है (root required)। इससे Developer Tool Access पासवर्ड डायलॉग (taskgated / Authorization Services) से बचा जाता है। वह डायलॉग Transparency, Consent, and Control (TCC) नहीं है।
sudo ./attach.sh [options] -p <pid> <entitled-binary> [args...]
| विकल्प | अर्थ |
|---|---|
-p, --pid PID | टारगेट प्रक्रिया ID (आवश्यक) |
-s, --search STRING | पठनीय क्षेत्रों में STRING खोजें |
-n, --max-regions N | हेक्स-डंप के लिए अधिकतम पठनीय क्षेत्र (डिफ़ॉल्ट 100)। केवल डंप पथ में |
-f, --force | जब codesign Hardened Runtime रिपोर्ट करे तब भी जारी रखें |
-h, --help | उपयोग प्रिंट करें (एग्ज़िट 1) |
पुष्टि करें कि किसी उम्मीदवार एन्टाइटल्ड बाइनरी में तीनों एन्टाइटलमेंट हैं। Cellar प्रीफ़िक्स और OpenJDK संस्करण अलग-अलग होते हैं; attach.sh अपनी हेल्प में यह लेआउट उपयोग करता है:
codesign -d --entitlements - \
/opt/homebrew/Cellar/openjdk/25.0.2/libexec/openjdk.jdk/Contents/Home/lib/jspawnhelper
PID 4543 के पठनीय क्षेत्र डंप करें:
sudo ./attach.sh -p 4543 \
/opt/homebrew/Cellar/openjdk/25.0.2/libexec/openjdk.jdk/Contents/Home/lib/jspawnhelper
उस प्रक्रिया में HELLO खोजें:
sudo ./attach.sh -s HELLO -p 4543 \
/opt/homebrew/Cellar/openjdk/25.0.2/libexec/openjdk.jdk/Contents/Home/lib/jspawnhelper
डंप को 50 पठनीय क्षेत्रों तक सीमित करें, java को एन्टाइटल्ड बाइनरी के रूप में उपयोग करते हुए। TestSpawn कमांड लाइन पर रहता है; java का main नहीं चलता:
sudo ./attach.sh -n 50 -p 4543 \
/opt/homebrew/Cellar/openjdk/25.0.2/bin/java TestSpawn
बिना Hardened Runtime वाला एडिटर एक काम करने योग्य स्मोक टारगेट है। इसे उस उपयोगकर्ता के रूप में शुरू करें जो बफ़र का स्वामी है, फिर root के रूप में अटैच करें। एक टर्मिनल में:
nano foo
HELLO को बफ़र में डालें ताकि स्ट्रिंग प्रक्रिया में रहे (फ़ाइल लिखें या बिना सहेजे छोड़ दें)। दूसरे टर्मिनल में, memdumper.dylib रखने वाली निर्देशिका से:
sudo ./attach.sh -s HELLO -p "$(pgrep nano)" \
/opt/homebrew/Cellar/openjdk/25.0.2/libexec/openjdk.jdk/Contents/Home/lib/jspawnhelper
हिट कुछ इस तरह दिखता है। उसके बाद प्रक्रिया एग्ज़िट 0 करती है:
Target: pid 9810 (nano)
Target has no hardened runtime
[MEMDUMPER] Injected into PID 9852 (UID 0)
[MEMDUMPER] Entitled binary: /opt/homebrew/Cellar/openjdk/25.0.2/libexec/openjdk.jdk/Contents/Home/lib/jspawnhelper
[MEMDUMPER] Target: PID 9810 (nano)
[METHOD1] task_for_pid() on PID 9810 (nano)
[*] Got task port 0x1013
[*] Task info: virt=425098.0MB res=8.3MB
[*] Threads: 1
[MEMORY SEARCH] Looking for "HELLO" in PID 9810
MATCH at 0xa70c60200 (region: 0xa70c00000-0xa71000000, prot: rw-)
Context:
0x0000000a70c601c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
0x0000000a70c601d0: 4f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |O...............|
0x0000000a70c601e0: 23 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |#...............|
0x0000000a70c601f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
0x0000000a70c60200: 48 45 4c 4c 4f 00 00 00 00 00 00 00 00 00 00 00 |HELLO...........|
0x0000000a70c60210: 66 6f 6f 00 00 00 00 00 00 00 00 00 00 00 00 00 |foo.............|
0x0000000a70c60220: 6f d9 b9 83 27 dc 6a ec 00 04 00 00 00 00 00 00 |o...'.j.........|
0x0000000a70c60230: 48 45 4c 4c 4f 00 00 00 00 00 00 00 00 00 00 00 |HELLO...........|
0x0000000a70c60240: 2e 2f 00 00 00 |./...|
MATCH at 0xa70c60230 (region: 0xa70c00000-0xa71000000, prot: rw-)
Context:
0x0000000a70c601f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
0x0000000a70c60200: 48 45 4c 4c 4f 00 00 00 00 00 00 00 00 00 00 00 |HELLO...........|
0x0000000a70c60210: 66 6f 6f 00 00 00 00 00 00 00 00 00 00 00 00 00 |foo.............|
0x0000000a70c60220: 6f d9 b9 83 27 dc 6a ec 00 04 00 00 00 00 00 00 |o...'.j.........|
0x0000000a70c60230: 48 45 4c 4c 4f 00 00 00 00 00 00 00 00 00 00 00 |HELLO...........|
0x0000000a70c60240: 2e 2f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |./..............|
0x0000000a70c60250: 66 6f 6f 00 00 00 00 00 00 00 00 00 00 00 00 00 |foo.............|
0x0000000a70c60260: 2f d9 b9 83 27 dc 6a ec 22 90 00 00 00 00 00 00 |/...'.j.".......|
0x0000000a70c60270: 00 00 00 00 00 |.....|
Search complete: 2 matches found in 70 regions
[METHOD2] ptrace(PT_ATTACHEXC) on PID 9810 (nano)
[*] Attached with ptrace
[*] Detached successfully
[METHOD3] proc_pidinfo() on PID 9810 (nano)
[*] Process info: virt=425098MB res=8MB threads=1
[RESULT] 3/3 methods successful - FULL ACCESS
[MEMDUMPER] Done
attach.sh एन्टाइटल्ड बाइनरी के एन्टाइटलमेंट की जाँच नहीं करता। तीनों में से कोई भी एन्टाइटलमेंट गायब होने पर बाइनरी इंसर्ट के समय या task_for_pid पर विफल हो जाती है।
| कोड | अर्थ |
|---|---|
| 0 | सफल इंसर्ट के बाद कंस्ट्रक्टर समाप्त हुआ |
| 1 | उपयोग त्रुटि, root नहीं है, वर्तमान निर्देशिका में memdumper.dylib नहीं है, -p गायब है, टारगेट PID नहीं मिला, --force के बिना Hardened Runtime, या इंसर्ट नहीं हुआ (फिर एन्टाइटल्ड बाइनरी चली और गैर-शून्य एग्ज़िट हुई) |
डंप परिणाम के लिए [RESULT] पढ़ें। एग्ज़िट 0 केवल यह दर्शाता है कि कंस्ट्रक्टर चला और उसने _exit किया।
dylib तीन पर्यावरण चर पढ़ता है। attach.sh उन्हें फ़्लैग्स से सेट करता है।
| वेरिएबल | द्वारा सेट | अर्थ |
|---|---|---|
MEMDUMPER_TARGET_PID | -p | टारगेट PID। यदि सेट न हो या धनात्मक पूर्णांक न हो, तो कंस्ट्रक्टर एक डायग्नोस्टिक प्रिंट करके लौट जाता है |
MEMDUMPER_SEARCH | -s | यदि खाली नहीं है, तो डंप के बजाय खोजें |
MEMDUMPER_MAX_REGIONS | -n | हेक्स-डंप करने योग्य पठनीय क्षेत्र (डिफ़ॉल्ट 100)। खोज पथ पर अनदेखा किया जाता है |