hacktricks/macos-hardening/macos-security-and-privilege-escalation/macos-gcd-grand-central-dispatch.md
2024-02-10 17:52:19 +00:00

9 KiB

macOS GCD - Grand Central Dispatch

htARTE (HackTricks AWS Red Team Expert) ! qaStaHvIS htARTE (HackTricks AWS Red Team Expert)!

Other ways to support HackTricks:

Basic Information

Grand Central Dispatch (GCD), also known as libdispatch, is available in both macOS and iOS. It's a technology developed by Apple to optimize application support for concurrent (multithreaded) execution on multicore hardware.

GCD provides and manages FIFO queues to which your application can submit tasks in the form of block objects. Blocks submitted to dispatch queues are executed on a pool of threads fully managed by the system. GCD automatically creates threads for executing the tasks in the dispatch queues and schedules those tasks to run on the available cores.

{% hint style="success" %} In summary, to execute code in parallel, processes can send blocks of code to GCD, which will take care of their execution. Therefore, processes don't create new threads; GCD executes the given code with its own pool of threads. {% endhint %}

This is very helpful to manage parallel execution successfully, greatly reducing the number of threads processes create and optimising the parallel execution. This is idea for tasks that require great parallelism (brute-forcing?) or for tasks that shouldn't block the main thread: For example, the main thread on iOS handles UI interactions, so any other functionality that could make the app hang (searching, accessing a web, reading a file...) is managed this way.

Objective-C

In Objetive-C there are different functions to send a block to be executed in parallel:

  • dispatch_async: Submits a block for asynchronous execution on a dispatch queue and returns immediately.
  • dispatch_sync: Submits a block object for execution and returns after that block finishes executing.
  • dispatch_once: Executes a block object only once for the lifetime of an application.
  • dispatch_async_and_wait: Submits a work item for execution and returns only after it finishes executing. Unlike dispatch_sync, this function respects all attributes of the queue when it executes the block.

These functions expect these parameters: dispatch_queue_t queue, dispatch_block_t block

This is the struct of a Block:

struct Block {
void *isa; // NSConcreteStackBlock,...
int flags;
int reserved;
void *invoke;
struct BlockDescriptor *descriptor;
// captured variables go here
};

ghItlh parallelism dispatch_async example vItlhutlh:

#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 jenpu'wI' 'ej Grand Central Dispatch (GCD) framework vItlhutlh C vItlhutlh.
libswiftDispatch jenpu'wI' C GCD APIs vItlhutlh, 'ej 'oH vItlhutlh Swift-friendly interface, vItlhutlh vItlhutlh 'ej vItlhutlh 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"))

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

The following Frida script can be used to hook into several dispatch functions and extract the queue name, the backtrace and the block: 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 vItlhutlh ObjectiveC dispatch_block_t ghItlh swift_dispatch_block ghItlh.

cha'logh ghItlh 'oH ghItlh 'oH ghItlh:

'oH ghItlh 'oH 'e' 'oH 'oH 'e' 'oH 'oH 'e':

{% hint style="success" %} "block" ghItlh 'oH ghItlh 'oH 'oH 'e' 'oH 'oH 'e' 'oH 'oH 'e'. {% endhint %}

'oH ghItlh 'oH 'oH -> Retype Variable 'ej 'oH 'oH swift_dispatch_block ghItlh:

Ghidra 'oH ghItlh 'oH 'oH:

Learn AWS hacking from zero to hero with htARTE (HackTricks AWS Red Team Expert)!

Other ways to support HackTricks: