xnu 采用了微内核的架构,
因此 Mach Message 与各模块都有着千丝万缕的联系,
异常也不例外。
如果想详细的学习 Mach Exception 是如何工作的,
其与 Unix Signal 的关系,
大家可以去阅读:
《Mac OS X Internals: A Systems Approach》
《Mac OS X and iOS Internals: To The Apple's Core》。
这里给出一个监控某个线程 Mach Exception 的代码,
主要用于在发生异常时分析其他线程的状态,
并且可以用来构建基于异常的反调试机制。
#import <mach/mach.h>
#import <mach/port.h>
#import <mach/exception.h>
#import <mach/exception_types.h>
#import <mach/task.h>
#import <stdio.h>
#import <pthread/pthread.h>
mach_port_t gExceptionPort = 0;
static void *ExceptionHandler(void *ignored)
{
mach_msg_return_t rc;
printf("--------->Exc handler listening\n");
typedef struct {
mach_msg_header_t Head;
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t thread;
mach_msg_port_descriptor_t task;
NDR_record_t NDR;
exception_type_t exception;
mach_msg_type_number_t codeCnt;
integer_t code[2];
int flavor;
mach_msg_type_number_t old_stateCnt;
natural_t old_state[144];
} Request;
Request exc;
for(;;) {
rc = mach_msg(&exc.Head,
MACH_RCV_MSG | MACH_RCV_LARGE,
0,
sizeof(Request),
gExceptionPort,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);
if(rc != MACH_MSG_SUCCESS) {
return 0;
};
printf("--------->Got Message\n");
exit(1);
}
}
static void CatchMACHExceptions()
{
kern_return_t rc = 0;
exception_mask_t excMask = EXC_MASK_BAD_ACCESS; // !!!这里只是监控了异常读写,实际使用时需要根据需要进行修改!!!
rc = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &gExceptionPort);
if (rc != KERN_SUCCESS) {
fprintf(stderr, "------->Fail to allocate exception port\n");
exit(-1);
}
rc = mach_port_insert_right(mach_task_self(), gExceptionPort, gExceptionPort, MACH_MSG_TYPE_MAKE_SEND);
if (rc != KERN_SUCCESS) {
fprintf(stderr, "-------->Fail to insert right");
exit(-2);
}
rc = thread_set_exception_ports(mach_thread_self(), excMask, gExceptionPort, EXCEPTION_DEFAULT, MACHINE_THREAD_STATE);
if (rc != KERN_SUCCESS) {
fprintf(stderr, "-------->Fail to set exception\n");
exit(-3);
}
pthread_t thread;
pthread_create(&thread, NULL, ExceptionHandler, NULL);
}