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