众所周知,macOS的沙盒一直是一个神秘的东西,我喜欢利用各种工具并从Jonathan Levin的《*OS Internals》等参考书再或者苹果官方自己都不太清楚的文档中收集的知识来分析它。苹果的安全机制并不是最好的,这不是什么新鲜事。沙盒技术有很长的历史,macOS的用户被沙盒保护已经有很长一段时间了,随着时间的推移,沙盒变得越来越强大。苹果一直在尽其所能加强其操作系统中的沙盒和其他许多安全机制,下面就让我们一起深入了解一下macOS沙盒的神奇之处。
苹果首次使用沙盒技术是在其OS X 10.5(Leopard)中,它被称为“SeatBelt”(安全带)。正如这个词语的意思一样,它就像在汽车旅行中为了安全而系上安全带一样,强制开发人员在应用程序上使用沙盒技术,以限制其对系统的访问。正如你想象的那样,没有多少开发者会这样做,而且由于“安全带”的最初概念是自愿限制,所以苹果也做不了什么。结合MandatoryAccessControl (MAC)Framework
,沙盒的想法肯定不错,但离成功还很远。MACF框架是苹果设备的整个安全模型构建的基础。
在OS X 10.7中,苹果公司吸取了OS X 10.5的教训,沙盒现在已经不再任由开发人员在应用程序上是否使用,默认情况下是强制执行的。即使是今天在macOS Mojave上,苹果仍然强制使用沙盒,基于应用程序拥有的权限(com.apple.security.app-sandbox
)。如果应用程序具有此权限,它将被放置在沙盒中,而不是考虑开发人员的意愿。也就是说,在新系统中开发者的意见是没有意义的,因为上传到Appstore的程序是由苹果公司签名的,在签名过程中,苹果公司在程序上授予沙盒权限,从而迫使所有Appstore中的程序沙盒化。
需要注意的是,与iOS的沙盒相比,macOS更容易操作。在iOS上,第三方程序均不可能逃脱沙盒,除非你使用沙盒逃逸技术,而大多数这种情况下是由内核漏洞或沙盒漏洞导致的(越狱)。所有第三方程序,不管它是从哪里安装的,都放在/var/mobile/containers
和/var/containers
两目录中。从ios8开始,这些目录发生了很大的变化,创建了新的文件夹,移动了程序资源,静态数据和运行时数据分离,所以在旧的iOS上,你可以找到安装在/var/mobile/Applications
甚至/var/mobile/ containers/bundl /
中的程序。任何在/var/
中的东西都要被沙盒化,因为你不能直接在其他地方安装你的程序,除非你越狱了。在macOS上,只有Appstore中的程序是沙盒的。如果你从开发人员网站直接下载DMG镜像中的程序,那么它很可能不受沙盒限制。
沙盒的唯一目的是限制程序访问系统的各种资源,比如系统调用、文件或任何东西,这是为了恶意程序肆意破坏系统。在iOS上,我可以骗你安装一个恶意的程序,但这个做法是是毫无意义的,除非我有内核或沙箱逃脱的漏洞(越狱),否则程序不会对你的设备造成很大的伤害(比如:删除你的手机里的一些重要文件)。iOS沙盒和其他保护措施会一起防止未经授权的访问,所以程序只能访问它自己的容器内的资源,并不能造成很大的破坏。同样的道理也适用于macOS应用商店的应用程序,但不适用于DMG格式的程序,因为DMG格式可能没有沙盒。
沙盒实际上是一项非常好的技术,这也就是为什么它一直沿用到今天的原因。假如你在Windows上打开了一个从非法来源上下载的恶意程序,而该程序若想删除System32
目录或其他重要文件,这是完全可以实现的。因为Windows上没有沙盒,需要使用到管理员权限的资源的地方,只需要欺骗用户点击允许管理员权限运行即可。
苹果官方说过:沙盒是一种在内核层面强制实施的访问控制技术(在内核层面,用户或任何受到损害的程序通常都无法控制)。沙盒可以确保它拦截沙盒程序执行的所有操作,并禁止访问程序没有访问权限的资源。
在macOS上,沙箱本身不是单个文件或单个进程,它被分割成多个组件,比如位于/usr/libexec/sandboxd
目录中的userland daemon
,这是com.apple.security.sandbox
是kext (Kernel Extension)
,还有依赖于AppContainer.Framework
的AppSandbox
私有框架。正如你所见,多个组件一起工作来实现本文所诉的程序沙箱。
在终端中运行kextstat | grep“sand”
命令,可以看到macOS上的kext处于活动状态。
Isabella:/ geosn0w$ kextstat | grep "sand"
381 0xffffff7f811a3000 0x210000x21000com.apple.security.sandbox (300.0) BDFF700A-6746-3643-A0A1-852628695B04 <37 30 18 7 6 5 4 3 2 1>
Isabella:/ geosn0w$
沙箱是多个MACF策略模块之一。AMFI (Apple Mobile File Integrity)的协同设计是另一个模块。
正如之前所提到的,该应用被沙盒化的一个明显迹象是应用程序二进制文件中是否需要com.apple.security.app-sandbox
权限。我们可以使用很多工具检查macOS上的权限,利用Jonathan Levin的jtool
这个工具,运行命令./jtool--ent /Applications/AppName.
在终端app中,我们可以看到程序所拥有的全部权限。以iHex为例,Appstore中的只需要OpenBoardView权限。DMG格式如下:
在终端中运行该命令会得到以下iHex结果:
需要注意的是,权限是存在的,并且密钥被设置为true
,此程序将被沙盒化。现在,正如你所见,这些权利是以类似于XML的格式列出的,它们实际上位于 .PLIST or Property List
文件中,而属性列表文件只不过是美化的XML。PLISTs可以采用二进制格式,可以使用命令plutil -convert xml1 -o
将其转换为可读的格式。
使用Jtool
可以替换程序的权限,但之后需要对程序进行伪造签名。总之,这是一种解除macOS应用程序沙盒的方法。这在iOS上并不容易做到,因为沙盒是基于应用程序的安装位置,而不是基于安装权限。
现在让我们来看看OpenBoardView,这是一款未从App Store下载的应用程序。
如你所见,程序没有任何权限。它不会被沙盒化,这意味着它可以比任何应用程序商店应用程序访问更多的源代码。
com.apple.security.app-sandbox
的权限并不是iHEX开发人员自己添加的,它是由苹果官方在App Store审核的过程中自动添加的。
另一种检查程序是否被沙盒化的方法是运行asctl sandbox check --pid XYZ
命令,其中XYZ是程序的PID(Process ID)
。可以从macOS上的Activity Monitor
程序获得正在运行的进程的PID
。下面是asctl
命令的输出。
进入沙盒容器中,也就是放置在$HOME/Library/Containers/
上的文件夹。此文件夹是为任何沙盒程序创建的,而不管实际二进制文件安装在何处。文件夹遵循简单的结构,但最重要的是,它包含一个Container.Plist
文件,其中包含有关其容器(由其CFBundleIdentifier
标识)、SandboxProfileData、SandboxProfileDataValidationInfo
和Version
的应用程序的信息。
找到iHEX 的 Container
,将目录切到上面提到的路径,然后运行ls -lF com.hewbo.hexeditor
。com.hewbo.hexeditor
是iHex的CFBundleIndentifier
(在.app文件夹中可以找到Info.Plist
)。
可以看到app的容器包含一个Data
文件夹和前面提到的Container.Plist
文件。数据文件夹非常有趣,如果将目录切到它,可以看到它模拟了用户的主目录。当然,所有这些都是严格控制的符号链接,该控制由沙盒容器强制执行。Container.plist
包含SandboxProfileDataValidationRedirectablePathsKey
,它指定哪些符号链接被批准。
在内部启动应用程序时,内核将调用mac_execve
函数,可以在XNU
源代码中看到。__mac_execve
几乎会加载二进制文件,但它也会检查MAC label
,看看是否应该强制执行沙箱。
/*
* __mac_execve
*
* Parameters: uap->fname File name to exec
* uap->argp Argument list
* uap->envp Environment list
* uap->mac_p MAC label supplied by caller
*
* Returns: 0 Success
* EINVAL Invalid argument
* ENOTSUP Not supported
* ENOEXEC Executable file format error
* exec_activate_image:EINVAL Invalid argument
* exec_activate_image:EACCES Permission denied
* exec_activate_image:EINTR Interrupted function
* exec_activate_image:ENOMEM Not enough space
* exec_activate_image:EFAULT Bad address
* exec_activate_image:ENAMETOOLONG Filename too long
* exec_activate_image:ENOEXEC Executable file format error
* exec_activate_image:ETXTBSY Text file busy [misuse of error code]
* exec_activate_image:EBADEXEC The executable is corrupt/unknown
* exec_activate_image:???
* mac_execve_enter:???
*
* TODO: Dynamic linker header address on stack is copied via suword()
*/
int
__mac_execve(proc_t p, struct __mac_execve_args *uap, int32_t *retval)
{
char *bufp = NULL;
struct image_params *imgp;
struct vnode_attr *vap;
struct vnode_attr *origvap;
int error;
char alt_p_comm[sizeof(p->p_comm)] = {0}; /* for PowerPC */
int is_64 = IS_64BIT_PROCESS(p);
struct vfs_context context;
context.vc_thread = current_thread();
context.vc_ucred = kauth_cred_proc_ref(p); /* XXX must NOT be kauth_cred_get() */
/* Allocate a big chunk for locals instead of using stack since these
* structures a pretty big.
*/
MALLOC(bufp, char *, (sizeof(*imgp) + sizeof(*vap) + sizeof(*origvap)), M_TEMP, M_WAITOK | M_ZERO);
imgp = (struct image_params *) bufp;
if (bufp == NULL) {
error = ENOMEM;
goto exit_with_error;
}
vap = (struct vnode_attr *) (bufp + sizeof(*imgp));
origvap = (struct vnode_attr *) (bufp + sizeof(*imgp) + sizeof(*vap));
/* Initialize the common data in the image_params structure */
imgp->ip_user_fname = uap->fname;
imgp->ip_user_argv = uap->argp;
imgp->ip_user_envv = uap->envp;
imgp->ip_vattr = vap;
imgp->ip_origvattr = origvap;
imgp->ip_vfs_context = &context;
imgp->ip_flags = (is_64 ? IMGPF_WAS_64BIT : IMGPF_NONE) | ((p->p_flag & P_DISABLE_ASLR) ? IMGPF_DISABLE_ASLR : IMGPF_NONE);
imgp->ip_p_comm = alt_p_comm; /* for PowerPC */
imgp->ip_seg = (is_64 ? UIO_USERSPACE64 : UIO_USERSPACE32);
#if CONFIG_MACF
if (uap->mac_p != USER_ADDR_NULL) {
error = mac_execve_enter(uap->mac_p, imgp);
if (error) {
kauth_cred_unref(&context.vc_ucred);
goto exit_with_error;
}
}
#endif
error = exec_activate_image(imgp);
kauth_cred_unref(&context.vc_ucred);
/* Image not claimed by any activator? */
if (error == -1)
error = ENOEXEC;
if (error == 0) {
exec_resettextvp(p, imgp);
error = check_for_signature(p, imgp);
}
if (imgp->ip_vp != NULLVP)
vnode_put(imgp->ip_vp);
if (imgp->ip_strings)
execargs_free(imgp);
#if CONFIG_MACF
if (imgp->ip_execlabelp)
mac_cred_label_free(imgp->ip_execlabelp);
if (imgp->ip_scriptlabelp)
mac_vnode_label_free(imgp->ip_scriptlabelp);
#endif
if (!error) {
struct uthread *uthread;
/* Sever any extant thread affinity */
thread_affinity_exec(current_thread());
DTRACE_PROC(exec__success);
uthread = get_bsdthread_info(current_thread());
if (uthread->uu_flag & UT_VFORK) {
vfork_return(p, retval, p->p_pid);
(void)thread_resume(imgp->ip_new_thread);
}
} else {
DTRACE_PROC1(exec__failure, int, error);
}
exit_with_error:
if (bufp != NULL) {
FREE(bufp, M_TEMP);
}
return(error);
}
当进程启动时,在其生命周期中很早就会加载libSystem.B
。因为所有的APIs
都依赖于它。在执行过程中的某个时刻,libSystem.B.initializer
将落入_libsecinit_setup_secinitd_client
,后者将落入xpc_copy_attribulements_for_pid
以从程序二进制文件中获取权限,然后它将权限以及应用程序是否应该通过XPC
消息被sandboxed
发送到位于/usr/libexec/secinitd
中的secinitd
守护进程。此消息传输发生在xpc_pipe_route
级别,相同的函数将处理从secinitd
守护进程接收的消息,该守护进程将解析从进程接收的XPC
消息。
secinitd
守护进程将承认这样一个事实:如果存在权限,沙盒应该被强制执行,那么它将调用AppSandbox.Framework
来创建沙盒配置文件。创建概要文件之后,secinitd
将返回一条XPC message
,其中包含CONTAINER_ID_KEY、CONTAINER_ROOT_PATH_KEY、SANDBOX_PROFILE_DATA_KEY
和其他数据。该信息将由_libsecinit_setup_app_sandbox
解析,然后该sandbox
落入__sandbox_ms
中,从而创建程序的沙盒并在运行时将其包含。
流程如下:
使用LLDB
可以调试一个沙盒程序,并查看到底发生了什么,包括从进程传递到secinitd
守护进程的XPC
消息。即将深入了解Terminal
和LLDB
,下面的清单可能很难理解。为了更容易理解发生了什么,最好尝试遵循重要的逻辑,比如传递的消息和回溯,以查看执行的函数调用。
起初,打开终端并调用lldb
。如果没有安装LLDB
,请安装Xcode
,因为它附带了您需要的所有调试工具。首先在xpc_pipe_routine
和__sandbox_ms
处下断点。
Last login: Thu Dec 27 16:44:59 on ttys000
Isabella:~ geosn0w$ lldb /Applications/iHex.app/Contents/MacOS/iHex
(lldb) target create "/Applications/iHex.app/Contents/MacOS/iHex"
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python/lldb/__init__.py", line 98, in <module>
import six
ImportError: No module named six
Traceback (most recent call last):
File "<string>", line 1, in <module>
NameError: name 'run_one_line' is not defined
Traceback (most recent call last):
File "<string>", line 1, in <module>
Current executable set to '/Applications/iHex.app/Contents/MacOS/iHex' (x86_64).
(lldb) b xpc_pipe_routine
Breakpoint 1: where = libxpc.dylib`xpc_pipe_routine, address = 0x0000000000005c40
(lldb) b __sandbox_ms
Breakpoint 2: where = libsystem_kernel.dylib`__mac_syscall, address = 0x000000000001c648
(lldb) run
Process 12594 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x00007fff6a75ec40 libxpc.dylib`xpc_pipe_routine
libxpc.dylib`xpc_pipe_routine:
-> 0x7fff6a75ec40 <+0>: pushq %rbp
0x7fff6a75ec41 <+1>: movq %rsp, %rbp
0x7fff6a75ec44 <+4>: pushq %r15
0x7fff6a75ec46 <+6>: pushq %r14
Target 0: (iHex) stopped.
(lldb) c
Process 12594 resuming
Process 12594 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x00007fff6a75ec40 libxpc.dylib`xpc_pipe_routine
libxpc.dylib`xpc_pipe_routine:
-> 0x7fff6a75ec40 <+0>: pushq %rbp
0x7fff6a75ec41 <+1>: movq %rsp, %rbp
0x7fff6a75ec44 <+4>: pushq %r15
0x7fff6a75ec46 <+6>: pushq %r14
Target 0: (iHex) stopped.
然后在libxpc.dylib
中停在xpc_pipe_.routine
。做一个backtrace
来看看发生了什么,可以通过bt
命令来实现这一点。
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
* frame #0: 0x00007fff6a75ec40 libxpc.dylib`xpc_pipe_routine
frame #1: 0x00007fff6a75eaad libxpc.dylib`_xpc_interface_routine + 167
frame #2: 0x00007fff6a7650b5 libxpc.dylib`_xpc_uncork_domain + 529
frame #3: 0x00007fff6a75ad85 libxpc.dylib`_libxpc_initializer + 1053
frame #4: 0x00007fff680aa9c8 libSystem.B.dylib`libSystem_initializer + 126
frame #5: 0x0000000100582ac6 dyld`ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&) + 420
frame #6: 0x0000000100582cf6 dyld`ImageLoaderMachO::doInitialization(ImageLoader::LinkContext const&) + 40
...
frame #18: 0x000000010056d3d4 dyld`dyldbootstrap::start(macho_header const*, int, char const**, long, macho_header const*, unsigned long*) + 453
frame #19: 0x000000010056d1d2 dyld`_dyld_start + 54
(lldb) c
Process 12594 resuming
Process 12594 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x00007fff6a75ec40 libxpc.dylib`xpc_pipe_routine
libxpc.dylib`xpc_pipe_routine:
-> 0x7fff6a75ec40 <+0>: pushq %rbp
0x7fff6a75ec41 <+1>: movq %rsp, %rbp
0x7fff6a75ec44 <+4>: pushq %r15
0x7fff6a75ec46 <+6>: pushq %r14
Target 0: (iHex) stopped.
很明显这个不是我们所需要的,这是libxpc.dylib
的_xpc_uncork_domain
函数。我们需要xpc_pipe_create,
按c继续并再次回溯。
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
* frame #0: 0x00007fff6a75ec40 libxpc.dylib`xpc_pipe_routine
frame #1: 0x00007fff6a75eaad libxpc.dylib`_xpc_interface_routine + 167
frame #2: 0x00007fff6a75e5d3 libxpc.dylib`bootstrap_look_up3 + 185
frame #3: 0x00007fff6a75e4ff libxpc.dylib`bootstrap_look_up2 + 41
frame #4: 0x00007fff6a7609d7 libxpc.dylib`xpc_pipe_create + 60
frame #5: 0x00007fff6a500485 libsystem_info.dylib`_mbr_xpc_pipe + 261
frame #6: 0x00007fff6a50033f libsystem_info.dylib`_mbr_od_available + 15
frame #7: 0x00007fff6a4fffe5 libsystem_info.dylib`mbr_identifier_translate + 645
frame #8: 0x00007fff6a4ffbf5 libsystem_info.dylib`mbr_identifier_to_uuid + 53
frame #9: 0x00007fff6a4ffbba libsystem_info.dylib`mbr_uid_to_uuid + 42
frame #10: 0x00007fff6a734db4 libsystem_secinit.dylib`_libsecinit_setup_secinitd_client + 728
frame #11: 0x00007fff6a734a7b libsystem_secinit.dylib`_libsecinit_initialize_once + 13
frame #12: 0x00007fff6a3d5db8 libdispatch.dylib`_dispatch_client_callout + 8
frame #13: 0x00007fff6a3d5d6b libdispatch.dylib`dispatch_once_f + 41
frame #14: 0x00007fff680aa9d2 libSystem.B.dylib`libSystem_initializer + 136
....
frame #29: 0x000000010056d1d2 dyld`_dyld_start + 54
找到所需的xpc_pipe_create
函数。可以使用p (char *) xpc_copy_description($rsi)
查看通过XPC
管道发送的消息,这调试非常有用。使用RSI
寄存器作为消息的第二个参数(第一个参数是管道)。
(lldb) p (char *) xpc_copy_description($rsi)
(char *) $0 = 0x0000000101101fa0 "<dictionary: 0x10100c430> { count = 9, transaction: 0, voucher = 0x0, contents =\n\t"subsystem" => <uint64: 0x10100c7a0>: 5\n\t"handle" => <uint64: 0x10100c540>: 0\n\t"instance" => <uuid: 0x10100c6e0> 00000000-0000-0000-0000-000000000000\n\t"routine" => <uint64: 0x10100c800>: 207\n\t"flags" => <uint64: 0x10100c750>: 8\n\t"name" => <string: 0x10100c620> { length = 42, contents = "com.apple.system.opendirectoryd.membership" }\n\t"type" => <uint64: 0x10100c4f0>: 7\n\t"targetpid" => <int64: 0x10100c680>: 0\n\t"domain-port" => <mach send right: 0x10100c590> { name = 1799, right = send, urefs = 5 }\n}"
这也不是所需要的。这只是一个握手信息,继续。
(lldb) c
Process 12594 resuming
Process 12594 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x00007fff6a75ec40 libxpc.dylib`xpc_pipe_routine
libxpc.dylib`xpc_pipe_routine:
-> 0x7fff6a75ec40 <+0>: pushq %rbp
0x7fff6a75ec41 <+1>: movq %rsp, %rbp
0x7fff6a75ec44 <+4>: pushq %r15
0x7fff6a75ec46 <+6>: pushq %r14
Target 0: (iHex) stopped.
...
(lldb) c
Process 12594 resuming
Process 12594 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x00007fff6a75ec40 libxpc.dylib`xpc_pipe_routine
libxpc.dylib`xpc_pipe_routine:
-> 0x7fff6a75ec40 <+0>: pushq %rbp
0x7fff6a75ec41 <+1>: movq %rsp, %rbp
0x7fff6a75ec44 <+4>: pushq %r15
0x7fff6a75ec46 <+6>: pushq %r14
Target 0: (iHex) stopped.
(lldb) p (char *) xpc_copy_description($rsi)
(char *) $5 = 0x0000000102821a00 "<dictionary: 0x1010051b0> { count = 11, transaction: 0, voucher = 0x0, contents =\n\t"SECINITD_REGISTRATION_MESSAGE_SHORT_NAME_KEY" => <string: 0x10100c2d0> { length = 4, contents = "iHex" }\n\t"SECINITD_REGISTRATION_MESSAGE_IS_SANDBOX_CANDIDATE_KEY" => <bool: 0x7fffa2befb98>: true\n\t"SECINITD_REGISTRATION_MESSAGE_ENTITLEMENTS_DICT_KEY" => <dictionary: 0x101009690> { count = 6, transaction: 0, voucher = 0x0, contents =\n\t\t"com.apple.security.app-sandbox" => <bool: 0x7fffa2befb98>: true\n\t\t"com.apple.application-identifier" => <string: 0x101009a60> { length = 30, contents = "A9TT2D59XS.com.hewbo.hexeditor" }\n\t\t"com.apple.security.print" => <bool: 0x7fffa2befb98>: true\n\t\t"com.apple.security.files.user-selected.read-write" => <bool: 0x7fffa2befb98>: true\n\t\t"com.apple.developer.team-identifier" => <string: 0x101002ec0> { length = 10, contents = "A9TT2D59XS" }\n\t\t"com.apple.security.network.client" => <bool: 0x7fffa2befb98>: true\n\t}\n\t"SECINITD_REGISTRATION_MESSAGE_LIBRARY_VALIDATION_KEY" => <bool: 0x7fffa2befbb8>: false\n"
(lldb)
包含程序的权限以及它是否是沙盒的候选项的宝贵信息。正如所见,SECINITD_REGISTRATION_MESSAGE_IS_SANDBOX_CANDIDATE_KEY
设置为bool true
,并且确实拥有com.apple.security.app-sandbox
权限。
可以看到了进程发送给secinitd
的内容,看是否正在创建沙盒。使用设置的第二个断点,即__sandbox_ms
上的断点,继续(c)直到找到它。
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
* frame #0: 0x00007fff6a55f648 libsystem_kernel.dylib`__mac_syscall
frame #1: 0x00007fff6a731bc9 libsystem_sandbox.dylib`sandbox_container_path_for_pid + 63
frame #2: 0x00007fff6a4edd0c libsystem_coreservices.dylib`_dirhelper_init + 159
frame #3: 0x00007fff6a71cf00 libsystem_platform.dylib`_os_once + 33
frame #4: 0x00007fff6a4ee754 libsystem_coreservices.dylib`_dirhelper + 1873
frame #5: 0x00007fff6a4604e9 libsystem_c.dylib`confstr + 525
frame #6: 0x00007fff6a7354a5 libsystem_secinit.dylib`_libsecinit_setup_app_sandbox + 474 # As you can see, the Sandbox is set.
frame #7: 0x00007fff6a734a82 libsystem_secinit.dylib`_libsecinit_initialize_once + 20
frame #8: 0x00007fff6a3d5db8 libdispatch.dylib`_dispatch_client_callout + 8
frame #9: 0x00007fff6a3d5d6b libdispatch.dylib`dispatch_once_f + 41
frame #10: 0x00007fff680aa9d2 libSystem.B.dylib`libSystem_initializer + 136
frame #11: 0x0000000100582ac6 dyld`ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&) + 420
frame #12: 0x0000000100582cf6 dyld`ImageLoaderMachO::doInitialization(ImageLoader::LinkContext const&) + 40
frame #13: 0x000000010057e218 dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, char const*, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) + 330
frame #14: 0x000000010057e1ab dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, char const*, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) + 221
frame #15: 0x000000010057e1ab dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, char const*, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) + 221
frame #16: 0x000000010057e1ab dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, char const*, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) + 221
frame #17: 0x000000010057e1ab dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, char const*, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) + 221
frame #18: 0x000000010057e1ab dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, char const*, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) + 221
frame #19: 0x000000010057e1ab dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, char const*, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) + 221
frame #20: 0x000000010057d34e dyld`ImageLoader::processInitializers(ImageLoader::LinkContext const&, unsigned int, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) + 134
frame #21: 0x000000010057d3e2 dyld`ImageLoader::runInitializers(ImageLoader::LinkContext const&, ImageLoader::InitializerTimingList&) + 74
frame #22: 0x000000010056e567 dyld`dyld::initializeMainExecutable() + 196
frame #23: 0x0000000100573239 dyld`dyld::_main(macho_header const*, unsigned long, int, char const**, char const**, char const**, unsigned long*) + 7242
frame #24: 0x000000010056d3d4 dyld`dyldbootstrap::start(macho_header const*, int, char const**, long, macho_header const*, unsigned long*) + 453
frame #25: 0x000000010056d1d2 dyld`_dyld_start + 54
(lldb)
接下来,调用libsystem_secinit
的_libsecinit_setup_app_sandbox
。这意味着沙盒已经创建好了,将在开始的时候把程序放入沙盒中。接下来的几个continue
命令将最终落入libsystem_sandbox.dylib
的sandbox_check_common
中。最后进入LaunchServices
,然后通过AppKit ' -[NSApplication init]
启动应用程序。
(lldb) c
Process 13280 resuming
Process 13280 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x00007fff6a55f648 libsystem_kernel.dylib`__mac_syscall
libsystem_kernel.dylib`__mac_syscall:
-> 0x7fff6a55f648 <+0>: movl $0x200017d, %eax ; imm = 0x200017D
0x7fff6a55f64d <+5>: movq %rcx, %r10
0x7fff6a55f650 <+8>: syscall
0x7fff6a55f652 <+10>: jae 0x7fff6a55f65c ; <+20>
Target 0: (iHex) stopped.
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
* frame #0: 0x00007fff6a55f648 libsystem_kernel.dylib`__mac_syscall
frame #1: 0x00007fff6a731646 libsystem_sandbox.dylib`sandbox_check_common + 322
frame #2: 0x00007fff6a7318f9 libsystem_sandbox.dylib`sandbox_check_by_audit_token + 177
frame #3: 0x00007fff43ae952e LaunchServices`_LSIsAuditTokenSandboxed + 149
frame #4: 0x00007fff6a3d5db8 libdispatch.dylib`_dispatch_client_callout + 8
frame #5: 0x00007fff6a3d5d6b libdispatch.dylib`dispatch_once_f + 41
frame #6: 0x00007fff439c7ed1 LaunchServices`_LSIsCurrentProcessSandboxed + 178
frame #7: 0x00007fff43ae92ec LaunchServices`_LSCheckMachPortAccessForAuditToken + 72
frame #8: 0x00007fff43ae9448 LaunchServices`_LSCheckLSDServiceAccessForAuditToken + 153
frame #9: 0x00007fff439c097a LaunchServices`_LSRegisterSelf + 64
frame #10: 0x00007fff439b9a7c LaunchServices`_LSApplicationCheckIn + 5420
frame #11: 0x00007fff40d7192c HIServices`_RegisterApplication + 4617
frame #12: 0x00007fff40d7064c HIServices`GetCurrentProcess + 24
frame #13: 0x00007fff417cf4ab HIToolbox`MenuBarInstance::GetAggregateUIMode(unsigned int*, unsigned int*) + 63
frame #14: 0x00007fff417cf435 HIToolbox`MenuBarInstance::IsVisible() + 51
frame #15: 0x00007fff3fa71197 AppKit`_NSInitializeAppContext + 35
frame #16: 0x00007fff3fa70590 AppKit`-[NSApplication init] + 443
frame #17: 0x00007fff3fa701e6 AppKit`+[NSApplication sharedApplication] + 138
frame #18: 0x00007fff3fa718b2 AppKit`NSApplicationMain + 356
frame #19: 0x0000000100001c04 iHex`___lldb_unnamed_symbol1$$iHex + 52
(lldb)
至此,程序沙盒化完成!
原文:https://geosn0w.github.io/A-Long-Evening-With-macOS's-Sandbox/