macOS GCD - Grand Central Dispatch
Last updated
Last updated
AWS Hacking öğrenin ve uygulayın:HackTricks Eğitim AWS Kırmızı Takım Uzmanı (ARTE) GCP Hacking öğrenin ve uygulayın: HackTricks Eğitim GCP Kırmızı Takım Uzmanı (GRTE)
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.
Ö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).
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.
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.
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.
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.
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'de bir bloğun paralel olarak yürütülmesi için farklı işlevler bulunmaktadır:
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: Bir blok nesnesini yürütüm için gönderir ve o blok yürütüldükten sonra döner.
dispatch_once: Bir uygulamanın ömrü boyunca bir blok nesnesini yalnızca bir kez yürütür.
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
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
queue,
dispatch_block_t
block
Bu, bir Blok'un yapısıdır:
Ve dispatch_async
kullanarak paralelizm kullanımına bir örnek:
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:
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
Ş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:
"block" ile yapılan tüm referansları not alarak, yapının nasıl kullanıldığını anlayabilirsiniz.
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: