hacktricks/macos-hardening/macos-security-and-privilege-escalation/macos-gcd-grand-central-dispatch.md
2024-02-10 21:30:13 +00:00

9.5 KiB

macOS GCD - Grand Central Dispatch

htARTE (HackTricks AWS Red Team Expert)에서 AWS 해킹을 처음부터 전문가까지 배워보세요!

HackTricks를 지원하는 다른 방법:

기본 정보

Grand Central Dispatch (GCD) 또는 libdispatch는 macOS와 iOS에서 모두 사용할 수 있습니다. 이는 Apple이 개발한 기술로, 다중 코어 하드웨어에서 동시 (멀티스레드) 실행을 위한 응용 프로그램 지원을 최적화하는 데 사용됩니다.

GCD는 응용 프로그램이 블록 객체 형태로 작업을 제출할 수 있는 FIFO 큐를 제공하고 관리합니다. 디스패치 큐에 제출된 블록은 시스템에 의해 완전히 관리되는 스레드 풀에서 실행됩니다. GCD는 디스패치 큐에서 작업을 실행하기 위해 스레드를 자동으로 생성하고 해당 작업을 사용 가능한 코어에서 실행하도록 일정합니다.

{% hint style="success" %} 요약하면, 병렬로 코드를 실행하기 위해 프로세스는 코드 블록을 GCD에 전송할 수 있으며, GCD가 실행을 처리합니다. 따라서 프로세스는 새로운 스레드를 생성하지 않으며, GCD는 자체 스레드 풀에서 주어진 코드를 실행합니다. {% endhint %}

이는 병렬 실행을 성공적으로 관리하는 데 매우 유용하며, 프로세스가 생성하는 스레드 수를 크게 줄이고 병렬 실행을 최적화하는 데 도움이 됩니다. 이는 큰 병렬성을 필요로 하는 작업 (무차별 대입?)이나 주 스레드를 차단해서는 안 되는 작업에 이상적입니다. 예를 들어, iOS의 주 스레드는 UI 상호작용을 처리하므로 앱이 멈추는 것을 방지하기 위해 다른 기능 (검색, 웹 접근, 파일 읽기 등)은 이 방식으로 처리됩니다.

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;
}

스위프트

**libswiftDispatch**는 원래 C로 작성된 Grand Central Dispatch (GCD) 프레임워크에 대한 스위프트 바인딩을 제공하는 라이브러리입니다.
libswiftDispatch 라이브러리는 C GCD API를 더 스위프트 친화적인 인터페이스로 래핑하여 스위프트 개발자가 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"))

코드 예시:

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 함수에 **후킹(hooking)**을 적용하고 큐 이름, 백트레이스 및 블록을 추출하는 데 사용할 수 있습니다: 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 구조를 이해하지 못합니다.

따라서 이를 이해하도록 하려면 그냥 선언해주면 됩니다:

그런 다음 코드에서 이들이 사용되는 곳을 찾으세요:

{% hint style="success" %} "block"에 대한 모든 참조를 찾아 구조체가 사용되는 방법을 이해하세요. {% endhint %}

변수를 마우스 오른쪽 클릭 -> 변수 형식 재지정을 선택하고 이 경우에는 **swift_dispatch_block**을 선택하세요:

Ghidra가 자동으로 모든 것을 다시 작성할 것입니다:

htARTE (HackTricks AWS Red Team Expert)를 통해 AWS 해킹을 처음부터 전문가까지 배워보세요!

HackTricks를 지원하는 다른 방법: