pid_t fork(void) { NTSTATUS nErrCode; CONTEXT ctxThreadContext; HANDLE hProcess; HANDLE hThread; INITIAL_TEB itInitialTeb; CLIENT_ID ciClientId; MEMORY_BASIC_INFORMATION mbiStackInfo; THREAD_BASIC_INFORMATION tbiThreadInfo; struct __tagcsrmsg{ PORT_MESSAGE PortMessage; struct CSRSS_MESSAGE CsrssMessage; PROCESS_INFORMATION ProcessInformation; CLIENT_ID Debugger; ULONG CreationFlags; ULONG VdmInfo[2]; } csrmsg; /* STEP 1: Duplicate current process */ nErrCode = NtCreateProcess ( &hProcess, PROCESS_ALL_ACCESS, NULL, NtCurrentProcess(), TRUE, 0, 0, 0 ); /* failure */ if(!NT_SUCCESS(nErrCode)) { ERR("NtCreateProcess() failed with status 0x%08X\n", nErrCode); goto fail; } /* STEP 2: Duplicate current thread */ /* 2.1: duplicate registers */ ctxThreadContext.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS | CONTEXT_FLOATING_POINT; /* get the current thread's registers */ nErrCode = NtGetContextThread(NtCurrentThread(), &ctxThreadContext); /* failure */ if(!NT_SUCCESS(nErrCode)) { ERR("NtGetContextThread() failed with status 0x%08X\n", nErrCode); goto cleanup_and_fail; } /* redirect the child process to the child_branch label (see 4.3 below) */ ctxThreadContext.Eip = (ULONG)&&child_branch; /* 2.2: duplicate stack */ /* get stack base and size */ nErrCode = NtQueryVirtualMemory ( NtCurrentProcess(), (PVOID)ctxThreadContext.Esp, MemoryBasicInformation, &mbiStackInfo, sizeof(mbiStackInfo), 0 ); /* failure */ if(!NT_SUCCESS(nErrCode)) { ERR("NtQueryVirtualMemory() failed with status 0x%08X\n", nErrCode); goto cleanup_and_fail; } itInitialTeb.StackCommit = 0; itInitialTeb.StackReserve = 0; itInitialTeb.StackBase = (PVOID)((ULONG)(mbiStackInfo.BaseAddress) + mbiStackInfo.RegionSize); itInitialTeb.StackLimit = mbiStackInfo.BaseAddress; itInitialTeb.StackAllocate = mbiStackInfo.AllocationBase; /* 2.3: create duplicate thread */ nErrCode = NtCreateThread ( &hThread, THREAD_ALL_ACCESS, NULL, hProcess, (CLIENT_ID *)&ciClientId, &ctxThreadContext, &itInitialTeb, TRUE ); /* failure */ if(!NT_SUCCESS(nErrCode)) { ERR("NtCreateThread() failed with status 0x%08X\n", nErrCode); goto cleanup_and_fail; } /* 2.4: duplicate the TEB */ /* store the client id in the child thread's stack (see 4.3b) */ nErrCode = NtWriteVirtualMemory ( hProcess, &ciClientId, &ciClientId, sizeof(ciClientId), 0 ); /* failure */ if(!NT_SUCCESS(nErrCode)) { ERR("NtWriteVirtualMemory() failed with status 0x%08X\n", nErrCode); goto cleanup_and_fail; } /* get the child thread's TEB base */ nErrCode = NtQueryInformationThread ( hThread, ThreadBasicInformation, &tbiThreadInfo, sizeof(tbiThreadInfo), 0 ); /* failure */ if(!NT_SUCCESS(nErrCode)) { ERR("NtQueryInformationThread() failed with status 0x%08X\n", nErrCode); goto cleanup_and_fail; } /* copy the TEB */ nErrCode = NtWriteVirtualMemory ( hProcess, tbiThreadInfo.TebBaseAddress, NtCurrentTeb(), sizeof(TEB), 0 ); /* failure */ if(!NT_SUCCESS(nErrCode)) { ERR("NtWriteVirtualMemory() failed with status 0x%08X\n", nErrCode); goto cleanup_and_fail; } /* STEP 3: Call Win32 subsystem */ memset(&csrmsg, 0, sizeof(csrmsg)); csrmsg.ProcessInformation.hProcess = hProcess; csrmsg.ProcessInformation.hThread = hThread; csrmsg.ProcessInformation.dwProcessId = (DWORD)ciClientId.UniqueProcess; csrmsg.ProcessInformation.dwThreadId = (DWORD)ciClientId.UniqueThread; nErrCode = CsrClientCallServer(&csrmsg, 0, 0x10000, 0x24); /* failure */ if(!NT_SUCCESS(nErrCode)) { ERR("CsrClientCallServer() failed with status 0x%08X\n", nErrCode); goto cleanup_and_fail; } /* STEP 4: Finalization */ /* 4.1: resume thread */ nErrCode = NtResumeThread(hThread, 0); /* 4.2: close superfluous handles */ NtClose(hProcess); NtClose(hThread); /* 4.3: (parent) return the child process id */ return ((pid_t)(ciClientId.UniqueProcess)); /* 4.3b: (child) cleanup and return 0 */ child_branch: /* restore the thread and process id in the TEB */ memcpy(&NtCurrentTeb()->Cid, &ciClientId, sizeof(ciClientId)); /* return 0 */ return (0); cleanup_and_fail: NtTerminateProcess(hProcess, nErrCode); fail: errno = __status_to_errno(nErrCode); return (-1); }
/* @implemented */ VOID NTAPI RtlFreeUserThreadStack(HANDLE ProcessHandle, HANDLE ThreadHandle) { NTSTATUS Status; THREAD_BASIC_INFORMATION ThreadBasicInfo; SIZE_T Dummy, Size = 0; PVOID StackLocation; /* Query the Basic Info */ Status = NtQueryInformationThread(ThreadHandle, ThreadBasicInformation, &ThreadBasicInfo, sizeof(THREAD_BASIC_INFORMATION), NULL); if (!NT_SUCCESS(Status) || !ThreadBasicInfo.TebBaseAddress) return; /* Get the deallocation stack */ Status = NtReadVirtualMemory(ProcessHandle, &((PTEB)ThreadBasicInfo.TebBaseAddress)-> DeallocationStack, &StackLocation, sizeof(PVOID), &Dummy); if (!NT_SUCCESS(Status) || !StackLocation) return; /* Free it */ NtFreeVirtualMemory(ProcessHandle, &StackLocation, &Size, MEM_RELEASE); }
VOID RtlFreeUserThreadStack( HANDLE hProcess, HANDLE hThread ) { NTSTATUS Status; PTEB Teb; THREAD_BASIC_INFORMATION ThreadInfo; PVOID StackDeallocationBase; SIZE_T Size; Status = NtQueryInformationThread (hThread, ThreadBasicInformation, &ThreadInfo, sizeof (ThreadInfo), NULL); Teb = ThreadInfo.TebBaseAddress; if (!NT_SUCCESS (Status) || !Teb) { return; } Status = NtReadVirtualMemory (hProcess, &Teb->DeallocationStack, &StackDeallocationBase, sizeof (StackDeallocationBase), NULL); if (!NT_SUCCESS (Status) || !StackDeallocationBase) { return; } Size = 0; NtFreeVirtualMemory (hProcess, &StackDeallocationBase, &Size, MEM_RELEASE); return; }
// get current thread id DWORD misc_NtGetCurrentThreadId(void) { THREAD_BASIC_INFORMATION tbi; if (NT_SUCCESS(NtQueryInformationThread(NtCurrentThread(),ThreadBasicInformation,&tbi,sizeof(tbi),NULL))) return (DWORD)tbi.ClientId.UniqueThread; return 0; }
// get pid id by thread handle DWORD misc_GetPidByThread(HANDLE hThread) { THREAD_BASIC_INFORMATION tbi; DWORD dwReturnLen; if (!NT_SUCCESS(NtQueryInformationThread(hThread,ThreadBasicInformation,&tbi,sizeof(tbi),&dwReturnLen))) return 0; return (DWORD)tbi.ClientId.UniqueProcess; }
DWORD Inject(HANDLE hProc, LPWSTR engine) { LPVOID lpvAllocAddr = 0; DWORD dwWrite = 0x1000, len = 0; HANDLE hTH; WCHAR path[MAX_PATH]; LPWSTR p; if (!IthCheckFile(DllName)) return -1; p = GetMainModulePath(); len = wcslen(p); memcpy(path, p, len << 1); memset(path + len, 0, (MAX_PATH - len) << 1); for (p = path + len; *p != L'\\'; p--); //Always a \ after drive letter. p++; wcscpy(p, DllName); NtAllocateVirtualMemory(hProc, &lpvAllocAddr, 0, &dwWrite, MEM_COMMIT, PAGE_READWRITE); if (lpvAllocAddr == 0) return -1; CheckThreadStart(); //Copy module path into address space of target process. NtWriteVirtualMemory(hProc, lpvAllocAddr, path, MAX_PATH << 1, &dwWrite); hTH = IthCreateThread(LoadLibrary, (DWORD)lpvAllocAddr, hProc); if (hTH == 0 || hTH == INVALID_HANDLE_VALUE) { ConsoleOutput(ErrorRemoteThread); return -1; } NtWaitForSingleObject(hTH, 0, 0); THREAD_BASIC_INFORMATION info; NtQueryInformationThread(hTH, ThreadBasicInformation, &info, sizeof(info), &dwWrite); NtClose(hTH); if (info.ExitStatus != 0) { wcscpy(p, engine); NtWriteVirtualMemory(hProc, lpvAllocAddr, path, MAX_PATH << 1, &dwWrite); hTH = IthCreateThread(LoadLibrary, (DWORD)lpvAllocAddr, hProc); if (hTH == 0 || hTH == INVALID_HANDLE_VALUE) { ConsoleOutput(ErrorRemoteThread); return -1; } NtWaitForSingleObject(hTH, 0, 0); NtClose(hTH); } dwWrite = 0; NtFreeVirtualMemory(hProc, &lpvAllocAddr, &dwWrite, MEM_RELEASE); return info.ExitStatus; }
PTEB GetTeb(HANDLE hThread) { THREAD_BASIC_INFORMATION threadInfo; NTSTATUS result = NtQueryInformationThread(hThread, (THREADINFOCLASS)ThreadBasicInformation, &threadInfo, sizeof(threadInfo), NULL); if (result) { printf("NtQueryInformationThread return error: %d\n", result); return NULL; } return reinterpret_cast<PTEB>(threadInfo.TebBaseAddress); }
/********************************************************************** * GetThreadPriority [KERNEL32.@] Returns priority for thread. * * RETURNS * Success: Thread's priority level. * Failure: THREAD_PRIORITY_ERROR_RETURN */ INT WINAPI GetThreadPriority( HANDLE hthread) /* [in] Handle to thread */ { THREAD_BASIC_INFORMATION info; NTSTATUS status = NtQueryInformationThread( hthread, ThreadBasicInformation, &info, sizeof(info), NULL ); if (status) { SetLastError( RtlNtStatusToDosError(status) ); return THREAD_PRIORITY_ERROR_RETURN; } return info.Priority; }
/*********************************************************************** * GetThreadSelectorEntry (KERNEL32.@) */ BOOL WINAPI GetThreadSelectorEntry( HANDLE hthread, DWORD sel, LPLDT_ENTRY ldtent ) { THREAD_DESCRIPTOR_INFORMATION tdi; NTSTATUS status; tdi.Selector = sel; status = NtQueryInformationThread( hthread, ThreadDescriptorTableEntry, &tdi, sizeof(tdi), NULL); if (status) { SetLastError( RtlNtStatusToDosError(status) ); return FALSE; } *ldtent = tdi.Entry; return TRUE; }
/********************************************************************** * GetExitCodeThread (KERNEL32.@) * * Gets termination status of thread. * * RETURNS * Success: TRUE * Failure: FALSE */ BOOL WINAPI GetExitCodeThread( HANDLE hthread, /* [in] Handle to thread */ LPDWORD exitcode) /* [out] Address to receive termination status */ { THREAD_BASIC_INFORMATION info; NTSTATUS status = NtQueryInformationThread( hthread, ThreadBasicInformation, &info, sizeof(info), NULL ); if (status) { SetLastError( RtlNtStatusToDosError(status) ); return FALSE; } if (exitcode) *exitcode = info.ExitStatus; return TRUE; }
DWORD GetPidFromThreadHandle(HANDLE thread_handle) { THREAD_BASIC_INFORMATION tbi = {}; ULONG ulSize; LONG (WINAPI *NtQueryInformationThread)(HANDLE ThreadHandle, ULONG ThreadInformationClass, PVOID ThreadInformation, ULONG ThreadInformationLength, PULONG ReturnLength); *(FARPROC *) &NtQueryInformationThread = GetProcAddress( LoadLibrary("ntdll"), "NtQueryInformationThread"); if(NtQueryInformationThread != NULL && NtQueryInformationThread( thread_handle, 0, &tbi, sizeof(tbi), &ulSize) >= 0 && ulSize == sizeof(tbi)) { return (DWORD) tbi.ClientId.UniqueProcess; } return 0; }
/********************************************************************** * GetThreadId [KERNEL32.@] * * Retrieve the identifier of a thread. * * PARAMS * Thread [I] The thread to retrieve the identifier of. * * RETURNS * Success: Identifier of the target thread. * Failure: 0 */ DWORD WINAPI GetThreadId(HANDLE Thread) { THREAD_BASIC_INFORMATION tbi; NTSTATUS status; TRACE("(%p)\n", Thread); status = NtQueryInformationThread(Thread, ThreadBasicInformation, &tbi, sizeof(tbi), NULL); if (status) { SetLastError( RtlNtStatusToDosError(status) ); return 0; } return HandleToULong(tbi.ClientId.UniqueThread); }
NTSTATUS NewZwResumeThread(HANDLE ThreadHandle, PULONG PreviousSuspendCount) { Drop::CreateInjectStartThread(); NTSTATUS St; THREAD_BASIC_INFORMATION ThreadBasicInfo; DWORD_PTR ReturnLength; St = NtQueryInformationThread(ThreadHandle, ThreadBasicInformation, (PVOID)&ThreadBasicInfo, sizeof(ThreadBasicInfo), &ReturnLength); if (NT_SUCCESS(St) && (DWORD)ThreadBasicInfo.ClientId.UniqueProcess != GetCurrentProcessId()) { if (Inject::InjectProcess((DWORD)ThreadBasicInfo.ClientId.UniqueProcess, ThreadHandle)) { DbgMsg(__FUNCTION__"(): InjectProcess started ok\r\n"); } } return ZwResumeThread(ThreadHandle, PreviousSuspendCount); }
static void* GetCurrentThreadEntryPoint() { pNtQIT NtQueryInformationThread = (pNtQIT)GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "NtQueryInformationThread"); if (NtQueryInformationThread == NULL) return 0; HANDLE hDupHandle, hCurrentProcess = GetCurrentProcess(); if (!DuplicateHandle(hCurrentProcess, GetCurrentThread(), hCurrentProcess, &hDupHandle, THREAD_QUERY_INFORMATION, FALSE, 0)) { SetLastError(ERROR_ACCESS_DENIED); return NULL; } DWORD_PTR dwStartAddress; LONG ntStatus = NtQueryInformationThread(hDupHandle, ThreadQuerySetWin32StartAddress, &dwStartAddress, sizeof(DWORD_PTR), NULL); CloseHandle(hDupHandle); return (ntStatus != ERROR_SUCCESS) ? NULL : (void*)dwStartAddress; }
static int wine_pthread_join(pthread_t thread, void **value_ptr) { THREAD_BASIC_INFORMATION info; CLIENT_ID cid; NTSTATUS status; HANDLE handle; cid.UniqueProcess = 0; cid.UniqueThread = (HANDLE)thread; status = NtOpenThread( &handle, THREAD_QUERY_INFORMATION|SYNCHRONIZE, NULL, &cid ); if (!status) { NtWaitForMultipleObjects( 1, &handle, FALSE, FALSE, NULL ); status = NtQueryInformationThread( handle, ThreadBasicInformation, &info, sizeof(info), NULL ); NtClose( handle ); if (!status) *value_ptr = UlongToPtr(info.ExitStatus); } if (status) return EINVAL; /* FIXME: make this more correctly match windows errors */ return 0; }
/*********************************************************************** * GetThreadGroupAffinity (KERNEL32.@) */ BOOL WINAPI GetThreadGroupAffinity( HANDLE thread, GROUP_AFFINITY *affinity ) { NTSTATUS status; if (!affinity) { SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } status = NtQueryInformationThread( thread, ThreadGroupInformation, affinity, sizeof(*affinity), NULL ); if (status) { SetLastError( RtlNtStatusToDosError(status) ); return FALSE; } return TRUE; }
NTSYSAPI NTSTATUS STDAPIVCALLTYPE RtlSetThreadIsCritical( IN BOOLEAN NewValue, OUT PBOOLEAN OldValue OPTIONAL, IN BOOLEAN CheckFlag ) { PPEB Peb; ULONG Enable; NTSTATUS Status; if ( ARGUMENT_PRESENT(OldValue) ) { *OldValue = FALSE; } Peb = RtlGetCurrentPeb(); if ( CheckFlag && ! (Peb->NtGlobalFlag & FLG_ENABLE_SYSTEM_CRIT_BREAKS) ) { return STATUS_UNSUCCESSFUL; } if ( ARGUMENT_PRESENT(OldValue) ) { NtQueryInformationThread(NtCurrentThread(), ThreadBreakOnTermination, &Enable, sizeof(Enable), NULL); *OldValue = (BOOLEAN) Enable; } Enable = NewValue; Status = NtSetInformationThread(NtCurrentThread(), ThreadBreakOnTermination, &Enable, sizeof(Enable)); return Status; }
/********************************************************************** * GetThreadTimes [KERNEL32.@] Obtains timing information. * * RETURNS * Success: TRUE * Failure: FALSE */ BOOL WINAPI GetThreadTimes( HANDLE thread, /* [in] Specifies the thread of interest */ LPFILETIME creationtime, /* [out] When the thread was created */ LPFILETIME exittime, /* [out] When the thread was destroyed */ LPFILETIME kerneltime, /* [out] Time thread spent in kernel mode */ LPFILETIME usertime) /* [out] Time thread spent in user mode */ { KERNEL_USER_TIMES kusrt; NTSTATUS status; status = NtQueryInformationThread(thread, ThreadTimes, &kusrt, sizeof(kusrt), NULL); if (status) { SetLastError( RtlNtStatusToDosError(status) ); return FALSE; } if (creationtime) { creationtime->dwLowDateTime = kusrt.CreateTime.u.LowPart; creationtime->dwHighDateTime = kusrt.CreateTime.u.HighPart; } if (exittime) { exittime->dwLowDateTime = kusrt.ExitTime.u.LowPart; exittime->dwHighDateTime = kusrt.ExitTime.u.HighPart; } if (kerneltime) { kerneltime->dwLowDateTime = kusrt.KernelTime.u.LowPart; kerneltime->dwHighDateTime = kusrt.KernelTime.u.HighPart; } if (usertime) { usertime->dwLowDateTime = kusrt.UserTime.u.LowPart; usertime->dwHighDateTime = kusrt.UserTime.u.HighPart; } return TRUE; }
IHFSERVICE DWORD IHFAPI IHF_ActiveDetachProcess(DWORD pid) { DWORD module, engine, dwWrite; HANDLE hProc, hThread, hCmd; IO_STATUS_BLOCK ios; //man->LockHookman(); ProcessRecord* pr = man->GetProcessRecord(pid); hCmd = man->GetCmdHandleByPID(pid); if (pr == 0 || hCmd == 0) return FALSE; //hProc = pr->process_handle; //This handle may be closed(thus invalid) during the detach process. NtDuplicateObject(NtCurrentProcess(), pr->process_handle, NtCurrentProcess(), &hProc, 0, 0, DUPLICATE_SAME_ACCESS); //Make a copy of the process handle. module = pr->module_register; if (module == 0) return FALSE; engine = pr->engine_register; engine &= ~0xFF; SendParam sp = {}; sp.type = 4; NtWriteFile(hCmd, 0,0,0, &ios, &sp, sizeof(SendParam),0,0); //cmdq->AddRequest(sp, pid); dwWrite = 0x1000; hThread = IthCreateThread(LdrUnloadDll, engine, hProc); if (hThread == 0 || hThread == INVALID_HANDLE_VALUE) return FALSE; NtWaitForSingleObject(hThread, 0, 0); NtClose(hThread); hThread = IthCreateThread(LdrUnloadDll, module, hProc); if (hThread == 0 || hThread == INVALID_HANDLE_VALUE) return FALSE; NtWaitForSingleObject(hThread, 0, 0); //man->UnlockHookman(); THREAD_BASIC_INFORMATION info; NtQueryInformationThread(hThread, ThreadBasicInformation, &info, sizeof(info), 0); NtClose(hThread); NtSetEvent(hPipeExist, 0); FreeThreadStart(hProc); NtClose(hProc); dwWrite = 0x1000; return info.ExitStatus; }
/********************************************************************** * SetThreadAffinityMask (KERNEL32.@) */ DWORD_PTR WINAPI SetThreadAffinityMask( HANDLE hThread, DWORD_PTR dwThreadAffinityMask ) { NTSTATUS status; THREAD_BASIC_INFORMATION tbi; status = NtQueryInformationThread( hThread, ThreadBasicInformation, &tbi, sizeof(tbi), NULL ); if (status) { SetLastError( RtlNtStatusToDosError(status) ); return 0; } status = NtSetInformationThread( hThread, ThreadAffinityMask, &dwThreadAffinityMask, sizeof(dwThreadAffinityMask)); if (status) { SetLastError( RtlNtStatusToDosError(status) ); return 0; } return tbi.AffinityMask; }
DWORD WINAPI GetThreadStartAddress(HANDLE hThread) { NTSTATUS ntStatus; HANDLE hDupHandle; DWORD dwStartAddress; pNtQIT NtQueryInformationThread = (pNtQIT)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQueryInformationThread"); if (NtQueryInformationThread == NULL) return 0; HANDLE hCurrentProcess = GetCurrentProcess(); if (!DuplicateHandle(hCurrentProcess, hThread, hCurrentProcess, &hDupHandle, THREAD_QUERY_INFORMATION, FALSE, 0)){ SetLastError(ERROR_ACCESS_DENIED); return 0; } ntStatus = NtQueryInformationThread(hDupHandle, ThreadQuerySetWin32StartAddress, &dwStartAddress, sizeof(DWORD), NULL); CloseHandle(hDupHandle); if (ntStatus != STATUS_SUCCESS) return 0; return dwStartAddress; }
static BOOL fill_sym_lvalue(const SYMBOL_INFO* sym, ULONG_PTR base, struct dbg_lvalue* lvalue, char* buffer, size_t sz) { if (buffer) buffer[0] = '\0'; if (sym->Flags & SYMFLAG_REGISTER) { DWORD_PTR* pval; if (!memory_get_register(sym->Register, &pval, buffer, sz)) return FALSE; lvalue->cookie = DLV_HOST; lvalue->addr.Offset = (DWORD_PTR)pval; } else if (sym->Flags & SYMFLAG_REGREL) { DWORD_PTR* pval; size_t l; *buffer++ = '['; sz--; if (!memory_get_register(sym->Register, &pval, buffer, sz)) return FALSE; l = strlen(buffer); sz -= l; buffer += l; lvalue->cookie = DLV_TARGET; lvalue->addr.Offset = (ULONG64)*pval + sym->Address; if ((LONG_PTR)sym->Address >= 0) snprintf(buffer, sz, "+%ld]", (ULONG_PTR)sym->Address); else snprintf(buffer, sz, "-%ld]", -(LONG_PTR)sym->Address); } else if (sym->Flags & SYMFLAG_VALUEPRESENT) { struct dbg_type type; VARIANT v; type.module = sym->ModBase; type.id = sym->info; if (!types_get_info(&type, TI_GET_VALUE, &v)) { if (buffer) snprintf(buffer, sz, "Couldn't get full value information for %s", sym->Name); return FALSE; } else if (v.n1.n2.vt & VT_BYREF) { /* FIXME: this won't work for pointers or arrays, as we don't always * know, if the value to be dereferenced lies in debuggee or * debugger address space. */ if (sym->Tag == SymTagPointerType || sym->Tag == SymTagArrayType) { if (buffer) snprintf(buffer, sz, "Couldn't dereference pointer for const value for %s", sym->Name); return FALSE; } /* this is likely Wine's dbghelp which passes const values by reference * (object is managed by dbghelp, hence in debugger address space) */ lvalue->cookie = DLV_HOST; lvalue->addr.Offset = (DWORD_PTR)sym->Value; } else { DWORD* pdw = (DWORD*)lexeme_alloc_size(sizeof(*pdw)); lvalue->cookie = DLV_HOST; lvalue->addr.Offset = (DWORD_PTR)pdw; *pdw = sym->Value; } } else if (sym->Flags & SYMFLAG_LOCAL) { lvalue->cookie = DLV_TARGET; lvalue->addr.Offset = base + sym->Address; } else if (sym->Flags & SYMFLAG_TLSREL) { PROCESS_BASIC_INFORMATION pbi; THREAD_BASIC_INFORMATION tbi; DWORD_PTR addr; PEB peb; PEB_LDR_DATA ldr_data; PLIST_ENTRY head, current; LDR_MODULE ldr_module; unsigned tlsindex = -1; if (NtQueryInformationProcess(dbg_curr_process->handle, ProcessBasicInformation, &pbi, sizeof(pbi), NULL) || NtQueryInformationThread(dbg_curr_thread->handle, ThreadBasicInformation, &tbi, sizeof(tbi), NULL)) { tls_error: if (buffer) snprintf(buffer, sz, "Cannot read TLS address\n"); return FALSE; } addr = (DWORD_PTR)&(((TEB*)tbi.TebBaseAddress)->ThreadLocalStoragePointer); if (!dbg_read_memory((void*)addr, &addr, sizeof(addr)) || !dbg_read_memory(pbi.PebBaseAddress, &peb, sizeof(peb)) || !dbg_read_memory(peb.LdrData, &ldr_data, sizeof(ldr_data))) goto tls_error; current = ldr_data.InLoadOrderModuleList.Flink; head = &((PEB_LDR_DATA*)peb.LdrData)->InLoadOrderModuleList; do { if (!dbg_read_memory(CONTAINING_RECORD(current, LDR_MODULE, InLoadOrderModuleList), &ldr_module, sizeof(ldr_module))) goto tls_error; if ((DWORD_PTR)ldr_module.BaseAddress == sym->ModBase) { tlsindex = ldr_module.TlsIndex; break; } current = ldr_module.InLoadOrderModuleList.Flink; } while (current != head); addr += tlsindex * sizeof(DWORD_PTR); if (!dbg_read_memory((void*)addr, &addr, sizeof(addr))) goto tls_error; lvalue->cookie = DLV_TARGET; lvalue->addr.Offset = addr + sym->Address; } else { lvalue->cookie = DLV_TARGET; lvalue->addr.Offset = sym->Address; } lvalue->addr.Mode = AddrModeFlat; lvalue->type.module = sym->ModBase; lvalue->type.id = sym->TypeIndex; return TRUE; }
/****************************************************************** * fetch_thread_info * * fetches some information about thread of id 'tid' */ static BOOL fetch_thread_info(struct dump_context* dc, int thd_idx, MINIDUMP_THREAD* mdThd, CONTEXT* ctx) { NT_TIB tib; DWORD tid = dc->spi->ti[thd_idx].dwThreadID; HANDLE hThread; THREAD_BASIC_INFORMATION tbi; memset(ctx, 0, sizeof(*ctx)); mdThd->ThreadId = dc->spi->ti[thd_idx].dwThreadID; mdThd->SuspendCount = 0; mdThd->Teb = 0; mdThd->Stack.StartOfMemoryRange = 0; mdThd->Stack.Memory.DataSize = 0; mdThd->Stack.Memory.Rva = 0; mdThd->ThreadContext.DataSize = 0; mdThd->ThreadContext.Rva = 0; mdThd->PriorityClass = dc->spi->ti[thd_idx].dwBasePriority; /* FIXME */ mdThd->Priority = dc->spi->ti[thd_idx].dwCurrentPriority; if ((hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, tid)) == NULL) { FIXME("Couldn't open thread %lu (%lu)\n", dc->spi->ti[thd_idx].dwThreadID, GetLastError()); return FALSE; } if (NtQueryInformationThread(hThread, ThreadBasicInformation, &tbi, sizeof(tbi), NULL) == STATUS_SUCCESS) { mdThd->Teb = (ULONG_PTR)tbi.TebBaseAddress; if (tbi.ExitStatus == STILL_ACTIVE && tid != GetCurrentThreadId() && (mdThd->SuspendCount = SuspendThread(hThread)) != (DWORD)-1) { mdThd->SuspendCount--; ctx->ContextFlags = CONTEXT_FULL; if (!GetThreadContext(hThread, ctx)) memset(ctx, 0, sizeof(*ctx)); if (ReadProcessMemory(dc->hProcess, tbi.TebBaseAddress, &tib, sizeof(tib), NULL)) { #ifdef __i386__ /* limiting the stack dumping to the size actually used */ if (ctx->Esp) mdThd->Stack.StartOfMemoryRange = (ctx->Esp - 4); else mdThd->Stack.StartOfMemoryRange = (ULONG_PTR)tib.StackLimit; #elif defined(__powerpc__) if (ctx->Iar) mdThd->Stack.StartOfMemoryRange = ctx->Iar - 4; else mdThd->Stack.StartOfMemoryRange = (ULONG_PTR)tib.StackLimit; #elif defined(__x86_64__) if (ctx->Rsp) mdThd->Stack.StartOfMemoryRange = (ctx->Rsp - 8); else mdThd->Stack.StartOfMemoryRange = (ULONG_PTR)tib.StackLimit; #else #error unsupported CPU #endif mdThd->Stack.Memory.DataSize = (ULONG_PTR)tib.StackBase - mdThd->Stack.StartOfMemoryRange; } ResumeThread(hThread); } } CloseHandle(hThread); return TRUE; }
/*++ * @name CsrCreateProcess * @implemented NT4 * * The CsrCreateProcess routine creates a CSR Process object for an NT Process. * * @param hProcess * Handle to an existing NT Process to which to associate this * CSR Process. * * @param hThread * Handle to an existing NT Thread to which to create its * corresponding CSR Thread for this CSR Process. * * @param ClientId * Pointer to the Client ID structure of the NT Process to associate * with this CSR Process. * * @param NtSession * @param Flags * @param DebugCid * * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise. * * @remarks None. * *--*/ NTSTATUS NTAPI CsrCreateProcess(IN HANDLE hProcess, IN HANDLE hThread, IN PCLIENT_ID ClientId, IN PCSR_NT_SESSION NtSession, IN ULONG Flags, IN PCLIENT_ID DebugCid) { PCSR_THREAD CurrentThread = CsrGetClientThread(); CLIENT_ID CurrentCid; PCSR_PROCESS CurrentProcess; PCSR_SERVER_DLL ServerDll; PVOID ProcessData; ULONG i; PCSR_PROCESS CsrProcess; NTSTATUS Status; PCSR_THREAD CsrThread; KERNEL_USER_TIMES KernelTimes; /* Get the current CID and lock Processes */ CurrentCid = CurrentThread->ClientId; CsrAcquireProcessLock(); /* Get the current CSR Thread */ CurrentThread = CsrLocateThreadByClientId(&CurrentProcess, &CurrentCid); if (!CurrentThread) { /* We've failed to locate the thread */ CsrReleaseProcessLock(); return STATUS_THREAD_IS_TERMINATING; } /* Allocate a new Process Object */ CsrProcess = CsrAllocateProcess(); if (!CsrProcess) { /* Couldn't allocate Process */ CsrReleaseProcessLock(); return STATUS_NO_MEMORY; } /* Inherit the Process Data */ CurrentProcess = CurrentThread->Process; ProcessData = &CsrProcess->ServerData[CSR_SERVER_DLL_MAX]; for (i = 0; i < CSR_SERVER_DLL_MAX; i++) { /* Get the current Server */ ServerDll = CsrLoadedServerDll[i]; /* Check if the DLL is Loaded and has Per Process Data */ if (ServerDll && ServerDll->SizeOfProcessData) { /* Set the pointer */ CsrProcess->ServerData[i] = ProcessData; /* Copy the Data */ RtlMoveMemory(ProcessData, CurrentProcess->ServerData[i], ServerDll->SizeOfProcessData); /* Update next data pointer */ ProcessData = (PVOID)((ULONG_PTR)ProcessData + ServerDll->SizeOfProcessData); } else { /* No data for this Server */ CsrProcess->ServerData[i] = NULL; } } /* Set the Exception Port for us */ Status = NtSetInformationProcess(hProcess, ProcessExceptionPort, &CsrApiPort, sizeof(CsrApiPort)); if (!NT_SUCCESS(Status)) { /* Failed */ CsrDeallocateProcess(CsrProcess); CsrReleaseProcessLock(); return STATUS_NO_MEMORY; } /* Check if CreateProcess got CREATE_NEW_PROCESS_GROUP */ if (Flags & CsrProcessCreateNewGroup) { /* * We create the process group leader of a new process group, therefore * its process group ID and sequence number are its own ones. */ CsrProcess->ProcessGroupId = HandleToUlong(ClientId->UniqueProcess); CsrProcess->ProcessGroupSequence = CsrProcess->SequenceNumber; } else { /* Inherit the process group ID and sequence number from the current process */ CsrProcess->ProcessGroupId = CurrentProcess->ProcessGroupId; CsrProcess->ProcessGroupSequence = CurrentProcess->ProcessGroupSequence; } /* Check if this is a console process */ if (Flags & CsrProcessIsConsoleApp) CsrProcess->Flags |= CsrProcessIsConsoleApp; /* Mask out non-debug flags */ Flags &= ~(CsrProcessIsConsoleApp | CsrProcessCreateNewGroup | CsrProcessPriorityFlags); /* Check if every process will be debugged */ if (!(Flags) && (CurrentProcess->DebugFlags & CsrDebugProcessChildren)) { /* Pass it on to the current process */ CsrProcess->DebugFlags = CsrDebugProcessChildren; CsrProcess->DebugCid = CurrentProcess->DebugCid; } /* Check if Debugging was used on this process */ if ((Flags & (CsrDebugOnlyThisProcess | CsrDebugProcessChildren)) && (DebugCid)) { /* Save the debug flag used */ CsrProcess->DebugFlags = Flags; /* Save the CID */ CsrProcess->DebugCid = *DebugCid; } /* Check if Debugging is enabled */ if (CsrProcess->DebugFlags) { /* Set the Debug Port for us */ Status = NtSetInformationProcess(hProcess, ProcessDebugPort, &CsrApiPort, sizeof(CsrApiPort)); ASSERT(NT_SUCCESS(Status)); if (!NT_SUCCESS(Status)) { /* Failed */ CsrDeallocateProcess(CsrProcess); CsrReleaseProcessLock(); return STATUS_NO_MEMORY; } } /* Get the Thread Create Time */ Status = NtQueryInformationThread(hThread, ThreadTimes, &KernelTimes, sizeof(KernelTimes), NULL); if (!NT_SUCCESS(Status)) { /* Failed */ CsrDeallocateProcess(CsrProcess); CsrReleaseProcessLock(); return STATUS_NO_MEMORY; } /* Allocate a CSR Thread Structure */ CsrThread = CsrAllocateThread(CsrProcess); if (!CsrThread) { /* Failed */ CsrDeallocateProcess(CsrProcess); CsrReleaseProcessLock(); return STATUS_NO_MEMORY; } /* Save the data we have */ CsrThread->CreateTime = KernelTimes.CreateTime; CsrThread->ClientId = *ClientId; CsrThread->ThreadHandle = hThread; ProtectHandle(hThread); CsrThread->Flags = 0; /* Insert the Thread into the Process */ Status = CsrInsertThread(CsrProcess, CsrThread); if (!NT_SUCCESS(Status)) { /* Bail out */ CsrDeallocateProcess(CsrProcess); CsrDeallocateThread(CsrThread); CsrReleaseProcessLock(); return Status; } /* Reference the session */ CsrReferenceNtSession(NtSession); CsrProcess->NtSession = NtSession; /* Setup Process Data */ CsrProcess->ClientId = *ClientId; CsrProcess->ProcessHandle = hProcess; CsrProcess->ShutdownLevel = 0x280; /* Set the Priority to Background */ CsrSetBackgroundPriority(CsrProcess); /* Insert the Process */ CsrInsertProcess(CurrentProcess, CsrProcess); /* Release lock and return */ CsrReleaseProcessLock(); return Status; }
VOID PhpThreadProviderUpdate( __in PPH_THREAD_PROVIDER ThreadProvider, __in PVOID ProcessInformation ) { PPH_THREAD_PROVIDER threadProvider = ThreadProvider; PSYSTEM_PROCESS_INFORMATION process; SYSTEM_PROCESS_INFORMATION localProcess; PSYSTEM_THREAD_INFORMATION threads; ULONG numberOfThreads; ULONG i; process = PhFindProcessInformation(ProcessInformation, threadProvider->ProcessId); if (!process) { // The process doesn't exist anymore. Pretend it does but // has no threads. process = &localProcess; process->NumberOfThreads = 0; } threads = process->Threads; numberOfThreads = process->NumberOfThreads; // System Idle Process has one thread per CPU. // They all have a TID of 0, but we can't have // multiple TIDs, so we'll assign unique TIDs. if (threadProvider->ProcessId == SYSTEM_IDLE_PROCESS_ID) { for (i = 0; i < numberOfThreads; i++) { threads[i].ClientId.UniqueThread = (HANDLE)i; } } // Look for dead threads. { PPH_LIST threadsToRemove = NULL; ULONG enumerationKey = 0; PPH_THREAD_ITEM *threadItem; while (PhEnumHashtable(threadProvider->ThreadHashtable, (PPVOID)&threadItem, &enumerationKey)) { BOOLEAN found = FALSE; // Check if the thread still exists. for (i = 0; i < numberOfThreads; i++) { PSYSTEM_THREAD_INFORMATION thread = &threads[i]; if ((*threadItem)->ThreadId == thread->ClientId.UniqueThread) { found = TRUE; break; } } if (!found) { // Raise the thread removed event. PhInvokeCallback(&threadProvider->ThreadRemovedEvent, *threadItem); if (!threadsToRemove) threadsToRemove = PhCreateList(2); PhAddItemList(threadsToRemove, *threadItem); } } if (threadsToRemove) { PhAcquireFastLockExclusive(&threadProvider->ThreadHashtableLock); for (i = 0; i < threadsToRemove->Count; i++) { PhpRemoveThreadItem( threadProvider, (PPH_THREAD_ITEM)threadsToRemove->Items[i] ); } PhReleaseFastLockExclusive(&threadProvider->ThreadHashtableLock); PhDereferenceObject(threadsToRemove); } } // Go through the queued thread query data. { PSLIST_ENTRY entry; PPH_THREAD_QUERY_DATA data; entry = RtlInterlockedFlushSList(&threadProvider->QueryListHead); while (entry) { data = CONTAINING_RECORD(entry, PH_THREAD_QUERY_DATA, ListEntry); entry = entry->Next; if (data->StartAddressResolveLevel == PhsrlFunction && data->StartAddressString) { PhSwapReference(&data->ThreadItem->StartAddressString, data->StartAddressString); data->ThreadItem->StartAddressResolveLevel = data->StartAddressResolveLevel; } PhSwapReference2(&data->ThreadItem->ServiceName, data->ServiceName); data->ThreadItem->JustResolved = TRUE; if (data->StartAddressString) PhDereferenceObject(data->StartAddressString); PhDereferenceObject(data->ThreadItem); PhFree(data); } } // Look for new threads and update existing ones. for (i = 0; i < numberOfThreads; i++) { PSYSTEM_THREAD_INFORMATION thread = &threads[i]; PPH_THREAD_ITEM threadItem; threadItem = PhReferenceThreadItem(threadProvider, thread->ClientId.UniqueThread); if (!threadItem) { ULONG64 cycles; PVOID startAddress = NULL; threadItem = PhCreateThreadItem(thread->ClientId.UniqueThread); threadItem->CreateTime = thread->CreateTime; threadItem->KernelTime = thread->KernelTime; threadItem->UserTime = thread->UserTime; PhUpdateDelta(&threadItem->ContextSwitchesDelta, thread->ContextSwitches); threadItem->Priority = thread->Priority; threadItem->BasePriority = thread->BasePriority; threadItem->State = (KTHREAD_STATE)thread->ThreadState; threadItem->WaitReason = thread->WaitReason; // Try to open a handle to the thread. if (!NT_SUCCESS(PhOpenThread( &threadItem->ThreadHandle, THREAD_QUERY_INFORMATION, threadItem->ThreadId ))) { PhOpenThread( &threadItem->ThreadHandle, ThreadQueryAccess, threadItem->ThreadId ); } // Get the cycle count. if (NT_SUCCESS(PhpGetThreadCycleTime( threadProvider, threadItem, &cycles ))) { PhUpdateDelta(&threadItem->CyclesDelta, cycles); } // Initialize the CPU time deltas. PhUpdateDelta(&threadItem->CpuKernelDelta, threadItem->KernelTime.QuadPart); PhUpdateDelta(&threadItem->CpuUserDelta, threadItem->UserTime.QuadPart); // Try to get the start address. if (threadItem->ThreadHandle) { NtQueryInformationThread( threadItem->ThreadHandle, ThreadQuerySetWin32StartAddress, &startAddress, sizeof(PVOID), NULL ); } if (!startAddress) startAddress = thread->StartAddress; threadItem->StartAddress = (ULONG64)startAddress; // Get the Win32 priority. threadItem->PriorityWin32 = GetThreadPriority(threadItem->ThreadHandle); if (PhTestEvent(&threadProvider->SymbolsLoadedEvent)) { threadItem->StartAddressString = PhpGetThreadBasicStartAddress( threadProvider, threadItem->StartAddress, &threadItem->StartAddressResolveLevel ); } if (!threadItem->StartAddressString) { threadItem->StartAddressResolveLevel = PhsrlAddress; threadItem->StartAddressString = PhCreateStringEx(NULL, PH_PTR_STR_LEN * 2); PhPrintPointer( threadItem->StartAddressString->Buffer, (PVOID)threadItem->StartAddress ); PhTrimToNullTerminatorString(threadItem->StartAddressString); } PhpQueueThreadQuery(threadProvider, threadItem); // Is it a GUI thread? if (threadItem->ThreadHandle && KphIsConnected()) { PVOID win32Thread; if (NT_SUCCESS(KphQueryInformationThread( threadItem->ThreadHandle, KphThreadWin32Thread, &win32Thread, sizeof(PVOID), NULL ))) { threadItem->IsGuiThread = win32Thread != NULL; } } // Add the thread item to the hashtable. PhAcquireFastLockExclusive(&threadProvider->ThreadHashtableLock); PhAddEntryHashtable(threadProvider->ThreadHashtable, &threadItem); PhReleaseFastLockExclusive(&threadProvider->ThreadHashtableLock); // Raise the thread added event. PhInvokeCallback(&threadProvider->ThreadAddedEvent, threadItem); } else { BOOLEAN modified = FALSE; if (threadItem->JustResolved) modified = TRUE; threadItem->KernelTime = thread->KernelTime; threadItem->UserTime = thread->UserTime; threadItem->Priority = thread->Priority; threadItem->BasePriority = thread->BasePriority; threadItem->State = (KTHREAD_STATE)thread->ThreadState; if (threadItem->WaitReason != thread->WaitReason) { threadItem->WaitReason = thread->WaitReason; modified = TRUE; } // If the resolve level is only at address, it probably // means symbols weren't loaded the last time we // tried to get the start address. Try again. if (threadItem->StartAddressResolveLevel == PhsrlAddress) { if (PhTestEvent(&threadProvider->SymbolsLoadedEvent)) { PPH_STRING newStartAddressString; newStartAddressString = PhpGetThreadBasicStartAddress( threadProvider, threadItem->StartAddress, &threadItem->StartAddressResolveLevel ); PhSwapReference2( &threadItem->StartAddressString, newStartAddressString ); modified = TRUE; } } // If we couldn't resolve the start address to a // module+offset, use the StartAddress instead // of the Win32StartAddress and try again. // Note that we check the resolve level again // because we may have changed it in the previous // block. if ( threadItem->JustResolved && threadItem->StartAddressResolveLevel == PhsrlAddress ) { if (threadItem->StartAddress != (ULONG64)thread->StartAddress) { threadItem->StartAddress = (ULONG64)thread->StartAddress; PhpQueueThreadQuery(threadProvider, threadItem); } } // Update the context switch count. { ULONG oldDelta; oldDelta = threadItem->ContextSwitchesDelta.Delta; PhUpdateDelta(&threadItem->ContextSwitchesDelta, thread->ContextSwitches); if (threadItem->ContextSwitchesDelta.Delta != oldDelta) { modified = TRUE; } } // Update the cycle count. { ULONG64 cycles; ULONG64 oldDelta; oldDelta = threadItem->CyclesDelta.Delta; if (NT_SUCCESS(PhpGetThreadCycleTime( threadProvider, threadItem, &cycles ))) { PhUpdateDelta(&threadItem->CyclesDelta, cycles); if (threadItem->CyclesDelta.Delta != oldDelta) { modified = TRUE; } } } // Update the CPU time deltas. PhUpdateDelta(&threadItem->CpuKernelDelta, threadItem->KernelTime.QuadPart); PhUpdateDelta(&threadItem->CpuUserDelta, threadItem->UserTime.QuadPart); // Update the CPU usage. // If the cycle time isn't available, we'll fall back to using the CPU time. if (PhEnableCycleCpuUsage && (threadProvider->ProcessId == SYSTEM_IDLE_PROCESS_ID || threadItem->ThreadHandle)) { threadItem->CpuUsage = (FLOAT)threadItem->CyclesDelta.Delta / PhCpuTotalCycleDelta; } else { threadItem->CpuUsage = (FLOAT)(threadItem->CpuKernelDelta.Delta + threadItem->CpuUserDelta.Delta) / (PhCpuKernelDelta.Delta + PhCpuUserDelta.Delta + PhCpuIdleDelta.Delta); } // Update the Win32 priority. { LONG oldPriorityWin32 = threadItem->PriorityWin32; threadItem->PriorityWin32 = GetThreadPriority(threadItem->ThreadHandle); if (threadItem->PriorityWin32 != oldPriorityWin32) { modified = TRUE; } } // Update the GUI thread status. if (threadItem->ThreadHandle && KphIsConnected()) { PVOID win32Thread; if (NT_SUCCESS(KphQueryInformationThread( threadItem->ThreadHandle, KphThreadWin32Thread, &win32Thread, sizeof(PVOID), NULL ))) { BOOLEAN oldIsGuiThread = threadItem->IsGuiThread; threadItem->IsGuiThread = win32Thread != NULL; if (threadItem->IsGuiThread != oldIsGuiThread) modified = TRUE; } } threadItem->JustResolved = FALSE; if (modified) { // Raise the thread modified event. PhInvokeCallback(&threadProvider->ThreadModifiedEvent, threadItem); } PhDereferenceObject(threadItem); } } PhInvokeCallback(&threadProvider->UpdatedEvent, NULL); threadProvider->RunId++; }
/* * @implemented */ NTSTATUS NTAPI DbgUiConvertStateChangeStructure(IN PDBGUI_WAIT_STATE_CHANGE WaitStateChange, OUT PVOID Win32DebugEvent) { NTSTATUS Status; OBJECT_ATTRIBUTES ObjectAttributes; THREAD_BASIC_INFORMATION ThreadBasicInfo; LPDEBUG_EVENT DebugEvent = Win32DebugEvent; HANDLE ThreadHandle; /* Write common data */ DebugEvent->dwProcessId = (DWORD)WaitStateChange-> AppClientId.UniqueProcess; DebugEvent->dwThreadId = (DWORD)WaitStateChange->AppClientId.UniqueThread; /* Check what kind of even this is */ switch (WaitStateChange->NewState) { /* New thread */ case DbgCreateThreadStateChange: /* Setup Win32 code */ DebugEvent->dwDebugEventCode = CREATE_THREAD_DEBUG_EVENT; /* Copy data over */ DebugEvent->u.CreateThread.hThread = WaitStateChange->StateInfo.CreateThread.HandleToThread; DebugEvent->u.CreateThread.lpStartAddress = WaitStateChange->StateInfo.CreateThread.NewThread.StartAddress; /* Query the TEB */ Status = NtQueryInformationThread(WaitStateChange->StateInfo. CreateThread.HandleToThread, ThreadBasicInformation, &ThreadBasicInfo, sizeof(ThreadBasicInfo), NULL); if (!NT_SUCCESS(Status)) { /* Failed to get PEB address */ DebugEvent->u.CreateThread.lpThreadLocalBase = NULL; } else { /* Write PEB Address */ DebugEvent->u.CreateThread.lpThreadLocalBase = ThreadBasicInfo.TebBaseAddress; } break; /* New process */ case DbgCreateProcessStateChange: /* Write Win32 debug code */ DebugEvent->dwDebugEventCode = CREATE_PROCESS_DEBUG_EVENT; /* Copy data over */ DebugEvent->u.CreateProcessInfo.hProcess = WaitStateChange->StateInfo.CreateProcessInfo.HandleToProcess; DebugEvent->u.CreateProcessInfo.hThread = WaitStateChange->StateInfo.CreateProcessInfo.HandleToThread; DebugEvent->u.CreateProcessInfo.hFile = WaitStateChange->StateInfo.CreateProcessInfo.NewProcess. FileHandle; DebugEvent->u.CreateProcessInfo.lpBaseOfImage = WaitStateChange->StateInfo.CreateProcessInfo.NewProcess. BaseOfImage; DebugEvent->u.CreateProcessInfo.dwDebugInfoFileOffset = WaitStateChange->StateInfo.CreateProcessInfo.NewProcess. DebugInfoFileOffset; DebugEvent->u.CreateProcessInfo.nDebugInfoSize = WaitStateChange->StateInfo.CreateProcessInfo.NewProcess. DebugInfoSize; DebugEvent->u.CreateProcessInfo.lpStartAddress = WaitStateChange->StateInfo.CreateProcessInfo.NewProcess. InitialThread.StartAddress; /* Query TEB address */ Status = NtQueryInformationThread(WaitStateChange->StateInfo. CreateProcessInfo.HandleToThread, ThreadBasicInformation, &ThreadBasicInfo, sizeof(ThreadBasicInfo), NULL); if (!NT_SUCCESS(Status)) { /* Failed to get PEB address */ DebugEvent->u.CreateProcessInfo.lpThreadLocalBase = NULL; } else { /* Write PEB Address */ DebugEvent->u.CreateProcessInfo.lpThreadLocalBase = ThreadBasicInfo.TebBaseAddress; } /* Clear image name */ DebugEvent->u.CreateProcessInfo.lpImageName = NULL; DebugEvent->u.CreateProcessInfo.fUnicode = TRUE; break; /* Thread exited */ case DbgExitThreadStateChange: /* Write the Win32 debug code and the exit status */ DebugEvent->dwDebugEventCode = EXIT_THREAD_DEBUG_EVENT; DebugEvent->u.ExitThread.dwExitCode = WaitStateChange->StateInfo.ExitThread.ExitStatus; break; /* Process exited */ case DbgExitProcessStateChange: /* Write the Win32 debug code and the exit status */ DebugEvent->dwDebugEventCode = EXIT_PROCESS_DEBUG_EVENT; DebugEvent->u.ExitProcess.dwExitCode = WaitStateChange->StateInfo.ExitProcess.ExitStatus; break; /* Any sort of exception */ case DbgExceptionStateChange: case DbgBreakpointStateChange: case DbgSingleStepStateChange: /* Check if this was a debug print */ if (WaitStateChange->StateInfo.Exception.ExceptionRecord. ExceptionCode == DBG_PRINTEXCEPTION_C) { /* Set the Win32 code */ DebugEvent->dwDebugEventCode = OUTPUT_DEBUG_STRING_EVENT; /* Copy debug string information */ DebugEvent->u.DebugString.lpDebugStringData = (PVOID)WaitStateChange-> StateInfo.Exception.ExceptionRecord. ExceptionInformation[1]; DebugEvent->u.DebugString.nDebugStringLength = WaitStateChange->StateInfo.Exception.ExceptionRecord. ExceptionInformation[0]; DebugEvent->u.DebugString.fUnicode = FALSE; } else if (WaitStateChange->StateInfo.Exception.ExceptionRecord. ExceptionCode == DBG_RIPEXCEPTION) { /* Set the Win32 code */ DebugEvent->dwDebugEventCode = RIP_EVENT; /* Set exception information */ DebugEvent->u.RipInfo.dwType = WaitStateChange->StateInfo.Exception.ExceptionRecord. ExceptionInformation[1]; DebugEvent->u.RipInfo.dwError = WaitStateChange->StateInfo.Exception.ExceptionRecord. ExceptionInformation[0]; } else { /* Otherwise, this is a debug event, copy info over */ DebugEvent->dwDebugEventCode = EXCEPTION_DEBUG_EVENT; DebugEvent->u.Exception.ExceptionRecord = WaitStateChange->StateInfo.Exception.ExceptionRecord; DebugEvent->u.Exception.dwFirstChance = WaitStateChange->StateInfo.Exception.FirstChance; } break; /* DLL Load */ case DbgLoadDllStateChange: /* Set the Win32 debug code */ DebugEvent->dwDebugEventCode = LOAD_DLL_DEBUG_EVENT; /* Copy the rest of the data */ DebugEvent->u.LoadDll.lpBaseOfDll = WaitStateChange->StateInfo.LoadDll.BaseOfDll; DebugEvent->u.LoadDll.hFile = WaitStateChange->StateInfo.LoadDll.FileHandle; DebugEvent->u.LoadDll.dwDebugInfoFileOffset = WaitStateChange->StateInfo.LoadDll.DebugInfoFileOffset; DebugEvent->u.LoadDll.nDebugInfoSize = WaitStateChange->StateInfo.LoadDll.DebugInfoSize; /* Open the thread */ InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL); Status = NtOpenThread(&ThreadHandle, THREAD_QUERY_INFORMATION, &ObjectAttributes, &WaitStateChange->AppClientId); if (NT_SUCCESS(Status)) { /* Query thread information */ Status = NtQueryInformationThread(ThreadHandle, ThreadBasicInformation, &ThreadBasicInfo, sizeof(ThreadBasicInfo), NULL); NtClose(ThreadHandle); } /* Check if we got thread information */ if (NT_SUCCESS(Status)) { /* Save the image name from the TIB */ DebugEvent->u.LoadDll.lpImageName = ((PTEB)ThreadBasicInfo.TebBaseAddress)-> NtTib.ArbitraryUserPointer; } else { /* Otherwise, no name */ DebugEvent->u.LoadDll.lpImageName = NULL; } /* It's Unicode */ DebugEvent->u.LoadDll.fUnicode = TRUE; break; /* DLL Unload */ case DbgUnloadDllStateChange: /* Set Win32 code and DLL Base */ DebugEvent->dwDebugEventCode = UNLOAD_DLL_DEBUG_EVENT; DebugEvent->u.UnloadDll.lpBaseOfDll = WaitStateChange->StateInfo.UnloadDll.BaseAddress; break; /* Anything else, fail */ default: return STATUS_UNSUCCESSFUL; } /* Return success */ return STATUS_SUCCESS; }
VOID PhpUpdateThreadDetails( _In_ HWND hwndDlg, _In_ PPH_THREADS_CONTEXT Context, _In_ BOOLEAN Force ) { PPH_THREAD_ITEM *threads; ULONG numberOfThreads; PPH_THREAD_ITEM threadItem; PPH_STRING startModule = NULL; PPH_STRING started = NULL; WCHAR kernelTime[PH_TIMESPAN_STR_LEN_1] = L"N/A"; WCHAR userTime[PH_TIMESPAN_STR_LEN_1] = L"N/A"; PPH_STRING contextSwitches = NULL; PPH_STRING cycles = NULL; PPH_STRING state = NULL; WCHAR priority[PH_INT32_STR_LEN_1] = L"N/A"; WCHAR basePriority[PH_INT32_STR_LEN_1] = L"N/A"; PWSTR ioPriority = L"N/A"; PWSTR pagePriority = L"N/A"; WCHAR idealProcessor[PH_INT32_STR_LEN + 1 + PH_INT32_STR_LEN + 1] = L"N/A"; HANDLE threadHandle; SYSTEMTIME time; IO_PRIORITY_HINT ioPriorityInteger; ULONG pagePriorityInteger; PROCESSOR_NUMBER idealProcessorNumber; ULONG suspendCount; PhGetSelectedThreadItems(&Context->ListContext, &threads, &numberOfThreads); if (numberOfThreads == 1) threadItem = threads[0]; else threadItem = NULL; PhFree(threads); if (numberOfThreads != 1 && !Force) return; if (numberOfThreads == 1) { startModule = threadItem->StartAddressFileName; PhLargeIntegerToLocalSystemTime(&time, &threadItem->CreateTime); started = PhaFormatDateTime(&time); PhPrintTimeSpan(kernelTime, threadItem->KernelTime.QuadPart, PH_TIMESPAN_HMSM); PhPrintTimeSpan(userTime, threadItem->UserTime.QuadPart, PH_TIMESPAN_HMSM); contextSwitches = PhaFormatUInt64(threadItem->ContextSwitchesDelta.Value, TRUE); if (WINDOWS_HAS_CYCLE_TIME) cycles = PhaFormatUInt64(threadItem->CyclesDelta.Value, TRUE); if (threadItem->State != Waiting) { if ((ULONG)threadItem->State < MaximumThreadState) state = PhaCreateString(PhKThreadStateNames[(ULONG)threadItem->State]); else state = PhaCreateString(L"Unknown"); } else { if ((ULONG)threadItem->WaitReason < MaximumWaitReason) state = PhaConcatStrings2(L"Wait:", PhKWaitReasonNames[(ULONG)threadItem->WaitReason]); else state = PhaCreateString(L"Waiting"); } PhPrintInt32(priority, threadItem->Priority); PhPrintInt32(basePriority, threadItem->BasePriority); if (NT_SUCCESS(PhOpenThread(&threadHandle, ThreadQueryAccess, threadItem->ThreadId))) { if (NT_SUCCESS(PhGetThreadIoPriority(threadHandle, &ioPriorityInteger)) && ioPriorityInteger < MaxIoPriorityTypes) { ioPriority = PhIoPriorityHintNames[ioPriorityInteger]; } if (NT_SUCCESS(PhGetThreadPagePriority(threadHandle, &pagePriorityInteger)) && pagePriorityInteger <= MEMORY_PRIORITY_NORMAL) { pagePriority = PhPagePriorityNames[pagePriorityInteger]; } if (NT_SUCCESS(NtQueryInformationThread(threadHandle, ThreadIdealProcessorEx, &idealProcessorNumber, sizeof(PROCESSOR_NUMBER), NULL))) { PH_FORMAT format[3]; PhInitFormatU(&format[0], idealProcessorNumber.Group); PhInitFormatC(&format[1], ':'); PhInitFormatU(&format[2], idealProcessorNumber.Number); PhFormatToBuffer(format, 3, idealProcessor, sizeof(idealProcessor), NULL); } if (threadItem->WaitReason == Suspended && NT_SUCCESS(NtQueryInformationThread(threadHandle, ThreadSuspendCount, &suspendCount, sizeof(ULONG), NULL))) { PH_FORMAT format[4]; PhInitFormatSR(&format[0], state->sr); PhInitFormatS(&format[1], L" ("); PhInitFormatU(&format[2], suspendCount); PhInitFormatS(&format[3], L")"); state = PH_AUTO(PhFormat(format, 4, 30)); } NtClose(threadHandle); } } if (Force) { // These don't change... SetDlgItemText(hwndDlg, IDC_STARTMODULE, PhGetStringOrEmpty(startModule)); EnableWindow(GetDlgItem(hwndDlg, IDC_OPENSTARTMODULE), !!startModule); SetDlgItemText(hwndDlg, IDC_STARTED, PhGetStringOrDefault(started, L"N/A")); } SetDlgItemText(hwndDlg, IDC_KERNELTIME, kernelTime); SetDlgItemText(hwndDlg, IDC_USERTIME, userTime); SetDlgItemText(hwndDlg, IDC_CONTEXTSWITCHES, PhGetStringOrDefault(contextSwitches, L"N/A")); SetDlgItemText(hwndDlg, IDC_CYCLES, PhGetStringOrDefault(cycles, L"N/A")); SetDlgItemText(hwndDlg, IDC_STATE, PhGetStringOrDefault(state, L"N/A")); SetDlgItemText(hwndDlg, IDC_PRIORITY, priority); SetDlgItemText(hwndDlg, IDC_BASEPRIORITY, basePriority); SetDlgItemText(hwndDlg, IDC_IOPRIORITY, ioPriority); SetDlgItemText(hwndDlg, IDC_PAGEPRIORITY, pagePriority); SetDlgItemText(hwndDlg, IDC_IDEALPROCESSOR, idealProcessor); }
/*++ * @name CsrSbCreateSession * * The CsrSbCreateSession API is called by the Session Manager whenever a new * session is created. * * @param ApiMessage * Pointer to the Session Manager API Message. * * @return TRUE in case of success, FALSE otherwise. * * @remarks The CsrSbCreateSession routine will initialize a new CSR NT * Session and allocate a new CSR Process for the subsystem process. * *--*/ BOOLEAN NTAPI CsrSbCreateSession(IN PSB_API_MSG ApiMessage) { PSB_CREATE_SESSION_MSG CreateSession = &ApiMessage->CreateSession; HANDLE hProcess, hThread; PCSR_PROCESS CsrProcess; NTSTATUS Status; KERNEL_USER_TIMES KernelTimes; PCSR_THREAD CsrThread; //PVOID ProcessData; //ULONG i; /* Save the Process and Thread Handles */ hProcess = CreateSession->ProcessInfo.ProcessHandle; hThread = CreateSession->ProcessInfo.ThreadHandle; /* Lock the Processes */ CsrAcquireProcessLock(); /* Allocate a new process */ CsrProcess = CsrAllocateProcess(); if (!CsrProcess) { /* Fail */ ApiMessage->ReturnValue = STATUS_NO_MEMORY; CsrReleaseProcessLock(); return TRUE; } /* Set the exception port */ Status = NtSetInformationProcess(hProcess, ProcessExceptionPort, &CsrApiPort, sizeof(HANDLE)); /* Check for success */ if (!NT_SUCCESS(Status)) { /* Fail the request */ CsrDeallocateProcess(CsrProcess); CsrReleaseProcessLock(); /* Strange as it seems, NTSTATUSes are actually returned */ return (BOOLEAN)STATUS_NO_MEMORY; } /* Get the Create Time */ Status = NtQueryInformationThread(hThread, ThreadTimes, &KernelTimes, sizeof(KERNEL_USER_TIMES), NULL); /* Check for success */ if (!NT_SUCCESS(Status)) { /* Fail the request */ CsrDeallocateProcess(CsrProcess); CsrReleaseProcessLock(); /* Strange as it seems, NTSTATUSes are actually returned */ return (BOOLEAN)Status; } /* Allocate a new Thread */ CsrThread = CsrAllocateThread(CsrProcess); if (!CsrThread) { /* Fail the request */ CsrDeallocateProcess(CsrProcess); CsrReleaseProcessLock(); ApiMessage->ReturnValue = STATUS_NO_MEMORY; return TRUE; } /* Setup the Thread Object */ CsrThread->CreateTime = KernelTimes.CreateTime; CsrThread->ClientId = CreateSession->ProcessInfo.ClientId; CsrThread->ThreadHandle = hThread; ProtectHandle(hThread); CsrThread->Flags = 0; /* Insert it into the Process List */ CsrInsertThread(CsrProcess, CsrThread); /* Setup Process Data */ CsrProcess->ClientId = CreateSession->ProcessInfo.ClientId; CsrProcess->ProcessHandle = hProcess; CsrProcess->NtSession = CsrAllocateNtSession(CreateSession->SessionId); /* Set the Process Priority */ CsrSetBackgroundPriority(CsrProcess); #if 0 /* Get the first data location */ ProcessData = &CsrProcess->ServerData[CSR_SERVER_DLL_MAX]; /* Loop every DLL */ for (i = 0; i < CSR_SERVER_DLL_MAX; i++) { /* Check if the DLL is loaded and has Process Data */ if (CsrLoadedServerDll[i] && CsrLoadedServerDll[i]->SizeOfProcessData) { /* Write the pointer to the data */ CsrProcess->ServerData[i] = ProcessData; /* Move to the next data location */ ProcessData = (PVOID)((ULONG_PTR)ProcessData + CsrLoadedServerDll[i]->SizeOfProcessData); } else { /* Nothing for this Process */ CsrProcess->ServerData[i] = NULL; } } #else /* HACKZ: should go in BaseSrv part of CreateCallback done in Insert below */ RtlInitializeCriticalSection(&CsrProcess->HandleTableLock); #endif /* Insert the Process */ CsrInsertProcess(NULL, NULL, CsrProcess); /* Activate the Thread */ ApiMessage->ReturnValue = NtResumeThread(hThread, NULL); /* Release lock and return */ CsrReleaseProcessLock(); return TRUE; }
/****************************************************************** * fetch_thread_info * * fetches some information about thread of id 'tid' */ static BOOL fetch_thread_info(struct dump_context* dc, int thd_idx, const MINIDUMP_EXCEPTION_INFORMATION* except, MINIDUMP_THREAD* mdThd, CONTEXT* ctx) { DWORD tid = dc->threads[thd_idx].tid; HANDLE hThread; THREAD_BASIC_INFORMATION tbi; memset(ctx, 0, sizeof(*ctx)); mdThd->ThreadId = tid; mdThd->SuspendCount = 0; mdThd->Teb = 0; mdThd->Stack.StartOfMemoryRange = 0; mdThd->Stack.Memory.DataSize = 0; mdThd->Stack.Memory.Rva = 0; mdThd->ThreadContext.DataSize = 0; mdThd->ThreadContext.Rva = 0; mdThd->PriorityClass = dc->threads[thd_idx].prio_class; mdThd->Priority = dc->threads[thd_idx].curr_prio; if ((hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, tid)) == NULL) { FIXME("Couldn't open thread %u (%u)\n", tid, GetLastError()); return FALSE; } if (NtQueryInformationThread(hThread, ThreadBasicInformation, &tbi, sizeof(tbi), NULL) == STATUS_SUCCESS) { mdThd->Teb = (ULONG_PTR)tbi.TebBaseAddress; if (tbi.ExitStatus == STILL_ACTIVE) { if (tid != GetCurrentThreadId() && (mdThd->SuspendCount = SuspendThread(hThread)) != (DWORD)-1) { ctx->ContextFlags = CONTEXT_FULL; if (!GetThreadContext(hThread, ctx)) memset(ctx, 0, sizeof(*ctx)); fetch_thread_stack(dc, tbi.TebBaseAddress, ctx, &mdThd->Stack); ResumeThread(hThread); } else if (tid == GetCurrentThreadId() && except) { CONTEXT lctx, *pctx; mdThd->SuspendCount = 1; if (except->ClientPointers) { EXCEPTION_POINTERS ep; ReadProcessMemory(dc->hProcess, except->ExceptionPointers, &ep, sizeof(ep), NULL); ReadProcessMemory(dc->hProcess, ep.ContextRecord, &lctx, sizeof(lctx), NULL); pctx = &lctx; } else pctx = except->ExceptionPointers->ContextRecord; *ctx = *pctx; fetch_thread_stack(dc, tbi.TebBaseAddress, pctx, &mdThd->Stack); } else mdThd->SuspendCount = 0; } } CloseHandle(hThread); return TRUE; }
BOOL GetThreadIDHTASKALIAS( DWORD dwThreadID32, HTASKALIAS *ha ) { OBJECT_ATTRIBUTES obja; THREAD_BASIC_INFORMATION ThreadInfo; HANDLE hThread; NTSTATUS Status; FILETIME ftDummy; CLIENT_ID cid; InitializeObjectAttributes( &obja, NULL, 0, NULL, 0 ); cid.UniqueProcess = 0; // Don't know it, 0 means any process cid.UniqueThread = (HANDLE)dwThreadID32; Status = NtOpenThread( &hThread, THREAD_QUERY_INFORMATION, &obja, &cid ); if ( !NT_SUCCESS(Status) ) { #if DBG DbgPrint("WOW32: Could not get open thread handle\n"); #endif return( FALSE ); } Status = NtQueryInformationThread( hThread, ThreadBasicInformation, (PVOID)&ThreadInfo, sizeof(THREAD_BASIC_INFORMATION), NULL ); ha->dwProcessID32 = (DWORD)ThreadInfo.ClientId.UniqueProcess; ha->dwThreadID32 = dwThreadID32; GetThreadTimes( hThread, &ha->ftCreationTime, &ftDummy, &ftDummy, &ftDummy ); Status = NtClose( hThread ); if ( !NT_SUCCESS(Status) ) { #if DBG DbgPrint("WOW32: Could not close thread handle\n"); DbgBreakPoint(); #endif return( FALSE ); } return( TRUE ); }