Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

256 lines
6.9 KiB

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
xtlexec.c
Abstract:
User Mode routines for creating user mode processes and threads.
Author:
Steve Wood (stevewo) 18-Aug-1989
Revision History:
Yaron Shamir (YaronS) 18-June-1991
Cut a lot and modify to the needs of os2ss. User mode only
--*/
#define INCL_OS2V20_TASKING
#define INCL_OS2V20_ERRORS
#include "os2srv.h"
#include <nturtl.h>
#define NTOS2_ONLY
#include "sesport.h"
#include "os2tile.h"
NTSTATUS
XtlRemoteCall(
HANDLE Process,
HANDLE Thread,
PVOID CallSite,
ULONG ArgumentCount,
PULONG Arguments,
BOOLEAN PassContext,
BOOLEAN AlreadySuspended,
PVOID CritSectionAddr
)
/*++
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.
CritSectionAddr - Address of critical section of code that we should
not suspend process in.
Return Value:
Status - Status value
--*/
{
NTSTATUS Status;
CONTEXT Context;
ULONG NewSp;
LARGE_INTEGER timeout;
PLARGE_INTEGER ptimeout = &timeout;
ULONG Count;
ULONG ArgumentsCopy[5];
ULONG SuspendCount;
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.
//
Count = 0;
while (TRUE) {
Context.ContextFlags = CONTEXT_FULL;
Status = NtGetContextThread(Thread, &Context);
if (!NT_SUCCESS(Status)) {
if (!AlreadySuspended) {
NtResumeThread(Thread, NULL);
}
if (!NT_SUCCESS(Status)) {
return(Status);
}
}
//
// Check that process context not in the middle of thunking
// between 16-bit & 32-bit code. We can not be any were between
// EntryFlat and the start of the first thunk. That means we can not
// be in the ExitFlat code. But we can be in the code for any of the
// thunks or beyond "Od2SignalDeliverer"
//
if ((Context.SegCs != 0x1b) || (Context.SegSs == 0x23)){
/*
(Context.Eip < (ULONG) CritSectionAddr) ||
(Context.Eip > (ULONG) CritSectionAddr + 0x66C0)) {
*/
if (Context.SegCs == 0x1b) {
Context.SegSs = Context.SegDs = Context.SegEs = 0x23;
}
break;
}
//
// At this point process is in thunk see if it was suspended, if it
// is not much we can do.
//
if (AlreadySuspended) {
ASSERT(FALSE);
return(TRUE);
}
do {
NtResumeThread(Thread, &SuspendCount);
} while (SuspendCount);
//
// Let process run.
//
timeout.LowPart = 0x989680; // wait one second
timeout.HighPart = 0;
NtWaitForSingleObject(Thread, (BOOLEAN)TRUE, ptimeout);
if (Count++ == 10) {
ASSERT(FALSE);
return TRUE;
}
//
// Try again
//
Status = NtSuspendThread(Thread, NULL);
if (!NT_SUCCESS(Status)) {
ASSERT(NT_SUCCESS(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.
//
if (Context.SegSs != 0x23) {
NewSp = ((ULONG)(SELTOFLAT(Context.SegSs)) + (USHORT) Context.Esp) & 0xfffffffc;
}
else {
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
RtlMoveMemory(&(ArgumentsCopy[1]),Arguments,ArgumentCount*sizeof( ULONG ));
ArgumentCount++;
}
else {
RtlMoveMemory(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.SegSs = Context.SegDs = Context.SegEs = 0x23;
Context.SegCs = 0x1b;
Context.Esp = NewSp;
Context.Eip = (ULONG)CallSite;
Status = NtSetContextThread( Thread, &Context );
// Don't resume the thread here. It will be resumed by the caller. The
// reason for this is that that sometimes caller wan't to perform some
// operations on suspended thread. For example it might be want to alert
// the thread. In such cases (signal deliverer is the case, actually)
// the thread will call to NtTestAlert in order to remove alert flag
// just in the case that it wasn't waiting for any alertable object.
// If the thread will be not suspended, the call to NtTestAlert might be
// executed before the server will alert it. Further, it will cause that
// for the first time the thread will wait on any alertable object
// NtWaitForSingleObject will return STATUS_ALERT (not good, but this is
// NT bug).
//if (!AlreadySuspended) {
// NtResumeThread( Thread, NULL );
//}
return( Status );
}