Esempio n. 1
0
int operate_on_backtrace(ULONG_PTR retaddr, ULONG_PTR sp, int(*func)(ULONG_PTR))
{
	int ret;
	PVOID backtrace[HOOK_BACKTRACE_DEPTH];
	lasterror_t lasterror;
	WORD frames;
	WORD i;

	get_lasterrors(&lasterror);

	hook_disable();

	frames = our_stackwalk(retaddr, sp, backtrace, HOOK_BACKTRACE_DEPTH);

	for (i = 0; i < frames; i++) {
		if (!addr_in_our_dll_range((ULONG_PTR)backtrace[i]))
			break;
	}

	if (((PUCHAR)backtrace[i])[0] == 0xeb && ((PUCHAR)backtrace[i])[1] == 0x08)
		i++;

	for (; i < frames; i++) {
		ret = func((ULONG_PTR)backtrace[i]);
		if (ret)
			goto out;
	}

out:
	hook_enable();
	set_lasterrors(&lasterror);
	return ret;
}
Esempio n. 2
0
void set_hooks()
{
    // the hooks contain executable code as well, so they have to be RWX
    DWORD old_protect;
    VirtualProtect(g_hooks, sizeof(g_hooks), PAGE_EXECUTE_READWRITE,
        &old_protect);

    hook_disable();

    // now, hook each api :)
    for (int i = 0; i < ARRAYSIZE(g_hooks); i++) {
        if(g_hooks[i].allow_hook_recursion != FALSE) {
            hook_api(&g_hooks[i], HOOKTYPE);
        }
        else {
            hook_api(&g_hooks[i], HOOKTYPE);
        }
    }

    hook_enable();
}
int hook_enable() {
	// Lock the thread control mutex.  This will be unlocked when the
	// thread has finished starting, or when it has fully stopped.
	#ifdef _WIN32
	WaitForSingleObject(hook_control_mutex, INFINITE);
	#else
	pthread_mutex_lock(&hook_control_mutex);
	#endif
	
	// Set the initial status.
	int status = UIOHOOK_FAILURE;
	
	#ifndef _WIN32
	// Create the thread attribute.
	pthread_attr_t hook_thread_attr;
	pthread_attr_init(&hook_thread_attr);

	// Get the policy and priority for the thread attr.
	int policy;
	pthread_attr_getschedpolicy(&hook_thread_attr, &policy);
	int priority = sched_get_priority_max(policy);
	#endif
	
	#if defined(_WIN32)
	DWORD hook_thread_id;
	DWORD *hook_thread_status = malloc(sizeof(DWORD));
	hook_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) hook_thread_proc, hook_thread_status, 0, &hook_thread_id);
	if (hook_thread != INVALID_HANDLE_VALUE) {
	#else
	int *hook_thread_status = malloc(sizeof(int));
	if (pthread_create(&hook_thread, &hook_thread_attr, hook_thread_proc, hook_thread_status) == 0) {
	#endif
		#if defined(_WIN32)
		// Attempt to set the thread priority to time critical.
		if (SetThreadPriority(hook_thread, THREAD_PRIORITY_TIME_CRITICAL) == 0) {
			logger_proc(LOG_LEVEL_WARN, "%s [%u]: Could not set thread priority %li for thread %#p! (%#lX)\n",
					__FUNCTION__, __LINE__, (long) THREAD_PRIORITY_TIME_CRITICAL,
					hook_thread	, (unsigned long) GetLastError());
		}
		#elif (defined(__APPLE__) && defined(__MACH__)) || _POSIX_C_SOURCE >= 200112L
		// Some POSIX revisions do not support pthread_setschedprio so we will 
		// use pthread_setschedparam instead.
		struct sched_param param = { .sched_priority = priority };
		if (pthread_setschedparam(hook_thread, SCHED_OTHER, &param) != 0) {
			logger_proc(LOG_LEVEL_WARN,	"%s [%u]: Could not set thread priority %i for thread 0x%lX!\n",
					__FUNCTION__, __LINE__, priority, (unsigned long) hook_thread);
		}
		#else
		// Raise the thread priority using glibc pthread_setschedprio.
		if (pthread_setschedprio(hook_thread, priority) != 0) {
			logger_proc(LOG_LEVEL_WARN,	"%s [%u]: Could not set thread priority %i for thread 0x%lX!\n",
					__FUNCTION__, __LINE__, priority, (unsigned long) hook_thread);
		}
		#endif
		
		
		// Wait for the thread to indicate that it has passed the 
		// initialization portion by blocking until either a EVENT_HOOK_ENABLED 
		// event is received or the thread terminates.
		// NOTE This unlocks the hook_control_mutex while we wait.
		#ifdef _WIN32
		WaitForSingleObject(hook_control_cond, INFINITE);
		#else
		pthread_cond_wait(&hook_control_cond, &hook_control_mutex);
		#endif

		#ifdef _WIN32
		if (WaitForSingleObject(hook_running_mutex, 0) != WAIT_TIMEOUT) {
		#else
		if (pthread_mutex_trylock(&hook_running_mutex) == 0) {
		#endif
			// Lock Successful; The hook is not running but the hook_control_cond 
			// was signaled!  This indicates that there was a startup problem!
			
			// Get the status back from the thread.
			#ifdef _WIN32
			WaitForSingleObject(hook_thread,  INFINITE);
			GetExitCodeThread(hook_thread, hook_thread_status);
			#else
			pthread_join(hook_thread, (void **) &hook_thread_status);
			status = *hook_thread_status;
			#endif
		}
		else {
			// Lock Failure; The hook is currently running and wait was signaled
			// indicating that we have passed all possible start checks.  We can 
			// always assume a successful startup at this point.
			status = UIOHOOK_SUCCESS;
		}
		
		free(hook_thread_status);
	
		logger_proc(LOG_LEVEL_DEBUG,	"%s [%u]: Thread Result: (%#X).\n",
				__FUNCTION__, __LINE__, status);
	}
	else {
		status = UIOHOOK_ERROR_THREAD_CREATE;
	}
	
	// Make sure the control mutex is unlocked.
	#ifdef _WIN32
	ReleaseMutex(hook_control_mutex);
	#else
	pthread_mutex_unlock(&hook_control_mutex);
	#endif
	
	return status;
}


int main() {
	// Lock the thread control mutex.  This will be unlocked when the
	// thread has finished starting, or when it has fully stopped.
	#ifdef _WIN32
	// Create event handles for the thread hook.
	hook_running_mutex = CreateMutex(NULL, FALSE, TEXT("hook_running_mutex"));
	hook_control_mutex = CreateMutex(NULL, FALSE, TEXT("hook_control_mutex"));
	hook_control_cond = CreateEvent(NULL, TRUE, FALSE, TEXT("hook_control_cond"));
	#else
	pthread_mutex_init(&hook_running_mutex, NULL);
	pthread_mutex_init(&hook_control_mutex, NULL);
	pthread_cond_init(&hook_control_cond, NULL);
	#endif
	
	// Set the logger callback for library output.
	hook_set_logger_proc(&logger_proc);
	
	// Set the event callback for uiohook events.
	hook_set_dispatch_proc(&dispatch_proc);

	// Start the hook and block.
	// NOTE If EVENT_HOOK_ENABLED was delivered, the status will always succeed.
	int status = hook_enable();
	switch (status) {
		case UIOHOOK_SUCCESS:
			// We no longer block, so we need to explicitly wait for the thread to die.
			#ifdef _WIN32
			WaitForSingleObject(hook_thread,  INFINITE);
			#else
			#if defined(__APPLE__) && defined(__MACH__)
			// NOTE Darwin requires that you start your own runloop from main.
			CFRunLoopRun();
			#endif
			
			pthread_join(hook_thread, NULL);
			#endif
			break;

		// System level errors.
		case UIOHOOK_ERROR_OUT_OF_MEMORY:
			logger_proc(LOG_LEVEL_ERROR, "Failed to allocate memory. (%#X)\n", status);
			break;


		// X11 specific errors.
		case UIOHOOK_ERROR_X_OPEN_DISPLAY:
			logger_proc(LOG_LEVEL_ERROR, "Failed to open X11 display. (%#X)\n", status);
			break;

		case UIOHOOK_ERROR_X_RECORD_NOT_FOUND:
			logger_proc(LOG_LEVEL_ERROR, "Unable to locate XRecord extension. (%#X)\n", status);
			break;

		case UIOHOOK_ERROR_X_RECORD_ALLOC_RANGE:
			logger_proc(LOG_LEVEL_ERROR, "Unable to allocate XRecord range. (%#X)\n", status);
			break;

		case UIOHOOK_ERROR_X_RECORD_CREATE_CONTEXT:
			logger_proc(LOG_LEVEL_ERROR, "Unable to allocate XRecord context. (%#X)\n", status);
			break;

		case UIOHOOK_ERROR_X_RECORD_ENABLE_CONTEXT:
			logger_proc(LOG_LEVEL_ERROR, "Failed to enable XRecord context. (%#X)\n", status);
			break;


		// Windows specific errors.
		case UIOHOOK_ERROR_SET_WINDOWS_HOOK_EX:
			logger_proc(LOG_LEVEL_ERROR, "Failed to register low level windows hook. (%#X)\n", status);
			break;


		// Darwin specific errors.
		case UIOHOOK_ERROR_AXAPI_DISABLED:
			logger_proc(LOG_LEVEL_ERROR, "Failed to enable access for assistive devices. (%#X)\n", status);
			break;

		case UIOHOOK_ERROR_CREATE_EVENT_PORT:
			logger_proc(LOG_LEVEL_ERROR, "Failed to create apple event port. (%#X)\n", status);
			break;

		case UIOHOOK_ERROR_CREATE_RUN_LOOP_SOURCE:
			logger_proc(LOG_LEVEL_ERROR, "Failed to create apple run loop source. (%#X)\n", status);
			break;

		case UIOHOOK_ERROR_GET_RUNLOOP:
			logger_proc(LOG_LEVEL_ERROR, "Failed to acquire apple run loop. (%#X)\n", status);
			break;

		case UIOHOOK_ERROR_CREATE_OBSERVER:
			logger_proc(LOG_LEVEL_ERROR, "Failed to create apple run loop observer. (%#X)\n", status);
			break;

		// Default error.
		case UIOHOOK_FAILURE:
		default:
			logger_proc(LOG_LEVEL_ERROR, "An unknown hook error occurred. (%#X)\n", status);
			break;
	}
	
	#ifdef _WIN32
	// Create event handles for the thread hook.
	CloseHandle(hook_thread);
	CloseHandle(hook_running_mutex);
	CloseHandle(hook_control_mutex);
	CloseHandle(hook_control_cond);
	#else
	pthread_mutex_destroy(&hook_running_mutex);
	pthread_mutex_destroy(&hook_control_mutex);
	pthread_cond_destroy(&hook_control_cond); 
	#endif

	return status;
}