/// Iterate all tasks and update/create their information. /// @return The call returns -1 on error, 0 indicate successful completion. static int read_tasks_table(void) { kern_return_t kr; processor_set_t pset; task_array_t tasks; processor_set_name_array_t psets; mach_msg_type_number_t i, j, pcnt, tcnt; kr = host_processor_sets(task_manager_port, &psets, &pcnt); if (kr != KERN_SUCCESS) { syslog(LOG_ERR, "error in host_processor_sets(): %s", mach_error_string(kr)); return -1; } for (i = 0; i < pcnt; i++) { kr = host_processor_set_priv(task_manager_port, psets[i], &pset); if (kr != KERN_SUCCESS) { syslog(LOG_ERR, "error in host_processor_set_priv(): %s", mach_error_string(kr)); return -1; } kr = processor_set_tasks(pset, &tasks, &tcnt); if (kr != KERN_SUCCESS) { syslog(LOG_ERR, "error in processor_set_tasks(): %s", mach_error_string(kr)); return -1; } for (j = 0; j < tcnt; j++) { read_task_info(tasks[j]); kr = mach_port_deallocate(mach_task_self(), tasks[j]); if (kr != KERN_SUCCESS) { syslog(LOG_WARNING, "%s, error in mach_port_deallocate(): %s", __FUNCTION__, mach_error_string(kr)); } } kr = vm_deallocate(mach_task_self(), (vm_address_t)tasks, tcnt * sizeof(processor_set_t)); kr = mach_port_deallocate(mach_task_self(), pset); kr = mach_port_deallocate(mach_task_self(), psets[i]); } kr = vm_deallocate(mach_task_self(), (vm_address_t)psets, pcnt * sizeof(processor_set_t)); return 0; }
static task_t task_for_pid_workaround(int pid) { host_t myhost = mach_host_self(); mach_port_t psDefault = 0; mach_port_t psDefault_control = 0; task_array_t tasks = NULL; mach_msg_type_number_t numTasks = 0; kern_return_t kr = -1; int i; if (pid == -1) { return MACH_PORT_NULL; } kr = processor_set_default (myhost, &psDefault); if (kr != KERN_SUCCESS) { return MACH_PORT_NULL; } kr = host_processor_set_priv (myhost, psDefault, &psDefault_control); if (kr != KERN_SUCCESS) { // eprintf ("host_processor_set_priv failed with error 0x%x\n", kr); //mach_error ("host_processor_set_priv",kr); return MACH_PORT_NULL; } numTasks = 0; kr = processor_set_tasks (psDefault_control, &tasks, &numTasks); if (kr != KERN_SUCCESS) { // eprintf ("processor_set_tasks failed with error %x\n", kr); return MACH_PORT_NULL; } if (pid == 0) { /* kernel task */ return tasks[0]; } for (i = 0; i < numTasks; i++) { int pid2 = -1; pid_for_task (i, &pid2); if (pid == pid2) { return tasks[i]; } } return MACH_PORT_NULL; }
/* * Credits to Jonathan Levin! * This function is able to "exploit" the processor_set_tasks mach trap to retrieve * the kernel's mach port. This only works on systems where SIP is either disabled or * not present at all. * If you want to use an alternative method to read from kernel memory, try with enabling * /dev/kmem and read from that device. * * Note that code in this project is tuned to read directly from kernel task, hence you * just need to disable SIP and you're good to go, instead of rewriting code to support * /dev/kmem. */ mach_port_t task_for_pid_workaround(int Pid) { host_t myhost = mach_host_self(); mach_port_t psDefault; mach_port_t psDefault_control; task_array_t tasks; mach_msg_type_number_t numTasks; int i; kern_return_t kr; kr = processor_set_default(myhost, &psDefault); kr = host_processor_set_priv(myhost, psDefault, &psDefault_control); if (kr != KERN_SUCCESS) { fprintf(stderr, "host_processor_set_priv failed with error %x\n", kr); mach_error("host_processor_set_priv",kr); exit(1); } kr = processor_set_tasks(psDefault_control, &tasks, &numTasks); if (kr != KERN_SUCCESS) { fprintf(stderr,"processor_set_tasks failed with error %x\n",kr); exit(1); } for (i = 0; i < numTasks; i++) { int pid; pid_for_task(tasks[i], &pid); if (pid == Pid) return (tasks[i]); } return (MACH_PORT_NULL); }
bool SysInfo::GetAllProcess() { kern_return_t error; processor_set_t *psets, pset; task_t *tasks; unsigned i, j, pcnt, tcnt; m_nTotalTime = 0; host_priv_t libtop_port = mach_host_self(); // 必须获得系统root权限才能访问所有process list,下面这段代码不能获得,暂用pxl制作包来解决权限问题 host_t myhost = mach_host_self(); processor_set_name_t p_default_set; processor_set_t p_default_set_control; /* get the default processor set */ error = processor_set_default(myhost, &p_default_set); if (KERN_SUCCESS != error) { printf("Error in processor_set_default(): %s \n",mach_error_string(error)); char szInfo[256] = { 0 }; snprintf(szInfo, sizeof(szInfo) - 1, "processor_set_default error"); LogMsg(szInfo); } /* get the control port for this processor set */ error = host_processor_set_priv(myhost, p_default_set, &p_default_set_control); if (KERN_SUCCESS != error) { } error = host_processor_sets(libtop_port, &psets, &pcnt); if (error != KERN_SUCCESS) { GetProcessInfo(mach_task_self()); return TRUE; } m_pInfoList.clear(); for (i = 0; i < pcnt; i++) { error = host_processor_set_priv(libtop_port, psets[i], &pset); if (error != KERN_SUCCESS) { printf("Error in host_processor_set_priv(): %s \n",mach_error_string(error)); char szInfo[256] = { 0 }; snprintf(szInfo, sizeof(szInfo) - 1, "host_processor_set_priv error"); LogMsg(szInfo); return true; } error = processor_set_tasks(pset, &tasks, &tcnt); if (error != KERN_SUCCESS) { printf("Error in processor_set_tasks(): %s \n",mach_error_string(error)); char szInfo[256] = { 0 }; snprintf(szInfo, sizeof(szInfo) - 1, "processor_set_tasks error"); LogMsg(szInfo); return true; } for (j = 0; j < tcnt; j++) { if (GetProcessInfo(tasks[j])) { return true; } mach_port_deallocate(mach_task_self(),tasks[j]); } error = vm_deallocate((vm_map_t)mach_task_self(),(vm_address_t)tasks, tcnt * sizeof(task_t)); if (error != KERN_SUCCESS) { printf("Error in vm_deallocate(): %s \n",mach_error_string(error)); return true; } if ((error = mach_port_deallocate(mach_task_self(),pset)) != KERN_SUCCESS || (error = mach_port_deallocate(mach_task_self(),psets[i])) != KERN_SUCCESS) { printf("Error in mach_port_deallocate(): %s \n",mach_error_string(error)); return true; } } error = vm_deallocate((vm_map_t)mach_task_self(),(vm_address_t)psets, pcnt * sizeof(processor_set_t)); if (error != KERN_SUCCESS) { printf("Error in vm_deallocate(): %s \n",mach_error_string(error)); return true; } return false; }
int main(int argc, char ** argv) { int option = 0; struct config cfg = {0}; header(); if (argc < 2) { usage(); } while( (option=getopt(argc,argv,"ha:Aco:Ci:rRs")) != -1 ) { switch(option) { case 'h': usage(); exit(1); case 'a': cfg.interrupt = atoi(optarg); break; case 'A': cfg.show_all_descriptors = 1; break; case 'c': cfg.create_file_archive = 1; break; case 'r': cfg.read_file_archive = 1; break; case 'R': cfg.restore_idt = 1; break; case 'o': if(strlen(optarg) > MAXPATHLEN - 1) { ERROR_MSG("File name too long."); return -1; } strncpy(cfg.out_filename, optarg, sizeof(cfg.out_filename)); break; case 'C': cfg.compare_idt = 1; break; case 'i': if(strlen(optarg) > MAXPATHLEN - 1) { ERROR_MSG("File name too long."); return -1; } strncpy(cfg.in_filename, optarg, sizeof(cfg.in_filename)); break; case 's': cfg.resolve = 1; break; } } OUTPUT_MSG(""); if (getuid() != 0) { ERROR_MSG("This program needs to be run as root!"); return -1; } cfg.kernel_type = get_kernel_type(); if (cfg.kernel_type == -1) { ERROR_MSG("Unable to retrieve kernel type."); return -1; } else if (cfg.kernel_type == X86) { ERROR_MSG("32 bits kernels not supported."); return -1; } cfg.idt_addr = get_addr_idt(cfg.kernel_type); cfg.idt_size = get_size_idt(); cfg.idt_entries = cfg.idt_size / sizeof(struct descriptor_idt); /* we need to populate the size variable else syscall fails */ cfg.kaslr_size = sizeof(cfg.kaslr_size); get_kaslr_slide(&cfg.kaslr_size, &cfg.kaslr_slide); OUTPUT_MSG("[INFO] Kaslr slide is 0x%llx", cfg.kaslr_slide); OUTPUT_MSG("[INFO] IDT base address is: 0x%llx", cfg.idt_addr); OUTPUT_MSG("[INFO] IDT size: 0x%x\n", cfg.idt_size); /* test if we can read kernel memory using processor_set_tasks() vulnerability */ /* vulnerability presented at BlackHat Asia 2014 by Ming-chieh Pan, Sung-ting Tsai. */ /* also described in Mac OS X and iOS Internals, page 387 */ host_t host_port = mach_host_self(); mach_port_t proc_set_default = 0; mach_port_t proc_set_default_control = 0; task_array_t all_tasks = NULL; mach_msg_type_number_t all_tasks_cnt = 0; kern_return_t kr = 0; int valid_kernel_port = 0; kr = processor_set_default(host_port, &proc_set_default); if (kr == KERN_SUCCESS) { kr = host_processor_set_priv(host_port, proc_set_default, &proc_set_default_control); if (kr == KERN_SUCCESS) { kr = processor_set_tasks(proc_set_default_control, &all_tasks, &all_tasks_cnt); if (kr == KERN_SUCCESS) { DEBUG_MSG("Found valid kernel port using processor_set_tasks() vulnerability!"); cfg.kernel_port = all_tasks[0]; valid_kernel_port = 1; } } } /* if we can't use the vulnerability then try /dev/kmem */ if (valid_kernel_port == 0) { if( (cfg.fd_kmem = open("/dev/kmem",O_RDWR)) == -1 ) { ERROR_MSG("Error while opening /dev/kmem. Is /dev/kmem enabled?"); ERROR_MSG("Verify that /Library/Preferences/SystemConfiguration/com.apple.Boot.plist has kmem=1 parameter configured."); return -1; } } if (cfg.resolve == 1) { retrieve_kernel_symbols(&cfg); } if(cfg.interrupt >= 0 || cfg.show_all_descriptors == 1) { show_idt_info(&cfg); } if(cfg.create_file_archive == 1) { create_idt_archive(&cfg); } if(cfg.read_file_archive == 1) { read_idt_archive(&cfg); } if(cfg.compare_idt == 1) { compare_idt(&cfg); } if(cfg.restore_idt == 1) { compare_idt(&cfg); } return 0; }