static load_return_t
set_code_unprotect(
		   struct encryption_info_command *eip,
		   caddr_t addr, 	
		   vm_map_t map,
		   int64_t slide,
		   uint8_t	*vp,
		   cpu_type_t cputype,
		   cpu_subtype_t cpusubtype)
{
	int result, len;
	pager_crypt_info_t crypt_info;
	const char * cryptname = 0;
	char *vpath;
	
	size_t offset;
	struct segment_command_64 *seg64;
	struct segment_command *seg32;
	vm_map_offset_t map_offset, map_size;
	kern_return_t kr;

	if (eip->cmdsize < sizeof(*eip)) return LOAD_BADMACHO;
	
	switch(eip->cryptid) {
		case 0:
			/* not encrypted, just an empty load command */
			return LOAD_SUCCESS;
		case 1:
			cryptname="com.apple.unfree";
			break;
		case 0x10:	
			/* some random cryptid that you could manually put into
			 * your binary if you want NULL */
			cryptname="com.apple.null";
			break;
		default:
			return LOAD_BADMACHO;
	}
	
	if (map == VM_MAP_NULL) return (LOAD_SUCCESS);
	if (NULL == text_crypter_create) return LOAD_FAILURE;

	MALLOC_ZONE(vpath, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
	if(vpath == NULL) return LOAD_FAILURE;
	
	len = MAXPATHLEN;
	result = vn_getpath(vp, vpath, &len);
	if(result) {
		FREE_ZONE(vpath, MAXPATHLEN, M_NAMEI);
		return LOAD_FAILURE;
	}
	
	/* set up decrypter first */
	crypt_file_data_t crypt_data = {
		.filename = vpath,
		.cputype = cputype,
		.cpusubtype = cpusubtype};
	kr=text_crypter_create(&crypt_info, cryptname, (void*)&crypt_data);
	FREE_ZONE(vpath, MAXPATHLEN, M_NAMEI);
	
	if(kr) {
		printf("set_code_unprotect: unable to create decrypter %s, kr=%d\n",
		       cryptname, kr);
		if (kr == kIOReturnNotPrivileged) {
			/* text encryption returned decryption failure */
			return(LOAD_DECRYPTFAIL);
		 }else
			return LOAD_RESOURCE;
	}
	
	/* this is terrible, but we have to rescan the load commands to find the
	 * virtual address of this encrypted stuff. This code is gonna look like
	 * the dyld source one day... */
	struct mach_header *header = (struct mach_header *)addr;
	size_t mach_header_sz = sizeof(struct mach_header);
	if (header->magic == MH_MAGIC_64 ||
	    header->magic == MH_CIGAM_64) {
	    	mach_header_sz = sizeof(struct mach_header_64);
	}
	offset = mach_header_sz;
	uint32_t ncmds = header->ncmds;
	while (ncmds--) {
		/*
		 *	Get a pointer to the command.
		 */
		struct load_command *lcp = (struct load_command *)(addr + offset);
		offset += lcp->cmdsize;
		
		switch(lcp->cmd) {
			case LC_SEGMENT_64:
				seg64 = (struct segment_command_64 *)lcp;
				if ((seg64->fileoff <= eip->cryptoff) &&
				    (seg64->fileoff+seg64->filesize >= 
				     eip->cryptoff+eip->cryptsize)) {
					map_offset = seg64->vmaddr + eip->cryptoff - seg64->fileoff + slide;
					map_size = eip->cryptsize;
					goto remap_now;
				}
			case LC_SEGMENT:
				seg32 = (struct segment_command *)lcp;
				if ((seg32->fileoff <= eip->cryptoff) &&
				    (seg32->fileoff+seg32->filesize >= 
				     eip->cryptoff+eip->cryptsize)) {
					map_offset = seg32->vmaddr + eip->cryptoff - seg32->fileoff + slide;
					map_size = eip->cryptsize;
					goto remap_now;
				}
		}
	}
	
	/* if we get here, did not find anything */
	return LOAD_BADMACHO;
	
remap_now:
	/* now remap using the decrypter */
	kr = vm_map_apple_protected(map, map_offset, map_offset+map_size, &crypt_info);
	if(kr) {
		printf("set_code_unprotect(): mapping failed with %x\n", kr);
		crypt_info.crypt_end(crypt_info.crypt_ops);
		return LOAD_PROTECT;
	}
	
	return LOAD_SUCCESS;
}
Exemple #2
0
int
mremap_encrypted(__unused struct proc *p, struct mremap_encrypted_args *uap, __unused int32_t *retval)
{
    mach_vm_offset_t	user_addr;
    mach_vm_size_t	user_size;
    kern_return_t	result;
    vm_map_t	user_map;
    uint32_t	cryptid;
    cpu_type_t	cputype;
    cpu_subtype_t	cpusubtype;
    pager_crypt_info_t	crypt_info;
    const char * cryptname = 0;
    char *vpath;
    int len, ret;
    struct proc_regioninfo_internal pinfo;
    vnode_t vp;
    uintptr_t vnodeaddr;
    uint32_t vid;
    
    AUDIT_ARG(addr, uap->addr);
    AUDIT_ARG(len, uap->len);
    
    user_map = current_map();
    user_addr = (mach_vm_offset_t) uap->addr;
    user_size = (mach_vm_size_t) uap->len;
    
    cryptid = uap->cryptid;
    cputype = uap->cputype;
    cpusubtype = uap->cpusubtype;
    
    if (user_addr & vm_map_page_mask(user_map)) {
        /* UNIX SPEC: user address is not page-aligned, return EINVAL */
        return EINVAL;
    }
    
    switch(cryptid) {
        case 0:
            /* not encrypted, just an empty load command */
            return 0;
        case 1:
            cryptname="com.apple.unfree";
            break;
        case 0x10:
            /* some random cryptid that you could manually put into
             * your binary if you want NULL */
            cryptname="com.apple.null";
            break;
        default:
            return EINVAL;
    }
    
    if (NULL == text_crypter_create) return ENOTSUP;
    
    ret = fill_procregioninfo_onlymappedvnodes( proc_task(p), user_addr, &pinfo, &vnodeaddr, &vid);
    if (ret == 0 || !vnodeaddr) {
        /* No really, this returns 0 if the memory address is not backed by a file */
        return (EINVAL);
    }
    
    vp = (vnode_t)vnodeaddr;
    if ((vnode_getwithvid(vp, vid)) == 0) {
        MALLOC_ZONE(vpath, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
        if(vpath == NULL) {
            vnode_put(vp);
            return (ENOMEM);
        }
        
        len = MAXPATHLEN;
        ret = vn_getpath(vp, vpath, &len);
        if(ret) {
            FREE_ZONE(vpath, MAXPATHLEN, M_NAMEI);
            vnode_put(vp);
            return (ret);
        }
        
        vnode_put(vp);
    } else {
        return (EINVAL);
    }

#if 0
    kprintf("%s vpath %s cryptid 0x%08x cputype 0x%08x cpusubtype 0x%08x range 0x%016llx size 0x%016llx\n",
            __FUNCTION__, vpath, cryptid, cputype, cpusubtype, (uint64_t)user_addr, (uint64_t)user_size);
#endif

    /* set up decrypter first */
    crypt_file_data_t crypt_data = {
        .filename = vpath,
        .cputype = cputype,
        .cpusubtype = cpusubtype };
    result = text_crypter_create(&crypt_info, cryptname, (void*)&crypt_data);
#if VM_MAP_DEBUG_APPLE_PROTECT
    if (vm_map_debug_apple_protect) {
	    printf("APPLE_PROTECT: %d[%s] map %p [0x%llx:0x%llx] %s(%s) -> 0x%x\n",
		   p->p_pid, p->p_comm,
		   user_map,
		   (uint64_t) user_addr,
		   (uint64_t) (user_addr + user_size),
		   __FUNCTION__, vpath, result);
    }
#endif /* VM_MAP_DEBUG_APPLE_PROTECT */
    FREE_ZONE(vpath, MAXPATHLEN, M_NAMEI);
    
    if(result) {
        printf("%s: unable to create decrypter %s, kr=%d\n",
               __FUNCTION__, cryptname, result);
        if (result == kIOReturnNotPrivileged) {
            /* text encryption returned decryption failure */
            return (EPERM);
        } else {
            return (ENOMEM);
        }
    }
    
    /* now remap using the decrypter */
    vm_object_offset_t crypto_backing_offset;
    crypto_backing_offset = -1;	/* i.e. use map entry's offset */
    result = vm_map_apple_protected(user_map,
				    user_addr,
				    user_addr+user_size,
				    crypto_backing_offset,
				    &crypt_info);
    if (result) {
        printf("%s: mapping failed with %d\n", __FUNCTION__, result);
    }
   
    if (result) {
        return (EPERM);
    }
    return 0;
}