|
|
/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
context.c
Abstract:
This module implements user-mode callable context manipulation routines. The interfaces exported from this module are portable, but they must be re-implemented for each architecture.
Author:
Mark Lucovsky (markl) 20-Jun-1989
Revision History:
Bryan Willman (bryanwi) 8-Mar-90
Ported to the 80386
--*/
#include "ntrtlp.h"
#if defined(ALLOC_PRAGMA) && defined(NTOS_KERNEL_RUNTIME)
#pragma alloc_text(PAGE,RtlInitializeContext)
#pragma alloc_text(PAGE,RtlRemoteCall)
#endif
VOID RtlInitializeContext( IN HANDLE Process, OUT PCONTEXT Context, IN PVOID Parameter OPTIONAL, IN PVOID InitialPc OPTIONAL, IN PVOID InitialSp OPTIONAL )
/*++
Routine Description:
This function initializes a context structure so that it can be used in a subsequent call to NtCreateThread.
Arguments:
Context - Supplies a context buffer to be initialized by this routine.
InitialPc - Supplies an initial program counter value.
InitialSp - Supplies an initial stack pointer value.
Return Value:
Raises STATUS_BAD_INITIAL_STACK if the value of InitialSp is not properly aligned.
Raises STATUS_BAD_INITIAL_PC if the value of InitialPc is not properly aligned.
--*/
{ RTL_PAGED_CODE();
Context->Eax = 0L; Context->Ebx = 1L; Context->Ecx = 2L; Context->Edx = 3L; Context->Esi = 4L; Context->Edi = 5L; Context->Ebp = 0L;
Context->SegGs = 0; Context->SegFs = KGDT_R3_TEB; Context->SegEs = KGDT_R3_DATA; Context->SegDs = KGDT_R3_DATA; Context->SegSs = KGDT_R3_DATA; Context->SegCs = KGDT_R3_CODE;
Context->EFlags = 0x200L; // force interrupts on, clear all else.
//
// Even though these are optional, they are used as is, since NULL
// is what these would have been initialized to anyway
//
Context->Esp = (ULONG) InitialSp; Context->Eip = (ULONG) InitialPc;
//
// add code to check alignment and raise exception...
//
Context->ContextFlags = CONTEXT_CONTROL|CONTEXT_INTEGER|CONTEXT_SEGMENTS;
//
// Set the initial context of the thread in a machine specific way.
// ie, pass the initial parameter to the start address
//
Context->Esp -= sizeof(Parameter); ZwWriteVirtualMemory(Process, (PVOID)Context->Esp, (PVOID)&Parameter, sizeof(Parameter), NULL); Context->Esp -= sizeof(Parameter); // Reserve room for ret address
}
NTSTATUS RtlRemoteCall( HANDLE Process, HANDLE Thread, PVOID CallSite, ULONG ArgumentCount, PULONG Arguments, BOOLEAN PassContext, BOOLEAN AlreadySuspended )
/*++
Routine Description:
This function calls a procedure in another thread/process, using NtGetContext and NtSetContext. Parameters are passed to the target procedure via its stack.
Arguments:
Process - Handle of the target process
Thread - Handle of the target thread within that process
CallSite - Address of the procedure to call in the target process.
ArgumentCount - Number of 32 bit parameters to pass to the target procedure.
Arguments - Pointer to the array of 32 bit parameters to pass.
PassContext - TRUE if an additional parameter is to be passed that points to a context record.
AlreadySuspended - TRUE if the target thread is already in a suspended or waiting state.
Return Value:
Status - Status value
--*/
{ NTSTATUS Status; CONTEXT Context; ULONG NewSp; ULONG ArgumentsCopy[5];
RTL_PAGED_CODE();
if (ArgumentCount > 4) return STATUS_INVALID_PARAMETER;
//
// If necessary, suspend the guy before with we mess with his stack.
//
if (!AlreadySuspended) { Status = NtSuspendThread( Thread, NULL ); if (!NT_SUCCESS( Status )) { return( Status ); } }
//
// Get the context record for the target thread.
//
Context.ContextFlags = CONTEXT_FULL; Status = NtGetContextThread( Thread, &Context ); if (!NT_SUCCESS( Status )) { if (!AlreadySuspended) { NtResumeThread( Thread, NULL ); } return( Status ); }
//
// Pass all parameters on the stack, regardless of whether a
// a context record is passed.
//
//
// Put Context Record on stack first, so it is above other args.
//
NewSp = Context.Esp; if (PassContext) { NewSp -= sizeof( CONTEXT ); Status = NtWriteVirtualMemory( Process, (PVOID)NewSp, &Context, sizeof( CONTEXT ), NULL ); if (!NT_SUCCESS( Status )) { if (!AlreadySuspended) { NtResumeThread( Thread, NULL ); } return( Status ); } ArgumentsCopy[0] = NewSp; // pass pointer to context
RtlCopyMemory(&(ArgumentsCopy[1]),Arguments,ArgumentCount*sizeof( ULONG )); ArgumentCount++; } else { RtlCopyMemory(ArgumentsCopy,Arguments,ArgumentCount*sizeof( ULONG )); }
//
// Copy the arguments onto the target stack
//
if (ArgumentCount) { NewSp -= ArgumentCount * sizeof( ULONG ); Status = NtWriteVirtualMemory( Process, (PVOID)NewSp, ArgumentsCopy, ArgumentCount * sizeof( ULONG ), NULL ); if (!NT_SUCCESS( Status )) { if (!AlreadySuspended) { NtResumeThread( Thread, NULL ); } return( Status ); } }
//
// Set the address of the target code into Eip, the new target stack
// into Esp, and reload context to make it happen.
//
Context.Esp = NewSp; Context.Eip = (ULONG)CallSite; Status = NtSetContextThread( Thread, &Context ); if (!AlreadySuspended) { NtResumeThread( Thread, NULL ); }
return( Status ); }
|