/// <summary> /// Create new thread in the target process /// Must be running in target process context /// </summary> /// <param name="pBaseAddress">Thread start address</param> /// <param name="pParam">Thread argument</param> /// <param name="flags">Thread creation flags</param> /// <param name="wait">If set to TRUE - wait for thread completion</param> /// <param name="pExitStatus">Thread exit status</param> /// <returns>Status code</returns> NTSTATUS BBExecuteInNewThread( IN PVOID pBaseAddress, IN PVOID pParam, IN ULONG flags, IN BOOLEAN wait, OUT PNTSTATUS pExitStatus ) { HANDLE hThread = NULL; OBJECT_ATTRIBUTES ob = { 0 }; InitializeObjectAttributes( &ob, NULL, OBJ_KERNEL_HANDLE, NULL, NULL ); NTSTATUS status = ZwCreateThreadEx( &hThread, THREAD_QUERY_LIMITED_INFORMATION, &ob, ZwCurrentProcess(), pBaseAddress, pParam, flags, 0, 0x1000, 0x100000, NULL ); // Wait for completion if (NT_SUCCESS( status ) && wait != FALSE) { // Force 60 sec timeout LARGE_INTEGER timeout = { 0 }; timeout.QuadPart = -(60ll * 10 * 1000 * 1000); status = ZwWaitForSingleObject( hThread, TRUE, &timeout ); if (NT_SUCCESS( status )) { THREAD_BASIC_INFORMATION info = { 0 }; ULONG bytes = 0; status = ZwQueryInformationThread( hThread, ThreadBasicInformation, &info, sizeof( info ), &bytes ); if (NT_SUCCESS( status ) && pExitStatus) { *pExitStatus = info.ExitStatus; } else if (!NT_SUCCESS( status )) { DPRINT( "BlackBone: %s: ZwQueryInformationThread failed with status 0x%X\n", __FUNCTION__, status ); } } else DPRINT( "BlackBone: %s: ZwWaitForSingleObject failed with status 0x%X\n", __FUNCTION__, status ); } else DPRINT( "BlackBone: %s: ZwCreateThreadEx failed with status 0x%X\n", __FUNCTION__, status ); if (hThread) ZwClose( hThread ); return status; }
EASYHOOK_NT_EXPORT DbgGetThreadIdByHandle( HANDLE InThreadHandle, ULONG* OutThreadId) { /* Description: Translates the given thread handle back to its thread ID if possible. Parameters: - InThreadHandle A thread handle with THREAD_QUERY_INFORMATION access. - OutThreadId Receives the thread ID. */ THREAD_BASIC_INFORMATION ThreadInfo; NTSTATUS NtStatus; if(!IsValidPointer(OutThreadId, sizeof(ULONG))) THROW(STATUS_INVALID_PARAMETER_2, L"Invalid TID storage specified."); if(ZwQueryInformationThread != NULL) { // use deprecated API FORCE(ZwQueryInformationThread( InThreadHandle, 0 /* ThreadBasicInformation */, &ThreadInfo, sizeof(ThreadInfo), NULL)); *OutThreadId = ThreadInfo.ClientId.UniqueThread; } else { ASSERT(ZwGetThreadId != NULL); // use new support API if((*OutThreadId = ZwGetThreadId(InThreadHandle)) == 0) THROW(STATUS_INVALID_PARAMETER_1, L"Invalid thread handler or improper privileges."); } RETURN; THROW_OUTRO: FINALLY_OUTRO: return NtStatus; }
/// <summary> /// Manually map driver into system space /// </summary> /// <param name="pPath">Fully qualified native path to the driver</param> /// <returns>Status code</returns> NTSTATUS BBMMapDriver( IN PUNICODE_STRING pPath ) { HANDLE hThread = NULL; CLIENT_ID clientID = { 0 }; OBJECT_ATTRIBUTES obAttr = { 0 }; PETHREAD pThread = NULL; OBJECT_HANDLE_INFORMATION handleInfo = { 0 }; InitializeObjectAttributes( &obAttr, NULL, OBJ_KERNEL_HANDLE, NULL, NULL ); ASSERT( pPath != NULL ); if (pPath == NULL) return STATUS_INVALID_PARAMETER; NTSTATUS status = PsCreateSystemThread( &hThread, THREAD_ALL_ACCESS, &obAttr, NULL, &clientID, &BBMapWorker, pPath ); if (!NT_SUCCESS( status )) { DPRINT( "BlackBone: %s: Failed to create worker thread. Status: 0x%X\n", __FUNCTION__, status ); return status; } // Wait on worker thread status = ObReferenceObjectByHandle( hThread, THREAD_ALL_ACCESS, *PsThreadType, KernelMode, &pThread, &handleInfo ); if (NT_SUCCESS( status )) { THREAD_BASIC_INFORMATION info = { 0 }; ULONG bytes = 0; status = KeWaitForSingleObject( pThread, Executive, KernelMode, TRUE, NULL ); status = ZwQueryInformationThread( hThread, ThreadBasicInformation, &info, sizeof( info ), &bytes ); status = info.ExitStatus; } if (pThread) ObDereferenceObject( pThread ); return status; }
/* * @implemented */ NTSTATUS NTAPI RtlSetThreadIsCritical(IN BOOLEAN NewValue, OUT PBOOLEAN OldValue OPTIONAL, IN BOOLEAN NeedBreaks) { ULONG BreakOnTermination; /* Initialize to FALSE */ if (OldValue) *OldValue = FALSE; /* Fail, if the critical breaks flag is required but is not set */ if ((NeedBreaks) && !(NtCurrentPeb()->NtGlobalFlag & FLG_ENABLE_SYSTEM_CRIT_BREAKS)) { return STATUS_UNSUCCESSFUL; } /* Check if the caller wants the old value */ if (OldValue) { /* Query and return the old break on termination flag for the process */ ZwQueryInformationThread(NtCurrentThread(), ThreadBreakOnTermination, &BreakOnTermination, sizeof(ULONG), NULL); *OldValue = (BOOLEAN)BreakOnTermination; } /* Set the break on termination flag for the process */ BreakOnTermination = NewValue; return ZwSetInformationThread(NtCurrentThread(), ThreadBreakOnTermination, &BreakOnTermination, sizeof(ULONG)); }