Blame src/debug/ntapi_tt_debug_break_process.c

2a7f67
/********************************************************/
2a7f67
/*  ntapi: Native API core library                      */
2a7f67
/*  Copyright (C) 2013--2019  Z. Gilboa                 */
2a7f67
/*  Released under GPLv2 and GPLv3; see COPYING.NTAPI.  */
2a7f67
/********************************************************/
2a7f67
2a7f67
#include <psxtypes/psxtypes.h>
2a7f67
#include <ntapi/nt_object.h>
2a7f67
#include <ntapi/nt_debug.h>
2a7f67
#include "ntapi_impl.h"
2a7f67
2a7f67
static int32_t __tt_debug_break_process_fail(void * hthread, int32_t status)
2a7f67
{
2a7f67
	__ntapi->zw_terminate_thread(
2a7f67
		hthread,status);
2a7f67
2a7f67
	return status;
2a7f67
}
2a7f67
2a7f67
struct __dbg_hoppla {
2a7f67
	void *		caller;
2a7f67
	void *		cx;
2a7f67
	intptr_t	dx;
2a7f67
	intptr_t	r9;
2a7f67
	intptr_t	r8;
2a7f67
};
2a7f67
2a7f67
int32_t __stdcall __ntapi_tt_debug_break_process(
2a7f67
	__in	void *		hprocess,
2a7f67
	__out	void **		hthread,
2a7f67
	__out	nt_cid *	cid)
2a7f67
{
2a7f67
	int32_t			status;
2a7f67
	nt_thread_params	tparams;
2a7f67
	nt_thread_context	context;
2a7f67
	nt_user_stack		spinfo;
2a7f67
	struct __dbg_hoppla	hoppla;
2a7f67
	uintptr_t		sptop;
2a7f67
	uintptr_t		spreg;
2a7f67
	int32_t			(*dbg_break_point)(void *);
2a7f67
2a7f67
	/* interrupt & return */
2a7f67
	dbg_break_point = pe_get_procedure_address(
2a7f67
		pe_get_ntdll_module_handle(),
2a7f67
		"DbgBreakPoint");
2a7f67
2a7f67
	/* thread params */
2a7f67
	__ntapi->tt_aligned_block_memset(
2a7f67
		&tparams,0,
2a7f67
		sizeof(tparams));
2a7f67
2a7f67
	__ntapi->tt_aligned_block_memset(
2a7f67
		&spinfo,0,
2a7f67
		sizeof(spinfo));
2a7f67
2a7f67
	tparams.start              = dbg_break_point;
2a7f67
	tparams.hprocess           = hprocess;
2a7f67
	tparams.stack_size_commit  = 0x1000;
2a7f67
	tparams.stack_size_reserve = 0x1000;
2a7f67
	tparams.stack_info         = &spinfo;
2a7f67
	tparams.creation_flags     = NT_CREATE_SUSPENDED;
2a7f67
2a7f67
	if ((status = __ntapi->tt_create_thread(&tparams)))
2a7f67
		return status;
2a7f67
2a7f67
	/* context */
2a7f67
	__ntapi->tt_aligned_block_memset(
2a7f67
		&context,0,
2a7f67
		sizeof(context));
2a7f67
2a7f67
	context.uc_context_flags = NT_CONTEXT_JUST_EVERYTHING;
2a7f67
2a7f67
	if ((status = __ntapi->zw_get_context_thread(
2a7f67
			tparams.hthread,
2a7f67
			&context)))
2a7f67
		return __tt_debug_break_process_fail(
2a7f67
			tparams.hthread,
2a7f67
			status);
2a7f67
2a7f67
	/* return address:=) */
2a7f67
	hoppla.caller = __ntapi->zw_terminate_thread;
2a7f67
	hoppla.cx     = NT_CURRENT_THREAD_HANDLE;
2a7f67
	hoppla.dx     = NT_STATUS_BREAKPOINT;
2a7f67
	hoppla.r8     = 0;
2a7f67
	hoppla.r9     = 0;
2a7f67
2a7f67
	sptop = (uintptr_t)tparams.stack_info->expandable_stack_base;
2a7f67
	spreg = context.STACK_POINTER_REGISTER;
2a7f67
2a7f67
	if (sptop - spreg < sizeof(hoppla))
2a7f67
		spreg -= sizeof(hoppla);
2a7f67
2a7f67
	if ((status = __ntapi->zw_write_virtual_memory(
2a7f67
			hprocess,
2a7f67
			(void *)spreg,
2a7f67
			(char *)&hoppla,
2a7f67
			sizeof(hoppla),0)))
2a7f67
		return __tt_debug_break_process_fail(
2a7f67
			tparams.hthread,
2a7f67
			status);
2a7f67
2a7f67
	/* (fast call args not needed on x86) */
2a7f67
	context.STACK_POINTER_REGISTER = spreg;
2a7f67
	context.FAST_CALL_ARG0         = (uintptr_t)hoppla.cx;
2a7f67
	context.FAST_CALL_ARG1         = hoppla.dx;
2a7f67
2a7f67
	if ((status = __ntapi->zw_set_context_thread(
2a7f67
			tparams.hthread,
2a7f67
			&context)))
2a7f67
		return __tt_debug_break_process_fail(
2a7f67
			tparams.hthread,
2a7f67
			status);
2a7f67
2a7f67
	/* at last... */
2a7f67
	if ((status = __ntapi->zw_resume_thread(tparams.hthread,0)))
2a7f67
		return __tt_debug_break_process_fail(
2a7f67
			tparams.hthread,
2a7f67
			status);
2a7f67
2a7f67
	/* yay */
2a7f67
	*hthread        = tparams.hthread;
2a7f67
	cid->thread_id  = tparams.cid.thread_id;
2a7f67
	cid->process_id = tparams.cid.process_id;
2a7f67
2a7f67
	return NT_STATUS_SUCCESS;
2a7f67
}