Esempio n. 1
0
EXPORT
int add_breakpoint(mach_port_t task, vm_address_t patch_addr, int cont, callback handler) {
    kern_return_t kret;
    char *tmp;
    mach_vm_size_t len = 1;     // number of bytes to write
    uint8_t opcode = 0xcc;      // the CC byte to write
    interface *face;

    face = find_interface(task);
    if(face->registered_exception_handler == 0) {
        DEBUG_PRINT("[+add_breakpoint] HERE IN ADD BREAK\n %d", 0);
        register_(task);
    }

    kret = mach_vm_protect(task, patch_addr, len, FALSE, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE);
    RETURN_ON_MACH_ERROR("[-add_breakpoint] mach_vm_protect()", kret);

    if (patch_addr <= MAX_BREAKS) {
        DEBUG_PRINT("[-add_breakpoint] INVALID BREAKPOINT ADDRESS %lx\n", patch_addr);
        return -1;
    } else if(face->current_break >= MAX_BREAKS) {
        DEBUG_PRINT("[-add_breakpoint] Max %d breaks reached!\n", MAX_BREAKS);
        return -1;
    }

    DEBUG_PRINT("[+add_breakpoint] Breakpoint %u: %lx added\n", face->current_break, patch_addr);
    tmp = (char*) read_memory(task, patch_addr, 1);

    breakpoint_struct *new_break = safe_malloc(sizeof(breakpoint_struct));
    new_break->address = patch_addr;
    new_break->original = tmp[0] & 0xff;
    new_break->handler = handler;
    if(face->single_step) {
        new_break->index = face->single_step_index;
    }
    else {
        new_break->index = face->current_break == 0 ? 0 : face->breaks[face->current_break-1]->index + 1;
    }
    new_break->flags = cont;


    if(face->max_break == 0) {
        face->max_break = 1;
    }

    if(face->current_break >= (face->max_break - 1)) {
        DEBUG_PRINT("[+add_breakpoint] ALLOCATING MORE BP! CURRENTLY: %d\n", face->current_break);
        face->breaks = safe_realloc(face->breaks, sizeof(breakpoint_struct*)  *(face->max_break*2));
        face->max_break *= 2;
    }

    // face->breaks = safe_realloc(face->breaks, sizeof(breakpoint_struct*)  *(face->current_break+1));
    face->breaks[face->current_break++] = new_break;

    write_memory(task, patch_addr, opcode, len); // write the byte
    kret = mach_vm_protect(task, patch_addr, (mach_vm_size_t)1, FALSE, VM_PROT_READ | VM_PROT_EXECUTE);
    RETURN_ON_MACH_ERROR("[-add_breakpoint] RESTORE mach_vm_protect()", kret);

    return 1;
}
Esempio n. 2
0
EXPORT
int start(mach_port_t task, pid_t infoPid) {
    kern_return_t kret;
    pthread_t tid[2];
    interface* face = find_interface(task);

    kret = mach_port_allocate(current_task(), MACH_PORT_RIGHT_RECEIVE, &face->server_port);
    RETURN_ON_MACH_ERROR("[-start] mach_port_allocate failed", kret);

    kret = mach_port_insert_right(current_task(), face->server_port, face->server_port, MACH_MSG_TYPE_MAKE_SEND);
    RETURN_ON_MACH_ERROR("[-start] mach_port_insert_right failed", kret);

    kret = task_set_exception_ports(task, EXC_MASK_ALL, face->server_port, EXCEPTION_DEFAULT|MACH_EXCEPTION_CODES, THREAD_STATE_NONE);
    RETURN_ON_MACH_ERROR("[-start] task_set_exception_ports failed", kret);

    int err = pthread_create(&tid[0], NULL, (void *(*)(void*))kqueue_loop, (void *)(unsigned long long)infoPid);
    if (err != 0)
        DEBUG_PRINT("\n[-start] can't create thread :[%s]", strerror(err));
    else
        DEBUG_PRINT("\n[-start] Thread created successfully %d\n", 0);

    err = pthread_create(&tid[1], NULL, (void *(*)(void*))exception_server, (void *(*)(void*))(unsigned long long)face->server_port);
    if (err != 0)
        DEBUG_PRINT("\n[-start] can't create thread :[%s]", strerror(err));
    else
        DEBUG_PRINT("\n[-start] Thread created successfully %d\n", 0);

    return 1;
}
Esempio n. 3
0
EXPORT
mach_port_t attach(pid_t infoPid) {
    mach_port_t task;
    int count = 0;

    task = get_task(infoPid);
    if(task == 0) {
        int kret = 0;
        RETURN_ON_MACH_ERROR("[-attach] invalid pid", kret);
    }

    if(bad_list.max_attach == 0) {
        bad_list.max_attach = 1;
    }

    while(count < bad_list.x) {
        if(bad_list.y[count]->task == task) {
            int kret = 0;
            RETURN_ON_MACH_ERROR("[-attach] duplicate pid", kret);
        }
        count++;
    }

    if(bad_list.x >= (bad_list.max_attach - 1)) {
        DEBUG_PRINT("ALLOCATING MORE! CURRENTLY: %d\n", bad_list.max_attach);
        bad_list.y = realloc(bad_list.y, sizeof(interface*) * (bad_list.max_attach*2));
        bad_list.max_attach *= 2;
    }


    bad_list.y[bad_list.x] = malloc(sizeof(interface*));

    interface* tmp = malloc(sizeof(interface));
    memset(tmp, 0, sizeof(interface));

    tmp->task = task;
    tmp->pid = infoPid;
    tmp->current_break = 0;
    tmp->current_exception = 0;
    tmp->single_step = NULL;
    tmp->registered_exception_handler = 0;

    bad_list.y[bad_list.x++] = tmp;

    DEBUG_PRINT("ATTACHING TO PROCESS # %d\n", bad_list.x);
    return task;
}
Esempio n. 4
0
/*
 * Removes a breakpoint from breaks array indicated by index or address (both are unsigned long long)
 */
EXPORT
int remove_breakpoint(mach_port_t task, vm_address_t bp) {
    kern_return_t kret;
    int c, position, index;
    mach_vm_address_t address;
    interface *face;

    face = find_interface(task);
    if(!face->registered_exception_handler) {
        DEBUG_PRINT("SHOULD NEVER HAPPEN :| %d\n", 1);
        return -1;
    }

    position = find_break(task, bp);
    if(position == -1) {
        DEBUG_PRINT("[-remove_breakpoint] Failed find_break %d\n", position);
        return -1;
    }

    breakpoint_struct *breakpoint = face->breaks[position];

    uint8_t opcode = breakpoint->original;                  // CC byte to write
    mach_vm_size_t len = 1;                                 // number of bytes to write

    kret = mach_vm_protect(task, breakpoint->address, len, FALSE, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE);
    RETURN_ON_MACH_ERROR("[-remove_breakpoint] mach_vm_protect()", kret);

    write_memory(task, breakpoint->address, opcode, len);   // and write the byte

    kret = mach_vm_protect(task, breakpoint->address, len, FALSE, VM_PROT_READ | VM_PROT_EXECUTE);
    RETURN_ON_MACH_ERROR("[-remove_breakpoint] RESTORE mach_vm_protect()", kret);

    address = face->breaks[position]->address;
    index = face->breaks[position]->index;

    if(face->single_step) face->single_step_index = index;

    for(c = position; c < face->current_break; c++) {
        face->breaks[c] = face->breaks[c+1];
    }

    DEBUG_PRINT("[-remove_breakpoint] Breakpoint %x at %llx removed\n", index, address);
    face->current_break -= 1; // decrement counter

    return 1;
}
Esempio n. 5
0
static bool xnu_create_exception_thread(RDebug *dbg) {
	kern_return_t kr;
	int ret;
	mach_port_t exception_port = MACH_PORT_NULL;
        // Got the mach port for the current process
	mach_port_t task_self = mach_task_self ();
	task_t task = pid_to_task (dbg->pid);
	if (task == -1) {
		eprintf ("error to get task for the debugging process"
			" xnu_start_exception_thread\n");
		return false;
	}
	if (!MACH_PORT_VALID (task_self)) {
		eprintf ("error to get the task for the current process"
			" xnu_start_exception_thread\n");
		return false;
	}
        // Allocate an exception port that we will use to track our child process
        kr = mach_port_allocate (task_self, MACH_PORT_RIGHT_RECEIVE,
				&exception_port);
	RETURN_ON_MACH_ERROR ("error to allocate mach_port exception\n", R_FALSE);
        // Add the ability to send messages on the new exception port
        kr  = mach_port_insert_right (task_self, exception_port,
				exception_port, MACH_MSG_TYPE_MAKE_SEND);
	RETURN_ON_MACH_ERROR ("error to allocate insert right\n", R_FALSE);
        // Save the original state of the exception ports for our child process
        ret = xnu_save_exception_ports (dbg);
	if (ret == R_FALSE) {
		eprintf ("error to save exception port info\n");
		return false;
	}
        // Set the ability to get all exceptions on this port
	kr = task_set_exception_ports (task, EXC_MASK_ALL, exception_port,
				EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES,
				THREAD_STATE_NONE);
	RETURN_ON_MACH_ERROR ("error to set port to receive exceptions\n", R_FALSE);
        // Create the exception thread
	//TODO where to save the exception thread
	//TODO see options pthread_create
        ret = pthread_create (&dbg->ex->thread, NULL, xnu_exception_thread, dbg);
	if (ret) {
		perror ("pthread_create");
		return false;
	}
	return true;
}
Esempio n. 6
0
bool xnu_create_exception_thread(RDebug *dbg) {
#if __POWERPC__
	return false;
#else
	kern_return_t kr;
	mach_port_t exception_port = MACH_PORT_NULL;
	mach_port_t req_port;
        // Got the mach port for the current process
	mach_port_t task_self = mach_task_self ();
	task_t task = pid_to_task (dbg->pid);
	if (!task) {
		eprintf ("error to get task for the debuggee process"
			" xnu_start_exception_thread\n");
		return false;
	}
	if (!MACH_PORT_VALID (task_self)) {
		eprintf ("error to get the task for the current process"
			" xnu_start_exception_thread\n");
		return false;
	}
        // Allocate an exception port that we will use to track our child process
        kr = mach_port_allocate (task_self, MACH_PORT_RIGHT_RECEIVE,
				&exception_port);
	RETURN_ON_MACH_ERROR ("error to allocate mach_port exception\n", false);
        // Add the ability to send messages on the new exception port
	kr = mach_port_insert_right (task_self, exception_port, exception_port,
				     MACH_MSG_TYPE_MAKE_SEND);
	RETURN_ON_MACH_ERROR ("error to allocate insert right\n", false);
	// Atomically swap out (and save) the child process's exception ports
	// for the one we just created. We'll want to receive all exceptions.
	ex.count = (sizeof (ex.ports) / sizeof (*ex.ports));
	kr = task_swap_exception_ports (task, EXC_MASK_ALL, exception_port,
		EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, THREAD_STATE_NONE,
		ex.masks, &ex.count, ex.ports, ex.behaviors, ex.flavors);
	RETURN_ON_MACH_ERROR ("failed to swap exception ports\n", false);
	//get notification when process die
	kr = mach_port_request_notification (task_self, task, MACH_NOTIFY_DEAD_NAME,
		 0, exception_port, MACH_MSG_TYPE_MAKE_SEND_ONCE, &req_port);
	if (kr != KERN_SUCCESS) {
		eprintf ("Termination notification request failed\n");
	}
	ex.exception_port = exception_port;
	return true;
#endif
}
Esempio n. 7
0
mach_port_t get_task(pid_t infoPid) {
    kern_return_t kret;
    mach_port_t task;

    DEBUG_PRINT("[+getstate] Trying pid %d\n", infoPid);

    kret = task_for_pid(current_task(), infoPid, &task);
    RETURN_ON_MACH_ERROR("[-get_state] task_for_pid failed", kret);

    return task;
}
Esempio n. 8
0
int persistent_break(exc_msg_t *exc) {
    interface *face;
    x86_thread_state64_t *break_state;
    kern_return_t kret;

    break_state = get_state(exc->thread);
    face = find_interface(exc->task);
    DEBUG_PRINT("[+presistent_break] single_step %lx\n", face->single_step->address);

    add_breakpoint(exc->task, face->single_step->address, PERSISTENT, face->single_step->handler);

    free(face->single_step);
    face->single_step = NULL;
    break_state->__rflags &= ~0x100;

    kret = thread_set_state(exc->thread, x86_THREAD_STATE64, (thread_state_t)break_state, x86_THREAD_STATE64_COUNT);
    RETURN_ON_MACH_ERROR("[-persistent_break] failed setting thread state", kret);

    return 1;
}
Esempio n. 9
0
int handle_break(exc_msg_t *exc) {
    interface* face;
    int ret, our_break;
    kern_return_t kret;
    x86_thread_state64_t *break_state;

    break_state = get_state(exc->thread);
    our_break = find_break(exc->task, break_state->__rip-1);

    //find_break returns -1 aka big unsigned int
    if(our_break == -1) {
        return -1;
    }

    face = find_interface(exc->task);
    face->breaks[our_break]->hit++;
    breakpoint_struct *actual = face->breaks[our_break];

    if(actual->flags == ONE_TIME) {
        remove_breakpoint(exc->task, actual->address);  //restore original byte
        break_state->__rip = actual->address;           //Restore original rip -- 1 byte back
    } else if(actual->flags == PERSISTENT) {
        face->single_step = actual;
        break_state->__rflags |= 0x100;                 //TRAP FLAG
        remove_breakpoint(exc->task, actual->address);
        break_state->__rip = actual->address;
    }

    kret = thread_set_state(exc->thread, x86_THREAD_STATE64, (thread_state_t)break_state, x86_THREAD_STATE64_COUNT);
    RETURN_ON_MACH_ERROR("[-handle_break] failed setting thread state", kret);

    if(actual->handler) {
        ret = actual->handler(exc);
        if(ret == -1) {
            return -1;
        }
    }

    return 1;
}
Esempio n. 10
0
//No synchronization issue so far, need to use synchronize if we run into any issues
int stop(mach_port_t task) {
    MachExceptionHandlerData old_handler;
    thread_act_port_array_t threadList;
    mach_msg_type_number_t threadCount;
    unsigned int count;
    kern_return_t kret;
    interface *face;

    threadCount=0;
    task_threads(current_task(), &threadList, &threadCount);
    DEBUG_PRINT("[+stop] Thread count before detaching %d\n", threadCount);

    face = find_interface(task);
    close(face->kq);                  //close kqueue
    count = 1;
    kret = task_swap_exception_ports(current_task(),
                                     EXC_MASK_ALL,
                                     MACH_PORT_NULL,
                                     EXCEPTION_DEFAULT|MACH_EXCEPTION_CODES,
                                     THREAD_STATE_NONE,
                                     (exception_mask_array_t) old_handler.masks,
                                     (mach_msg_type_number_t *) &old_handler.count,
                                     (exception_handler_array_t) old_handler.ports,
                                     (exception_behavior_array_t) old_handler.behaviors,
                                     (exception_flavor_array_t) old_handler.flavors);

    kret = mach_port_mod_refs(mach_task_self(), face->server_port, MACH_PORT_RIGHT_RECEIVE, -1);

    if (kret != KERN_SUCCESS) {
        RETURN_ON_MACH_ERROR("[-stop] mach_port_mod_refs failed", kret);
    }

    kret = mach_port_get_refs(mach_task_self(), face->server_port, MACH_PORT_RIGHT_RECEIVE, &count );
    RETURN_ON_MACH_ERROR("[-stop] mach_port_get_refs failed", kret);


    if (face->server_port) {
        kret = mach_port_deallocate(current_task(),face->server_port);
        RETURN_ON_MACH_ERROR("[-stop] mach_port_deallocate failed", kret);
    }

    if (count) {
        DEBUG_PRINT("[-stop] failed to reset server port ref count exp:0 actual: %d\n", count);
        return 0;
    }

    task_threads(task, &threadList, &threadCount);
    DEBUG_PRINT("[+stop] Thread count after detaching %d\n", threadCount);

    face->registered_exception_handler = 0;
    count = 0;

    //REMOVE PID FROM BAD LIST TO ALLOW REATTACHING
    while(count < bad_list.x) {
        if(bad_list.y[count]->task == task) {
            break;
        }
        count++;
    }

    DEBUG_PRINT("TASK IS NUMBER: %d\n", count);

    int c;
    for(c = count; c < bad_list.x; c++) {
        bad_list.y[c] =  bad_list.y[c+1];
    }
    bad_list.x -= 1;

    return 1;
}