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

  1. /*++
  2. Copyright(c) 1999-2002 Microsoft Corporation
  3. --*/
  4. #include "pch.cpp"
  5. #include "platform.h"
  6. #include "nt4p.h"
  7. //----------------------------------------------------------------------------
  8. //
  9. // NtWin32LiveSystemProvider.
  10. //
  11. //----------------------------------------------------------------------------
  12. class NtWin32LiveSystemProvider : public Win32LiveSystemProvider
  13. {
  14. public:
  15. NtWin32LiveSystemProvider(ULONG BuildNumber);
  16. ~NtWin32LiveSystemProvider(void);
  17. virtual HRESULT Initialize(void);
  18. virtual void Release(void);
  19. virtual HRESULT OpenThread(IN ULONG DesiredAccess,
  20. IN BOOL InheritHandle,
  21. IN ULONG ThreadId,
  22. OUT PHANDLE Handle);
  23. virtual HRESULT GetTeb(IN HANDLE Thread,
  24. OUT PULONG64 Offset,
  25. OUT PULONG Size);
  26. virtual HRESULT GetThreadInfo(IN HANDLE Process,
  27. IN HANDLE Thread,
  28. OUT PULONG64 Teb,
  29. OUT PULONG SizeOfTeb,
  30. OUT PULONG64 StackBase,
  31. OUT PULONG64 StackLimit,
  32. OUT PULONG64 StoreBase,
  33. OUT PULONG64 StoreLimit);
  34. virtual HRESULT GetPeb(IN HANDLE Process,
  35. OUT PULONG64 Offset,
  36. OUT PULONG Size);
  37. virtual HRESULT StartProcessEnum(IN HANDLE Process,
  38. IN ULONG ProcessId);
  39. virtual HRESULT EnumModules(OUT PULONG64 Base,
  40. OUT PWSTR Path,
  41. IN ULONG PathChars);
  42. virtual HRESULT EnumFunctionTables(OUT PULONG64 MinAddress,
  43. OUT PULONG64 MaxAddress,
  44. OUT PULONG64 BaseAddress,
  45. OUT PULONG EntryCount,
  46. OUT PVOID RawTable,
  47. IN ULONG RawTableSize,
  48. OUT PVOID* RawEntryHandle);
  49. virtual HRESULT EnumFunctionTableEntries(IN PVOID RawTable,
  50. IN ULONG RawTableSize,
  51. IN PVOID RawEntryHandle,
  52. OUT PVOID RawEntries,
  53. IN ULONG RawEntriesSize);
  54. virtual HRESULT EnumFunctionTableEntryMemory(IN ULONG64 TableBase,
  55. IN PVOID RawEntries,
  56. IN ULONG Index,
  57. OUT PULONG64 Start,
  58. OUT PULONG Size);
  59. virtual HRESULT EnumUnloadedModules(OUT PWSTR Path,
  60. IN ULONG PathChars,
  61. OUT PULONG64 BaseOfModule,
  62. OUT PULONG SizeOfModule,
  63. OUT PULONG CheckSum,
  64. OUT PULONG TimeDateStamp);
  65. virtual void FinishProcessEnum(void);
  66. virtual HRESULT StartHandleEnum(IN HANDLE Process,
  67. IN ULONG ProcessId,
  68. OUT PULONG Count);
  69. virtual HRESULT EnumHandles(OUT PULONG64 Handle,
  70. OUT PULONG Attributes,
  71. OUT PULONG GrantedAccess,
  72. OUT PULONG HandleCount,
  73. OUT PULONG PointerCount,
  74. OUT PWSTR TypeName,
  75. IN ULONG TypeNameChars,
  76. OUT PWSTR ObjectName,
  77. IN ULONG ObjectNameChars);
  78. virtual void FinishHandleEnum(void);
  79. virtual HRESULT EnumPebMemory(IN HANDLE Process,
  80. IN ULONG64 PebOffset,
  81. IN ULONG PebSize,
  82. IN MiniDumpProviderCallbacks* Callback);
  83. virtual HRESULT EnumTebMemory(IN HANDLE Process,
  84. IN HANDLE Thread,
  85. IN ULONG64 TebOffset,
  86. IN ULONG TebSize,
  87. IN MiniDumpProviderCallbacks* Callback);
  88. void EnumUnicodeString(IN PUNICODE_STRING String,
  89. IN MiniDumpProviderCallbacks* Callback)
  90. {
  91. if (String->Length > 0 && String->Buffer)
  92. {
  93. Callback->EnumMemory((LONG_PTR)String->Buffer, String->Length);
  94. }
  95. }
  96. void TranslateNtPathName(IN OUT PWSTR Path);
  97. protected:
  98. HINSTANCE m_NtDll;
  99. NT_OPEN_THREAD m_NtOpenThread;
  100. NT_QUERY_SYSTEM_INFORMATION m_NtQuerySystemInformation;
  101. NT_QUERY_INFORMATION_PROCESS m_NtQueryInformationProcess;
  102. NT_QUERY_INFORMATION_THREAD m_NtQueryInformationThread;
  103. NT_QUERY_OBJECT m_NtQueryObject;
  104. RTL_FREE_HEAP m_RtlFreeHeap;
  105. RTL_GET_FUNCTION_TABLE_LIST_HEAD m_RtlGetFunctionTableListHead;
  106. RTL_GET_UNLOAD_EVENT_TRACE m_RtlGetUnloadEventTrace;
  107. PLIST_ENTRY m_FuncTableHead;
  108. PLIST_ENTRY m_FuncTable;
  109. PRTL_UNLOAD_EVENT_TRACE m_Unloads;
  110. PRTL_UNLOAD_EVENT_TRACE m_Unload;
  111. ULONG m_UnloadArraySize;
  112. ULONG m_NumUnloads;
  113. ULONG m_Handle;
  114. };
  115. NtWin32LiveSystemProvider::NtWin32LiveSystemProvider(ULONG BuildNumber)
  116. : Win32LiveSystemProvider(VER_PLATFORM_WIN32_NT, BuildNumber)
  117. {
  118. m_NtDll = NULL;
  119. m_NtOpenThread = NULL;
  120. m_NtQuerySystemInformation = NULL;
  121. m_NtQueryInformationProcess = NULL;
  122. m_NtQueryInformationThread = NULL;
  123. m_NtQueryObject = NULL;
  124. m_RtlFreeHeap = NULL;
  125. m_RtlGetFunctionTableListHead = NULL;
  126. m_RtlGetUnloadEventTrace = NULL;
  127. m_Unloads = NULL;
  128. }
  129. NtWin32LiveSystemProvider::~NtWin32LiveSystemProvider(void)
  130. {
  131. if (m_NtDll) {
  132. FreeLibrary(m_NtDll);
  133. }
  134. if (m_Unloads) {
  135. HeapFree(GetProcessHeap(), 0, m_Unloads);
  136. }
  137. }
  138. HRESULT
  139. NtWin32LiveSystemProvider::Initialize(void)
  140. {
  141. HRESULT Status;
  142. if ((Status = Win32LiveSystemProvider::Initialize()) != S_OK) {
  143. return Status;
  144. }
  145. m_NtDll = LoadLibrary("ntdll.dll");
  146. if (m_NtDll) {
  147. m_NtOpenThread = (NT_OPEN_THREAD)
  148. GetProcAddress(m_NtDll, "NtOpenThread");
  149. m_NtQuerySystemInformation = (NT_QUERY_SYSTEM_INFORMATION)
  150. GetProcAddress(m_NtDll, "NtQuerySystemInformation");
  151. m_NtQueryInformationProcess = (NT_QUERY_INFORMATION_PROCESS)
  152. GetProcAddress(m_NtDll, "NtQueryInformationProcess");
  153. m_NtQueryInformationThread = (NT_QUERY_INFORMATION_THREAD)
  154. GetProcAddress(m_NtDll, "NtQueryInformationThread");
  155. m_NtQueryObject = (NT_QUERY_OBJECT)
  156. GetProcAddress(m_NtDll, "NtQueryObject");
  157. m_RtlFreeHeap = (RTL_FREE_HEAP)
  158. GetProcAddress(m_NtDll, "RtlFreeHeap");
  159. m_RtlGetFunctionTableListHead = (RTL_GET_FUNCTION_TABLE_LIST_HEAD)
  160. GetProcAddress(m_NtDll, "RtlGetFunctionTableListHead");
  161. m_RtlGetUnloadEventTrace = (RTL_GET_UNLOAD_EVENT_TRACE)
  162. GetProcAddress(m_NtDll, "RtlGetUnloadEventTrace");
  163. }
  164. return S_OK;
  165. }
  166. void
  167. NtWin32LiveSystemProvider::Release(void)
  168. {
  169. delete this;
  170. }
  171. HRESULT
  172. NtWin32LiveSystemProvider::OpenThread(IN ULONG DesiredAccess,
  173. IN BOOL InheritHandle,
  174. IN ULONG ThreadId,
  175. OUT PHANDLE Handle)
  176. {
  177. if (m_OpenThread) {
  178. // OS supports regular Win32 OpenThread, so try it.
  179. *Handle = m_OpenThread(DesiredAccess, InheritHandle, ThreadId);
  180. if (*Handle) {
  181. return S_OK;
  182. }
  183. }
  184. if (!m_NtOpenThread) {
  185. return E_NOTIMPL;
  186. }
  187. NTSTATUS Status;
  188. NT4_OBJECT_ATTRIBUTES Obja;
  189. NT4_CLIENT_ID ClientId;
  190. ClientId.UniqueThread = (HANDLE)LongToHandle(ThreadId);
  191. ClientId.UniqueProcess = (HANDLE)NULL;
  192. Nt4InitializeObjectAttributes(&Obja,
  193. NULL,
  194. (InheritHandle ? NT4_OBJ_INHERIT : 0),
  195. NULL,
  196. NULL);
  197. Status = m_NtOpenThread(Handle,
  198. (ACCESS_MASK)DesiredAccess,
  199. (POBJECT_ATTRIBUTES)&Obja,
  200. (PCLIENT_ID)&ClientId);
  201. if (!NT_SUCCESS(Status)) {
  202. return HRESULT_FROM_NT(Status);
  203. }
  204. return S_OK;
  205. }
  206. HRESULT
  207. NtWin32LiveSystemProvider::GetTeb(IN HANDLE Thread,
  208. OUT PULONG64 Offset,
  209. OUT PULONG Size)
  210. {
  211. if (!m_NtQueryInformationThread) {
  212. return E_NOTIMPL;
  213. }
  214. THREAD_BASIC_INFORMATION ThreadInformation;
  215. NTSTATUS NtStatus;
  216. NtStatus = m_NtQueryInformationThread(Thread,
  217. ThreadBasicInformation,
  218. &ThreadInformation,
  219. sizeof(ThreadInformation),
  220. NULL);
  221. if (NT_SUCCESS(NtStatus)) {
  222. // The TEB is a little smaller than a page but
  223. // save the entire page so that adjacent TEB
  224. // pages get coalesced into a single region.
  225. // As TEBs are normally adjacent this is a common case.
  226. *Offset = (LONG_PTR)ThreadInformation.TebBaseAddress;
  227. *Size = PAGE_SIZE;
  228. return S_OK;
  229. } else {
  230. *Offset = 0;
  231. *Size = 0;
  232. return HRESULT_FROM_NT(NtStatus);
  233. }
  234. }
  235. HRESULT
  236. NtWin32LiveSystemProvider::GetThreadInfo(IN HANDLE Process,
  237. IN HANDLE Thread,
  238. OUT PULONG64 Teb,
  239. OUT PULONG SizeOfTeb,
  240. OUT PULONG64 StackBase,
  241. OUT PULONG64 StackLimit,
  242. OUT PULONG64 StoreBase,
  243. OUT PULONG64 StoreLimit)
  244. {
  245. HRESULT Status;
  246. if ((Status = GetTeb(Thread, Teb, SizeOfTeb)) != S_OK) {
  247. return Status;
  248. }
  249. return TibGetThreadInfo(Process, *Teb,
  250. StackBase, StackLimit,
  251. StoreBase, StoreLimit);
  252. }
  253. HRESULT
  254. NtWin32LiveSystemProvider::GetPeb(IN HANDLE Process,
  255. OUT PULONG64 Offset,
  256. OUT PULONG Size)
  257. {
  258. if (!m_NtQueryInformationProcess) {
  259. return E_NOTIMPL;
  260. }
  261. PROCESS_BASIC_INFORMATION Information;
  262. NTSTATUS NtStatus;
  263. NtStatus = m_NtQueryInformationProcess(Process,
  264. ProcessBasicInformation,
  265. &Information,
  266. sizeof(Information),
  267. NULL);
  268. if (NT_SUCCESS(NtStatus)) {
  269. *Offset = (LONG_PTR)Information.PebBaseAddress;
  270. *Size = sizeof(PEB);
  271. return S_OK;
  272. } else {
  273. *Offset = 0;
  274. *Size = 0;
  275. return HRESULT_FROM_NT(NtStatus);
  276. }
  277. }
  278. HRESULT
  279. NtWin32LiveSystemProvider::StartProcessEnum(IN HANDLE Process,
  280. IN ULONG ProcessId)
  281. {
  282. HRESULT Status;
  283. SIZE_T Done;
  284. if ((Status = Win32LiveSystemProvider::
  285. StartProcessEnum(Process, ProcessId)) != S_OK) {
  286. return Status;
  287. }
  288. //
  289. // On systems that support dynamic function tables
  290. // ntdll exports a function called RtlGetFunctionTableListHead
  291. // to retrieve the head of a process's function table list.
  292. // Currently this is always a global LIST_ENTRY in ntdll
  293. // and so is at the same address in all processes since ntdll
  294. // is mapped at the same address in every process. This
  295. // means we can call it in our process and get a pointer
  296. // that's valid in the process being dumped.
  297. //
  298. // We also use the presence of RGFTLH as a signal of
  299. // whether dynamic function tables are supported or not.
  300. //
  301. m_FuncTableHead = NULL;
  302. m_FuncTable = NULL;
  303. if (m_RtlGetFunctionTableListHead) {
  304. PLIST_ENTRY HeadAddr, HeadFirst;
  305. HeadAddr = m_RtlGetFunctionTableListHead();
  306. if (ReadProcessMemory(Process, HeadAddr,
  307. &HeadFirst, sizeof(HeadFirst),
  308. &Done) &&
  309. Done == sizeof(HeadFirst)) {
  310. m_FuncTableHead = HeadAddr;
  311. m_FuncTable = HeadFirst;
  312. }
  313. }
  314. //
  315. // On systems that support unload traces
  316. // ntdll exports a function called RtlGetUnloadEventTrace
  317. // to retrieve the base of an unload trace array.
  318. // Currently this is always a global in ntdll
  319. // and so is at the same address in all processes since ntdll
  320. // is mapped at the same address in every process. This
  321. // means we can call it in our process and get a pointer
  322. // that's valid in the process being dumped.
  323. //
  324. // We also use the presence of RGUET as a signal of
  325. // whether unload traces are supported or not.
  326. //
  327. m_Unloads = NULL;
  328. m_Unload = NULL;
  329. m_NumUnloads = 0;
  330. m_UnloadArraySize = 0;
  331. if (m_RtlGetUnloadEventTrace) {
  332. PRTL_UNLOAD_EVENT_TRACE TraceAddr;
  333. ULONG Entries;
  334. TraceAddr = m_RtlGetUnloadEventTrace();
  335. // Currently there are always 16 entries.
  336. Entries = 16;
  337. m_UnloadArraySize = Entries;
  338. m_Unloads = (PRTL_UNLOAD_EVENT_TRACE)
  339. HeapAlloc(GetProcessHeap(), 0, sizeof(*TraceAddr) * Entries);
  340. if (m_Unloads &&
  341. ReadProcessMemory(Process, TraceAddr,
  342. m_Unloads, sizeof(*TraceAddr) * Entries,
  343. &Done) &&
  344. Done == sizeof(*TraceAddr) * Entries) {
  345. PRTL_UNLOAD_EVENT_TRACE Oldest;
  346. //
  347. // Find the true number of entries in use and sort.
  348. // The sequence numbers of the trace records increase with
  349. // time and we want to have the head of the list be the
  350. // most recent record, so sort by decreasing sequence number.
  351. // We know that the array is a circular buffer, so things
  352. // are already in order except there may be a transition
  353. // of sequence after the newest record. Find that transition
  354. // and sorting becomes trivial.
  355. //
  356. Oldest = m_Unloads;
  357. for (ULONG i = 0; i < Entries; i++) {
  358. if (!m_Unloads[i].BaseAddress ||
  359. !m_Unloads[i].SizeOfImage) {
  360. // Unused entry, no need to continue.
  361. Entries = i;
  362. break;
  363. }
  364. if (m_Unloads[i].Sequence < Oldest->Sequence) {
  365. Oldest = m_Unloads + i;
  366. }
  367. }
  368. m_Unload = Oldest;
  369. m_NumUnloads = Entries;
  370. }
  371. }
  372. return S_OK;
  373. }
  374. HRESULT
  375. NtWin32LiveSystemProvider::EnumModules(OUT PULONG64 Base,
  376. OUT PWSTR Path,
  377. IN ULONG PathChars)
  378. {
  379. HRESULT Status;
  380. if ((Status = Win32LiveSystemProvider::
  381. EnumModules(Base, Path, PathChars)) != S_OK)
  382. {
  383. return Status;
  384. }
  385. TranslateNtPathName(Path);
  386. return S_OK;
  387. }
  388. HRESULT
  389. NtWin32LiveSystemProvider::EnumFunctionTables(OUT PULONG64 MinAddress,
  390. OUT PULONG64 MaxAddress,
  391. OUT PULONG64 BaseAddress,
  392. OUT PULONG EntryCount,
  393. OUT PVOID RawTable,
  394. IN ULONG RawTableSize,
  395. OUT PVOID* RawEntryHandle)
  396. {
  397. #if defined(_AMD64_) || defined(_IA64_)
  398. if (RawTableSize != sizeof(DYNAMIC_FUNCTION_TABLE)) {
  399. return E_INVALIDARG;
  400. }
  401. Restart:
  402. if (!m_FuncTable || m_FuncTable == m_FuncTableHead) {
  403. return S_FALSE;
  404. }
  405. PDYNAMIC_FUNCTION_TABLE TableAddr =
  406. #ifdef _AMD64_
  407. CONTAINING_RECORD(m_FuncTable, DYNAMIC_FUNCTION_TABLE, ListEntry);
  408. #else
  409. CONTAINING_RECORD(m_FuncTable, DYNAMIC_FUNCTION_TABLE, Links);
  410. #endif
  411. PDYNAMIC_FUNCTION_TABLE Table = (PDYNAMIC_FUNCTION_TABLE)RawTable;
  412. SIZE_T Done;
  413. if (!ReadProcessMemory(m_ProcessHandle, TableAddr,
  414. Table, sizeof(*Table), &Done)) {
  415. return WIN32_LAST_STATUS();
  416. }
  417. if (Done != sizeof(*Table)) {
  418. return HRESULT_FROM_WIN32(ERROR_READ_FAULT);
  419. }
  420. #ifdef _AMD64_
  421. m_FuncTable = Table->ListEntry.Flink;
  422. #else
  423. m_FuncTable = Table->Links.Flink;
  424. #endif
  425. *MinAddress = (LONG_PTR)Table->MinimumAddress;
  426. *MaxAddress = (LONG_PTR)Table->MaximumAddress;
  427. *BaseAddress = (LONG_PTR)Table->BaseAddress;
  428. *RawEntryHandle = NULL;
  429. //
  430. // AMD64 and IA64 support a type of function table
  431. // where the data is retrieved via a callback rather
  432. // than being is a plain data table. In order to
  433. // get at the data from out-of-process the table
  434. // must have an out-of-process access DLL registered.
  435. //
  436. if (Table->Type == RF_CALLBACK) {
  437. WCHAR DllName[MAX_PATH];
  438. HMODULE OopDll;
  439. POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK OopCb;
  440. if (!m_RtlFreeHeap) {
  441. return E_NOTIMPL;
  442. }
  443. if (!Table->OutOfProcessCallbackDll) {
  444. // No out-of-process access is possible.
  445. goto Restart;
  446. }
  447. if (!ReadProcessMemory(m_ProcessHandle,
  448. Table->OutOfProcessCallbackDll,
  449. DllName, sizeof(DllName) - sizeof(WCHAR),
  450. &Done)) {
  451. goto Restart;
  452. }
  453. DllName[Done / sizeof(WCHAR)] = 0;
  454. OopDll = LoadLibraryW(DllName);
  455. if (!OopDll) {
  456. goto Restart;
  457. }
  458. OopCb = (POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK)GetProcAddress
  459. (OopDll, OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK_EXPORT_NAME);
  460. if (OopCb == NULL) {
  461. FreeLibrary(OopDll);
  462. goto Restart;
  463. }
  464. if (!NT_SUCCESS(OopCb(m_ProcessHandle,
  465. TableAddr,
  466. EntryCount,
  467. (PRUNTIME_FUNCTION*)RawEntryHandle))) {
  468. FreeLibrary(OopDll);
  469. goto Restart;
  470. }
  471. FreeLibrary(OopDll);
  472. } else {
  473. *EntryCount = Table->EntryCount;
  474. }
  475. return S_OK;
  476. #else
  477. return S_FALSE;
  478. #endif
  479. }
  480. HRESULT
  481. NtWin32LiveSystemProvider::EnumFunctionTableEntries(IN PVOID RawTable,
  482. IN ULONG RawTableSize,
  483. IN PVOID RawEntryHandle,
  484. OUT PVOID RawEntries,
  485. IN ULONG RawEntriesSize)
  486. {
  487. #if defined(_AMD64_) || defined(_IA64_)
  488. if (RawTableSize != sizeof(DYNAMIC_FUNCTION_TABLE)) {
  489. return E_INVALIDARG;
  490. }
  491. PDYNAMIC_FUNCTION_TABLE Table = (PDYNAMIC_FUNCTION_TABLE)RawTable;
  492. if (Table->Type == RF_CALLBACK) {
  493. memcpy(RawEntries, RawEntryHandle, RawEntriesSize);
  494. m_RtlFreeHeap(RtlProcessHeap(), 0, RawEntryHandle);
  495. } else {
  496. SIZE_T Done;
  497. if (!ReadProcessMemory(m_ProcessHandle,
  498. Table->FunctionTable,
  499. RawEntries,
  500. RawEntriesSize,
  501. &Done)) {
  502. return WIN32_LAST_STATUS();
  503. }
  504. if (Done != RawEntriesSize) {
  505. return HRESULT_FROM_WIN32(ERROR_READ_FAULT);
  506. }
  507. }
  508. return S_OK;
  509. #else
  510. return E_NOTIMPL;
  511. #endif
  512. }
  513. HRESULT
  514. NtWin32LiveSystemProvider::EnumFunctionTableEntryMemory(IN ULONG64 TableBase,
  515. IN PVOID RawEntries,
  516. IN ULONG Index,
  517. OUT PULONG64 Start,
  518. OUT PULONG Size)
  519. {
  520. #if defined(_IA64_) || defined(_AMD64_)
  521. UNWIND_INFO Info;
  522. PRUNTIME_FUNCTION FuncEnt = (PRUNTIME_FUNCTION)RawEntries + Index;
  523. SIZE_T Done;
  524. #endif
  525. #if defined(_IA64_)
  526. *Start = TableBase + FuncEnt->UnwindInfoAddress;
  527. if (!ReadProcessMemory(m_ProcessHandle, (PVOID)(ULONG_PTR)*Start,
  528. &Info, sizeof(Info), &Done)) {
  529. return WIN32_LAST_STATUS();
  530. }
  531. if (Done != sizeof(Info)) {
  532. return HRESULT_FROM_WIN32(ERROR_READ_FAULT);
  533. }
  534. *Size = sizeof(Info) + Info.DataLength * sizeof(ULONG64);
  535. #elif defined(_AMD64_)
  536. *Start = TableBase + FuncEnt->UnwindData;
  537. if (!ReadProcessMemory(m_ProcessHandle, (PVOID)(ULONG_PTR)*Start,
  538. &Info, sizeof(Info), &Done)) {
  539. return WIN32_LAST_STATUS();
  540. }
  541. if (Done != sizeof(Info)) {
  542. return HRESULT_FROM_WIN32(ERROR_READ_FAULT);
  543. }
  544. *Size = sizeof(Info) + (Info.CountOfCodes - 1) * sizeof(UNWIND_CODE);
  545. // An extra alignment code and pointer may be added on to handle
  546. // the chained info case where the chain pointer is just
  547. // beyond the end of the normal code array.
  548. if ((Info.Flags & UNW_FLAG_CHAININFO) != 0) {
  549. if ((Info.CountOfCodes & 1) != 0) {
  550. (*Size) += sizeof(UNWIND_CODE);
  551. }
  552. (*Size) += sizeof(ULONG64);
  553. }
  554. #endif
  555. #if defined(_IA64_) || defined(_AMD64_)
  556. return S_OK;
  557. #else
  558. return E_NOTIMPL;
  559. #endif
  560. }
  561. HRESULT
  562. NtWin32LiveSystemProvider::EnumUnloadedModules(OUT PWSTR Path,
  563. IN ULONG PathChars,
  564. OUT PULONG64 BaseOfModule,
  565. OUT PULONG SizeOfModule,
  566. OUT PULONG CheckSum,
  567. OUT PULONG TimeDateStamp)
  568. {
  569. if (m_NumUnloads == 0) {
  570. return S_FALSE;
  571. }
  572. GenStrCopyNW(Path, m_Unload->ImageName, PathChars);
  573. *BaseOfModule = (LONG_PTR)m_Unload->BaseAddress;
  574. *SizeOfModule = (ULONG)m_Unload->SizeOfImage;
  575. *CheckSum = m_Unload->CheckSum;
  576. *TimeDateStamp = m_Unload->TimeDateStamp;
  577. if (m_Unload == m_Unloads + (m_UnloadArraySize - 1)) {
  578. m_Unload = m_Unloads;
  579. } else {
  580. m_Unload++;
  581. }
  582. m_NumUnloads--;
  583. return S_OK;
  584. }
  585. void
  586. NtWin32LiveSystemProvider::FinishProcessEnum(void)
  587. {
  588. if (m_Unloads) {
  589. HeapFree(GetProcessHeap(), 0, m_Unloads);
  590. m_Unloads = NULL;
  591. }
  592. Win32LiveSystemProvider::FinishProcessEnum();
  593. }
  594. HRESULT
  595. NtWin32LiveSystemProvider::StartHandleEnum(IN HANDLE Process,
  596. IN ULONG ProcessId,
  597. OUT PULONG Count)
  598. {
  599. NTSTATUS NtStatus;
  600. if (!m_NtQueryInformationProcess ||
  601. !m_NtQueryObject) {
  602. return E_NOTIMPL;
  603. }
  604. NtStatus = m_NtQueryInformationProcess(Process,
  605. ProcessHandleCount,
  606. Count,
  607. sizeof(*Count),
  608. NULL);
  609. if (!NT_SUCCESS(NtStatus)) {
  610. return HRESULT_FROM_NT(NtStatus);
  611. }
  612. m_ProcessHandle = Process ;
  613. m_Handle = 4;
  614. return S_OK;
  615. }
  616. HRESULT
  617. NtWin32LiveSystemProvider::EnumHandles(OUT PULONG64 Handle,
  618. OUT PULONG Attributes,
  619. OUT PULONG GrantedAccess,
  620. OUT PULONG HandleCount,
  621. OUT PULONG PointerCount,
  622. OUT PWSTR TypeName,
  623. IN ULONG TypeNameChars,
  624. OUT PWSTR ObjectName,
  625. IN ULONG ObjectNameChars)
  626. {
  627. #ifdef _WIN32_WCE
  628. return E_NOTIMPL;
  629. #else
  630. NTSTATUS NtStatus;
  631. ULONG64 Buffer[1024 / sizeof(ULONG64)];
  632. POBJECT_TYPE_INFORMATION TypeInfo =
  633. (POBJECT_TYPE_INFORMATION)Buffer;
  634. POBJECT_NAME_INFORMATION NameInfo =
  635. (POBJECT_NAME_INFORMATION)Buffer;
  636. OBJECT_BASIC_INFORMATION BasicInfo;
  637. HANDLE Dup;
  638. ULONG Len;
  639. for (;;) {
  640. if (m_Handle >= (1 << 24)) {
  641. return S_FALSE;
  642. }
  643. if (::DuplicateHandle(m_ProcessHandle, UlongToHandle(m_Handle),
  644. GetCurrentProcess(), &Dup,
  645. 0, FALSE, DUPLICATE_SAME_ACCESS)) {
  646. // If we can't get the basic info and type there isn't much
  647. // point in writing anything out so skip the handle.
  648. if (NT_SUCCESS(m_NtQueryObject(Dup, ObjectBasicInformation,
  649. &BasicInfo, sizeof(BasicInfo),
  650. NULL)) &&
  651. NT_SUCCESS(m_NtQueryObject(Dup, ObjectTypeInformation,
  652. TypeInfo, sizeof(Buffer), NULL))) {
  653. break;
  654. }
  655. ::CloseHandle(Dup);
  656. }
  657. m_Handle += 4;
  658. }
  659. Len = TypeInfo->TypeName.Length;
  660. if (Len > (TypeNameChars - 1) * sizeof(*TypeName)) {
  661. Len = (TypeNameChars - 1) * sizeof(*TypeName);
  662. }
  663. memcpy(TypeName, TypeInfo->TypeName.Buffer, Len);
  664. TypeName[Len / sizeof(*TypeName)] = 0;
  665. // Don't get the name of file objects as it
  666. // can cause deadlocks. If we fail getting the
  667. // name just leave it out and don't consider it fatal.
  668. if (GenStrCompareW(TypeName, L"File") &&
  669. NT_SUCCESS(m_NtQueryObject(Dup, ObjectNameInformation,
  670. NameInfo, sizeof(Buffer), NULL)) &&
  671. NameInfo->Name.Buffer != NULL) {
  672. Len = NameInfo->Name.Length;
  673. if (Len > (ObjectNameChars - 1) * sizeof(*ObjectName)) {
  674. Len = (ObjectNameChars - 1) * sizeof(*ObjectName);
  675. }
  676. memcpy(ObjectName, NameInfo->Name.Buffer, Len);
  677. ObjectName[Len / sizeof(*ObjectName)] = 0;
  678. } else {
  679. ObjectName[0] = 0;
  680. }
  681. *Handle = m_Handle;
  682. *Attributes = BasicInfo.Attributes;
  683. *GrantedAccess = BasicInfo.GrantedAccess;
  684. *HandleCount = BasicInfo.HandleCount;
  685. *PointerCount = BasicInfo.PointerCount;
  686. ::CloseHandle(Dup);
  687. m_Handle += 4;
  688. return S_OK;
  689. #endif // #ifdef _WIN32_WCE
  690. }
  691. void
  692. NtWin32LiveSystemProvider::FinishHandleEnum(void)
  693. {
  694. // Nothing to do.
  695. }
  696. HRESULT
  697. NtWin32LiveSystemProvider::EnumPebMemory(IN HANDLE Process,
  698. IN ULONG64 PebOffset,
  699. IN ULONG PebSize,
  700. IN MiniDumpProviderCallbacks*
  701. Callback)
  702. {
  703. HRESULT Status;
  704. PEB Peb;
  705. if (PebSize > sizeof(Peb)) {
  706. PebSize = sizeof(Peb);
  707. }
  708. if ((Status = ReadAllVirtual(Process, PebOffset, &Peb, PebSize)) != S_OK) {
  709. return Status;
  710. }
  711. //
  712. // Save the process parameters.
  713. //
  714. RTL_USER_PROCESS_PARAMETERS Params;
  715. if (Peb.ProcessParameters &&
  716. ReadAllVirtual(Process, (LONG_PTR)Peb.ProcessParameters,
  717. &Params, sizeof(Params)) == S_OK) {
  718. Callback->EnumMemory((LONG_PTR)Peb.ProcessParameters, sizeof(Params));
  719. EnumUnicodeString(&Params.CurrentDirectory.DosPath, Callback);
  720. EnumUnicodeString(&Params.DllPath, Callback);
  721. EnumUnicodeString(&Params.ImagePathName, Callback);
  722. EnumUnicodeString(&Params.CommandLine, Callback);
  723. // There's no indicator of how big the environment is,
  724. // so just save an arbitrary amount.
  725. Callback->EnumMemory((LONG_PTR)Params.Environment, 8192);
  726. EnumUnicodeString(&Params.WindowTitle, Callback);
  727. EnumUnicodeString(&Params.DesktopInfo, Callback);
  728. EnumUnicodeString(&Params.ShellInfo, Callback);
  729. EnumUnicodeString(&Params.RuntimeData, Callback);
  730. }
  731. return S_OK;
  732. }
  733. HRESULT
  734. NtWin32LiveSystemProvider::EnumTebMemory(IN HANDLE Process,
  735. IN HANDLE Thread,
  736. IN ULONG64 TebOffset,
  737. IN ULONG TebSize,
  738. IN MiniDumpProviderCallbacks*
  739. Callback)
  740. {
  741. HRESULT Status;
  742. TEB Teb;
  743. if (TebSize > sizeof(Teb)) {
  744. TebSize = sizeof(Teb);
  745. }
  746. if ((Status = ReadAllVirtual(Process, TebOffset, &Teb, TebSize)) != S_OK) {
  747. return Status;
  748. }
  749. //
  750. // Save any TLS expansion.
  751. //
  752. if (m_BuildNumber >= NT_BUILD_WIN2K &&
  753. Teb.TlsExpansionSlots) {
  754. Callback->EnumMemory((LONG_PTR)Teb.TlsExpansionSlots,
  755. TLS_EXPANSION_SLOTS * sizeof(ULONG_PTR));
  756. }
  757. //
  758. // Save FLS data.
  759. //
  760. if (m_BuildNumber > NT_BUILD_XP &&
  761. Teb.FlsData) {
  762. Callback->EnumMemory((LONG_PTR)Teb.FlsData,
  763. (FLS_MAXIMUM_AVAILABLE + 2) * sizeof(ULONG_PTR));
  764. }
  765. return S_OK;
  766. }
  767. void
  768. NtWin32LiveSystemProvider::TranslateNtPathName(IN OUT PWSTR Path)
  769. {
  770. if (Path[0] == L'\\' &&
  771. Path[1] == L'?' &&
  772. Path[2] == L'?' &&
  773. Path[3] == L'\\')
  774. {
  775. ULONG Len = (GenStrLengthW(Path) + 1) * sizeof(*Path);
  776. if (Path[4] == L'U' &&
  777. Path[5] == L'N' &&
  778. Path[6] == L'C' &&
  779. Path[7] == L'\\')
  780. {
  781. // Compress \??\UNC\ to \\.
  782. memmove(Path + 1, Path + 7,
  783. Len - 7 * sizeof(*Path));
  784. }
  785. else
  786. {
  787. // Remove \??\.
  788. memmove(Path, Path + 4,
  789. Len - 4 * sizeof(*Path));
  790. }
  791. }
  792. }
  793. //----------------------------------------------------------------------------
  794. //
  795. // NtEnumModWin32LiveSystemProvider.
  796. //
  797. //----------------------------------------------------------------------------
  798. class NtEnumModWin32LiveSystemProvider : public NtWin32LiveSystemProvider
  799. {
  800. public:
  801. NtEnumModWin32LiveSystemProvider(ULONG BuildNumber);
  802. ~NtEnumModWin32LiveSystemProvider(void);
  803. virtual void Release(void);
  804. virtual HRESULT StartProcessEnum(IN HANDLE Process,
  805. IN ULONG ProcessId);
  806. virtual HRESULT EnumModules(OUT PULONG64 Base,
  807. OUT PWSTR Path,
  808. IN ULONG PathChars);
  809. virtual void FinishProcessEnum(void);
  810. protected:
  811. HMODULE* m_ProcModules;
  812. ULONG m_NumProcModules;
  813. };
  814. NtEnumModWin32LiveSystemProvider::
  815. NtEnumModWin32LiveSystemProvider(ULONG BuildNumber)
  816. : NtWin32LiveSystemProvider(BuildNumber)
  817. {
  818. m_ProcModules = NULL;
  819. m_NumProcModules = 0;
  820. }
  821. NtEnumModWin32LiveSystemProvider::~NtEnumModWin32LiveSystemProvider(void)
  822. {
  823. if (m_ProcModules) {
  824. HeapFree(GetProcessHeap(), 0, m_ProcModules);
  825. }
  826. }
  827. void
  828. NtEnumModWin32LiveSystemProvider::Release(void)
  829. {
  830. delete this;
  831. }
  832. HRESULT
  833. NtEnumModWin32LiveSystemProvider::StartProcessEnum(IN HANDLE Process,
  834. IN ULONG ProcessId)
  835. {
  836. HRESULT Status;
  837. if (!m_EnumProcessModules ||
  838. !m_GetModuleFileNameExW) {
  839. return E_NOTIMPL;
  840. }
  841. if ((Status = NtWin32LiveSystemProvider::
  842. StartProcessEnum(Process, ProcessId)) != S_OK) {
  843. return Status;
  844. }
  845. ULONG ProcModSize = 16384;
  846. m_ProcModules = (HMODULE*)HeapAlloc(GetProcessHeap(), 0, ProcModSize);
  847. if (!m_ProcModules) {
  848. NtWin32LiveSystemProvider::FinishProcessEnum();
  849. return E_OUTOFMEMORY;
  850. }
  851. //
  852. // Walk module list, getting module information. Use PSAPI instead of
  853. // toolhelp since it it does not exhibit the deadlock issues with
  854. // the loader lock. ( on old versions of os )
  855. //
  856. ULONG Needed;
  857. if (!m_EnumProcessModules(Process,
  858. m_ProcModules,
  859. ProcModSize,
  860. &Needed)) {
  861. Status = WIN32_LAST_STATUS();
  862. NtWin32LiveSystemProvider::FinishProcessEnum();
  863. HeapFree(GetProcessHeap(), 0, m_ProcModules);
  864. m_ProcModules = NULL;
  865. return Status;
  866. }
  867. m_NumProcModules = Needed / sizeof(m_ProcModules[0]);
  868. return S_OK;
  869. }
  870. HRESULT
  871. NtEnumModWin32LiveSystemProvider::EnumModules(OUT PULONG64 Base,
  872. OUT PWSTR Path,
  873. IN ULONG PathChars)
  874. {
  875. HRESULT Status;
  876. if (m_ModuleIndex >= m_NumProcModules) {
  877. return S_FALSE;
  878. }
  879. *Base = (LONG_PTR)m_ProcModules[m_ModuleIndex];
  880. if (!m_GetModuleFileNameExW(m_ProcessHandle,
  881. m_ProcModules[m_ModuleIndex],
  882. Path,
  883. PathChars)) {
  884. return WIN32_LAST_STATUS();
  885. }
  886. TranslateNtPathName(Path);
  887. m_ModuleIndex++;
  888. return S_OK;
  889. }
  890. void
  891. NtEnumModWin32LiveSystemProvider::FinishProcessEnum(void)
  892. {
  893. HeapFree(GetProcessHeap(), 0, m_ProcModules);
  894. m_ProcModules = NULL;
  895. NtWin32LiveSystemProvider::FinishProcessEnum();
  896. }
  897. //----------------------------------------------------------------------------
  898. //
  899. // Nt4Win32LiveSystemProvider.
  900. //
  901. //----------------------------------------------------------------------------
  902. class Nt4Win32LiveSystemProvider : public NtWin32LiveSystemProvider
  903. {
  904. public:
  905. Nt4Win32LiveSystemProvider(ULONG BuildNumber);
  906. ~Nt4Win32LiveSystemProvider(void);
  907. virtual void Release(void);
  908. virtual HRESULT StartProcessEnum(IN HANDLE Process,
  909. IN ULONG ProcessId);
  910. virtual HRESULT EnumThreads(OUT PULONG ThreadId);
  911. virtual HRESULT EnumModules(OUT PULONG64 Base,
  912. OUT PWSTR Path,
  913. IN ULONG PathChars);
  914. virtual void FinishProcessEnum(void);
  915. protected:
  916. PLIST_ENTRY m_LdrHead;
  917. PLIST_ENTRY m_LdrEntry;
  918. PNT4_SYSTEM_PROCESS_INFORMATION m_NtProcessInfo;
  919. PNT4_SYSTEM_THREAD_INFORMATION m_NtThread;
  920. ULONG m_NtThreads;
  921. };
  922. Nt4Win32LiveSystemProvider::
  923. Nt4Win32LiveSystemProvider(ULONG BuildNumber)
  924. : NtWin32LiveSystemProvider(BuildNumber)
  925. {
  926. m_NtProcessInfo = NULL;
  927. }
  928. Nt4Win32LiveSystemProvider::~Nt4Win32LiveSystemProvider(void)
  929. {
  930. if (m_NtProcessInfo) {
  931. HeapFree(GetProcessHeap(), 0, m_NtProcessInfo);
  932. }
  933. }
  934. void
  935. Nt4Win32LiveSystemProvider::Release(void)
  936. {
  937. delete this;
  938. }
  939. HRESULT
  940. Nt4Win32LiveSystemProvider::StartProcessEnum(IN HANDLE Process,
  941. IN ULONG ProcessId)
  942. {
  943. NTSTATUS NtStatus;
  944. if (!m_NtQuerySystemInformation ||
  945. !m_NtQueryInformationProcess) {
  946. return E_NOTIMPL;
  947. }
  948. //
  949. // Get the head of the loaded module list.
  950. // Some system processes have no PEB and it's
  951. // possible for a process to not have a loader list.
  952. //
  953. NT4_PROCESS_BASIC_INFORMATION BasicInfo;
  954. PNT4_PEB Peb;
  955. PNT4_PEB_LDR_DATA Ldr;
  956. SIZE_T Done;
  957. NtStatus = m_NtQueryInformationProcess(Process,
  958. Nt4ProcessBasicInformation,
  959. &BasicInfo,
  960. sizeof(BasicInfo),
  961. NULL);
  962. if (!NT_SUCCESS(NtStatus)) {
  963. return HRESULT_FROM_NT(NtStatus);
  964. }
  965. m_LdrHead = NULL;
  966. m_LdrEntry = NULL;
  967. Peb = BasicInfo.PebBaseAddress;
  968. if (Peb) {
  969. if (!ReadProcessMemory(Process, &Peb->Ldr, &Ldr, sizeof(Ldr), &Done)) {
  970. return WIN32_LAST_STATUS();
  971. }
  972. if (Done < sizeof(Ldr)) {
  973. return HRESULT_FROM_WIN32(ERROR_READ_FAULT);
  974. }
  975. if (Ldr) {
  976. m_LdrHead = &Ldr->InMemoryOrderModuleList;
  977. if (!ReadProcessMemory(Process, &m_LdrHead->Flink,
  978. &m_LdrEntry, sizeof(m_LdrEntry), &Done)) {
  979. return WIN32_LAST_STATUS();
  980. }
  981. if (Done < sizeof(m_LdrEntry)) {
  982. return HRESULT_FROM_WIN32(ERROR_READ_FAULT);
  983. }
  984. }
  985. }
  986. //
  987. // Snap the set of threads in the process.
  988. //
  989. ULONG ProcInfoSize = 65536;
  990. do {
  991. if (m_NtProcessInfo) {
  992. HeapFree(GetProcessHeap(), 0, m_NtProcessInfo);
  993. }
  994. m_NtProcessInfo = (PNT4_SYSTEM_PROCESS_INFORMATION)
  995. HeapAlloc(GetProcessHeap(), 0, ProcInfoSize);
  996. if (!m_NtProcessInfo) {
  997. return E_OUTOFMEMORY;
  998. }
  999. NtStatus = m_NtQuerySystemInformation(Nt4SystemProcessInformation,
  1000. m_NtProcessInfo,
  1001. ProcInfoSize,
  1002. NULL);
  1003. if (NT_SUCCESS(NtStatus)) {
  1004. break;
  1005. } else if (NtStatus != STATUS_INFO_LENGTH_MISMATCH) {
  1006. HeapFree(GetProcessHeap(), 0, m_NtProcessInfo);
  1007. m_NtProcessInfo = NULL;
  1008. return HRESULT_FROM_NT(NtStatus);
  1009. }
  1010. ProcInfoSize += 16384;
  1011. } while (NtStatus == STATUS_INFO_LENGTH_MISMATCH);
  1012. //
  1013. // Find the correct process in the process list.
  1014. //
  1015. PNT4_SYSTEM_PROCESS_INFORMATION ProcInfo = m_NtProcessInfo;
  1016. while (ProcInfo->NextEntryOffset &&
  1017. ProcInfo->UniqueProcessId != (HANDLE)(ULONG_PTR)ProcessId) {
  1018. ProcInfo = (PNT4_SYSTEM_PROCESS_INFORMATION)
  1019. ((ULONG_PTR)ProcInfo + ProcInfo->NextEntryOffset);
  1020. }
  1021. if (ProcInfo->UniqueProcessId != (HANDLE)(ULONG_PTR)ProcessId) {
  1022. // Could not find a matching process in the process list.
  1023. HeapFree(GetProcessHeap(), 0, m_NtProcessInfo);
  1024. m_NtProcessInfo = NULL;
  1025. return E_NOINTERFACE;
  1026. }
  1027. m_NtThread = (PNT4_SYSTEM_THREAD_INFORMATION)(ProcInfo + 1);
  1028. m_NtThreads = ProcInfo->NumberOfThreads;
  1029. // Don't support function tables for NT4.
  1030. m_FuncTableHead = NULL;
  1031. m_FuncTable = NULL;
  1032. // NT4 doesn't have an unloaded module list.
  1033. m_Unloads = NULL;
  1034. m_Unload = NULL;
  1035. m_NumUnloads = 0;
  1036. m_UnloadArraySize = 0;
  1037. m_ProcessHandle = Process;
  1038. m_ProcessId = ProcessId;
  1039. return S_OK;
  1040. }
  1041. HRESULT
  1042. Nt4Win32LiveSystemProvider::EnumThreads(OUT PULONG ThreadId)
  1043. {
  1044. if (m_NtThreads == 0) {
  1045. return S_FALSE;
  1046. }
  1047. *ThreadId = (ULONG)(ULONG_PTR)m_NtThread->ClientId.UniqueThread;
  1048. m_NtThread++;
  1049. m_NtThreads--;
  1050. return S_OK;
  1051. }
  1052. HRESULT
  1053. Nt4Win32LiveSystemProvider::EnumModules(OUT PULONG64 Base,
  1054. OUT PWSTR Path,
  1055. IN ULONG PathChars)
  1056. {
  1057. HRESULT Status;
  1058. if (!m_LdrEntry ||
  1059. m_LdrEntry == m_LdrHead) {
  1060. return S_FALSE;
  1061. }
  1062. PNT4_LDR_DATA_TABLE_ENTRY LdrEntry;
  1063. NT4_LDR_DATA_TABLE_ENTRY LdrEntryData;
  1064. SIZE_T Done;
  1065. LdrEntry = CONTAINING_RECORD(m_LdrEntry,
  1066. NT4_LDR_DATA_TABLE_ENTRY,
  1067. InMemoryOrderLinks);
  1068. if (!ReadProcessMemory(m_ProcessHandle, LdrEntry,
  1069. &LdrEntryData, sizeof(LdrEntryData), &Done)) {
  1070. return WIN32_LAST_STATUS();
  1071. }
  1072. if (Done < sizeof(LdrEntryData)) {
  1073. return HRESULT_FROM_WIN32(ERROR_READ_FAULT);
  1074. }
  1075. *Base = (LONG_PTR)LdrEntryData.DllBase;
  1076. if (PathChars) {
  1077. ULONG Read = LdrEntryData.FullDllName.Length;
  1078. PathChars = (PathChars - 1) * sizeof(Path[0]);
  1079. if (Read > PathChars) {
  1080. Read = PathChars;
  1081. }
  1082. if (Read) {
  1083. if (!ReadProcessMemory(m_ProcessHandle,
  1084. LdrEntryData.FullDllName.Buffer,
  1085. Path, Read, &Done)) {
  1086. return WIN32_LAST_STATUS();
  1087. }
  1088. if (Done < Read) {
  1089. return HRESULT_FROM_WIN32(ERROR_READ_FAULT);
  1090. }
  1091. }
  1092. Path[Read / sizeof(Path[0])] = 0;
  1093. }
  1094. TranslateNtPathName(Path);
  1095. m_LdrEntry = LdrEntryData.InMemoryOrderLinks.Flink;
  1096. return S_OK;
  1097. }
  1098. void
  1099. Nt4Win32LiveSystemProvider::FinishProcessEnum(void)
  1100. {
  1101. HeapFree(GetProcessHeap(), 0, m_NtProcessInfo);
  1102. m_NtProcessInfo = NULL;
  1103. }
  1104. //----------------------------------------------------------------------------
  1105. //
  1106. // NewNtWin32LiveSystemProvider.
  1107. //
  1108. //----------------------------------------------------------------------------
  1109. Win32LiveSystemProvider*
  1110. NewNtWin32LiveSystemProvider(ULONG BuildNumber)
  1111. {
  1112. if (BuildNumber < NT_BUILD_WIN2K) {
  1113. return new Nt4Win32LiveSystemProvider(BuildNumber);
  1114. } else if (BuildNumber < NT_BUILD_TH_MODULES) {
  1115. return new NtEnumModWin32LiveSystemProvider(BuildNumber);
  1116. } else {
  1117. return new NtWin32LiveSystemProvider(BuildNumber);
  1118. }
  1119. }