Example #1
1
NTSTATUS DllInject(HANDLE hProcessID, PEPROCESS pepProcess, PKTHREAD pktThread)
{
	HANDLE hProcess;
	OBJECT_ATTRIBUTES oaAttributes={sizeof(OBJECT_ATTRIBUTES)};
	CLIENT_ID cidProcess;
	PVOID pvMemory = 0;
	DWORD dwSize = 0x1000;

	cidProcess.UniqueProcess = hProcessID;
	cidProcess.UniqueThread = 0;
	if (NT_SUCCESS(ZwOpenProcess(&hProcess, PROCESS_ALL_ACCESS, &oaAttributes, &cidProcess)))
	{
		if (NT_SUCCESS(ZwAllocateVirtualMemory(hProcess, &pvMemory, 0, &dwSize, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE)))
		{
			KAPC_STATE kasState;
			PKAPC pkaApc;
			PVOID FunctionAddress;

			KeStackAttachProcess((PKPROCESS)pepProcess, &kasState);

			FunctionAddress = GetProcAddressInModule(L"kernel32.dll", "LoadLibraryExW");
			if (!FunctionAddress) DbgPrint("GetProcAddressInModule error\n");

			wcscpy((PWCHAR)pvMemory, g_wcDllName);

			KeUnstackDetachProcess(&kasState);

			pkaApc = (PKAPC)ExAllocatePool(NonPagedPool, sizeof(KAPC));
			if (pkaApc)
			{
				KeInitializeApc(pkaApc, pktThread, 0, APCKernelRoutine, 0, (PKNORMAL_ROUTINE)FunctionAddress, UserMode, pvMemory);
				KeInsertQueueApc(pkaApc, 0, 0, IO_NO_INCREMENT);

				return STATUS_SUCCESS;
			}
		}
		else
		{
			DbgPrint("ZwAllocateVirtualMemory error\n");
		}

		ZwClose(hProcess);
	}
	else
	{
		DbgPrint("ZwOpenProcess error\n");
	}

	return STATUS_NO_MEMORY;
}
Example #2
1
NTSTATUS BDKitTerminateProcessByAPC (__in PEPROCESS EProcess)
{
	NTSTATUS	nsStatus	= STATUS_SUCCESS;
	PETHREAD	Thread		= NULL;
	PKAPC		ExitApc		= NULL;
	ULONG num;   //线程数量
	ULONG Head;  //链表头
	ULONG address;//地址
	ULONG i;
	do 
	{
		num=*(ULONG *)((ULONG)EProcess+0x1a0);   //EPROCESS中ActiveThreads的数量  0x1a0是EPROCESS中ActiveThread的偏移量

		Head=(ULONG)EProcess+ 0x190;              //List_entry第一个节点地址	
		for(i=0;i<num;i++)
		{
			//记录线程地址
			Head=(ULONG)((PLIST_ENTRY)Head)->Flink;
			address=Head-0x22c;

			Thread=(PETHREAD)address;                                       //转换成线程指针 
			ExitApc=(PKAPC)ExAllocatePoolWithTag(NonPagedPool,sizeof(KAPC),'apc');
			if(ExitApc==NULL)
			{

				return STATUS_UNSUCCESSFUL;
			}
			KeInitializeApc(ExitApc,
				(PKTHREAD)&Thread,                         //线程
				OriginalApcEnvironment,
				KernelKillThreadRoutine,
				NULL,
				NULL,
				KernelMode,
				NULL);//为线程初始化APC
			nsStatus=KeInsertQueueApc(ExitApc,ExitApc,NULL,2);   //插入Apc到线程队列
		}


		nsStatus = STATUS_SUCCESS;
	} while (FALSE);

	return nsStatus;
}
Example #3
0
/// <summary>
/// Queue user-mode APC to the target thread
/// </summary>
/// <param name="pThread">Target thread</param>
/// <param name="pUserFunc">APC function</param>
/// <param name="Arg1">Argument 1</param>
/// <param name="Arg2">Argument 2</param>
/// <param name="Arg3">Argument 3</param>
/// <param name="bForce">If TRUE - force delivery by issuing special kernel APC</param>
/// <returns>Status code</returns>
NTSTATUS BBQueueUserApc(
    IN PETHREAD pThread,
    IN PVOID pUserFunc,
    IN PVOID Arg1,
    IN PVOID Arg2,
    IN PVOID Arg3,
    IN BOOLEAN bForce )
{
    ASSERT( pThread != NULL );
    if (pThread == NULL)
        return STATUS_INVALID_PARAMETER;

    // Allocate APC
    PKAPC pPrepareApc = NULL;
    PKAPC pInjectApc = ExAllocatePoolWithTag( NonPagedPool, sizeof( KAPC ), BB_POOL_TAG );

    if (pInjectApc == NULL)
    {
        DPRINT( "BlackBone: %s: Failed to allocate APC\n", __FUNCTION__ );
        return STATUS_NO_MEMORY;
    }

    // Actual APC
    KeInitializeApc(
        pInjectApc, (PKTHREAD)pThread,
        OriginalApcEnvironment, &KernelApcInjectCallback,
        NULL, (PKNORMAL_ROUTINE)(ULONG_PTR)pUserFunc, UserMode, Arg1
        );

    // Setup force-delivery APC
    if (bForce)
    {
        pPrepareApc = ExAllocatePoolWithTag( NonPagedPool, sizeof( KAPC ), BB_POOL_TAG );
        KeInitializeApc(
            pPrepareApc, (PKTHREAD)pThread,
            OriginalApcEnvironment, &KernelApcPrepareCallback,
            NULL, NULL, KernelMode, NULL
            );
    }

    // Insert APC
    if (KeInsertQueueApc( pInjectApc, Arg2, Arg3, 0 ))
    {
        if (bForce && pPrepareApc)
            KeInsertQueueApc( pPrepareApc, NULL, NULL, 0 );

        return STATUS_SUCCESS;
    }
    else
    {
        DPRINT( "BlackBone: %s: Failed to insert APC\n", __FUNCTION__ );

        ExFreePoolWithTag( pInjectApc, BB_POOL_TAG );

        if (pPrepareApc)
            ExFreePoolWithTag( pPrepareApc, BB_POOL_TAG );

        return STATUS_NOT_CAPABLE;
    }
}
Example #4
0
VOID InjectDllIntoProcess(PWCHAR ProcessName)
{
	HANDLE ThreadId;
	HANDLE ProcessId = GetPidAndTidByName(ProcessName, &ThreadId);
	if (ProcessId)
	{
		PETHREAD Thread;
		NTSTATUS St = PsLookupThreadByThreadId(ThreadId, &Thread);
		if (NT_SUCCESS(St))
		{
			PKAPC pkaApc = (PKAPC)ExAllocatePool(NonPagedPool, sizeof(KAPC));
			if(pkaApc)
			{
				KeInitializeApc(pkaApc, (PKTHREAD)Thread, 0, APCInjectRoutine, 0, 0, KernelMode, 0);
				KeInsertQueueApc(pkaApc, 0, 0, IO_NO_INCREMENT);
			}

			ObDereferenceObject(Thread);
		}
	}
	else
	{
		DbgPrint("GetPidAndTidByName error\n");
	}
}
Example #5
0
NTSTATUS
AlertDrvSendTheSignal(PETHREAD	uThread)
{
  NTSTATUS   ntStatus = STATUS_SUCCESS;
  PKAPC      kApc;

  /* Allocate an KAPC structure from NonPagedPool */
  kApc = ExAllocatePool(NonPagedPool, sizeof(KAPC));
  if (kApc == NULL)
    {
      AlertDrvKdPrint (("ExAllocatePool returned NULL\n"));
      return !ntStatus;
    }

  KeInitializeApc(kApc,
                  (PKTHREAD) uThread,
                  0,
                  (PKKERNEL_ROUTINE) &KernelApcCallBack,
                  0,
                  (PKNORMAL_ROUTINE) &UserApcCallBack,
                  KernelMode,
                  NULL);

  KeInsertQueueApc (kApc, NULL, NULL, 0);

  return ntStatus;
}
Example #6
0
/*
 * @implemented
 */
VOID
NTAPI
IoRaiseHardError(IN PIRP Irp,
                 IN PVPB Vpb,
                 IN PDEVICE_OBJECT RealDeviceObject)
{
    PETHREAD Thread = (PETHREAD)&Irp->Tail.Overlay.Thread;
    PKAPC ErrorApc;

    /* Don't do anything if hard errors are disabled on the thread */
    if (Thread->HardErrorsAreDisabled)
    {
        /* Complete the request */
        Irp->IoStatus.Information = 0;
        IoCompleteRequest(Irp, IO_DISK_INCREMENT);
        return;
    }

    /* Setup an APC */
    ErrorApc = ExAllocatePoolWithTag(NonPagedPool,
                                     sizeof(KAPC),
                                     TAG_APC);
    KeInitializeApc(ErrorApc,
                    &Thread->Tcb,
                    Irp->ApcEnvironment,
                    NULL,
                    (PKRUNDOWN_ROUTINE)IopFreeApc,
                    (PKNORMAL_ROUTINE)IopRaiseHardError,
                    KernelMode,
                    Irp);

    /* Queue an APC to deal with the error (see osr documentation) */
    KeInsertQueueApc(ErrorApc, Vpb, RealDeviceObject, 0);
}
Example #7
0
File: work.c Project: killvxk/NT_OS
VOID
NTAPI
ExSwapinWorkerThreads(IN BOOLEAN AllowSwap)
{
    KEVENT Event;
    PETHREAD CurrentThread = PsGetCurrentThread(), Thread;
    PEPROCESS Process = PsInitialSystemProcess;
    KAPC Apc;
    PAGED_CODE();

    /* Initialize an event so we know when we're done */
    KeInitializeEvent(&Event, NotificationEvent, FALSE);

    /* Lock this routine */
    ExAcquireFastMutex(&ExpWorkerSwapinMutex);

    /* New threads cannot swap anymore */
    ExpWorkersCanSwap = AllowSwap;

    /* Loop all threads in the system process */
    Thread = PsGetNextProcessThread(Process, NULL);
    while (Thread)
    {
        /* Skip threads with explicit permission to do this */
        if (Thread->ExWorkerCanWaitUser) goto Next;

        /* Check if we reached ourselves */
        if (Thread == CurrentThread)
        {
            /* Do it inline */
            KeSetKernelStackSwapEnable(AllowSwap);
        }
        else
        {
            /* Queue an APC */
            KeInitializeApc(&Apc,
                            &Thread->Tcb,
                            InsertApcEnvironment,
                            ExpSetSwappingKernelApc,
                            NULL,
                            NULL,
                            KernelMode,
                            &AllowSwap);
            if (KeInsertQueueApc(&Apc, &Event, NULL, 3))
            {
                /* Wait for the APC to run */
                KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
                KeClearEvent(&Event);
            }
        }
        
        /* Next thread */
Next:
        Thread = PsGetNextProcessThread(Process, Thread);
    }

    /* Release the lock */
    ExReleaseFastMutex(&ExpWorkerSwapinMutex);
}
Example #8
0
void DBKSuspendThread(ULONG ThreadID)
{
	KIRQL OldIrql;
	
	struct ThreadData *t_data;


    KeAcquireSpinLock(&ProcesslistSL,&OldIrql); 

	DbgPrint("Going to suspend this thread\n");

	//find the thread in the threadlist


	//find the threadid in the processlist
	t_data=GetThreaddata(ThreadID);
	if (t_data)
	{
		DbgPrint("Suspending thread....\n");	

		

		if (!t_data->PEThread)
		{
			//not yet initialized
			t_data->PEThread=(PETHREAD)getPEThread(ThreadID);
			KeInitializeApc(&t_data->SuspendApc,
							(PKTHREAD)t_data->PEThread,
							0,
							(PKKERNEL_ROUTINE)Ignore,
							(PKRUNDOWN_ROUTINE)NULL,
							(PKNORMAL_ROUTINE)SuspendThreadAPCRoutine,
							KernelMode,
							t_data);

		}	
		DbgPrint("x should be %p",t_data);
		t_data->suspendcount++;

		if (t_data->suspendcount==1) //not yet suspended so suspend it
            KeInsertQueueApc(&t_data->SuspendApc, t_data, t_data, 0);		
	}
	else
		DbgPrint("Thread not found in the list\n");

	KeReleaseSpinLock(&ProcesslistSL,OldIrql);
}
Example #9
0
BOOLEAN TerminateThread(PETHREAD Thread)
{
	PKAPC Apc = NULL;
	BOOLEAN success = FALSE;
	if (!MmIsAddressValid(Thread))
		return FALSE;
	Apc = ExAllocatePool(NonPagedPool, sizeof(KAPC));
	KeInitializeApc(
		Apc,
		Thread,
		OriginalApcEnvironment,
		KernelTerminateThreadRoutine,
		NULL,
		NULL,
		KernelMode,
		NULL);
	success = KeInsertQueueApc(Apc,
		NULL,
		NULL,
		0);
	return success;
}
Example #10
0
VOID
NTAPI
PspExitNormalApc(IN PVOID NormalContext,
                 IN PVOID SystemArgument1,
                 IN PVOID SystemArgument2)
{
    PKAPC Apc = (PKAPC)SystemArgument1;
    PETHREAD Thread = PsGetCurrentThread();
    PAGED_CODE();
    PSTRACE(PS_KILL_DEBUG, "SystemArgument2: %p \n", SystemArgument2);

    /* This should never happen */
    ASSERT(!(((ULONG_PTR)SystemArgument2) & 1));

    /* If we're here, this is not a System Thread, so kill it from User-Mode */
    KeInitializeApc(Apc,
                    &Thread->Tcb,
                    OriginalApcEnvironment,
                    PsExitSpecialApc,
                    PspExitApcRundown,
                    PspExitNormalApc,
                    UserMode,
                    NormalContext);

    /* Now insert the APC with the User-Mode Flag */
    if (!(KeInsertQueueApc(Apc,
                           Apc,
                           (PVOID)((ULONG_PTR)SystemArgument2 | 1),
                           2)))
    {
        /* Failed to insert, free the APC */
        PspExitApcRundown(Apc);
    }

    /* Set the APC Pending flag */
    Thread->Tcb.ApcState.UserApcPending = TRUE;
}
Example #11
0
BOOLEAN InjectDll(PINJECT_INFO InjectInfo)
{
	PEPROCESS Process;
	PETHREAD Thread;

	PKINJECT mem;
	ULONG size;

	PKAPC_STATE ApcState;
	PKAPC apc;

	PVOID buffer;
	PSYSTEM_PROCESS_INFO pSpi;

	LARGE_INTEGER delay;

	buffer=ExAllocatePool(NonPagedPool,1024*1024); // Allocate memory for the system information

	if(!buffer)
	{
		DbgPrint("Error: Unable to allocate memory for the process thread list.");
		return FALSE;
	}

	// Get the process thread list

	if(!NT_SUCCESS(ZwQuerySystemInformation(5,buffer,1024*1024,NULL)))
	{
		DbgPrint("Error: Unable to query process thread list.");
		
		ExFreePool(buffer);
		return FALSE;
	}

	pSpi=(PSYSTEM_PROCESS_INFO)buffer;

	// Find a target thread

	while(pSpi->NextEntryOffset)
	{
		if(pSpi->UniqueProcessId==InjectInfo->ProcessId)
		{
			DbgPrint("Target thread found. TID: %d",pSpi->Threads[0].ClientId.UniqueThread);
			break;
		}

		pSpi=(PSYSTEM_PROCESS_INFO)((PUCHAR)pSpi+pSpi->NextEntryOffset);
	}

	// Reference the target process

	if(!NT_SUCCESS(PsLookupProcessByProcessId(InjectInfo->ProcessId,&Process)))
	{
		DbgPrint("Error: Unable to reference the target process.");
		
		ExFreePool(buffer);
		return FALSE;
	}

	DbgPrint("Process name: %s",PsGetProcessImageFileName(Process));
	DbgPrint("EPROCESS address: %#x",Process);

	// Reference the target thread

	if(!NT_SUCCESS(PsLookupThreadByThreadId(pSpi->Threads[0].ClientId.UniqueThread,&Thread)))
	{
		DbgPrint("Error: Unable to reference the target thread.");
		ObDereferenceObject(Process); // Dereference the target process

		ExFreePool(buffer); // Free the allocated memory
		return FALSE;
	}

	DbgPrint("ETHREAD address: %#x",Thread);

	ExFreePool(buffer); // Free the allocated memory
	KeAttachProcess(Process); // Attach to target process's address space

	mem=NULL;
	size=4096;

	// Allocate memory in the target process

	if(!NT_SUCCESS(ZwAllocateVirtualMemory(NtCurrentProcess(),(PVOID*)&mem,0,&size,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE)))
	{
	    DbgPrint("Error: Unable to allocate memory in the target process.");
		KeDetachProcess(); // Detach from target process's address space

		ObDereferenceObject(Process); // Dereference the target process
		ObDereferenceObject(Thread); // Dereference the target thread

		return FALSE;
	}

	DbgPrint("Memory allocated at %#x",mem);

	mem->LdrLoadDll=LdrLoadDll; // Write the address of LdrLoadDll to target process
	wcscpy(mem->Buffer,InjectInfo->DllName); // Write the DLL name to target process

	RtlInitUnicodeString(&mem->DllName,mem->Buffer); // Initialize the UNICODE_STRING structure
	ApcState=(PKAPC_STATE)((PUCHAR)Thread+ApcStateOffset); // Calculate the address of the ApcState structure

	ApcState->UserApcPending=TRUE; // Force the target thread to execute APC

	memcpy((PKINJECT)(mem+1),InjectDllApc,(ULONG)KernelRoutine-(ULONG)InjectDllApc); // Copy the APC code to target process
	DbgPrint("APC code address: %#x",(PKINJECT)(mem+1));

	apc=(PKAPC)ExAllocatePool(NonPagedPool,sizeof(KAPC)); // Allocate the APC object

	if(!apc)
	{
		DbgPrint("Error: Unable to allocate the APC object.");
		size=0;

		ZwFreeVirtualMemory(NtCurrentProcess(),(PVOID*)&mem,&size,MEM_RELEASE);  // Free the allocated memory
		KeDetachProcess(); // Detach from target process's address space

		ObDereferenceObject(Process); // Dereference the target process
		ObDereferenceObject(Thread); // Dereference the target thread

		return FALSE;
	}

	KeInitializeApc(apc,Thread,OriginalApcEnvironment,KernelRoutine,NULL,(PKNORMAL_ROUTINE)((PKINJECT)mem+1),UserMode,mem); // Initialize the APC
	DbgPrint("Inserting APC to target thread");

	// Insert the APC to the target thread

	if(!KeInsertQueueApc(apc,NULL,NULL,IO_NO_INCREMENT))
	{
		DbgPrint("Error: Unable to insert APC to target thread.");
		size=0;
		
		ZwFreeVirtualMemory(NtCurrentProcess(),(PVOID*)&mem,&size,MEM_RELEASE); // Free the allocated memory
		KeDetachProcess(); // Detach from target process's address space

		ObDereferenceObject(Process); // Dereference the target process
		ObDereferenceObject(Thread); // Dereference the target thread

		ExFreePool(apc); // Free the APC object
		return FALSE;
	}

	delay.QuadPart=-100*10000;

	while(!mem->Executed)
	{
		KeDelayExecutionThread(KernelMode,FALSE,&delay); // Wait for the injection to complete
	}

	if(!mem->DllBase)
	{
		DbgPrint("Error: Unable to inject DLL into target process.");
		size=0;

		ZwFreeVirtualMemory(NtCurrentProcess(),(PVOID*)&mem,&size,MEM_RELEASE);
		KeDetachProcess();

		ObDereferenceObject(Process);
		ObDereferenceObject(Thread);
		
		return FALSE;
	}

	DbgPrint("DLL injected at %#x",mem->DllBase);
	size=0;

	ZwFreeVirtualMemory(NtCurrentProcess(),(PVOID*)&mem,&size,MEM_RELEASE); // Free the allocated memory
	KeDetachProcess(); // Detach from target process's address space

	ObDereferenceObject(Process); // Dereference the target process
	ObDereferenceObject(Thread);  // Dereference the target thread

	return TRUE;
}
Example #12
0
/*
 * See "Windows Internals" - Chapter 13, Page 49
 */
NTSTATUS
NTAPI
PspTerminateThreadByPointer(IN PETHREAD Thread,
                            IN NTSTATUS ExitStatus,
                            IN BOOLEAN bSelf)
{
    PKAPC Apc;
    NTSTATUS Status = STATUS_SUCCESS;
    ULONG Flags;
    PAGED_CODE();
    PSTRACE(PS_KILL_DEBUG, "Thread: %p ExitStatus: %d\n", Thread, ExitStatus);
    PSREFTRACE(Thread);

    /* Check if this is a Critical Thread, and Bugcheck */
    if (Thread->BreakOnTermination)
    {
        /* Break to debugger */
        PspCatchCriticalBreak("Terminating critical thread 0x%p (%s)\n",
                              Thread,
                              Thread->ThreadsProcess->ImageFileName);
    }

    /* Check if we are already inside the thread */
    if ((bSelf) || (PsGetCurrentThread() == Thread))
    {
        /* This should only happen at passive */
        ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);

        /* Mark it as terminated */
        PspSetCrossThreadFlag(Thread, CT_TERMINATED_BIT);

        /* Directly terminate the thread */
        PspExitThread(ExitStatus);
    }

    /* This shouldn't be a system thread */
    if (Thread->SystemThread) return STATUS_ACCESS_DENIED;

    /* Allocate the APC */
    Apc = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC), TAG_TERMINATE_APC);
    if (!Apc) return STATUS_INSUFFICIENT_RESOURCES;

    /* Set the Terminated Flag */
    Flags = Thread->CrossThreadFlags | CT_TERMINATED_BIT;

    /* Set it, and check if it was already set while we were running */
    if (!(InterlockedExchange((PLONG)&Thread->CrossThreadFlags, Flags) &
          CT_TERMINATED_BIT))
    {
        /* Initialize a Kernel Mode APC to Kill the Thread */
        KeInitializeApc(Apc,
                        &Thread->Tcb,
                        OriginalApcEnvironment,
                        PsExitSpecialApc,
                        PspExitApcRundown,
                        PspExitNormalApc,
                        KernelMode,
                        (PVOID)ExitStatus);

        /* Insert it into the APC Queue */
        if (!KeInsertQueueApc(Apc, Apc, NULL, 2))
        {
            /* The APC was already in the queue, fail */
            Status = STATUS_UNSUCCESSFUL;
        }
        else
        {
            /* Forcefully resume the thread and return */
            KeForceResumeThread(&Thread->Tcb);
            return Status;
        }
    }

    /* We failed, free the APC */
    ExFreePoolWithTag(Apc, TAG_TERMINATE_APC);

    /* Return Status */
    return Status;
}
Example #13
0
void DBKSuspendProcess(ULONG ProcessID)
{
	KIRQL OldIrql;
	
	struct ThreadData *t_data=NULL;
	struct ProcessData *tempProcessData=NULL;


    KeAcquireSpinLock(&ProcesslistSL,&OldIrql); 
	

	DbgPrint("Going to suspend this process\n");

	//find the process in the threadlist

	tempProcessData=processlist;
	while (tempProcessData)
	{
		if (tempProcessData->ProcessID==(HANDLE)(UINT_PTR)ProcessID)
		{
			t_data=tempProcessData->Threads;
			break;
		}
		tempProcessData=tempProcessData->next;
	}

	if (!t_data)
	{
		DbgPrint("This process was not found\n");
		KeReleaseSpinLock(&ProcesslistSL,OldIrql);
		return; //no process found
	}


	while (t_data)
	{
		DbgPrint("Suspending thread....\n");		

		if (!t_data->PEThread)
		{
			//not yet initialized
			t_data->PEThread=(PETHREAD)getPEThread((UINT_PTR)t_data->ThreadID);
			KeInitializeApc(&t_data->SuspendApc,
							(PKTHREAD)t_data->PEThread,
							0,
							(PKKERNEL_ROUTINE)Ignore,
							(PKRUNDOWN_ROUTINE)NULL,
							(PKNORMAL_ROUTINE)SuspendThreadAPCRoutine,
							KernelMode,
							t_data);

		}	
		DbgPrint("x should be %p",t_data); 
		t_data->suspendcount++;

		if (t_data->suspendcount==1) //not yet suspended so suspend it
			KeInsertQueueApc(&t_data->SuspendApc, t_data, t_data, 0);

		t_data=t_data->next; //next thread
	}

	KeReleaseSpinLock(&ProcesslistSL,OldIrql);

}
Example #14
0
NTSTATUS
NtSetTimer (
    IN HANDLE TimerHandle,
    IN PLARGE_INTEGER DueTime,
    IN PTIMER_APC_ROUTINE TimerApcRoutine OPTIONAL,
    IN PVOID TimerContext OPTIONAL,
    IN BOOLEAN WakeTimer,
    IN LONG Period OPTIONAL,
    OUT PBOOLEAN PreviousState OPTIONAL
    )

/*++

Routine Description:

    This function sets an timer object to a Not-Signaled state and sets the timer
    to expire at the specified time.

Arguments:

    TimerHandle - Supplies a handle to an timer object.

    DueTime - Supplies a pointer to absolute of relative time at which the
        timer is to expire.

    TimerApcRoutine - Supplies an optional pointer to a function which is to
        be executed when the timer expires. If this parameter is not specified,
        then the TimerContext parameter is ignored.

    TimerContext - Supplies an optional pointer to an arbitrary data structure
        that will be passed to the function specified by the TimerApcRoutine
        parameter. This parameter is ignored if the TimerApcRoutine parameter
        is not specified.

    WakeTimer - Supplies a boolean value that specifies whether the timer
        wakes computer operation if sleeping

    Period - Supplies an optional repetitive period for the timer.

    PreviousState - Supplies an optional pointer to a variable that will
        receive the previous state of the timer object.

Return Value:

    TBS

--*/

{

    BOOLEAN AssociatedApc;
    BOOLEAN Dereference;
    PETHREAD ExThread;
    PETIMER ExTimer;
    LARGE_INTEGER ExpirationTime;
    KIRQL OldIrql1;
    KPROCESSOR_MODE PreviousMode;
    BOOLEAN State;
    NTSTATUS Status;

    //
    // Establish an exception handler, probe the due time and previous state
    // address if specified, reference the timer object, and set the timer
    // object. If the probe fails, then return the exception code as the
    // service status. Otherwise return the status value returned by the
    // reference object by handle routine.
    //

    try {

        //
        // Get previous processor mode and probe previous state address
        // if necessary.
        //

        PreviousMode = KeGetPreviousMode();
        if (PreviousMode != KernelMode) {
            if (ARGUMENT_PRESENT(PreviousState)) {
                ProbeForWriteBoolean(PreviousState);
            }

            ProbeForRead(DueTime, sizeof(LARGE_INTEGER), sizeof(ULONG));
        }

        //
        // Check argument validity.
        //

        if (Period < 0) {
            return STATUS_INVALID_PARAMETER_6;
        }

        //
        // Capture the expiration time.
        //

        ExpirationTime = *DueTime;

        //
        // Reference timer object by handle.
        //

        Status = ObReferenceObjectByHandle(TimerHandle,
                                           TIMER_MODIFY_STATE,
                                           ExTimerObjectType,
                                           PreviousMode,
                                           (PVOID *)&ExTimer,
                                           NULL);

        //
        // If this WakeTimer flag is set, return the appropiate informational
        // success status code.
        //

        if (NT_SUCCESS(Status) && WakeTimer && !PoWakeTimerSupported()) {
            Status = STATUS_TIMER_RESUME_IGNORED;
        }

        //
        // If the reference was successful, then cancel the timer object, set
        // the timer object, dereference time object, and write the previous
        // state value if specified. If the write of the previous state value
        // fails, then do not report an error. When the caller attempts to
        // access the previous state value, an access violation will occur.
        //

        if (NT_SUCCESS(Status)) {
            ExAcquireSpinLock(&ExTimer->Lock, &OldIrql1);

            if (ExTimer->ApcAssociated) {
                ExThread = CONTAINING_RECORD(ExTimer->TimerApc.Thread, ETHREAD, Tcb);
                ExAcquireSpinLockAtDpcLevel(&ExThread->ActiveTimerListLock);
                RemoveEntryList(&ExTimer->ActiveTimerListEntry);
                ExTimer->ApcAssociated = FALSE;
                ExReleaseSpinLockFromDpcLevel(&ExThread->ActiveTimerListLock);
                KeCancelTimer(&ExTimer->KeTimer);
                KeRemoveQueueDpc(&ExTimer->TimerDpc);
                KeRemoveQueueApc(&ExTimer->TimerApc);
                Dereference = TRUE;

            } else {
                KeCancelTimer(&ExTimer->KeTimer);
                Dereference = FALSE;
            }

            //
            // Read the current state of the timer.
            //

            State = KeReadStateTimer(&ExTimer->KeTimer);

            //
            // If this is a wake timer ensure it's on the wake timer list
            //

            ExTimer->WakeTimer = WakeTimer;
            ExAcquireSpinLockAtDpcLevel(&ExpWakeTimerListLock);
            if (WakeTimer) {
                if (!ExTimer->WakeTimerListEntry.Flink) {
                    InsertTailList(&ExpWakeTimerList, &ExTimer->WakeTimerListEntry);
                }
            } else {
                if (ExTimer->WakeTimerListEntry.Flink) {
                    RemoveEntryList(&ExTimer->WakeTimerListEntry);
                    ExTimer->WakeTimerListEntry.Flink = NULL;
                }
            }
            ExReleaseSpinLockFromDpcLevel(&ExpWakeTimerListLock);

            //
            // If an APC routine is specified, then initialize the APC, acquire the
            // thread's active time list lock, insert the timer in the thread's
            // active timer list, set the timer with an associated DPC, and set the
            // associated APC flag TRUE. Otherwise set the timer without an associated
            // DPC, and set the associated APC flag FALSE.
            //

            ExTimer->Period = Period;
            if (ARGUMENT_PRESENT(TimerApcRoutine)) {
                ExThread = PsGetCurrentThread();
                KeInitializeApc(&ExTimer->TimerApc,
                                &ExThread->Tcb,
                                CurrentApcEnvironment,
                                ExpTimerApcRoutine,
                                (PKRUNDOWN_ROUTINE)NULL,
                                (PKNORMAL_ROUTINE)TimerApcRoutine,
                                PreviousMode,
                                TimerContext);

                ExAcquireSpinLockAtDpcLevel(&ExThread->ActiveTimerListLock);
                InsertTailList(&ExThread->ActiveTimerListHead,
                               &ExTimer->ActiveTimerListEntry);

                ExTimer->ApcAssociated = TRUE;
                ExReleaseSpinLockFromDpcLevel(&ExThread->ActiveTimerListLock);
                KeSetTimerEx(&ExTimer->KeTimer,
                             ExpirationTime,
                             Period,
                             &ExTimer->TimerDpc);

                AssociatedApc = TRUE;

            } else {
                KeSetTimerEx(&ExTimer->KeTimer,
                             ExpirationTime,
                             Period,
                             NULL);

                AssociatedApc = FALSE;
            }

            ExReleaseSpinLock(&ExTimer->Lock, OldIrql1);

            //
            // Dereference the object as appropriate.
            //

            if (Dereference) {
                ObDereferenceObject((PVOID)ExTimer);
            }

            if (AssociatedApc == FALSE) {
                ObDereferenceObject((PVOID)ExTimer);
            }

            if (ARGUMENT_PRESENT(PreviousState)) {
                try {
                    *PreviousState = State;

                } except(ExSystemExceptionFilter()) {
                }
            }
        }

    //
    // If an exception occurs during the probe of the current state address,
    // then always handle the exception and return the exception code as the
    // status value.
    //

    } except(ExSystemExceptionFilter()) {
        return GetExceptionCode();
    }

    //
    // Return service status.
    //

    return Status;
}
Example #15
0
VOID
ExSwapinWorkerThreads (
    IN BOOLEAN AllowSwap
    )

/*++

Routine Description:

    Sets the kernel stacks of the delayed worker threads to be swappable
    or pins them into memory.

Arguments:

    AllowSwap - Supplies TRUE if worker kernel stacks should be swappable,
                FALSE if not.

Return Value:

    None.

--*/

{
    PETHREAD         Thread;
    PETHREAD         CurrentThread;
    PEPROCESS        Process;
    KAPC             Apc;
    KEVENT           SwapSetEvent;

    PAGED_CODE();

    CurrentThread = PsGetCurrentThread();

    KeInitializeEvent (&SwapSetEvent,
                       NotificationEvent,
                       FALSE);

    Process = PsInitialSystemProcess;

    //
    // Serialize callers.
    //

    ExAcquireFastMutex (&ExpWorkerSwapinMutex);

    //
    // Stop new threads from swapping.
    //

    ExpWorkersCanSwap = AllowSwap;

    //
    // Stop existing worker threads from swapping.
    //

    for (Thread = PsGetNextProcessThread (Process, NULL);
         Thread != NULL;
         Thread = PsGetNextProcessThread (Process, Thread)) {

        //
        // Skip threads that are not worker threads or worker threads that
        // were permanently marked noswap at creation time.
        //

        if (Thread->ExWorkerCanWaitUser == 0) {
            continue;
        }

        if (Thread == CurrentThread) {

            //
            // No need to use an APC on the current thread.
            //

            KeSetKernelStackSwapEnable (AllowSwap);
        }
        else {

            //
            // Queue an APC to the thread, and wait for it to fire:
            //

            KeInitializeApc (&Apc,
                             &Thread->Tcb,
                             InsertApcEnvironment,
                             ExpSetSwappingKernelApc,
                             NULL,
                             NULL,
                             KernelMode,
                             &AllowSwap);

            if (KeInsertQueueApc (&Apc, &SwapSetEvent, NULL, 3)) {

                KeWaitForSingleObject (&SwapSetEvent,
                                       Executive,
                                       KernelMode,
                                       FALSE,
                                       NULL);

                KeClearEvent(&SwapSetEvent);
            }
        }
    }

    ExReleaseFastMutex (&ExpWorkerSwapinMutex);
}
Example #16
0
NTSTATUS
NtGetContextThread(
    IN HANDLE ThreadHandle,
    IN OUT PCONTEXT ThreadContext
    )

/*++

Routine Description:

    This function returns the usermode context of the specified thread. This
    function will fail if the specified thread is a system thread. It will
    return the wrong answer if the thread is a non-system thread that does
    not execute in user-mode.

Arguments:

    ThreadHandle - Supplies an open handle to the thread object from
                   which to retrieve context information.  The handle
                   must allow THREAD_GET_CONTEXT access to the thread.

    ThreadContext - Supplies the address of a buffer that will receive
                    the context of the specified thread.

Return Value:

    None.

--*/

{

    ULONG Alignment;
    ULONG ContextFlags;
    GETSETCONTEXT ContextFrame;
    ULONG ContextLength;
    KIRQL Irql;
    KPROCESSOR_MODE Mode;
    NTSTATUS Status;
    PETHREAD Thread;

    PAGED_CODE();

    //
    // Get previous mode and reference specified thread.
    //

    Mode = KeGetPreviousMode();
    Status = ObReferenceObjectByHandle(ThreadHandle,
                                   THREAD_GET_CONTEXT,
                                   PsThreadType,
                                   Mode,
                                   (PVOID *)&Thread,
                                   NULL);

    //
    // If the reference was successful, the check if the specified thread
    // is a system thread.
    //

    if (NT_SUCCESS(Status)) {

        //
        // If the thread is not a system thread, then attempt to get the
        // context of the thread.
        //

        if (IS_SYSTEM_THREAD(Thread) == FALSE) {

            //
            // Attempt to get the context of the specified thread.
            //

            try {

                //
                // Set the default alignment, capture the context flags,
                // and set the default size of the context record.
                //

                Alignment = CONTEXT_ALIGN;
                ContextFlags = ProbeAndReadUlong(&ThreadContext->ContextFlags);
                ContextLength = sizeof(CONTEXT);

#if defined(_X86_)
                //
                // CONTEXT_EXTENDED_REGISTERS is SET, then we want sizeof(CONTEXT) set above
                // otherwise (not set) we only want the old part of the context record.
                //
                if ((ContextFlags & CONTEXT_EXTENDED_REGISTERS) != CONTEXT_EXTENDED_REGISTERS) {
                    ContextLength = FIELD_OFFSET(CONTEXT, ExtendedRegisters);
                }
#endif

#if defined(_MIPS_)

                //
                // The following code is included for backward compatibility
                // with old code that does not understand extended context
                // records on MIPS systems.
                //

                if ((ContextFlags & CONTEXT_EXTENDED_INTEGER) != CONTEXT_EXTENDED_INTEGER) {
                    Alignment = sizeof(ULONG);
                    ContextLength = FIELD_OFFSET(CONTEXT, ContextFlags) + 4;
                }

#endif

                if (Mode != KernelMode) {
                    ProbeForWrite(ThreadContext, ContextLength, Alignment);
                }

            } except(EXCEPTION_EXECUTE_HANDLER) {
                Status = GetExceptionCode();
            }

            //
            // If an exception did not occur during the probe of the thread
            // context, then get the context of the target thread.
            //

            if (NT_SUCCESS(Status)) {
                KeInitializeEvent(&ContextFrame.OperationComplete,
                                  NotificationEvent,
                                  FALSE);

                ContextFrame.Context.ContextFlags = ContextFlags;

                ContextFrame.Mode = Mode;
                if (Thread == PsGetCurrentThread()) {
                    ContextFrame.Apc.SystemArgument1 = NULL;
                    ContextFrame.Apc.SystemArgument2 = Thread;
                    KeRaiseIrql(APC_LEVEL, &Irql);
                    PspGetSetContextSpecialApc(&ContextFrame.Apc,
                                               NULL,
                                               NULL,
                                               &ContextFrame.Apc.SystemArgument1,
                                               &ContextFrame.Apc.SystemArgument2);

                    KeLowerIrql(Irql);

                    //
                    // Move context to specfied context record. If an exception
                    // occurs, then silently handle it and return success.
                    //

                    try {
                        RtlMoveMemory(ThreadContext,
                                      &ContextFrame.Context,
                                      ContextLength);

                    } except(EXCEPTION_EXECUTE_HANDLER) {
                    }

                } else {
                    KeInitializeApc(&ContextFrame.Apc,
                                    &Thread->Tcb,
                                    OriginalApcEnvironment,
                                    PspGetSetContextSpecialApc,
                                    NULL,
                                    NULL,
                                    KernelMode,
                                    NULL);

                    if (!KeInsertQueueApc(&ContextFrame.Apc, NULL, Thread, 2)) {
                        Status = STATUS_UNSUCCESSFUL;

                    } else {
                        KeWaitForSingleObject(&ContextFrame.OperationComplete,
                                              Executive,
                                              KernelMode,
                                              FALSE,
                                              NULL);
                        //
                        // Move context to specfied context record. If an
                        // exception occurs, then silently handle it and
                        // return success.
                        //

                        try {
                            RtlMoveMemory(ThreadContext,
                                          &ContextFrame.Context,
                                          ContextLength);

                        } except(EXCEPTION_EXECUTE_HANDLER) {
                        }
                    }
                }
            }

        } else {
Example #17
0
BOOLEAN InjectDll(PINJECT_INFO InjectInfo)
{
	PEPROCESS Process;
	PETHREAD Thread;
	PKINJECT mem;
    ULONG size;
	PKAPC_STATE ApcState;
	PKAPC apc;
	PVOID buffer;
	PSYSTEM_PROCESS_INFO pSpi;
	LARGE_INTEGER delay;
	buffer=ExAllocatePool(NonPagedPool,1024*1024); 
	if(!buffer)
	{
		DbgPrint("Error: Unable to allocate memory for the process thread list.");
		return FALSE;
	}

	//5	SystemProcessInformation,
	if(!NT_SUCCESS(ZwQuerySystemInformation(5,buffer,1024*1024,NULL)))
	{
		DbgPrint("Error: Unable to query process thread list.");

		ExFreePool(buffer);
		return FALSE;
	}

	pSpi=(PSYSTEM_PROCESS_INFO)buffer;

	//找到目标进程
	while(pSpi->NextEntryOffset)
	{
		if(pSpi->UniqueProcessId==InjectInfo->ProcessId)
		{
			DbgPrint("Target thread found. TID: %d",pSpi->Threads[0].ClientId.UniqueThread);
			break;
		}

		pSpi=(PSYSTEM_PROCESS_INFO)((PUCHAR)pSpi+pSpi->NextEntryOffset);
	}

	// 引用目标进程EProcess,
	if(!NT_SUCCESS(PsLookupProcessByProcessId(InjectInfo->ProcessId,&Process)))
	{
		DbgPrint("Error: Unable to reference the target process.");
		ExFreePool(buffer);
		return FALSE;
	}

	DbgPrint("Process name: %s",PsGetProcessImageFileName(Process));
	DbgPrint("EPROCESS address: %#x",Process);

	//目标进程主线程
	if(!NT_SUCCESS(PsLookupThreadByThreadId(pSpi->Threads[0].ClientId.UniqueThread,&Thread)))
	{
		DbgPrint("Error: Unable to reference the target thread.");
		ObDereferenceObject(Process); 
		ExFreePool(buffer); 
		return FALSE;
	}

	DbgPrint("ETHREAD address: %#x",Thread);

	ExFreePool(buffer); 
	//切入到目标进程
	KeAttachProcess(Process); 

	mem=NULL;
	size=4096;

	//在目标进程申请内存
	if(!NT_SUCCESS(ZwAllocateVirtualMemory(NtCurrentProcess(),(PVOID*)&mem,0,&size,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE)))
	{
		DbgPrint("Error: Unable to allocate memory in the target process.");
		KeDetachProcess(); 

		ObDereferenceObject(Process);
		ObDereferenceObject(Thread); 
		return FALSE;
	}

	DbgPrint("Memory allocated at %#x",mem);
	mem->LdrLoadDll=LdrLoadDll; 
	wcscpy(mem->Buffer,InjectInfo->DllName); 
	RtlInitUnicodeString(&mem->DllName,mem->Buffer); 
	ApcState=(PKAPC_STATE)((PUCHAR)Thread+ApcStateOffset); 
	ApcState->UserApcPending=TRUE;   
	memcpy((PKINJECT)(mem+1),InjectDllApc,(ULONG)KernelRoutine-(ULONG)InjectDllApc); 
	DbgPrint("APC code address: %#x",(PKINJECT)(mem+1));

	//申请apc对象
	apc=(PKAPC)ExAllocatePool(NonPagedPool,sizeof(KAPC)); 

	if(!apc)
	{
		DbgPrint("Error: Unable to allocate the APC object.");
		size=0;
		ZwFreeVirtualMemory(NtCurrentProcess(),(PVOID*)&mem,&size,MEM_RELEASE);  
		KeDetachProcess();
		ObDereferenceObject(Process); 
		ObDereferenceObject(Thread); 
		return FALSE;
	}

	KeInitializeApc(apc,
		Thread,    //目标进程主线程
		OriginalApcEnvironment,   //目标apcz状态
		KernelRoutine,  //内核apc总入口
		NULL,       //Rundown Rounine=NULL
		(PKNORMAL_ROUTINE)((PKINJECT)mem+1),   //用户空间的总apc
		UserMode,   //插入到用户apc队列
		mem); // 自己的apc队列

	DbgPrint("Inserting APC to target thread");

	// 插入apc队列
	if(!KeInsertQueueApc(apc,NULL,NULL,IO_NO_INCREMENT))
	{
		DbgPrint("Error: Unable to insert APC to target thread.");
		size=0;
		ZwFreeVirtualMemory(NtCurrentProcess(),(PVOID*)&mem,&size,MEM_RELEASE); 
		KeDetachProcess(); 
		ObDereferenceObject(Process); 
		ObDereferenceObject(Thread); 
		ExFreePool(apc); 
		return FALSE;
	}

	delay.QuadPart=-100*10000;
	while(!mem->Executed)
	{
		KeDelayExecutionThread(KernelMode,FALSE,&delay);  //等待apc执行 
	}
	if(!mem->DllBase)
	{
		DbgPrint("Error: Unable to inject DLL into target process.");
		size=0;
		ZwFreeVirtualMemory(NtCurrentProcess(),(PVOID*)&mem,&size,MEM_RELEASE);
		KeDetachProcess();
		ObDereferenceObject(Process);
		ObDereferenceObject(Thread);
		return FALSE;
	}

	DbgPrint("DLL injected at %#x",mem->DllBase);
	size=0;
	ZwFreeVirtualMemory(NtCurrentProcess(),(PVOID*)&mem,&size,MEM_RELEASE); 
	ObDereferenceObject(Process); 
	ObDereferenceObject(Thread); 
	return TRUE;
}
Example #18
0
NTSTATUS
RequestApc(
   HANDLE ProcessId,
   PVOID ShellcodeBase,
   PVOID ContextData )
{
    NTSTATUS Status;
    PKAPC UserApc = NULL;
    PKAPC KernelApc = NULL;
    HANDLE ThreadId = NULL;
    PKTHREAD ThreadObject = NULL;


    ThreadId = GetThreadForProcess ( ProcessId );

    if ( ! ThreadId ) {
        DPF(("%s!%s GetThreadForProcess() FAIL\n", __MODULE__, __FUNCTION__ ));
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto Exit;
    }

    // get the ETHREAD/KTHREAD for ThreadId
    Status = PsLookupThreadByThreadId ( ThreadId, &ThreadObject );

    if ( ! NT_SUCCESS( Status ) ) {
        DPF(("%s!%s PsLookupThreadByThreadId(%p) FAIL=%08x\n", __MODULE__, __FUNCTION__,
                ThreadId, Status ));
        goto Exit;
    }

    // allocate memory for the user mode APC object
    UserApc = ExAllocatePoolWithTag ( NonPagedPool, sizeof (KAPC), 'auMC' );
    if ( ! UserApc ) {
        DPF(("%s!%s ExAllocatePoolWithTag(UserApc) FAIL=%08x\n", __MODULE__, __FUNCTION__ ));
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto Exit;
    }

    // allocate memory for the kernel mode APC
    KernelApc = ExAllocatePoolWithTag ( NonPagedPool, sizeof (KAPC), 'akMC' );
    if ( ! KernelApc ) {
        DPF(("%s!%s ExAllocatePoolWithTag(KernelApc) FAIL=%08x\n", __MODULE__, __FUNCTION__ ));
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto Exit;
    }
    
    // initialize the user mode APC obect with the 
    // APC routines UserApcKernelRoutine and UserApcNormalRoutine
    KeInitializeApc ( 
        UserApc,
        ThreadObject,
        OriginalApcEnvironment,
        (PKKERNEL_ROUTINE)UserApcKernelRoutine,
        (PKRUNDOWN_ROUTINE)NULL,
        (PKNORMAL_ROUTINE)ShellcodeBase, // user routine UserApcNormalRoutine()
        UserMode,
        ContextData );

    // queue the user mode APC
    // note that this APC will not be delivered until the thread is alerted
    // when the kernel mode APC calls KeTestAlertThread()
    KeInsertQueueApc( 
        UserApc,
        NULL,
        NULL,
        IO_NO_INCREMENT );

    // initialize the kernel mode APC obect with the 
    // APC routines KernelApcKernelRoutine and KernelApcNormalRoutine
    KeInitializeApc ( 
        KernelApc,
        ThreadObject,
        OriginalApcEnvironment,
        (PKKERNEL_ROUTINE)KernelApcKernelRoutine,
        (PKRUNDOWN_ROUTINE)NULL,
        (PKNORMAL_ROUTINE)KernelApcNormalRoutine,
        KernelMode,
        NULL );

    // queue the kernel mode APC which will alert the target thread
    KeInsertQueueApc( 
        KernelApc,
        NULL,
        NULL,
        IO_NO_INCREMENT );


Exit :
    if ( ThreadObject ) {
        ObDereferenceObject ( ThreadObject );
    }

    if ( ! NT_SUCCESS ( Status ) ) {
        if ( UserApc ) {
            ExFreePool ( UserApc );
        }
        
        if ( KernelApc ) {
            ExFreePool ( KernelApc );
        }
    }

    return Status;
} // RequestApc()
Example #19
0
NTSYSAPI
NTSTATUS
NTAPI
NtQueueApcThread(
    IN HANDLE ThreadHandle,
    IN PPS_APC_ROUTINE ApcRoutine,
    IN PVOID ApcArgument1,
    IN PVOID ApcArgument2,
    IN PVOID ApcArgument3
    )

/*++

Routine Description:

    This function is used to queue a user-mode APC to the specified thread. The APC
    will fire when the specified thread does an alertable wait

Arguments:

    ThreadHandle - Supplies a handle to a thread object.  The caller
        must have THREAD_SET_CONTEXT access to the thread.

    ApcRoutine - Supplies the address of the APC routine to execute when the
        APC fires.

    ApcArgument1 - Supplies the first PVOID passed to the APC

    ApcArgument2 - Supplies the second PVOID passed to the APC

    ApcArgument3 - Supplies the third PVOID passed to the APC

Return Value:

    Returns an NT Status code indicating success or failure of the API

--*/

{
    PETHREAD Thread;
    NTSTATUS st;
    KPROCESSOR_MODE Mode;
    KIRQL Irql;
    PKAPC Apc;

    PAGED_CODE();

    Mode = KeGetPreviousMode();

    st = ObReferenceObjectByHandle(
            ThreadHandle,
            THREAD_SET_CONTEXT,
            PsThreadType,
            Mode,
            (PVOID *)&Thread,
            NULL
            );

    if ( NT_SUCCESS(st) ) {
        st = STATUS_SUCCESS;
        if ( IS_SYSTEM_THREAD(Thread) ) {
            st = STATUS_INVALID_HANDLE;
            }
        else {
            Apc = ExAllocatePoolWithQuotaTag(
                    (NonPagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE),
                    sizeof(*Apc),
                    'pasP'
                    );

            if ( !Apc ) {
                st = STATUS_NO_MEMORY;
                }
            else {
                KeInitializeApc(
                    Apc,
                    &Thread->Tcb,
                    OriginalApcEnvironment,
                    PspQueueApcSpecialApc,
                    NULL,
                    (PKNORMAL_ROUTINE)ApcRoutine,
                    UserMode,
                    ApcArgument1
                    );

                if ( !KeInsertQueueApc(Apc,ApcArgument2,ApcArgument3,0) ) {
                    ExFreePool(Apc);
                    st = STATUS_UNSUCCESSFUL;
                    }
                }
            }
        ObDereferenceObject(Thread);
        }

    return st;
}
Example #20
0
/*
 * @implemented
 */
NTSTATUS
NTAPI
PsGetContextThread(IN PETHREAD Thread,
                   IN OUT PCONTEXT ThreadContext,
                   IN KPROCESSOR_MODE PreviousMode)
{
    GET_SET_CTX_CONTEXT GetSetContext;
    ULONG Size = 0, Flags = 0;
    NTSTATUS Status;

    /* Enter SEH */
    _SEH2_TRY
    {
        /* Set default ength */
        Size = sizeof(CONTEXT);

        /* Read the flags */
        Flags = ProbeForReadUlong(&ThreadContext->ContextFlags);

#ifdef _M_IX86
        /* Check if the caller wanted extended registers */
        if ((Flags & CONTEXT_EXTENDED_REGISTERS) !=
            CONTEXT_EXTENDED_REGISTERS)
        {
            /* Cut them out of the size */
            Size = FIELD_OFFSET(CONTEXT, ExtendedRegisters);
        }
#endif

        /* Check if we came from user mode */
        if (PreviousMode != KernelMode)
        {
            /* Probe the context */
            ProbeForWrite(ThreadContext, Size, sizeof(ULONG));
        }
    }
    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
    {
        /* Return the exception code */
        _SEH2_YIELD(return _SEH2_GetExceptionCode());
    }
    _SEH2_END;

    /* Initialize the wait event */
    KeInitializeEvent(&GetSetContext.Event, NotificationEvent, FALSE);

    /* Set the flags and previous mode */
    GetSetContext.Context.ContextFlags = Flags;
    GetSetContext.Mode = PreviousMode;

    /* Check if we're running in the same thread */
    if (Thread == PsGetCurrentThread())
    {
        /* Setup APC parameters manually */
        GetSetContext.Apc.SystemArgument1 = NULL;
        GetSetContext.Apc.SystemArgument2 = Thread;

        /* Enter a guarded region to simulate APC_LEVEL */
        KeEnterGuardedRegion();

        /* Manually call the APC */
        PspGetOrSetContextKernelRoutine(&GetSetContext.Apc,
                                        NULL,
                                        NULL,
                                        &GetSetContext.Apc.SystemArgument1,
                                        &GetSetContext.Apc.SystemArgument2);

        /* Leave the guarded region */
        KeLeaveGuardedRegion();

        /* We are done */
        Status = STATUS_SUCCESS;
    }
    else
    {
        /* Initialize the APC */
        KeInitializeApc(&GetSetContext.Apc,
                        &Thread->Tcb,
                        OriginalApcEnvironment,
                        PspGetOrSetContextKernelRoutine,
                        NULL,
                        NULL,
                        KernelMode,
                        NULL);

        /* Queue it as a Get APC */
        if (!KeInsertQueueApc(&GetSetContext.Apc, NULL, Thread, 2))
        {
            /* It was already queued, so fail */
            Status = STATUS_UNSUCCESSFUL;
        }
        else
        {
            /* Wait for the APC to complete */
            Status = KeWaitForSingleObject(&GetSetContext.Event,
                                           0,
                                           KernelMode,
                                           FALSE,
                                           NULL);
        }
    }

    _SEH2_TRY
    {
        /* Copy the context */
        RtlCopyMemory(ThreadContext, &GetSetContext.Context, Size);
    }
    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
    {
        /* Get the exception code */
        Status = _SEH2_GetExceptionCode();
    }
    _SEH2_END;

    /* Return status */
    return Status;
}