/*
 * check if a found kernel is the one we are running atm
 */
static boolean_t is_current_kernel(void *kernel_header) {
	// search backwards for the kernel base address (mach-o header)
	mach_vm_address_t kernel_base = find_kernel_base();
	
	uint64_t *uuid1 = get_uuid(kernel_header);
	uint64_t *uuid2 = get_uuid((void*)kernel_base);
	
	if(!uuid1 || !uuid2) {
		return FALSE;
	}
	
	return uuid1[0] == uuid2[0] && uuid1[1] == uuid2[1];
}
/*
 * retrieve the __TEXT address of current loaded kernel so we can compute the KASLR slide
 * also the size of __text
 */
static kern_return_t get_running_text_address(kernel_info *kinfo, mach_vm_address_t slide) {
	// search backwards for the kernel base address (mach-o header)
    mach_vm_address_t base = slide ? slide : find_kernel_base();
    if (base) {
        // get the vm address of __TEXT segment
        struct mach_header_64* mh = (void*)(base);
        size_t headerSize = sizeof(struct mach_header_64);

        struct load_command *loadCmd;
        uint8_t* addr = (uint8_t *)(base) + headerSize;
        uint8_t* endaddr = (uint8_t *)(base) + HEADER_SIZE;
        for (uint32_t i = 0; i < mh->ncmds; i++) {
            loadCmd = (struct load_command *)(addr);

            if (addr + sizeof(struct load_command) > endaddr || addr + loadCmd->cmdsize > endaddr) {
//                SYSLOG("mach", "running command %u of info %s exceeds header size", i, objectId ? objectId : "(null)");
                return KERN_FAILURE;
            }

            if (loadCmd->cmd == LC_SEGMENT_64) {
                struct segment_command_64 *segCmd = (struct segment_command_64 *)(loadCmd);
                if (!strncmp(segCmd->segname, "__TEXT", sizeof(segCmd->segname))) {
                    kinfo->running_text_addr = segCmd->vmaddr;
                    kinfo->mh = mh;
                    break;
                }
            }
            addr += loadCmd->cmdsize;
        }
    }

    // compute kaslr slide
    if (kinfo->running_text_addr && kinfo->mh) {
        if (!slide) // This is kernel image
            kinfo->kaslr_slide = kinfo->running_text_addr - kinfo->disk_text_addr;
        else // This is kext image
            kinfo->kaslr_slide = kinfo->prelink_slid ? kinfo->prelink_vmaddr : slide;
        kinfo->kaslr_slide_set = true;

//        DBGLOG("mach", "aslr/load slide is 0x%llx", kaslr_slide);
    } else {
//        SYSLOG("mach", "couldn't find the running addresses");
        return KERN_FAILURE;
    }

    return KERN_SUCCESS;
}
Beispiel #3
0
/*
 * brute force search sysent
 * this method works in all versions
 * returns a pointer to the sysent structure
 * Note: 32/64 bits compatible
 */
static void *
bruteforce_sysent(mach_vm_address_t *out_kernel_base)
{
    // retrieves the address of the IDT
    mach_vm_address_t idt_address = 0;
    get_addr_idt(&idt_address);
    LOG_DEBUG("IDT Address is 0x%llx", idt_address);
    // calculate the address of the int80 handler
    mach_vm_address_t int80_address = calculate_int80address(idt_address);
    // search backwards for the kernel base address (mach-o header)
    mach_vm_address_t kernel_base = find_kernel_base(int80_address);
    *out_kernel_base = kernel_base;
    uint64_t data_address = 0;
    uint64_t data_size = 0;
    // search for the __DATA segment
    process_header(kernel_base, &data_address, &data_size);
    uint64_t data_limit = data_address + data_size;
    // bruteforce search for sysent in __DATA segment
    while (data_address <= data_limit)
    {
        if (version_major == YOSEMITE || version_major == EL_CAPITAN)
        {
            struct sysent_yosemite *table = (struct sysent_yosemite*)data_address;
            if((void*)table != NULL &&
               table[SYS_exit].sy_narg      == 1 &&
               table[SYS_fork].sy_narg      == 0 &&
               table[SYS_read].sy_narg      == 3 &&
               table[SYS_wait4].sy_narg     == 4 &&
               table[SYS_ptrace].sy_narg    == 4 &&
               table[SYS_getxattr].sy_narg  == 6 &&
               table[SYS_listxattr].sy_narg == 4 &&
               table[SYS_recvmsg].sy_narg   == 3 )
            {
                LOG_DEBUG("exit() address is %p", (void*)table[SYS_exit].sy_call);
                LOG_DEBUG("no. of args for exit()  %d", table[SYS_exit].sy_narg);
                LOG_DEBUG("Success!! Done here.");
                return (void*)data_address;
            }
        }
        /* mavericks or higher */
        else if (version_major == MAVERICKS)
        {
            struct sysent_mavericks *table = (struct sysent_mavericks*)data_address;
            if((void*)table != NULL &&
               table[SYS_exit].sy_narg      == 1 &&
               table[SYS_fork].sy_narg      == 0 &&
               table[SYS_read].sy_narg      == 3 &&
               table[SYS_wait4].sy_narg     == 4 &&
               table[SYS_ptrace].sy_narg    == 4 &&
               table[SYS_getxattr].sy_narg  == 6 &&
               table[SYS_listxattr].sy_narg == 4 &&
               table[SYS_recvmsg].sy_narg   == 3 )
            {
                LOG_DEBUG("exit() address is %p", (void*)table[SYS_exit].sy_call);
                return (void*)data_address;
            }
        }
        /* all previous versions */
        else
        {
            struct sysent *table = (struct sysent*)data_address;
            if((void*)table != NULL &&
               table[SYS_exit].sy_narg      == 1 &&
               table[SYS_fork].sy_narg      == 0 &&
               table[SYS_read].sy_narg      == 3 &&
               table[SYS_wait4].sy_narg     == 4 &&
               table[SYS_ptrace].sy_narg    == 4 &&
               table[SYS_getxattr].sy_narg  == 6 &&
               table[SYS_listxattr].sy_narg == 4 &&
               table[SYS_recvmsg].sy_narg   == 3 )
            {
                LOG_DEBUG("exit() address is %p", (void*)table[SYS_exit].sy_call);
                return (void*)data_address;
            }
        }
        data_address++;
    }
    return NULL;
}
Beispiel #4
0
int
main(int argc, char ** argv)
{
    	
	header();
    	
	// we need to run this as root
	if (getuid() != 0)
	{
		printf("[ERROR] Please run me as root!\n");
		exit(1);
	}
	
	int8_t kernel_type = get_kernel_type();
	if (kernel_type == -1)
	{
		printf("[ERROR] Unable to retrieve kernel type!\n");
		exit(1);
	}
	
	if((fd_kmem = open("/dev/kmem",O_RDWR)) == -1)
	{
		fprintf(stderr,"[ERROR] Error while opening /dev/kmem. Is /dev/kmem enabled?\n");
		fprintf(stderr,"Add parameter kmem=1 to /Library/Preferences/SystemConfiguration/com.apple.Boot.plist\n");
		exit(1);
	}
	    
	// retrieve int80 address
    idt_t idt_address = get_addr_idt(kernel_type);
    uint64_t int80_address = calculate_int80address(idt_address, kernel_type);
    
    uint64_t kernel_base = find_kernel_base(int80_address, kernel_type);
    if (kernel_base == 0)
    {
        fprintf(stderr, "[ERROR] Could not find kernel base address!\n");
        exit(1);
    }
    uint64_t data_address = 0;
    uint64_t data_size    = 0;
    
    process_header(kernel_base, &data_address, &data_size);
    
    uint8_t *read = malloc((size_t)data_size);
	if (read == NULL)
    {
        printf("[ERROR] Memory allocation failed!\n");
        exit(1);
    }

	// read kernel memory and find sysent
    readkmem(fd_kmem, read, data_address, (size_t)data_size);
    uint64_t sysent_address = find_sysent(read, data_address, data_size);
    
    if (sysent_address)
    {
        printf("[OK] Found sysent address at %p\n",(void*)sysent_address);
    }
    else
    {
        printf("[ERROR] Could not found sysent address!\n");
    }

    free(read);
	return 0;
}