모든 macOS 애플리케이션은 실행 시점에 동적 라이브러리(dylib)와 프레임워크를 로드합니다. 이렇게 로드된 모듈을 검사하면 링크 문제를 디버깅하고, 서드파티 의존성을 감사하고, 주입된 라이브러리를 탐지하고, 앱의 내부 아키텍처를 이해하는 데 도움이 됩니다. 이 가이드에서는 기본 제공 명령줄 도구부터 전용 GUI 앱까지, 프로세스가 어떤 모듈을 로드했는지 확인하는 다섯 가지 방법을 다룹니다.
빠른 답변
터미널에서 vmmap <pid> | grep '\.dylib'를 사용하면 실행 중인 프로세스가 로드한 모든 동적 라이브러리를 나열할 수 있습니다. 정적 링크 의존성은 otool -L /path/to/binary를 사용하세요. 로드된 모듈을 파일 경로, 버전, UUID와 함께 한 번의 클릭으로 보여 주는 시각적이고 검색 가능한 인터페이스가 필요하다면 **ProcXray**를 사용하세요.
macOS에서 로드된 모듈이란 무엇인가?
로드된 모듈이란 macOS 동적 링커(dyld)가 실행 시점에 프로세스의 주소 공간에 매핑하는 동적 라이브러리(.dylib), 프레임워크(.framework), 또는 번들(.bundle)을 말합니다. 두 가지 범주가 있습니다.
- 로드 시점 의존성 — 바이너리가 컴파일 시점에 링크하는 라이브러리. 동적 링커는 프로세스가 시작될 때 이들을 자동으로 로드합니다.
- 런타임 로드 라이브러리 — 실행 중에
dlopen()을 통해 필요에 따라 로드되는 라이브러리. 플러그인, 확장 기능, 선택적 기능이 흔히 이 패턴을 사용합니다.
macOS 시스템 프로세스는 일반적으로 100~300개의 모듈을 로드하는 반면, Xcode나 Chrome 같은 복잡한 앱은 1,000개가 넘는 모듈을 로드할 수 있습니다. 어떤 모듈이 로드되어 있는지 아는 것은 충돌을 진단하고, 버전 충돌을 식별하고, 보안을 감사하는 데 매우 중요합니다.
방법 1: vmmap — 실행 중인 프로세스의 로드된 모든 모듈 나열
vmmap 명령은 실행 중인 프로세스의 가상 메모리 영역을 표시합니다. 로드된 각 dylib은 자체 메모리 영역을 차지하므로, 출력을 필터링하여 현재 메모리에 있는 모든 모듈을 볼 수 있습니다.
# PID로 실행 중인 프로세스의 로드된 모든 dylib 나열
vmmap <pid> | grep '\.dylib'
먼저 PID를 찾으려면:
# Safari의 PID 찾기
pgrep -x Safari
출력 예시:
__TEXT 7FF80B2A0000-7FF80B2C1000 r-x/r-x /usr/lib/system/libsystem_kernel.dylib
__TEXT 7FF80B2C1000-7FF80B2FD000 r-x/r-x /usr/lib/system/libsystem_c.dylib
__TEXT 7FF80B300000-7FF80B365000 r-x/r-x /usr/lib/libobjc.A.dylib
각 줄은 메모리 주소 범위, 권한, 로드된 라이브러리의 전체 경로를 보여 줍니다.
프레임워크도 포함하려면:
# 로드된 모든 dylib과 프레임워크 표시
vmmap <pid> | grep -E '\.(dylib|framework)/'
로드된 모듈의 개수를 세려면:
vmmap <pid> | grep '\.dylib' | awk '{print $NF}' | sort -u | wc -l
vmmap을 사용해야 할 때
실행 중인 프로세스가 실제로 메모리에 로드한 모든 것을, otool이 보여 줄 수 없는 런타임 로드 모듈까지 포함해서 봐야 할 때 vmmap을 사용하세요. 프로세스가 실행 중이어야 하며, 시스템 프로세스의 경우 상승된 권한이 필요할 수 있습니다.
방법 2: otool -L — 정적 링크 의존성 확인
otool 명령은 Mach-O 바이너리를 검사합니다. -L 플래그는 바이너리가 컴파일 시점에 링크하는 모든 동적 라이브러리를 나열합니다.
# 애플리케이션 바이너리의 링크된 라이브러리 나열
otool -L /Applications/Safari.app/Contents/MacOS/Safari
출력 예시:
/Applications/Safari.app/Contents/MacOS/Safari:
/System/Library/Frameworks/WebKit.framework/Versions/A/WebKit
/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit
/usr/lib/libSystem.B.dylib
/usr/lib/libc++.1.dylib
이는 바이너리가 로드할 것으로 예상되는 라이브러리, 즉 컴파일 시점 의존성을 보여 줍니다. dlopen()을 통해 런타임에 로드되는 라이브러리는 표시하지 않습니다.
특정 dylib 자체의 의존성을 검사하려면:
otool -L /usr/lib/libobjc.A.dylib
otool을 사용해야 할 때
바이너리를 실행하기도 전에 무엇을 로드해야 하는지 알고 싶을 때 otool -L을 사용하세요. 빌드 구성을 확인하고, 올바른 SDK 프레임워크가 링크되어 있는지 점검하고, 누락된 의존성을 탐지하는 데 유용합니다.
방법 3: lsof — 열린 파일을 통해 로드된 라이브러리 찾기
lsof 명령은 프로세스가 연 모든 파일을 나열합니다. 로드된 라이브러리는 메모리 매핑된 파일이므로 lsof 출력에 나타납니다.
# 프로세스의 로드된 모든 .dylib 파일 나열
lsof -p <pid> | grep '\.dylib'
프레임워크를 포함하려면:
lsof -p <pid> | grep -E '\.(dylib|framework)'
lsof를 사용해야 할 때
빠른 확인이 필요하고 이미 익숙한 도구라면 lsof를 사용하세요. 다만 vmmap이 더 상세한 정보(메모리 주소, 권한)를 제공하며 모듈 검사에 더 선호되는 도구입니다.
방법 4: dyld_info — 동적 링커 검사
macOS 12(Monterey)부터 Apple은 동적 링커 정보를 검사하는 dyld_info 명령을 제공합니다.
# 바이너리의 모든 의존 dylib 표시
dyld_info -dependents /Applications/Safari.app/Contents/MacOS/Safari
실행 중인 프로세스의 dyld 공유 캐시 사용을 검사하려면:
# 플랫폼과 의존성 나열
dyld_info -platform -dependents /usr/lib/libobjc.A.dylib
dyld_info를 사용해야 할 때
플랫폼 요구 사항과 의존성 체인을 포함하여 동적 링커 동작에 대한 상세한 정보가 필요할 때 dyld_info를 사용하세요. 의존성 분석에서는 otool보다 더 깔끔한 출력을 제공합니다.
방법 5: ProcXray — 시각적 모듈 검사기
ProcXray는 실행 중인 모든 프로세스의 로드된 모든 모듈을 표시하는 전용 Modules 탭을 제공합니다. 외울 명령도, 분석할 출력도 없습니다.
ProcXray로 모듈 검사하는 방법
- ProcXray를 실행합니다.
- 프로세스 목록에서 프로세스를 선택합니다(검색 막대나 트리 보기로 찾으세요).
- 세부 정보 패널에서 Modules 탭을 클릭합니다.
- 파일 경로와 세부 정보가 함께 표시되는, 로드된 dylib과 프레임워크의 전체 목록을 살펴봅니다.
Modules 탭의 검색 필드를 사용해 라이브러리 이름으로 필터링하세요. 예를 들어 “libsystem”을 입력하면 로드된 모든 시스템 라이브러리를 찾을 수 있고, “swift”를 입력하면 Swift 런타임 모듈을 찾을 수 있습니다.

ProcXray가 CLI 도구보다 더해 주는 것
- 원클릭 검사. 프로세스를 선택하고 Modules를 클릭하면 끝입니다. PID를 찾거나 명령을 입력할 필요가 없습니다.
- 검색과 필터링. 실시간 결과로 모듈을 이름으로 즉시 필터링합니다.
- 완전한 맥락. 인접한 탭에서 프로세스의 환경 변수, 열린 파일, 네트워크 연결, 코드 서명과 함께 모듈을 볼 수 있습니다.
- 모든 프로세스에 작동. 상황마다 다른 명령을 조합할 필요 없이 실행 중인 모든 프로세스를 검사할 수 있습니다.
방법 비교
| 기능 | vmmap | otool -L | lsof | dyld_info | ProcXray |
|---|---|---|---|---|---|
| 런타임 로드 모듈 표시 | 예 | 아니요 | 예 | 아니요 | 예 |
| 정적 의존성 표시 | 아니요 | 예 | 아니요 | 예 | 아니요 |
| 프로세스 실행 필요 | 예 | 아니요 | 예 | 아니요 | 예 |
| 메모리 주소 세부 정보 | 예 | 아니요 | 아니요 | 아니요 | 아니요 |
| 검색 / 필터 | 수동(grep) | 수동(grep) | 수동(grep) | 아니요 | 기본 제공 |
| 사용 편의성 | 보통 | 쉬움 | 보통 | 쉬움 | 가장 쉬움 |
| macOS 버전 | 전체 | 전체 | 전체 | 12+ | 14+ |
실용적인 활용 사례
누락되거나 잘못된 라이브러리 버전과 관련된 충돌 디버깅
# 예상한 라이브러리 버전이 로드되었는지 확인
vmmap <pid> | grep 'libssl'
출력이 예상과 다른 libssl(예: 시스템 버전 대신 Homebrew 버전)을 가리킨다면 버전 충돌을 찾은 것입니다.
주입된 라이브러리를 찾기 위한 앱 감사
보안 연구자와 개발자는 예상치 못한 라이브러리가 프로세스에 로드되었는지 확인할 수 있습니다.
# /System 또는 /usr/lib 출신이 아닌 라이브러리 찾기
vmmap <pid> | grep '\.dylib' | grep -v '/System/' | grep -v '/usr/lib/'
어떤 결과든 서드파티 주입, 플러그인, 또는 살펴볼 가치가 있는 커스텀 프레임워크를 의미할 수 있습니다.
앱이 특정 프레임워크를 사용하는지 확인
# 이 앱이 SwiftUI를 사용하는가?
vmmap <pid> | grep 'SwiftUI'
# Metal에 링크되어 있는가?
otool -L /path/to/binary | grep 'Metal'
자주 묻는 질문
macOS에서 dylib과 프레임워크의 차이는 무엇인가요?
.dylib은 독립적인 동적 라이브러리 파일입니다. .framework는 dylib과 함께 헤더, 리소스, 메타데이터를 담고 있는 번들 디렉터리입니다. 프레임워크는 Apple의 시스템 라이브러리와 서드파티 SDK의 표준 패키징 형식입니다. 실행 시점에는 둘 다 dyld에 의해 동일한 방식으로 로드됩니다.
터미널 없이 실행 중인 앱이 사용하는 dylib을 볼 수 있나요?
네. ProcXray를 사용하면 실행 중인 모든 프로세스를 선택하여 검색 기능이 내장된 그래픽 인터페이스에서 로드된 모듈을 볼 수 있습니다. 터미널 명령은 필요 없습니다.
프로세스는 왜 수백 개의 라이브러리를 로드하나요?
macOS는 동적 링크에 크게 의존합니다. Swift로 작성한 간단한 “Hello World” 앱조차도 100개가 넘는 모듈을 로드하는데, 이는 Swift 런타임, Foundation 프레임워크, 핵심 시스템 라이브러리가 각각 자체 의존성을 끌어오기 때문입니다. 이는 정상적이며 의도된 설계입니다. 공유 라이브러리는 시스템 전반의 메모리 사용을 줄여 줍니다.
otool -L이 프로세스가 로드할 모든 것을 보여 주나요?
아니요. otool -L은 컴파일 시점 링크 의존성만 보여 줍니다. 플러그인, 선택적 기능, 지연 로드 구성 요소처럼 dlopen()을 통해 런타임에 로드되는 라이브러리는 표시되지 않습니다. 전체 그림을 보려면 실행 중인 프로세스에 vmmap을 사용하세요.
다른 프로세스의 모듈을 검사하려면 sudo가 필요한가요?
자신의 프로세스라면 필요 없습니다. 시스템 프로세스나 다른 사용자가 소유한 프로세스의 경우 vmmap과 lsof에 sudo가 필요할 수 있습니다. ProcXray는 처음 실행할 때 필요한 macOS 권한을 요청합니다.
출처 및 참고 자료
- Apple: vmmap man page
- Apple: otool man page
- Apple: dyld — Dynamic Link Editor
- Apple: lsof man page
ProcXray 다운로드 → — 무료, macOS Sonoma+.