Introduction to ARM64v8
Last updated
Last updated
AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE) GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE)
ARMv8 आर्किटेक्चर में, निष्पादन स्तर, जिसे अपवाद स्तर (ELs) के रूप में जाना जाता है, निष्पादन वातावरण के विशेषाधिकार स्तर और क्षमताओं को परिभाषित करता है। चार अपवाद स्तर हैं, जो EL0 से EL3 तक फैले हुए हैं, प्रत्येक का एक अलग उद्देश्य है:
EL0 - उपयोगकर्ता मोड:
यह सबसे कम विशेषाधिकार स्तर है और नियमित एप्लिकेशन कोड निष्पादित करने के लिए उपयोग किया जाता है।
EL0 पर चलने वाले एप्लिकेशन एक-दूसरे और सिस्टम सॉफ़्टवेयर से अलग होते हैं, जिससे सुरक्षा और स्थिरता बढ़ती है।
EL1 - ऑपरेटिंग सिस्टम कर्नेल मोड:
अधिकांश ऑपरेटिंग सिस्टम कर्नेल इस स्तर पर चलते हैं।
EL1 के पास EL0 की तुलना में अधिक विशेषाधिकार होते हैं और यह सिस्टम संसाधनों तक पहुँच सकता है, लेकिन सिस्टम की अखंडता सुनिश्चित करने के लिए कुछ प्रतिबंधों के साथ।
EL2 - हाइपरवाइजर मोड:
यह स्तर वर्चुअलाइजेशन के लिए उपयोग किया जाता है। EL2 पर चलने वाला एक हाइपरवाइजर एक ही भौतिक हार्डवेयर पर कई ऑपरेटिंग सिस्टम (प्रत्येक अपने EL1 में) का प्रबंधन कर सकता है।
EL2 वर्चुअलाइज्ड वातावरण के लिए अलगाव और नियंत्रण की सुविधाएँ प्रदान करता है।
EL3 - सुरक्षित मॉनिटर मोड:
यह सबसे अधिक विशेषाधिकार स्तर है और अक्सर सुरक्षित बूटिंग और विश्वसनीय निष्पादन वातावरण के लिए उपयोग किया जाता है।
EL3 सुरक्षित और गैर-सुरक्षित राज्यों (जैसे सुरक्षित बूट, विश्वसनीय OS, आदि) के बीच पहुँच को प्रबंधित और नियंत्रित कर सकता है।
इन स्तरों का उपयोग विभिन्न सिस्टम पहलुओं को प्रबंधित करने के लिए एक संरचित और सुरक्षित तरीके की अनुमति देता है, उपयोगकर्ता एप्लिकेशन से लेकर सबसे विशेषाधिकार प्राप्त सिस्टम सॉफ़्टवेयर तक। ARMv8 का विशेषाधिकार स्तरों के प्रति दृष्टिकोण विभिन्न सिस्टम घटकों को प्रभावी ढंग से अलग करने में मदद करता है, जिससे सिस्टम की सुरक्षा और मजबूती बढ़ती है।
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-बिट संस्करण हैं।
इसके अलावा, 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 में कई प्रक्रिया घटक होते हैं जो ऑपरेटिंग-सिस्टम-दृश्यमान SPSR_ELx
विशेष रजिस्टर में अनुक्रमित होते हैं, X वह अनुमति स्तर है जिस पर अपवाद उत्पन्न होता है (यह अपवाद समाप्त होने पर प्रक्रिया की स्थिति को पुनर्प्राप्त करने की अनुमति देता है)।
ये सुलभ क्षेत्र हैं:
N
, Z
, C
और V
स्थिति ध्वज:
N
का अर्थ है कि ऑपरेशन ने नकारात्मक परिणाम दिया
Z
का अर्थ है कि ऑपरेशन ने शून्य दिया
C
का अर्थ है कि ऑपरेशन ने कैरी किया
V
का अर्थ है कि ऑपरेशन ने साइन ओवरफ्लो दिया:
दो सकारात्मक संख्याओं का योग नकारात्मक परिणाम देता है।
दो नकारात्मक संख्याओं का योग सकारात्मक परिणाम देता है।
घटाव में, जब एक बड़ा नकारात्मक संख्या एक छोटे सकारात्मक संख्या (या इसके विपरीत) से घटाई जाती है, और परिणाम को दिए गए बिट आकार की सीमा के भीतर प्रदर्शित नहीं किया जा सकता है।
स्पष्ट रूप से प्रोसेसर नहीं जानता कि ऑपरेशन साइन किया गया है या नहीं, इसलिए यह ऑपरेशनों में C और V की जांच करेगा और संकेत देगा कि यदि यह साइन किया गया था या असाइन किया गया था तो कैरी हुआ।
सभी निर्देश इन ध्वजों को अपडेट नहीं करते हैं। कुछ जैसे 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 से नहीं किया जा सकता है।
ARM64 कॉलिंग कन्वेंशन निर्दिष्ट करता है कि एक फ़ंक्शन के लिए पहले आठ पैरामीटर रजिस्टर x0
से x7
में पास किए जाते हैं। अतिरिक्त पैरामीटर स्टैक पर पास किए जाते हैं। रिटर्न मान रजिस्टर x0
में वापस पास किया जाता है, या x1
में भी यदि यह 128 बिट लंबा है। x19
से x30
और sp
रजिस्टर को फ़ंक्शन कॉल के बीच संरक्षित किया जाना चाहिए।
जब असेंबली में एक फ़ंक्शन पढ़ते हैं, तो फ़ंक्शन प्रस्तावना और उपसंहार की तलाश करें। प्रस्तावना आमतौर पर फ्रेम पॉइंटर (x29
) को सहेजने, नए फ्रेम पॉइंटर को सेट करने, और स्टैक स्पेस आवंटित करने में शामिल होती है। उपसंहार आमतौर पर सहेजे गए फ्रेम पॉइंटर को पुनर्स्थापित करने और फ़ंक्शन से लौटने में शामिल होता है।
स्विफ्ट में अपनी कॉलिंग कन्वेंशन है जिसे https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst#arm64 में पाया जा सकता है।
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 x29, sp
(वर्तमान फ़ंक्शन के लिए नए फ्रेम पॉइंटर को सेट करता है)
स्थानीय चर के लिए स्टैक पर स्थान आवंटित करें (यदि आवश्यक हो): sub sp, sp, <size>
(जहाँ <size>
आवश्यक बाइट्स की संख्या है)
स्थानीय चर को डिआलोकट करें (यदि कोई आवंटित किया गया हो): add sp, sp, <size>
लिंक रजिस्टर और फ्रेम पॉइंटर को पुनर्स्थापित करें:
Return: ret
(कॉलर को लिंक रजिस्टर में पते का उपयोग करके नियंत्रण लौटाता है)
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
में संक्रमण कर सके, जो CPSR** के आधार पर A32 या T32 में प्रवेश करता है।**
interworking
CPSR के J और T बिट्स का उपयोग करके होता है। J=0
और T=0
का अर्थ है A32
और J=0
और T=1
का अर्थ है T32। यह मूल रूप से सबसे निचले बिट को 1 पर सेट करने का संकेत देता है कि निर्देश सेट T32 है।
यह interworking शाखा निर्देशों के दौरान सेट किया जाता है, लेकिन जब PC को गंतव्य रजिस्टर के रूप में सेट किया जाता है तो इसे अन्य निर्देशों के साथ सीधे भी सेट किया जा सकता है। उदाहरण:
एक और उदाहरण:
16 32-बिट रजिस्टर हैं (r0-r15)। r0 से r14 का उपयोग किसी भी ऑपरेशन के लिए किया जा सकता है, हालाँकि इनमें से कुछ आमतौर पर आरक्षित होते हैं:
r15
: प्रोग्राम काउंटर (हमेशा)। अगले निर्देश का पता रखता है। A32 में वर्तमान + 8, T32 में, वर्तमान + 4।
r11
: फ्रेम पॉइंटर
r12
: इंट्रा-प्रोसीजरल कॉल रजिस्टर
r13
: स्टैक पॉइंटर
r14
: लिंक रजिस्टर
इसके अलावा, रजिस्टर बैंक्ड रजिस्ट्रियों
में बैकअप होते हैं। ये ऐसे स्थान हैं जो रजिस्टर के मानों को संग्रहीत करते हैं जिससे तेज़ संदर्भ स्विचिंग को सक्षम किया जा सके, अपवाद प्रबंधन और विशेषाधिकार प्राप्त संचालन में, हर बार रजिस्टर को मैन्युअल रूप से सहेजने और पुनर्स्थापित करने की आवश्यकता से बचने के लिए।
यह CPSR
से प्रोसेसर मोड के SPSR
में प्रोसेसर स्थिति को सहेजकर किया जाता है, जिस पर अपवाद लिया गया है। अपवाद लौटने पर, CPSR
को SPSR
से पुनर्स्थापित किया जाता है।
AArch32 में CPSR AArch64 में PSTATE
के समान काम करता है और इसे अपवाद लिए जाने पर बाद में निष्पादन को पुनर्स्थापित करने के लिए SPSR_ELx
में भी संग्रहीत किया जाता है:
फील्ड कुछ समूहों में विभाजित हैं:
एप्लिकेशन प्रोग्राम स्थिति रजिस्टर (APSR): अंकगणितीय ध्वज और EL0 से सुलभ
निष्पादन स्थिति रजिस्टर: प्रक्रिया का व्यवहार (OS द्वारा प्रबंधित)।
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 वर्तमान में उपयोग किए जा रहे अपवाद मोड का प्रतिनिधित्व करते हैं (जब कोई अपवाद होता है और इसे संभाला जा रहा है)। सेट किया गया संख्या वर्तमान प्राथमिकता को इंगित करता है यदि इस दौरान कोई अन्य अपवाद उत्पन्न होता है।
AIF
: कुछ अपवादों को A
, I
, F
बिट्स का उपयोग करके अक्षम किया जा सकता है। यदि A
1 है तो इसका मतलब है कि असिंक्रोनस एबॉर्ट्स उत्पन्न होंगे। I
बाहरी हार्डवेयर इंटरप्ट रिक्वेस्ट्स (IRQs) का उत्तर देने के लिए कॉन्फ़िगर करता है। और F फास्ट इंटरप्ट रिक्वेस्ट्स (FIRs) से संबंधित है।
syscalls.master पर जाएं। BSD syscalls में x16 > 0 होगा।
syscall_sw.c में mach_trap_table
और mach_traps.h में प्रोटोटाइप देखें। Mach traps की अधिकतम संख्या MACH_TRAP_TABLE_COUNT
= 128 है। Mach traps में x16 < 0 होगा, इसलिए आपको पिछले सूची से नंबरों को माइनस के साथ कॉल करना होगा: _kernelrpc_mach_vm_allocate_trap
-10
है।
आप libsystem_kernel.dylib
को एक डिस्सेम्बलर में भी देख सकते हैं यह जानने के लिए कि इन (और BSD) syscalls को कैसे कॉल किया जाए:
ध्यान दें कि Ida और Ghidra केवल कैश को पास करके विशिष्ट dylibs को भी डिकंपाइल कर सकते हैं।
कभी-कभी libsystem_kernel.dylib
से डिकंपाइल किया गया कोड जांचना स्रोत कोड की तुलना में आसान होता है क्योंकि कई syscalls (BSD और Mach) का कोड स्क्रिप्ट के माध्यम से उत्पन्न होता है (स्रोत कोड में टिप्पणियाँ देखें) जबकि dylib में आप देख सकते हैं कि क्या कॉल किया जा रहा है।
XNU एक और प्रकार के कॉल का समर्थन करता है जिसे मशीन निर्भर कहा जाता है। इन कॉल की संख्या आर्किटेक्चर पर निर्भर करती है और न तो कॉल और न ही संख्या स्थिर रहने की गारंटी है।
यह एक कर्नेल मालिक मेमोरी पृष्ठ है जो हर उपयोगकर्ता प्रक्रिया के पते के स्केप में मैप किया गया है। इसका उद्देश्य उपयोगकर्ता मोड से कर्नेल स्पेस में संक्रमण को तेज करना है, ताकि कर्नेल सेवाओं के लिए syscalls का उपयोग करने की तुलना में यह संक्रमण बहुत अप्रभावी न हो।
उदाहरण के लिए, कॉल gettimeofdate
सीधे comm पृष्ठ से timeval
का मान पढ़ता है।
यह फ़ंक्शन Objective-C या Swift प्रोग्रामों में उपयोग में लाना बहुत सामान्य है। यह फ़ंक्शन एक Objective-C ऑब्जेक्ट के एक मेथड को कॉल करने की अनुमति देता है।
पैरामीटर (दस्तावेज़ में अधिक जानकारी):
x0: self -> उदाहरण के लिए पॉइंटर
x1: op -> मेथड का सेलेक्टर
x2... -> कॉल किए गए मेथड के शेष तर्क
तो, यदि आप इस फ़ंक्शन की शाखा से पहले ब्रेकपॉइंट लगाते हैं, तो आप आसानी से lldb में देख सकते हैं कि क्या कॉल किया गया है (इस उदाहरण में ऑब्जेक्ट NSConcreteTask
से एक ऑब्जेक्ट को कॉल करता है जो एक कमांड चलाएगा):
पर्यावरण चर NSObjCMessageLoggingEnabled=1
सेट करने से यह लॉग करना संभव है कि यह फ़ंक्शन कब कॉल किया गया है, जैसे कि /tmp/msgSends-pid
फ़ाइल में।
इसके अलावा, OBJC_HELP=1
सेट करने और किसी भी बाइनरी को कॉल करने पर आप अन्य पर्यावरण चर देख सकते हैं जिनका उपयोग आप log करने के लिए कर सकते हैं जब कुछ Objc-C क्रियाएँ होती हैं।
जब यह फ़ंक्शन कॉल किया जाता है, तो निर्दिष्ट उदाहरण के कॉल किए गए तरीके को ढूंढना आवश्यक है, इसके लिए विभिन्न खोजें की जाती हैं:
आशावादी कैश लुकअप करें:
यदि सफल, तो समाप्त
runtimeLock प्राप्त करें (पढ़ें)
यदि (realize && !cls->realized) वर्ग को वास्तविक बनाएं
यदि (initialize && !cls->initialized) वर्ग को प्रारंभ करें
वर्ग की अपनी कैश का प्रयास करें:
यदि सफल, तो समाप्त
वर्ग विधि सूची का प्रयास करें:
यदि पाया गया, तो कैश भरें और समाप्त
सुपरक्लास कैश का प्रयास करें:
यदि सफल, तो समाप्त
सुपरक्लास विधि सूची का प्रयास करें:
यदि पाया गया, तो कैश भरें और समाप्त
यदि (resolver) विधि रिसॉल्वर का प्रयास करें, और वर्ग लुकअप से दोहराएं
यदि अभी भी यहाँ हैं (= सभी अन्य विफल हो गए हैं) तो फॉरवर्डर का प्रयास करें
संकलन करने के लिए:
बाइट्स निकालने के लिए:
नए macOS के लिए:
सीखें और AWS हैकिंग का अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE) सीखें और GCP हैकिंग का अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE)