macOS GCD - Grand Central Dispatch
Last updated
Last updated
Naučite i vežbajte hakovanje AWS-a:HackTricks Training AWS Red Team Expert (ARTE) Naučite i vežbajte hakovanje GCP-a: HackTricks Training GCP Red Team Expert (GRTE)
Grand Central Dispatch (GCD), takođe poznat kao libdispatch (libdispatch.dyld
), dostupan je i na macOS-u i iOS-u. To je tehnologija koju je Apple razvio kako bi optimizovao podršku aplikacija za konkurentno (višenitno) izvršavanje na višejezgarnom hardveru.
GCD obezbeđuje i upravlja FIFO redovima u koje vaša aplikacija može podneti zadatke u obliku blok objekata. Blokovi podneti dispečerskim redovima se izvršavaju na skupu niti potpuno upravljanih od strane sistema. GCD automatski kreira niti za izvršavanje zadataka u dispečerskim redovima i raspoređuje te zadatke da se izvrše na dostupnim jezgrima.
U suštini, da bi se izvršio kod paralelno, procesi mogu poslati blokove koda GCD-u, koji će se pobrinuti za njihovo izvršavanje. Dakle, procesi ne stvaraju nove niti; GCD izvršava dati kod sa svojim sopstvenim skupom niti (koji se može povećati ili smanjiti po potrebi).
Ovo je veoma korisno za uspešno upravljanje paralelnim izvršavanjem, značajno smanjujući broj niti koje procesi kreiraju i optimizujući paralelno izvršavanje. Ovo je idealno za zadatke koji zahtevaju veliku paralelnost (bruteforcing?) ili za zadatke koji ne bi trebalo da blokiraju glavnu nit: Na primer, glavna nit na iOS-u upravlja interakcijama sa korisničkim interfejsom, pa se na ovaj način upravlja svaka druga funkcionalnost koja bi mogla da učini da aplikacija zastane (pretraga, pristup vebu, čitanje fajla...).
Blok je samo-sadržani deo koda (kao funkcija sa argumentima koji vraćaju vrednost) i može takođe specificirati vezane promenljive.
Međutim, na nivou kompajlera blokovi ne postoje, oni su os_object
-i. Svaki od ovih objekata se sastoji od dve strukture:
blok literal:
Počinje sa poljem isa
, koje pokazuje na klasu bloka:
NSConcreteGlobalBlock
(blokovi iz __DATA.__const
)
NSConcreteMallocBlock
(blokovi u hipu)
NSConcreateStackBlock
(blokovi na steku)
Ima flags
(koji ukazuju na polja prisutna u opisu bloka) i nekoliko rezervisanih bajtova
Pokazivač na funkciju koja se poziva
Pokazivač na opis bloka
Uvezeni blokovi promenljivih (ako ih ima)
opis bloka: Njegova veličina zavisi od podataka koji su prisutni (kako je naznačeno u prethodnim zastavicama)
Ima nekoliko rezervisanih bajtova
Veličina
Obično će imati pokazivač na potpis u stilu Objective-C da bi se znalo koliko prostora je potrebno za parametre (zastava BLOCK_HAS_SIGNATURE
)
Ako se referišu promenljive, ovaj blok će takođe imati pokazivače na pomoćnika za kopiranje (kopiranje vrednosti na početku) i pomoćnika za oslobađanje (oslobađanje).
Dispečerski red je nazivani objekat koji obezbeđuje FIFO redosled blokova za izvršavanje.
Blokovi se postavljaju u redove da bi se izvršili, i oni podržavaju 2 moda: DISPATCH_QUEUE_SERIAL
i DISPATCH_QUEUE_CONCURRENT
. Naravno, serijski neće imati probleme sa trkom za resursima jer blok neće biti izvršen dok prethodni ne završi. Ali drugi tip reda može imati.
Podrazumevani redovi:
.main-thread
: Iz dispatch_get_main_queue()
.libdispatch-manager
: Menadžer redova GCD-a
.root.libdispatch-manager
: Menadžer redova GCD-a
.root.maintenance-qos
: Zadaci najniže prioriteta
.root.maintenance-qos.overcommit
.root.background-qos
: Dostupno kao DISPATCH_QUEUE_PRIORITY_BACKGROUND
.root.background-qos.overcommit
.root.utility-qos
: Dostupno kao DISPATCH_QUEUE_PRIORITY_NON_INTERACTIVE
.root.utility-qos.overcommit
.root.default-qos
: Dostupno kao DISPATCH_QUEUE_PRIORITY_DEFAULT
.root.background-qos.overcommit
.root.user-initiated-qos
: Dostupno kao DISPATCH_QUEUE_PRIORITY_HIGH
.root.background-qos.overcommit
.root.user-interactive-qos
: Najviši prioritet
.root.background-qos.overcommit
Primetite da će sistem odlučiti koje niti rukuju kojim redovima u svakom trenutku (više niti može raditi u istom redu ili ista nit može raditi u različitim redovima u nekom trenutku)
Prilikom kreiranja reda sa dispatch_queue_create
treći argument je dispatch_queue_attr_t
, koji obično može biti ili DISPATCH_QUEUE_SERIAL
(što je zapravo NULL) ili DISPATCH_QUEUE_CONCURRENT
koji je pokazivač na strukturu dispatch_queue_attr_t
koja omogućava kontrolu nekih parametara reda.
Postoji nekoliko objekata koje libdispatch koristi i redovi i blokovi su samo 2 od njih. Moguće je kreirati ove objekte sa dispatch_object_create
:
blok
data
: Blokovi podataka
grupa
: Grupa blokova
io
: Asinhroni I/O zahtevi
mach
: Mach portovi
mach_msg
: Mach poruke
pthread_root_queue
: Red sa pthread baziranim bazenom niti i ne radnim redovima
red
semafor
izvor
: Izvor događaja
U Objective-C-u postoje različite funkcije za slanje bloka da se izvrši paralelno:
dispatch_async: Podnosi blok za asinhrono izvršavanje na dispečerskom redu i odmah se vraća.
dispatch_sync: Podnosi blok za izvršavanje i vraća se nakon što se taj blok završi sa izvršavanjem.
dispatch_once: Izvršava blok samo jednom za vreme trajanja aplikacije.
dispatch_async_and_wait: Podnosi radnu stavku za izvršavanje i vraća se tek nakon što se završi izvršavanje. Za razliku od dispatch_sync
, ova funkcija poštuje sve atribute reda kada izvršava blok.
Ove funkcije očekuju ove parametre: dispatch_queue_t
queue,
dispatch_block_t
block
Ovo je struktura Bloka:
I ovo je primer korišćenja paralelizma sa dispatch_async
:
libswiftDispatch
je biblioteka koja pruža Swift veze sa Grand Central Dispatch (GCD) okvirom koji je originalno napisan u C jeziku.
Biblioteka libswiftDispatch
omotava C GCD API-je u interfejs koji je prijateljskiji za Swift, čineći ga lakšim i intuitivnijim za rad sa GCD-om.
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"))
Primer koda:
Sledeći Frida skript može se koristiti za povezivanje na nekoliko dispatch
funkcija i izvlačenje imena reda, steka poziva i bloka: https://github.com/seemoo-lab/frida-scripts/blob/main/scripts/libdispatch.js
Trenutno Ghidra ne razume ni strukturu ObjectiveC dispatch_block_t
, ni swift_dispatch_block
.
Dakle, ako želite da ih razume, jednostavno ih možete deklarisati:
Zatim pronađite mesto u kodu gde se oni koriste:
Zabeležite sve reference na "block" kako biste razumeli kako možete utvrditi da se struktura koristi.
Desni klik na promenljivu -> Promeni tip promenljive i izaberite u ovom slučaju swift_dispatch_block
:
Ghidra će automatski prepraviti sve: