macOS GCD - Grand Central Dispatch
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μ μ μΆνμ¬ ν΄νΉ νΈλ¦μ 곡μ νμΈμ.
Basic Information
Grand Central Dispatch (GCD), λν libdispatch (libdispatch.dyld)λ‘ μλ €μ Έ μμΌλ©°, macOSμ iOS λͺ¨λμμ μ¬μ©ν μ μμ΅λλ€. μ΄λ Appleμ΄ λ€μ€ μ½μ΄ νλμ¨μ΄μμ λμ(λ©ν°μ€λ λ) μ€νμ μ΅μ ννκΈ° μν΄ κ°λ°ν κΈ°μ μ
λλ€.
GCDλ μ ν리μΌμ΄μ μ΄ λΈλ‘ κ°μ²΄ ννλ‘ μμ μ μ μΆν μ μλ FIFO νλ₯Ό μ 곡νκ³ κ΄λ¦¬ν©λλ€. λμ€ν¨μΉ νμ μ μΆλ λΈλ‘μ μμ€ν μ μν΄ μμ ν κ΄λ¦¬λλ μ€λ λ νμμ μ€νλ©λλ€. GCDλ λμ€ν¨μΉ νμμ μμ μ μ€ννκΈ° μν΄ μ€λ λλ₯Ό μλμΌλ‘ μμ±νκ³ , μ¬μ© κ°λ₯ν μ½μ΄μμ μ€νν μμ μ μμ½ν©λλ€.
Tip
μμ½νμλ©΄, λ³λ ¬λ‘ μ½λλ₯Ό μ€ννκΈ° μν΄ νλ‘μΈμ€λ GCDμ μ½λ λΈλ‘μ μ μ‘ν μ μμΌλ©°, GCDκ° μ€νμ μ²λ¦¬ν©λλ€. λ°λΌμ νλ‘μΈμ€λ μλ‘μ΄ μ€λ λλ₯Ό μμ±νμ§ μμΌλ©°, GCDλ μ체 μ€λ λ νμ μ¬μ©νμ¬ μ£Όμ΄μ§ μ½λλ₯Ό μ€νν©λλ€(νμμ λ°λΌ μ¦κ°νκ±°λ κ°μν μ μμ΅λλ€).
μ΄λ λ³λ ¬ μ€νμ μ±κ³΅μ μΌλ‘ κ΄λ¦¬νλ λ° λ§€μ° μ μ©νλ©°, νλ‘μΈμ€κ° μμ±νλ μ€λ λ μλ₯Ό ν¬κ² μ€μ΄κ³ λ³λ ¬ μ€νμ μ΅μ νν©λλ€. μ΄λ ν° λ³λ ¬μ±(λ¬΄μ°¨λ³ λμ ?)μ΄ νμν μμ μ΄λ λ©μΈ μ€λ λλ₯Ό μ°¨λ¨ν΄μλ μ λλ μμ μ μ΄μμ μ λλ€: μλ₯Ό λ€μ΄, iOSμ λ©μΈ μ€λ λλ UI μνΈμμ©μ μ²λ¦¬νλ―λ‘, μ±μ λ©μΆκ² ν μ μλ λ€λ₯Έ κΈ°λ₯(κ²μ, μΉ μ κ·Ό, νμΌ μ½κΈ° λ±)μ μ΄ λ°©μμΌλ‘ κ΄λ¦¬λ©λλ€.
Blocks
λΈλ‘μ μ체 ν¬ν¨λ μ½λ μΉμ
(κ°μ λ°ννλ μΈμκ° μλ ν¨μμ μ μ¬)μ΄λ©°, λ°μΈλ λ³μλ₯Ό μ§μ ν μλ μμ΅λλ€.
κ·Έλ¬λ μ»΄νμΌλ¬ μμ€μμ λΈλ‘μ μ‘΄μ¬νμ§ μμΌλ©°, os_objectμ
λλ€. μ΄λ¬ν κ° κ°μ²΄λ λ κ°μ κ΅¬μ‘°μ²΄λ‘ κ΅¬μ±λ©λλ€:
- λΈλ‘ 리ν°λ΄:
- λΈλ‘μ ν΄λμ€μ ν¬μΈν°λ₯Ό κ°λ¦¬ν€λ
isaνλλ‘ μμν©λλ€: NSConcreteGlobalBlock(__DATA.__constμ λΈλ‘)NSConcreteMallocBlock(νμ λΈλ‘)NSConcreateStackBlock(μ€νμ λΈλ‘)flags(λΈλ‘ μ€λͺ μμ μ‘΄μ¬νλ νλλ₯Ό λνλ) λ° μΌλΆ μμ½λ λ°μ΄νΈκ° μμ΅λλ€.- νΈμΆν ν¨μ ν¬μΈν°
- λΈλ‘ μ€λͺ μμ λν ν¬μΈν°
- κ°μ Έμ¨ λΈλ‘ λ³μ(μλ κ²½μ°)
- λΈλ‘ μ€λͺ μ: ν¬κΈ°λ μ‘΄μ¬νλ λ°μ΄ν°μ λ°λΌ λ€λ¦ λλ€(μ΄μ νλκ·Έμμ λνλΈ λλ‘).
- μΌλΆ μμ½λ λ°μ΄νΈκ° μμ΅λλ€.
- ν¬κΈ°
- μΌλ°μ μΌλ‘ λ§€κ°λ³μμ νμν 곡κ°μ μκΈ° μν΄ Objective-C μ€νμΌ μλͺ
μ λν ν¬μΈν°κ° μμ κ²μ
λλ€(νλκ·Έ
BLOCK_HAS_SIGNATURE). - λ³μκ° μ°Έμ‘°λλ κ²½μ°, μ΄ λΈλ‘μ λ³΅μ¬ λμ°λ―Έ(μμ μ κ°μ 볡μ¬) λ° ν΄μ λμ°λ―Έ(ν΄μ )λ₯Ό κ°λ¦¬ν€λ ν¬μΈν°λ κ°μ§λλ€.
Queues
λμ€ν¨μΉ νλ μ€νμ μν λΈλ‘μ FIFO μμλ₯Ό μ 곡νλ λͺ λͺ λ κ°μ²΄μ λλ€.
λΈλ‘μ μ€νμ μν΄ νμ μ€μ λλ©°, μ΄λ€μ DISPATCH_QUEUE_SERIAL λ° DISPATCH_QUEUE_CONCURRENTμ λ κ°μ§ λͺ¨λλ₯Ό μ§μν©λλ€. λ¬Όλ‘ μ§λ ¬ νλ κ²½μ 쑰건 λ¬Έμ κ° μμΌλ©°, λΈλ‘μ μ΄μ λΈλ‘μ΄ μλ£λ λκΉμ§ μ€νλμ§ μμ΅λλ€. κ·Έλ¬λ λ€λ₯Έ μ νμ νλ κ·Έλ΄ μ μμ΅λλ€.
κΈ°λ³Έ ν:
.main-thread:dispatch_get_main_queue()μμ.libdispatch-manager: GCDμ ν κ΄λ¦¬μ.root.libdispatch-manager: GCDμ ν κ΄λ¦¬μ.root.maintenance-qos: μ΅μ μ°μ μμ μμ.root.maintenance-qos.overcommit.root.background-qos:DISPATCH_QUEUE_PRIORITY_BACKGROUNDλ‘ μ¬μ© κ°λ₯.root.background-qos.overcommit.root.utility-qos:DISPATCH_QUEUE_PRIORITY_NON_INTERACTIVEλ‘ μ¬μ© κ°λ₯.root.utility-qos.overcommit.root.default-qos:DISPATCH_QUEUE_PRIORITY_DEFAULTλ‘ μ¬μ© κ°λ₯.root.background-qos.overcommit.root.user-initiated-qos:DISPATCH_QUEUE_PRIORITY_HIGHλ‘ μ¬μ© κ°λ₯.root.background-qos.overcommit.root.user-interactive-qos: κ°μ₯ λμ μ°μ μμ.root.background-qos.overcommit
κ° μμ μμ μ΄λ€ μ€λ λκ° μ΄λ€ νλ₯Ό μ²λ¦¬ν μ§ κ²°μ νλ κ²μ μμ€ν μ΄λ―λ‘ μ£ΌμνμΈμ(μ¬λ¬ μ€λ λκ° λμΌν νμμ μμ ν μ μκ±°λ λμΌν μ€λ λκ° μ¬λ¬ νμμ μμ ν μ μμ΅λλ€).
Attributtes
**dispatch_queue_create**λ‘ νλ₯Ό μμ±ν λ μΈ λ²μ§Έ μΈμλ dispatch_queue_attr_tλ‘, μΌλ°μ μΌλ‘ DISPATCH_QUEUE_SERIAL(μ€μ λ‘λ NULL) λλ DISPATCH_QUEUE_CONCURRENTλ‘, νμ μΌλΆ λ§€κ°λ³μλ₯Ό μ μ΄ν μ μλ dispatch_queue_attr_t ꡬ쑰체μ λν ν¬μΈν°μ
λλ€.
Dispatch objects
libdispatchκ° μ¬μ©νλ μ¬λ¬ κ°μ²΄κ° μμΌλ©°, νμ λΈλ‘μ κ·Έ μ€ λ κ°μ§μ λΆκ³Όν©λλ€. μ΄λ¬ν κ°μ²΄λ dispatch_object_createλ‘ μμ±ν μ μμ΅λλ€:
blockdata: λ°μ΄ν° λΈλ‘group: λΈλ‘ κ·Έλ£Ήio: λΉλκΈ° I/O μμ²mach: Mach ν¬νΈmach_msg: Mach λ©μμ§pthread_root_queue: pthread μ€λ λ νμ κ°μ§ ν λ° μμ νκ° μλqueuesemaphoresource: μ΄λ²€νΈ μμ€
Objective-C
Objective-Cμμλ λΈλ‘μ λ³λ ¬λ‘ μ€ννκΈ° μν΄ μ μ‘νλ λ€μν ν¨μκ° μμ΅λλ€:
- dispatch_async: λμ€ν¨μΉ νμμ λΉλκΈ° μ€νμ μν΄ λΈλ‘μ μ μΆνκ³ μ¦μ λ°νν©λλ€.
- dispatch_sync: μ€νμ μν΄ λΈλ‘ κ°μ²΄λ₯Ό μ μΆνκ³ ν΄λΉ λΈλ‘μ΄ μ€νμ λ§μΉ ν λ°νν©λλ€.
- dispatch_once: μ ν리μΌμ΄μ μ μμ λμ λΈλ‘ κ°μ²΄λ₯Ό ν λ²λ§ μ€νν©λλ€.
- dispatch_async_and_wait: μ€νμ μν΄ μμ
νλͺ©μ μ μΆνκ³ μ€νμ΄ μλ£λ νμλ§ λ°νν©λλ€.
dispatch_syncμ λ¬λ¦¬, μ΄ ν¨μλ λΈλ‘μ μ€νν λ νμ λͺ¨λ μμ±μ μ‘΄μ€ν©λλ€.
μ΄λ¬ν ν¨μλ λ€μ λ§€κ°λ³μλ₯Ό κΈ°λν©λλ€: dispatch_queue_t queue, dispatch_block_t block
μ΄κ²μ λΈλ‘μ ꡬ쑰체μ λλ€:
struct Block {
void *isa; // NSConcreteStackBlock,...
int flags;
int reserved;
void *invoke;
struct BlockDescriptor *descriptor;
// captured variables go here
};
κ·Έλ¦¬κ³ μ΄κ²μ **dispatch_async**μ ν¨κ» λ³λ ¬μ±μ μ¬μ©νλ μμ
λλ€:
#import <Foundation/Foundation.h>
// Define a block
void (^backgroundTask)(void) = ^{
// Code to be executed in the background
for (int i = 0; i < 10; i++) {
NSLog(@"Background task %d", i);
sleep(1); // Simulate a long-running task
}
};
int main(int argc, const char * argv[]) {
@autoreleasepool {
// Create a dispatch queue
dispatch_queue_t backgroundQueue = dispatch_queue_create("com.example.backgroundQueue", NULL);
// Submit the block to the queue for asynchronous execution
dispatch_async(backgroundQueue, backgroundTask);
// Continue with other work on the main queue or thread
for (int i = 0; i < 10; i++) {
NSLog(@"Main task %d", i);
sleep(1); // Simulate a long-running task
}
}
return 0;
}
Swift
**libswiftDispatch**λ μλ Cλ‘ μμ±λ Grand Central Dispatch (GCD) νλ μμν¬μ λν Swift λ°μΈλ©μ μ 곡νλ λΌμ΄λΈλ¬λ¦¬μ
λλ€.libswiftDispatch λΌμ΄λΈλ¬λ¦¬λ C GCD APIλ₯Ό λ Swift μΉνμ μΈ μΈν°νμ΄μ€λ‘ κ°μΈ, Swift κ°λ°μκ° GCDμ μμ
νκΈ° μ½κ² νκ³ μ§κ΄μ μΌλ‘ λ§λλλ€.
DispatchQueue.global().sync{ ... }DispatchQueue.global().async{ ... }let onceToken = DispatchOnce(); onceToken.perform { ... }async awaitvar (data, response) = await URLSession.shared.data(from: URL(string: "https://api.example.com/getData"))
Code example:
import Foundation
// Define a closure (the Swift equivalent of a block)
let backgroundTask: () -> Void = {
for i in 0..<10 {
print("Background task \(i)")
sleep(1) // Simulate a long-running task
}
}
// Entry point
autoreleasepool {
// Create a dispatch queue
let backgroundQueue = DispatchQueue(label: "com.example.backgroundQueue")
// Submit the closure to the queue for asynchronous execution
backgroundQueue.async(execute: backgroundTask)
// Continue with other work on the main queue
for i in 0..<10 {
print("Main task \(i)")
sleep(1) // Simulate a long-running task
}
}
Frida
λ€μ Frida μ€ν¬λ¦½νΈλ μ¬λ¬ dispatch ν¨μμ ννΉνκ³ ν μ΄λ¦, λ°±νΈλ μ΄μ€ λ° λΈλ‘μ μΆμΆνλ λ° μ¬μ©ν μ μμ΅λλ€: https://github.com/seemoo-lab/frida-scripts/blob/main/scripts/libdispatch.js
frida -U <prog_name> -l libdispatch.js
dispatch_sync
Calling queue: com.apple.UIKit._UIReusePool.reuseSetAccess
Callback function: 0x19e3a6488 UIKitCore!__26-[_UIReusePool addObject:]_block_invoke
Backtrace:
0x19e3a6460 UIKitCore!-[_UIReusePool addObject:]
0x19e3a5db8 UIKitCore!-[UIGraphicsRenderer _enqueueContextForReuse:]
0x19e3a57fc UIKitCore!+[UIGraphicsRenderer _destroyCGContext:withRenderer:]
[...]
Ghidra
νμ¬ Ghidraλ ObjectiveC dispatch_block_t ꡬ쑰체μ swift_dispatch_block ꡬ쑰체λ₯Ό μ΄ν΄νμ§ λͺ»ν©λλ€.
κ·Έλμ μ΄λ€μ μ΄ν΄νλλ‘ νλ €λ©΄, μ μΈνλ©΄ λ©λλ€:
.png)
.png)
.png)
κ·Έλ° λ€μ, μ½λμμ μ΄λ€μ΄ μ¬μ©λλ μμΉλ₯Ό μ°Ύμ΅λλ€:
Tip
βblockβμ λν λͺ¨λ μ°Έμ‘°λ₯Ό κΈ°λ‘νμ¬ κ΅¬μ‘°μ²΄κ° μ¬μ©λκ³ μμμ νμ νλ λ°©λ²μ μ΄ν΄νμΈμ.
.png)
λ³μμμ μ€λ₯Έμͺ½ ν΄λ¦ -> λ³μ μ¬μ
λ ₯ λ° μ΄ κ²½μ° **swift_dispatch_block**μ μ νν©λλ€:
.png)
Ghidraλ λͺ¨λ κ²μ μλμΌλ‘ λ€μ μμ±ν©λλ€:
.png)
References
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μ μ μΆνμ¬ ν΄νΉ νΈλ¦μ 곡μ νμΈμ.


