# macOS GCD - Grand Central Dispatch
{% hint style="success" %}
AWS Hacking öğrenin ve uygulayın:[**HackTricks Eğitim AWS Kırmızı Takım Uzmanı (ARTE)**](https://training.hacktricks.xyz/courses/arte)\
GCP Hacking öğrenin ve uygulayın: [**HackTricks Eğitim GCP Kırmızı Takım Uzmanı (GRTE)**](https://training.hacktricks.xyz/courses/grte)
HackTricks'i Destekleyin
* [**Abonelik planlarını**](https://github.com/sponsors/carlospolop) kontrol edin!
* 💬 [**Discord grubuna**](https://discord.gg/hRep4RUj7f) katılın veya [**telegram grubuna**](https://t.me/peass) katılın veya bizi **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)** takip edin.**
* **Hacking püf noktalarını paylaşarak** [**HackTricks**](https://github.com/carlospolop/hacktricks) ve [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github depolarına PR gönderin.
{% endhint %}
## Temel Bilgiler
**Grand Central Dispatch (GCD),** aynı zamanda **libdispatch** (`libdispatch.dyld`) olarak da bilinir ve macOS ve iOS'te mevcuttur. Apple tarafından geliştirilen bir teknolojidir ve çok çekirdekli donanımlarda eşzamanlı (çoklu iş parçacıklı) yürütme için uygulama desteğini optimize etmek amacıyla geliştirilmiştir.
**GCD**, uygulamanızın **blok nesneleri** şeklinde **görevleri gönderebileceği FIFO kuyruklarını sağlar ve yönetir**. Gönderilen bloklar, sistem tarafından tamamen yönetilen bir **iş parçacığı havuzunda yürütülür**. GCD, görevleri yürütmek için otomatik olarak iş parçacıkları oluşturur ve bu görevleri mevcut çekirdeklere çalışacak şekilde planlar.
{% hint style="success" %}
Özetle, **paralel olarak kodu yürütmek** için işlemler, **GCD'ye kod blokları gönderebilir**, bu da onların yürütümüyle ilgilenir. Bu nedenle, işlemler yeni iş parçacıkları oluşturmaz; **GCD, verilen kodu kendi iş parçacığı havuzuyla yürütür** (gerektiğinde artabilir veya azalabilir).
{% endhint %}
Bu, paralel yürütümü başarılı bir şekilde yönetmek için çok yardımcı olur, işlemlerin oluşturduğu iş parçacığı sayısını büyük ölçüde azaltır ve paralel yürütümü optimize eder. Bu, **büyük paralelizm** gerektiren görevler için (kaba kuvvet?) veya ana iş parçacığını engellememesi gereken görevler için idealdir: Örneğin, iOS'taki ana iş parçacığı UI etkileşimlerini yönetir, bu nedenle uygulamanın donmasına neden olabilecek herhangi başka bir işlev (arama, web'e erişim, dosya okuma...) bu şekilde yönetilir.
### Bloklar
Bir blok, **kendi başına bir kod bölümü** (argüman döndüren bir işlev gibi) ve bağlı değişkenleri de belirtebilir.\
Ancak, derleyici düzeyinde bloklar mevcut değildir, bunlar `os_object`'lerdir. Bu nesnelerin her biri iki yapıdan oluşur:
* **blok literali**:
* Bloğun sınıfına işaret eden **`isa`** alanıyla başlar:
* `NSConcreteGlobalBlock` (`__DATA.__const` blokları)
* `NSConcreteMallocBlock` (heap'teki bloklar)
* `NSConcreateStackBlock` (yığında bloklar)
* Blok tanımlayıcısında bulunan alanları gösteren **`flags`** ve bazı ayrılmış baytlar
* Çağrılacak işlev işaretçisi
* Bir blok tanımlayıcısına işaretçi
* İçe aktarılan blok değişkenleri (varsa)
* **blok tanımlayıcısı**: Bu, mevcut veriye bağlı olarak boyutu değişen bir yapıdır (önceki bayraklarda belirtildiği gibi)
* Bazı ayrılmış baytlar içerir
* Boyutu
* Genellikle, parametreler için ne kadar alanın gerektiğini bilmek için bir Objective-C tarzı imza işaretçisine işaret eder (bayrak `BLOCK_HAS_SIGNATURE`)
* Değişkenler referans alınıyorsa, bu blok ayrıca bir kopya yardımcısına (değeri başlangıçta kopyalayan) ve atma yardımcısına (serbest bırakan) işaretçilere sahip olacaktır.
### Kuyruklar
Bir dağıtım kuyruğu, blokların yürütülmesi için FIFO sıralaması sağlayan adlandırılmış bir nesnedir.
Blokların yürütülmesi için kuyruklara yerleştirilir ve bunlar 2 modu destekler: `DISPATCH_QUEUE_SERIAL` ve `DISPATCH_QUEUE_CONCURRENT`. Tabii ki, **seri** olan **yarış koşulu** sorunlarına sahip olmayacak çünkü bir blok, önceki blok bitene kadar yürütülmeyecektir. Ancak **diğer kuyruk türü bunu yapabilir**.
Varsayılan kuyruklar:
* `.main-thread`: `dispatch_get_main_queue()`'den
* `.libdispatch-manager`: GCD'nin kuyruk yöneticisi
* `.root.libdispatch-manager`: GCD'nin kuyruk yöneticisi
* `.root.maintenance-qos`: En düşük öncelikli görevler
* `.root.maintenance-qos.overcommit`
* `.root.background-qos`: `DISPATCH_QUEUE_PRIORITY_BACKGROUND` olarak mevcut
* `.root.background-qos.overcommit`
* `.root.utility-qos`: `DISPATCH_QUEUE_PRIORITY_NON_INTERACTIVE` olarak mevcut
* `.root.utility-qos.overcommit`
* `.root.default-qos`: `DISPATCH_QUEUE_PRIORITY_DEFAULT` olarak mevcut
* `.root.background-qos.overcommit`
* `.root.user-initiated-qos`: `DISPATCH_QUEUE_PRIORITY_HIGH` olarak mevcut
* `.root.background-qos.overcommit`
* `.root.user-interactive-qos`: En yüksek öncelikli
* `.root.background-qos.overcommit`
Her zaman **hangi iş parçacıklarının hangi kuyrukları her zaman ele alacağını** (çoklu iş parçacıkları aynı kuyrukta çalışabilir veya aynı iş parçacığı farklı kuyruklarda çalışabilir) sistem belirleyecektir.
#### Özellikler
**`dispatch_queue_create`** ile bir kuyruk oluşturulurken üçüncü argüman bir `dispatch_queue_attr_t` olup genellikle ya `DISPATCH_QUEUE_SERIAL` (aslında NULL) ya da `DISPATCH_QUEUE_CONCURRENT` olabilir, bu da kuyruğun bazı parametrelerini kontrol etmeye olanak tanıyan bir `dispatch_queue_attr_t` yapısına işaret eder.
### Dağıtım nesneleri
Libdispatch'in kullandığı ve kuyruklar ve blokların sadece 2 tanesidir. Bu nesneleri `dispatch_object_create` ile oluşturmak mümkündür:
* `block`
* `data`: Veri blokları
* `group`: Blok grubu
* `io`: Asenkron G/Ç istekleri
* `mach`: Mach bağlantı noktaları
* `mach_msg`: Mach mesajları
* `pthread_root_queue`: İş parçacığı havuzuna sahip bir kuyruk ve iş kuyrukları yok
* `queue`
* `semaphore`
* `source`: Olay kaynağı
## Objective-C
Objective-C'de bir bloğun paralel olarak yürütülmesi için farklı işlevler bulunmaktadır:
* [**dispatch\_async**](https://developer.apple.com/documentation/dispatch/1453057-dispatch\_async): Bir bloğu bir dağıtım kuyruğunda asenkron olarak yürütmek için gönderir ve hemen döner.
* [**dispatch\_sync**](https://developer.apple.com/documentation/dispatch/1452870-dispatch\_sync): Bir blok nesnesini yürütüm için gönderir ve o blok yürütüldükten sonra döner.
* [**dispatch\_once**](https://developer.apple.com/documentation/dispatch/1447169-dispatch\_once): Bir uygulamanın ömrü boyunca bir blok nesnesini yalnızca bir kez yürütür.
* [**dispatch\_async\_and\_wait**](https://developer.apple.com/documentation/dispatch/3191901-dispatch\_async\_and\_wait): Bir iş öğesi için yürütümü gönderir ve yalnızca o iş öğesi yürütüldükten sonra döner. [**`dispatch_sync`**](https://developer.apple.com/documentation/dispatch/1452870-dispatch\_sync) gibi, bu işlev, bloğu yürütürken kuyruğun tüm özelliklerine saygı duyar.
Bu işlevler şu parametreleri bekler: [**`dispatch_queue_t`**](https://developer.apple.com/documentation/dispatch/dispatch\_queue\_t) **`queue,`** [**`dispatch_block_t`**](https://developer.apple.com/documentation/dispatch/dispatch\_block\_t) **`block`**
Bu, bir Blok'un **yapısıdır**:
```c
struct Block {
void *isa; // NSConcreteStackBlock,...
int flags;
int reserved;
void *invoke;
struct BlockDescriptor *descriptor;
// captured variables go here
};
```
Ve **`dispatch_async`** kullanarak **paralelizm** kullanımına bir örnek:
```objectivec
#import
// 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`** is a library that provides **Swift bindings** to the Grand Central Dispatch (GCD) framework which is originally written in C.\
The **`libswiftDispatch`** library wraps the C GCD APIs in a more Swift-friendly interface, making it easier and more intuitive for Swift developers to work with GCD.
* **`DispatchQueue.global().sync{ ... }`**
* **`DispatchQueue.global().async{ ... }`**
* **`let onceToken = DispatchOnce(); onceToken.perform { ... }`**
* **`async await`**
* **`var (data, response) = await URLSession.shared.data(from: URL(string: "https://api.example.com/getData"))`**
**Kod örneği**:
```swift
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
Aşağıdaki Frida betiği, birkaç `dispatch` fonksiyonuna **kanca takmak** ve sıra adını, geri izlemeyi ve bloğu çıkarmak için kullanılabilir: [**https://github.com/seemoo-lab/frida-scripts/blob/main/scripts/libdispatch.js**](https://github.com/seemoo-lab/frida-scripts/blob/main/scripts/libdispatch.js)
```bash
frida -U -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
Şu anda Ghidra, ne ObjectiveC **`dispatch_block_t`** yapısını ne de **`swift_dispatch_block`** yapısını anlamıyor.
Bu nedenle, onları anlamasını istiyorsanız, sadece **bildirmeniz gerekebilir**:
Ardından, kodun içinde **kullanıldığı yeri bulun**:
{% hint style="success" %}
"block" ile yapılan tüm referansları not alarak, yapının nasıl kullanıldığını anlayabilirsiniz.
{% endhint %}
Değişkenin üzerine sağ tıklayın -> Değişkeni Yeniden Türle ve bu durumda **`swift_dispatch_block`**'u seçin:
Ghidra otomatik olarak her şeyi yeniden yazacaktır:
## Referanslar
* [**\*OS Internals, Volume I: User Mode. Jonathan Levin tarafından**](https://www.amazon.com/MacOS-iOS-Internals-User-Mode/dp/099105556X)