Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1327 lines
42 KiB

/*++
Copyright(c) 1999-2002 Microsoft Corporation
--*/
#include "pch.cpp"
#include "platform.h"
#include "nt4p.h"
//----------------------------------------------------------------------------
//
// NtWin32LiveSystemProvider.
//
//----------------------------------------------------------------------------
class NtWin32LiveSystemProvider : public Win32LiveSystemProvider
{
public:
NtWin32LiveSystemProvider(ULONG BuildNumber);
~NtWin32LiveSystemProvider(void);
virtual HRESULT Initialize(void);
virtual void Release(void);
virtual HRESULT OpenThread(IN ULONG DesiredAccess,
IN BOOL InheritHandle,
IN ULONG ThreadId,
OUT PHANDLE Handle);
virtual HRESULT GetTeb(IN HANDLE Thread,
OUT PULONG64 Offset,
OUT PULONG Size);
virtual HRESULT GetThreadInfo(IN HANDLE Process,
IN HANDLE Thread,
OUT PULONG64 Teb,
OUT PULONG SizeOfTeb,
OUT PULONG64 StackBase,
OUT PULONG64 StackLimit,
OUT PULONG64 StoreBase,
OUT PULONG64 StoreLimit);
virtual HRESULT GetPeb(IN HANDLE Process,
OUT PULONG64 Offset,
OUT PULONG Size);
virtual HRESULT StartProcessEnum(IN HANDLE Process,
IN ULONG ProcessId);
virtual HRESULT EnumModules(OUT PULONG64 Base,
OUT PWSTR Path,
IN ULONG PathChars);
virtual HRESULT EnumFunctionTables(OUT PULONG64 MinAddress,
OUT PULONG64 MaxAddress,
OUT PULONG64 BaseAddress,
OUT PULONG EntryCount,
OUT PVOID RawTable,
IN ULONG RawTableSize,
OUT PVOID* RawEntryHandle);
virtual HRESULT EnumFunctionTableEntries(IN PVOID RawTable,
IN ULONG RawTableSize,
IN PVOID RawEntryHandle,
OUT PVOID RawEntries,
IN ULONG RawEntriesSize);
virtual HRESULT EnumFunctionTableEntryMemory(IN ULONG64 TableBase,
IN PVOID RawEntries,
IN ULONG Index,
OUT PULONG64 Start,
OUT PULONG Size);
virtual HRESULT EnumUnloadedModules(OUT PWSTR Path,
IN ULONG PathChars,
OUT PULONG64 BaseOfModule,
OUT PULONG SizeOfModule,
OUT PULONG CheckSum,
OUT PULONG TimeDateStamp);
virtual void FinishProcessEnum(void);
virtual HRESULT StartHandleEnum(IN HANDLE Process,
IN ULONG ProcessId,
OUT PULONG Count);
virtual HRESULT EnumHandles(OUT PULONG64 Handle,
OUT PULONG Attributes,
OUT PULONG GrantedAccess,
OUT PULONG HandleCount,
OUT PULONG PointerCount,
OUT PWSTR TypeName,
IN ULONG TypeNameChars,
OUT PWSTR ObjectName,
IN ULONG ObjectNameChars);
virtual void FinishHandleEnum(void);
virtual HRESULT EnumPebMemory(IN HANDLE Process,
IN ULONG64 PebOffset,
IN ULONG PebSize,
IN MiniDumpProviderCallbacks* Callback);
virtual HRESULT EnumTebMemory(IN HANDLE Process,
IN HANDLE Thread,
IN ULONG64 TebOffset,
IN ULONG TebSize,
IN MiniDumpProviderCallbacks* Callback);
void EnumUnicodeString(IN PUNICODE_STRING String,
IN MiniDumpProviderCallbacks* Callback)
{
if (String->Length > 0 && String->Buffer)
{
Callback->EnumMemory((LONG_PTR)String->Buffer, String->Length);
}
}
void TranslateNtPathName(IN OUT PWSTR Path);
protected:
HINSTANCE m_NtDll;
NT_OPEN_THREAD m_NtOpenThread;
NT_QUERY_SYSTEM_INFORMATION m_NtQuerySystemInformation;
NT_QUERY_INFORMATION_PROCESS m_NtQueryInformationProcess;
NT_QUERY_INFORMATION_THREAD m_NtQueryInformationThread;
NT_QUERY_OBJECT m_NtQueryObject;
RTL_FREE_HEAP m_RtlFreeHeap;
RTL_GET_FUNCTION_TABLE_LIST_HEAD m_RtlGetFunctionTableListHead;
RTL_GET_UNLOAD_EVENT_TRACE m_RtlGetUnloadEventTrace;
PLIST_ENTRY m_FuncTableHead;
PLIST_ENTRY m_FuncTable;
PRTL_UNLOAD_EVENT_TRACE m_Unloads;
PRTL_UNLOAD_EVENT_TRACE m_Unload;
ULONG m_UnloadArraySize;
ULONG m_NumUnloads;
ULONG m_Handle;
};
NtWin32LiveSystemProvider::NtWin32LiveSystemProvider(ULONG BuildNumber)
: Win32LiveSystemProvider(VER_PLATFORM_WIN32_NT, BuildNumber)
{
m_NtDll = NULL;
m_NtOpenThread = NULL;
m_NtQuerySystemInformation = NULL;
m_NtQueryInformationProcess = NULL;
m_NtQueryInformationThread = NULL;
m_NtQueryObject = NULL;
m_RtlFreeHeap = NULL;
m_RtlGetFunctionTableListHead = NULL;
m_RtlGetUnloadEventTrace = NULL;
m_Unloads = NULL;
}
NtWin32LiveSystemProvider::~NtWin32LiveSystemProvider(void)
{
if (m_NtDll) {
FreeLibrary(m_NtDll);
}
if (m_Unloads) {
HeapFree(GetProcessHeap(), 0, m_Unloads);
}
}
HRESULT
NtWin32LiveSystemProvider::Initialize(void)
{
HRESULT Status;
if ((Status = Win32LiveSystemProvider::Initialize()) != S_OK) {
return Status;
}
m_NtDll = LoadLibrary("ntdll.dll");
if (m_NtDll) {
m_NtOpenThread = (NT_OPEN_THREAD)
GetProcAddress(m_NtDll, "NtOpenThread");
m_NtQuerySystemInformation = (NT_QUERY_SYSTEM_INFORMATION)
GetProcAddress(m_NtDll, "NtQuerySystemInformation");
m_NtQueryInformationProcess = (NT_QUERY_INFORMATION_PROCESS)
GetProcAddress(m_NtDll, "NtQueryInformationProcess");
m_NtQueryInformationThread = (NT_QUERY_INFORMATION_THREAD)
GetProcAddress(m_NtDll, "NtQueryInformationThread");
m_NtQueryObject = (NT_QUERY_OBJECT)
GetProcAddress(m_NtDll, "NtQueryObject");
m_RtlFreeHeap = (RTL_FREE_HEAP)
GetProcAddress(m_NtDll, "RtlFreeHeap");
m_RtlGetFunctionTableListHead = (RTL_GET_FUNCTION_TABLE_LIST_HEAD)
GetProcAddress(m_NtDll, "RtlGetFunctionTableListHead");
m_RtlGetUnloadEventTrace = (RTL_GET_UNLOAD_EVENT_TRACE)
GetProcAddress(m_NtDll, "RtlGetUnloadEventTrace");
}
return S_OK;
}
void
NtWin32LiveSystemProvider::Release(void)
{
delete this;
}
HRESULT
NtWin32LiveSystemProvider::OpenThread(IN ULONG DesiredAccess,
IN BOOL InheritHandle,
IN ULONG ThreadId,
OUT PHANDLE Handle)
{
if (m_OpenThread) {
// OS supports regular Win32 OpenThread, so try it.
*Handle = m_OpenThread(DesiredAccess, InheritHandle, ThreadId);
if (*Handle) {
return S_OK;
}
}
if (!m_NtOpenThread) {
return E_NOTIMPL;
}
NTSTATUS Status;
NT4_OBJECT_ATTRIBUTES Obja;
NT4_CLIENT_ID ClientId;
ClientId.UniqueThread = (HANDLE)LongToHandle(ThreadId);
ClientId.UniqueProcess = (HANDLE)NULL;
Nt4InitializeObjectAttributes(&Obja,
NULL,
(InheritHandle ? NT4_OBJ_INHERIT : 0),
NULL,
NULL);
Status = m_NtOpenThread(Handle,
(ACCESS_MASK)DesiredAccess,
(POBJECT_ATTRIBUTES)&Obja,
(PCLIENT_ID)&ClientId);
if (!NT_SUCCESS(Status)) {
return HRESULT_FROM_NT(Status);
}
return S_OK;
}
HRESULT
NtWin32LiveSystemProvider::GetTeb(IN HANDLE Thread,
OUT PULONG64 Offset,
OUT PULONG Size)
{
if (!m_NtQueryInformationThread) {
return E_NOTIMPL;
}
THREAD_BASIC_INFORMATION ThreadInformation;
NTSTATUS NtStatus;
NtStatus = m_NtQueryInformationThread(Thread,
ThreadBasicInformation,
&ThreadInformation,
sizeof(ThreadInformation),
NULL);
if (NT_SUCCESS(NtStatus)) {
// The TEB is a little smaller than a page but
// save the entire page so that adjacent TEB
// pages get coalesced into a single region.
// As TEBs are normally adjacent this is a common case.
*Offset = (LONG_PTR)ThreadInformation.TebBaseAddress;
*Size = PAGE_SIZE;
return S_OK;
} else {
*Offset = 0;
*Size = 0;
return HRESULT_FROM_NT(NtStatus);
}
}
HRESULT
NtWin32LiveSystemProvider::GetThreadInfo(IN HANDLE Process,
IN HANDLE Thread,
OUT PULONG64 Teb,
OUT PULONG SizeOfTeb,
OUT PULONG64 StackBase,
OUT PULONG64 StackLimit,
OUT PULONG64 StoreBase,
OUT PULONG64 StoreLimit)
{
HRESULT Status;
if ((Status = GetTeb(Thread, Teb, SizeOfTeb)) != S_OK) {
return Status;
}
return TibGetThreadInfo(Process, *Teb,
StackBase, StackLimit,
StoreBase, StoreLimit);
}
HRESULT
NtWin32LiveSystemProvider::GetPeb(IN HANDLE Process,
OUT PULONG64 Offset,
OUT PULONG Size)
{
if (!m_NtQueryInformationProcess) {
return E_NOTIMPL;
}
PROCESS_BASIC_INFORMATION Information;
NTSTATUS NtStatus;
NtStatus = m_NtQueryInformationProcess(Process,
ProcessBasicInformation,
&Information,
sizeof(Information),
NULL);
if (NT_SUCCESS(NtStatus)) {
*Offset = (LONG_PTR)Information.PebBaseAddress;
*Size = sizeof(PEB);
return S_OK;
} else {
*Offset = 0;
*Size = 0;
return HRESULT_FROM_NT(NtStatus);
}
}
HRESULT
NtWin32LiveSystemProvider::StartProcessEnum(IN HANDLE Process,
IN ULONG ProcessId)
{
HRESULT Status;
SIZE_T Done;
if ((Status = Win32LiveSystemProvider::
StartProcessEnum(Process, ProcessId)) != S_OK) {
return Status;
}
//
// On systems that support dynamic function tables
// ntdll exports a function called RtlGetFunctionTableListHead
// to retrieve the head of a process's function table list.
// Currently this is always a global LIST_ENTRY in ntdll
// and so is at the same address in all processes since ntdll
// is mapped at the same address in every process. This
// means we can call it in our process and get a pointer
// that's valid in the process being dumped.
//
// We also use the presence of RGFTLH as a signal of
// whether dynamic function tables are supported or not.
//
m_FuncTableHead = NULL;
m_FuncTable = NULL;
if (m_RtlGetFunctionTableListHead) {
PLIST_ENTRY HeadAddr, HeadFirst;
HeadAddr = m_RtlGetFunctionTableListHead();
if (ReadProcessMemory(Process, HeadAddr,
&HeadFirst, sizeof(HeadFirst),
&Done) &&
Done == sizeof(HeadFirst)) {
m_FuncTableHead = HeadAddr;
m_FuncTable = HeadFirst;
}
}
//
// On systems that support unload traces
// ntdll exports a function called RtlGetUnloadEventTrace
// to retrieve the base of an unload trace array.
// Currently this is always a global in ntdll
// and so is at the same address in all processes since ntdll
// is mapped at the same address in every process. This
// means we can call it in our process and get a pointer
// that's valid in the process being dumped.
//
// We also use the presence of RGUET as a signal of
// whether unload traces are supported or not.
//
m_Unloads = NULL;
m_Unload = NULL;
m_NumUnloads = 0;
m_UnloadArraySize = 0;
if (m_RtlGetUnloadEventTrace) {
PRTL_UNLOAD_EVENT_TRACE TraceAddr;
ULONG Entries;
TraceAddr = m_RtlGetUnloadEventTrace();
// Currently there are always 16 entries.
Entries = 16;
m_UnloadArraySize = Entries;
m_Unloads = (PRTL_UNLOAD_EVENT_TRACE)
HeapAlloc(GetProcessHeap(), 0, sizeof(*TraceAddr) * Entries);
if (m_Unloads &&
ReadProcessMemory(Process, TraceAddr,
m_Unloads, sizeof(*TraceAddr) * Entries,
&Done) &&
Done == sizeof(*TraceAddr) * Entries) {
PRTL_UNLOAD_EVENT_TRACE Oldest;
//
// Find the true number of entries in use and sort.
// The sequence numbers of the trace records increase with
// time and we want to have the head of the list be the
// most recent record, so sort by decreasing sequence number.
// We know that the array is a circular buffer, so things
// are already in order except there may be a transition
// of sequence after the newest record. Find that transition
// and sorting becomes trivial.
//
Oldest = m_Unloads;
for (ULONG i = 0; i < Entries; i++) {
if (!m_Unloads[i].BaseAddress ||
!m_Unloads[i].SizeOfImage) {
// Unused entry, no need to continue.
Entries = i;
break;
}
if (m_Unloads[i].Sequence < Oldest->Sequence) {
Oldest = m_Unloads + i;
}
}
m_Unload = Oldest;
m_NumUnloads = Entries;
}
}
return S_OK;
}
HRESULT
NtWin32LiveSystemProvider::EnumModules(OUT PULONG64 Base,
OUT PWSTR Path,
IN ULONG PathChars)
{
HRESULT Status;
if ((Status = Win32LiveSystemProvider::
EnumModules(Base, Path, PathChars)) != S_OK)
{
return Status;
}
TranslateNtPathName(Path);
return S_OK;
}
HRESULT
NtWin32LiveSystemProvider::EnumFunctionTables(OUT PULONG64 MinAddress,
OUT PULONG64 MaxAddress,
OUT PULONG64 BaseAddress,
OUT PULONG EntryCount,
OUT PVOID RawTable,
IN ULONG RawTableSize,
OUT PVOID* RawEntryHandle)
{
#if defined(_AMD64_) || defined(_IA64_)
if (RawTableSize != sizeof(DYNAMIC_FUNCTION_TABLE)) {
return E_INVALIDARG;
}
Restart:
if (!m_FuncTable || m_FuncTable == m_FuncTableHead) {
return S_FALSE;
}
PDYNAMIC_FUNCTION_TABLE TableAddr =
#ifdef _AMD64_
CONTAINING_RECORD(m_FuncTable, DYNAMIC_FUNCTION_TABLE, ListEntry);
#else
CONTAINING_RECORD(m_FuncTable, DYNAMIC_FUNCTION_TABLE, Links);
#endif
PDYNAMIC_FUNCTION_TABLE Table = (PDYNAMIC_FUNCTION_TABLE)RawTable;
SIZE_T Done;
if (!ReadProcessMemory(m_ProcessHandle, TableAddr,
Table, sizeof(*Table), &Done)) {
return WIN32_LAST_STATUS();
}
if (Done != sizeof(*Table)) {
return HRESULT_FROM_WIN32(ERROR_READ_FAULT);
}
#ifdef _AMD64_
m_FuncTable = Table->ListEntry.Flink;
#else
m_FuncTable = Table->Links.Flink;
#endif
*MinAddress = (LONG_PTR)Table->MinimumAddress;
*MaxAddress = (LONG_PTR)Table->MaximumAddress;
*BaseAddress = (LONG_PTR)Table->BaseAddress;
*RawEntryHandle = NULL;
//
// AMD64 and IA64 support a type of function table
// where the data is retrieved via a callback rather
// than being is a plain data table. In order to
// get at the data from out-of-process the table
// must have an out-of-process access DLL registered.
//
if (Table->Type == RF_CALLBACK) {
WCHAR DllName[MAX_PATH];
HMODULE OopDll;
POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK OopCb;
if (!m_RtlFreeHeap) {
return E_NOTIMPL;
}
if (!Table->OutOfProcessCallbackDll) {
// No out-of-process access is possible.
goto Restart;
}
if (!ReadProcessMemory(m_ProcessHandle,
Table->OutOfProcessCallbackDll,
DllName, sizeof(DllName) - sizeof(WCHAR),
&Done)) {
goto Restart;
}
DllName[Done / sizeof(WCHAR)] = 0;
OopDll = LoadLibraryW(DllName);
if (!OopDll) {
goto Restart;
}
OopCb = (POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK)GetProcAddress
(OopDll, OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK_EXPORT_NAME);
if (OopCb == NULL) {
FreeLibrary(OopDll);
goto Restart;
}
if (!NT_SUCCESS(OopCb(m_ProcessHandle,
TableAddr,
EntryCount,
(PRUNTIME_FUNCTION*)RawEntryHandle))) {
FreeLibrary(OopDll);
goto Restart;
}
FreeLibrary(OopDll);
} else {
*EntryCount = Table->EntryCount;
}
return S_OK;
#else
return S_FALSE;
#endif
}
HRESULT
NtWin32LiveSystemProvider::EnumFunctionTableEntries(IN PVOID RawTable,
IN ULONG RawTableSize,
IN PVOID RawEntryHandle,
OUT PVOID RawEntries,
IN ULONG RawEntriesSize)
{
#if defined(_AMD64_) || defined(_IA64_)
if (RawTableSize != sizeof(DYNAMIC_FUNCTION_TABLE)) {
return E_INVALIDARG;
}
PDYNAMIC_FUNCTION_TABLE Table = (PDYNAMIC_FUNCTION_TABLE)RawTable;
if (Table->Type == RF_CALLBACK) {
memcpy(RawEntries, RawEntryHandle, RawEntriesSize);
m_RtlFreeHeap(RtlProcessHeap(), 0, RawEntryHandle);
} else {
SIZE_T Done;
if (!ReadProcessMemory(m_ProcessHandle,
Table->FunctionTable,
RawEntries,
RawEntriesSize,
&Done)) {
return WIN32_LAST_STATUS();
}
if (Done != RawEntriesSize) {
return HRESULT_FROM_WIN32(ERROR_READ_FAULT);
}
}
return S_OK;
#else
return E_NOTIMPL;
#endif
}
HRESULT
NtWin32LiveSystemProvider::EnumFunctionTableEntryMemory(IN ULONG64 TableBase,
IN PVOID RawEntries,
IN ULONG Index,
OUT PULONG64 Start,
OUT PULONG Size)
{
#if defined(_IA64_) || defined(_AMD64_)
UNWIND_INFO Info;
PRUNTIME_FUNCTION FuncEnt = (PRUNTIME_FUNCTION)RawEntries + Index;
SIZE_T Done;
#endif
#if defined(_IA64_)
*Start = TableBase + FuncEnt->UnwindInfoAddress;
if (!ReadProcessMemory(m_ProcessHandle, (PVOID)(ULONG_PTR)*Start,
&Info, sizeof(Info), &Done)) {
return WIN32_LAST_STATUS();
}
if (Done != sizeof(Info)) {
return HRESULT_FROM_WIN32(ERROR_READ_FAULT);
}
*Size = sizeof(Info) + Info.DataLength * sizeof(ULONG64);
#elif defined(_AMD64_)
*Start = TableBase + FuncEnt->UnwindData;
if (!ReadProcessMemory(m_ProcessHandle, (PVOID)(ULONG_PTR)*Start,
&Info, sizeof(Info), &Done)) {
return WIN32_LAST_STATUS();
}
if (Done != sizeof(Info)) {
return HRESULT_FROM_WIN32(ERROR_READ_FAULT);
}
*Size = sizeof(Info) + (Info.CountOfCodes - 1) * sizeof(UNWIND_CODE);
// An extra alignment code and pointer may be added on to handle
// the chained info case where the chain pointer is just
// beyond the end of the normal code array.
if ((Info.Flags & UNW_FLAG_CHAININFO) != 0) {
if ((Info.CountOfCodes & 1) != 0) {
(*Size) += sizeof(UNWIND_CODE);
}
(*Size) += sizeof(ULONG64);
}
#endif
#if defined(_IA64_) || defined(_AMD64_)
return S_OK;
#else
return E_NOTIMPL;
#endif
}
HRESULT
NtWin32LiveSystemProvider::EnumUnloadedModules(OUT PWSTR Path,
IN ULONG PathChars,
OUT PULONG64 BaseOfModule,
OUT PULONG SizeOfModule,
OUT PULONG CheckSum,
OUT PULONG TimeDateStamp)
{
if (m_NumUnloads == 0) {
return S_FALSE;
}
GenStrCopyNW(Path, m_Unload->ImageName, PathChars);
*BaseOfModule = (LONG_PTR)m_Unload->BaseAddress;
*SizeOfModule = (ULONG)m_Unload->SizeOfImage;
*CheckSum = m_Unload->CheckSum;
*TimeDateStamp = m_Unload->TimeDateStamp;
if (m_Unload == m_Unloads + (m_UnloadArraySize - 1)) {
m_Unload = m_Unloads;
} else {
m_Unload++;
}
m_NumUnloads--;
return S_OK;
}
void
NtWin32LiveSystemProvider::FinishProcessEnum(void)
{
if (m_Unloads) {
HeapFree(GetProcessHeap(), 0, m_Unloads);
m_Unloads = NULL;
}
Win32LiveSystemProvider::FinishProcessEnum();
}
HRESULT
NtWin32LiveSystemProvider::StartHandleEnum(IN HANDLE Process,
IN ULONG ProcessId,
OUT PULONG Count)
{
NTSTATUS NtStatus;
if (!m_NtQueryInformationProcess ||
!m_NtQueryObject) {
return E_NOTIMPL;
}
NtStatus = m_NtQueryInformationProcess(Process,
ProcessHandleCount,
Count,
sizeof(*Count),
NULL);
if (!NT_SUCCESS(NtStatus)) {
return HRESULT_FROM_NT(NtStatus);
}
m_ProcessHandle = Process ;
m_Handle = 4;
return S_OK;
}
HRESULT
NtWin32LiveSystemProvider::EnumHandles(OUT PULONG64 Handle,
OUT PULONG Attributes,
OUT PULONG GrantedAccess,
OUT PULONG HandleCount,
OUT PULONG PointerCount,
OUT PWSTR TypeName,
IN ULONG TypeNameChars,
OUT PWSTR ObjectName,
IN ULONG ObjectNameChars)
{
#ifdef _WIN32_WCE
return E_NOTIMPL;
#else
NTSTATUS NtStatus;
ULONG64 Buffer[1024 / sizeof(ULONG64)];
POBJECT_TYPE_INFORMATION TypeInfo =
(POBJECT_TYPE_INFORMATION)Buffer;
POBJECT_NAME_INFORMATION NameInfo =
(POBJECT_NAME_INFORMATION)Buffer;
OBJECT_BASIC_INFORMATION BasicInfo;
HANDLE Dup;
ULONG Len;
for (;;) {
if (m_Handle >= (1 << 24)) {
return S_FALSE;
}
if (::DuplicateHandle(m_ProcessHandle, UlongToHandle(m_Handle),
GetCurrentProcess(), &Dup,
0, FALSE, DUPLICATE_SAME_ACCESS)) {
// If we can't get the basic info and type there isn't much
// point in writing anything out so skip the handle.
if (NT_SUCCESS(m_NtQueryObject(Dup, ObjectBasicInformation,
&BasicInfo, sizeof(BasicInfo),
NULL)) &&
NT_SUCCESS(m_NtQueryObject(Dup, ObjectTypeInformation,
TypeInfo, sizeof(Buffer), NULL))) {
break;
}
::CloseHandle(Dup);
}
m_Handle += 4;
}
Len = TypeInfo->TypeName.Length;
if (Len > (TypeNameChars - 1) * sizeof(*TypeName)) {
Len = (TypeNameChars - 1) * sizeof(*TypeName);
}
memcpy(TypeName, TypeInfo->TypeName.Buffer, Len);
TypeName[Len / sizeof(*TypeName)] = 0;
// Don't get the name of file objects as it
// can cause deadlocks. If we fail getting the
// name just leave it out and don't consider it fatal.
if (GenStrCompareW(TypeName, L"File") &&
NT_SUCCESS(m_NtQueryObject(Dup, ObjectNameInformation,
NameInfo, sizeof(Buffer), NULL)) &&
NameInfo->Name.Buffer != NULL) {
Len = NameInfo->Name.Length;
if (Len > (ObjectNameChars - 1) * sizeof(*ObjectName)) {
Len = (ObjectNameChars - 1) * sizeof(*ObjectName);
}
memcpy(ObjectName, NameInfo->Name.Buffer, Len);
ObjectName[Len / sizeof(*ObjectName)] = 0;
} else {
ObjectName[0] = 0;
}
*Handle = m_Handle;
*Attributes = BasicInfo.Attributes;
*GrantedAccess = BasicInfo.GrantedAccess;
*HandleCount = BasicInfo.HandleCount;
*PointerCount = BasicInfo.PointerCount;
::CloseHandle(Dup);
m_Handle += 4;
return S_OK;
#endif // #ifdef _WIN32_WCE
}
void
NtWin32LiveSystemProvider::FinishHandleEnum(void)
{
// Nothing to do.
}
HRESULT
NtWin32LiveSystemProvider::EnumPebMemory(IN HANDLE Process,
IN ULONG64 PebOffset,
IN ULONG PebSize,
IN MiniDumpProviderCallbacks*
Callback)
{
HRESULT Status;
PEB Peb;
if (PebSize > sizeof(Peb)) {
PebSize = sizeof(Peb);
}
if ((Status = ReadAllVirtual(Process, PebOffset, &Peb, PebSize)) != S_OK) {
return Status;
}
//
// Save the process parameters.
//
RTL_USER_PROCESS_PARAMETERS Params;
if (Peb.ProcessParameters &&
ReadAllVirtual(Process, (LONG_PTR)Peb.ProcessParameters,
&Params, sizeof(Params)) == S_OK) {
Callback->EnumMemory((LONG_PTR)Peb.ProcessParameters, sizeof(Params));
EnumUnicodeString(&Params.CurrentDirectory.DosPath, Callback);
EnumUnicodeString(&Params.DllPath, Callback);
EnumUnicodeString(&Params.ImagePathName, Callback);
EnumUnicodeString(&Params.CommandLine, Callback);
// There's no indicator of how big the environment is,
// so just save an arbitrary amount.
Callback->EnumMemory((LONG_PTR)Params.Environment, 8192);
EnumUnicodeString(&Params.WindowTitle, Callback);
EnumUnicodeString(&Params.DesktopInfo, Callback);
EnumUnicodeString(&Params.ShellInfo, Callback);
EnumUnicodeString(&Params.RuntimeData, Callback);
}
return S_OK;
}
HRESULT
NtWin32LiveSystemProvider::EnumTebMemory(IN HANDLE Process,
IN HANDLE Thread,
IN ULONG64 TebOffset,
IN ULONG TebSize,
IN MiniDumpProviderCallbacks*
Callback)
{
HRESULT Status;
TEB Teb;
if (TebSize > sizeof(Teb)) {
TebSize = sizeof(Teb);
}
if ((Status = ReadAllVirtual(Process, TebOffset, &Teb, TebSize)) != S_OK) {
return Status;
}
//
// Save any TLS expansion.
//
if (m_BuildNumber >= NT_BUILD_WIN2K &&
Teb.TlsExpansionSlots) {
Callback->EnumMemory((LONG_PTR)Teb.TlsExpansionSlots,
TLS_EXPANSION_SLOTS * sizeof(ULONG_PTR));
}
//
// Save FLS data.
//
if (m_BuildNumber > NT_BUILD_XP &&
Teb.FlsData) {
Callback->EnumMemory((LONG_PTR)Teb.FlsData,
(FLS_MAXIMUM_AVAILABLE + 2) * sizeof(ULONG_PTR));
}
return S_OK;
}
void
NtWin32LiveSystemProvider::TranslateNtPathName(IN OUT PWSTR Path)
{
if (Path[0] == L'\\' &&
Path[1] == L'?' &&
Path[2] == L'?' &&
Path[3] == L'\\')
{
ULONG Len = (GenStrLengthW(Path) + 1) * sizeof(*Path);
if (Path[4] == L'U' &&
Path[5] == L'N' &&
Path[6] == L'C' &&
Path[7] == L'\\')
{
// Compress \??\UNC\ to \\.
memmove(Path + 1, Path + 7,
Len - 7 * sizeof(*Path));
}
else
{
// Remove \??\.
memmove(Path, Path + 4,
Len - 4 * sizeof(*Path));
}
}
}
//----------------------------------------------------------------------------
//
// NtEnumModWin32LiveSystemProvider.
//
//----------------------------------------------------------------------------
class NtEnumModWin32LiveSystemProvider : public NtWin32LiveSystemProvider
{
public:
NtEnumModWin32LiveSystemProvider(ULONG BuildNumber);
~NtEnumModWin32LiveSystemProvider(void);
virtual void Release(void);
virtual HRESULT StartProcessEnum(IN HANDLE Process,
IN ULONG ProcessId);
virtual HRESULT EnumModules(OUT PULONG64 Base,
OUT PWSTR Path,
IN ULONG PathChars);
virtual void FinishProcessEnum(void);
protected:
HMODULE* m_ProcModules;
ULONG m_NumProcModules;
};
NtEnumModWin32LiveSystemProvider::
NtEnumModWin32LiveSystemProvider(ULONG BuildNumber)
: NtWin32LiveSystemProvider(BuildNumber)
{
m_ProcModules = NULL;
m_NumProcModules = 0;
}
NtEnumModWin32LiveSystemProvider::~NtEnumModWin32LiveSystemProvider(void)
{
if (m_ProcModules) {
HeapFree(GetProcessHeap(), 0, m_ProcModules);
}
}
void
NtEnumModWin32LiveSystemProvider::Release(void)
{
delete this;
}
HRESULT
NtEnumModWin32LiveSystemProvider::StartProcessEnum(IN HANDLE Process,
IN ULONG ProcessId)
{
HRESULT Status;
if (!m_EnumProcessModules ||
!m_GetModuleFileNameExW) {
return E_NOTIMPL;
}
if ((Status = NtWin32LiveSystemProvider::
StartProcessEnum(Process, ProcessId)) != S_OK) {
return Status;
}
ULONG ProcModSize = 16384;
m_ProcModules = (HMODULE*)HeapAlloc(GetProcessHeap(), 0, ProcModSize);
if (!m_ProcModules) {
NtWin32LiveSystemProvider::FinishProcessEnum();
return E_OUTOFMEMORY;
}
//
// Walk module list, getting module information. Use PSAPI instead of
// toolhelp since it it does not exhibit the deadlock issues with
// the loader lock. ( on old versions of os )
//
ULONG Needed;
if (!m_EnumProcessModules(Process,
m_ProcModules,
ProcModSize,
&Needed)) {
Status = WIN32_LAST_STATUS();
NtWin32LiveSystemProvider::FinishProcessEnum();
HeapFree(GetProcessHeap(), 0, m_ProcModules);
m_ProcModules = NULL;
return Status;
}
m_NumProcModules = Needed / sizeof(m_ProcModules[0]);
return S_OK;
}
HRESULT
NtEnumModWin32LiveSystemProvider::EnumModules(OUT PULONG64 Base,
OUT PWSTR Path,
IN ULONG PathChars)
{
HRESULT Status;
if (m_ModuleIndex >= m_NumProcModules) {
return S_FALSE;
}
*Base = (LONG_PTR)m_ProcModules[m_ModuleIndex];
if (!m_GetModuleFileNameExW(m_ProcessHandle,
m_ProcModules[m_ModuleIndex],
Path,
PathChars)) {
return WIN32_LAST_STATUS();
}
TranslateNtPathName(Path);
m_ModuleIndex++;
return S_OK;
}
void
NtEnumModWin32LiveSystemProvider::FinishProcessEnum(void)
{
HeapFree(GetProcessHeap(), 0, m_ProcModules);
m_ProcModules = NULL;
NtWin32LiveSystemProvider::FinishProcessEnum();
}
//----------------------------------------------------------------------------
//
// Nt4Win32LiveSystemProvider.
//
//----------------------------------------------------------------------------
class Nt4Win32LiveSystemProvider : public NtWin32LiveSystemProvider
{
public:
Nt4Win32LiveSystemProvider(ULONG BuildNumber);
~Nt4Win32LiveSystemProvider(void);
virtual void Release(void);
virtual HRESULT StartProcessEnum(IN HANDLE Process,
IN ULONG ProcessId);
virtual HRESULT EnumThreads(OUT PULONG ThreadId);
virtual HRESULT EnumModules(OUT PULONG64 Base,
OUT PWSTR Path,
IN ULONG PathChars);
virtual void FinishProcessEnum(void);
protected:
PLIST_ENTRY m_LdrHead;
PLIST_ENTRY m_LdrEntry;
PNT4_SYSTEM_PROCESS_INFORMATION m_NtProcessInfo;
PNT4_SYSTEM_THREAD_INFORMATION m_NtThread;
ULONG m_NtThreads;
};
Nt4Win32LiveSystemProvider::
Nt4Win32LiveSystemProvider(ULONG BuildNumber)
: NtWin32LiveSystemProvider(BuildNumber)
{
m_NtProcessInfo = NULL;
}
Nt4Win32LiveSystemProvider::~Nt4Win32LiveSystemProvider(void)
{
if (m_NtProcessInfo) {
HeapFree(GetProcessHeap(), 0, m_NtProcessInfo);
}
}
void
Nt4Win32LiveSystemProvider::Release(void)
{
delete this;
}
HRESULT
Nt4Win32LiveSystemProvider::StartProcessEnum(IN HANDLE Process,
IN ULONG ProcessId)
{
NTSTATUS NtStatus;
if (!m_NtQuerySystemInformation ||
!m_NtQueryInformationProcess) {
return E_NOTIMPL;
}
//
// Get the head of the loaded module list.
// Some system processes have no PEB and it's
// possible for a process to not have a loader list.
//
NT4_PROCESS_BASIC_INFORMATION BasicInfo;
PNT4_PEB Peb;
PNT4_PEB_LDR_DATA Ldr;
SIZE_T Done;
NtStatus = m_NtQueryInformationProcess(Process,
Nt4ProcessBasicInformation,
&BasicInfo,
sizeof(BasicInfo),
NULL);
if (!NT_SUCCESS(NtStatus)) {
return HRESULT_FROM_NT(NtStatus);
}
m_LdrHead = NULL;
m_LdrEntry = NULL;
Peb = BasicInfo.PebBaseAddress;
if (Peb) {
if (!ReadProcessMemory(Process, &Peb->Ldr, &Ldr, sizeof(Ldr), &Done)) {
return WIN32_LAST_STATUS();
}
if (Done < sizeof(Ldr)) {
return HRESULT_FROM_WIN32(ERROR_READ_FAULT);
}
if (Ldr) {
m_LdrHead = &Ldr->InMemoryOrderModuleList;
if (!ReadProcessMemory(Process, &m_LdrHead->Flink,
&m_LdrEntry, sizeof(m_LdrEntry), &Done)) {
return WIN32_LAST_STATUS();
}
if (Done < sizeof(m_LdrEntry)) {
return HRESULT_FROM_WIN32(ERROR_READ_FAULT);
}
}
}
//
// Snap the set of threads in the process.
//
ULONG ProcInfoSize = 65536;
do {
if (m_NtProcessInfo) {
HeapFree(GetProcessHeap(), 0, m_NtProcessInfo);
}
m_NtProcessInfo = (PNT4_SYSTEM_PROCESS_INFORMATION)
HeapAlloc(GetProcessHeap(), 0, ProcInfoSize);
if (!m_NtProcessInfo) {
return E_OUTOFMEMORY;
}
NtStatus = m_NtQuerySystemInformation(Nt4SystemProcessInformation,
m_NtProcessInfo,
ProcInfoSize,
NULL);
if (NT_SUCCESS(NtStatus)) {
break;
} else if (NtStatus != STATUS_INFO_LENGTH_MISMATCH) {
HeapFree(GetProcessHeap(), 0, m_NtProcessInfo);
m_NtProcessInfo = NULL;
return HRESULT_FROM_NT(NtStatus);
}
ProcInfoSize += 16384;
} while (NtStatus == STATUS_INFO_LENGTH_MISMATCH);
//
// Find the correct process in the process list.
//
PNT4_SYSTEM_PROCESS_INFORMATION ProcInfo = m_NtProcessInfo;
while (ProcInfo->NextEntryOffset &&
ProcInfo->UniqueProcessId != (HANDLE)(ULONG_PTR)ProcessId) {
ProcInfo = (PNT4_SYSTEM_PROCESS_INFORMATION)
((ULONG_PTR)ProcInfo + ProcInfo->NextEntryOffset);
}
if (ProcInfo->UniqueProcessId != (HANDLE)(ULONG_PTR)ProcessId) {
// Could not find a matching process in the process list.
HeapFree(GetProcessHeap(), 0, m_NtProcessInfo);
m_NtProcessInfo = NULL;
return E_NOINTERFACE;
}
m_NtThread = (PNT4_SYSTEM_THREAD_INFORMATION)(ProcInfo + 1);
m_NtThreads = ProcInfo->NumberOfThreads;
// Don't support function tables for NT4.
m_FuncTableHead = NULL;
m_FuncTable = NULL;
// NT4 doesn't have an unloaded module list.
m_Unloads = NULL;
m_Unload = NULL;
m_NumUnloads = 0;
m_UnloadArraySize = 0;
m_ProcessHandle = Process;
m_ProcessId = ProcessId;
return S_OK;
}
HRESULT
Nt4Win32LiveSystemProvider::EnumThreads(OUT PULONG ThreadId)
{
if (m_NtThreads == 0) {
return S_FALSE;
}
*ThreadId = (ULONG)(ULONG_PTR)m_NtThread->ClientId.UniqueThread;
m_NtThread++;
m_NtThreads--;
return S_OK;
}
HRESULT
Nt4Win32LiveSystemProvider::EnumModules(OUT PULONG64 Base,
OUT PWSTR Path,
IN ULONG PathChars)
{
HRESULT Status;
if (!m_LdrEntry ||
m_LdrEntry == m_LdrHead) {
return S_FALSE;
}
PNT4_LDR_DATA_TABLE_ENTRY LdrEntry;
NT4_LDR_DATA_TABLE_ENTRY LdrEntryData;
SIZE_T Done;
LdrEntry = CONTAINING_RECORD(m_LdrEntry,
NT4_LDR_DATA_TABLE_ENTRY,
InMemoryOrderLinks);
if (!ReadProcessMemory(m_ProcessHandle, LdrEntry,
&LdrEntryData, sizeof(LdrEntryData), &Done)) {
return WIN32_LAST_STATUS();
}
if (Done < sizeof(LdrEntryData)) {
return HRESULT_FROM_WIN32(ERROR_READ_FAULT);
}
*Base = (LONG_PTR)LdrEntryData.DllBase;
if (PathChars) {
ULONG Read = LdrEntryData.FullDllName.Length;
PathChars = (PathChars - 1) * sizeof(Path[0]);
if (Read > PathChars) {
Read = PathChars;
}
if (Read) {
if (!ReadProcessMemory(m_ProcessHandle,
LdrEntryData.FullDllName.Buffer,
Path, Read, &Done)) {
return WIN32_LAST_STATUS();
}
if (Done < Read) {
return HRESULT_FROM_WIN32(ERROR_READ_FAULT);
}
}
Path[Read / sizeof(Path[0])] = 0;
}
TranslateNtPathName(Path);
m_LdrEntry = LdrEntryData.InMemoryOrderLinks.Flink;
return S_OK;
}
void
Nt4Win32LiveSystemProvider::FinishProcessEnum(void)
{
HeapFree(GetProcessHeap(), 0, m_NtProcessInfo);
m_NtProcessInfo = NULL;
}
//----------------------------------------------------------------------------
//
// NewNtWin32LiveSystemProvider.
//
//----------------------------------------------------------------------------
Win32LiveSystemProvider*
NewNtWin32LiveSystemProvider(ULONG BuildNumber)
{
if (BuildNumber < NT_BUILD_WIN2K) {
return new Nt4Win32LiveSystemProvider(BuildNumber);
} else if (BuildNumber < NT_BUILD_TH_MODULES) {
return new NtEnumModWin32LiveSystemProvider(BuildNumber);
} else {
return new NtWin32LiveSystemProvider(BuildNumber);
}
}