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.

1038 lines
23 KiB

  1. /*++
  2. Copyright (c) 1999-2002 Microsoft Corporation
  3. Algorithm:
  4. Unfortunately, implementing OpenThread cannot be done in a simple
  5. manner. What follows is a very system dependent hack. If the structure
  6. of the TDB or the implementation of OpenProcess change very much, this
  7. function will break.
  8. To have any idea of what we are doing here, you should be familiar with
  9. Win9x internals. If you are not familiar with the Win9x source, consult
  10. the book "Windows 95 System Programming SECRETS" by Matt Pietrek. Things
  11. are not exactly the same for Win98 -- but pretty close.
  12. OpenThread is a very simple function. If we were compiled withing the
  13. Win9x source code base, the code would be simple:
  14. OpenThread:
  15. pObj = TidToTDB (dwThreadId);
  16. return AllocHandle (GetCurrentPdb(), pObj, Flags);
  17. Since we are not, the challenge is implementing the functions TidToTDB()
  18. and AllocHandle().
  19. Our approach is as follows:
  20. 1) We reverse-engineer TidToTDB since it is simple. TidToTDB is just
  21. the thread-id xor'd with the Win9x Obfuscator.
  22. 2) We search through the code of OpenProcess until we find the address
  23. of AllocHandle. We use this to allocate new handles in the
  24. process's handle database.
  25. 3) OpenThread is then implemented in terms of the above primitives.
  26. Author:
  27. Matthew D Hendel (math) 01-Sept-1999
  28. --*/
  29. #include "pch.cpp"
  30. //
  31. // Win9x support is x86-only.
  32. //
  33. #ifdef _X86_
  34. typedef struct _MATCH_BUFFER {
  35. ULONG Offset;
  36. BYTE Byte;
  37. } MATCH_BUFFER, *PMATCH_BUFFER;
  38. typedef struct _OS_INFORMATION {
  39. PMATCH_BUFFER MatchBuffer;
  40. ULONG AllocHandleOffset;
  41. } OS_INFORMATION, POS_INFORMATION;
  42. /*++
  43. Operating System:
  44. Win95
  45. Description:
  46. This is the disasm of the OpenProcess routine on Win95. We attempt to
  47. match this routine and pull out the value for AllocHandle from the code
  48. for this routine. In this case, AllocHande is called by the third call in
  49. this function.
  50. The instructions marked by '*' are those we use for matching.
  51. OpenProcess:
  52. * BFF9404C: FF 74 24 0C push dword ptr [esp+0Ch]
  53. * BFF94050: E8 2D 87 FE FF call BFF7C782
  54. BFF94055: 85 C0 test eax,eax
  55. BFF94057: 75 04 jne BFF9405D
  56. BFF94059: 33 C0 xor eax,eax
  57. BFF9405B: EB 56 jmp BFF940B3
  58. BFF9405D: 83 38 05 cmp dword ptr [eax],5
  59. BFF94060: 74 0E je BFF94070
  60. BFF94062: 6A 57 push 57h
  61. * BFF94064: E8 BC 68 FE FF call BFF7A925
  62. BFF94069: B9 FF FF FF FF mov ecx,0FFFFFFFFh
  63. BFF9406E: EB 33 jmp BFF940A3
  64. BFF94070: B9 00 00 00 00 mov ecx,0
  65. BFF94075: 8B 54 24 04 mov edx,dword ptr [esp+4]
  66. BFF94079: 83 7C 24 08 01 cmp dword ptr [esp+8],1
  67. BFF9407E: 83 D1 FF adc ecx,0FFFFFFFFh
  68. BFF94081: 81 E2 BF FF 1F 00 and edx,1FFFBFh
  69. BFF94087: 81 E1 00 00 00 80 and ecx,80000000h
  70. BFF9408D: 0B CA or ecx,edx
  71. BFF9408F: 8B 15 7C C2 FB BF mov edx,dword ptr ds:[BFFBC27Ch]
  72. BFF94095: 80 C9 40 or cl,40h
  73. BFF94098: 51 push ecx
  74. BFF94099: 50 push eax
  75. BFF9409A: FF 32 push dword ptr [edx]
  76. * BFF9409C: E8 6E 76 FE FF call BFF7B70F
  77. BFF940A1: 8B C8 mov ecx,eax
  78. BFF940A3: 8D 41 01 lea eax,[ecx+1]
  79. BFF940A6: 83 F8 01 cmp eax,1
  80. BFF940A9: B8 00 00 00 00 mov eax,0
  81. BFF940AE: 83 D0 FF adc eax,0FFFFFFFFh
  82. BFF940B1: 23 C1 and eax,ecx
  83. BFF940B3: C2 0C 00 ret 0Ch
  84. --*/
  85. MATCH_BUFFER Win95AllocHandleMatch [] = {
  86. //
  87. // ret 0x0C at offset 103
  88. //
  89. { 103, 0xC2 },
  90. { 104, 0x0C },
  91. { 105, 0x00 },
  92. //
  93. // push dword ptr [exp 0x0C] at offset 0
  94. //
  95. { 0, 0xFF },
  96. { 1, 0x74 },
  97. { 2, 0x24 },
  98. { 3, 0x0C },
  99. //
  100. // call at offset 4
  101. //
  102. { 4, 0xE8 },
  103. //
  104. // call at offset 24
  105. //
  106. { 24, 0xE8 },
  107. //
  108. // call at offset 80
  109. //
  110. { 80, 0xE8 },
  111. //
  112. // End of match list.
  113. //
  114. { -1, -1 }
  115. };
  116. /*++
  117. Operating system:
  118. Win98
  119. Description:
  120. See comments above regarding OpenProcess.
  121. OpenProcess:
  122. * BFF95C4D: FF 74 24 0C push dword ptr [esp+0Ch]
  123. * BFF95C51: E8 C9 8E FE FF call BFF7EB1F
  124. BFF95C56: 85 C0 test eax,eax
  125. BFF95C58: 75 04 jne BFF95C5E
  126. BFF95C5A: 33 C0 xor eax,eax
  127. BFF95C5C: EB 53 jmp BFF95CB1
  128. BFF95C5E: 80 38 06 cmp byte ptr [eax],6
  129. BFF95C61: 74 0E je BFF95C71
  130. BFF95C63: 6A 57 push 57h
  131. * BFF95C65: E8 27 6D FE FF call BFF7C991
  132. BFF95C6A: B9 FF FF FF FF mov ecx,0FFFFFFFFh
  133. BFF95C6F: EB 30 jmp BFF95CA1
  134. BFF95C71: B9 00 00 00 00 mov ecx,0
  135. BFF95C76: 8B 54 24 04 mov edx,dword ptr [esp+4]
  136. BFF95C7A: 83 7C 24 08 01 cmp dword ptr [esp+8],1
  137. BFF95C7F: 83 D1 FF adc ecx,0FFFFFFFFh
  138. BFF95C82: 81 E2 FF 0F 1F 00 and edx,1F0FFFh
  139. BFF95C88: 81 E1 00 00 00 80 and ecx,80000000h
  140. BFF95C8E: 0B CA or ecx,edx
  141. BFF95C90: 8B 15 DC 9C FC BF mov edx,dword ptr ds:[BFFC9CDCh]
  142. BFF95C96: 51 push ecx
  143. BFF95C97: 50 push eax
  144. BFF95C98: FF 32 push dword ptr [edx]
  145. * BFF95C9A: E8 5A 7E FE FF call BFF7DAF9
  146. BFF95C9F: 8B C8 mov ecx,eax
  147. BFF95CA1: 8D 41 01 lea eax,[ecx+1]
  148. BFF95CA4: 83 F8 01 cmp eax,1
  149. BFF95CA7: B8 00 00 00 00 mov eax,0
  150. BFF95CAC: 83 D0 FF adc eax,0FFFFFFFFh
  151. BFF95CAF: 23 C1 and eax,ecx
  152. * BFF95CB1: C2 0C 00 ret 0Ch
  153. --*/
  154. MATCH_BUFFER Win98AllocHandleMatch [] = {
  155. //
  156. // ret 0x0C at offset 100
  157. //
  158. { 100, 0xC2 },
  159. { 101, 0x0C },
  160. { 102, 0x00 },
  161. //
  162. // push dword ptr [exp 0x0C] at offset 0
  163. //
  164. { 0, 0xFF },
  165. { 1, 0x74 },
  166. { 2, 0x24 },
  167. { 3, 0x0C },
  168. //
  169. // call at offset 4
  170. //
  171. { 4, 0xE8 },
  172. //
  173. // call at offset 24
  174. //
  175. { 24, 0xE8 },
  176. //
  177. // call at offset 77
  178. //
  179. { 77, 0xE8 },
  180. //
  181. // End of match list.
  182. //
  183. { -1, -1 }
  184. };
  185. OS_INFORMATION SupportedSystems [] =
  186. {
  187. { Win95AllocHandleMatch, 81 },
  188. { Win98AllocHandleMatch, 78 }
  189. };
  190. typedef
  191. HANDLE
  192. (__stdcall * ALLOC_HANDLE_ROUTINE) (
  193. PVOID Pdb,
  194. PVOID Obj,
  195. DWORD Flags
  196. );
  197. //
  198. // Global variables
  199. //
  200. ALLOC_HANDLE_ROUTINE WinpAllocHandle = NULL;
  201. DWORD WinpObfuscator = 0;
  202. #pragma warning (disable:4035)
  203. //
  204. // OffsetTib is NOT dependent on the OS. The compiler uses this value.
  205. //
  206. #define OffsetTib 0x18
  207. _inline
  208. PVOID
  209. WinpGetCurrentTib(
  210. )
  211. {
  212. __asm mov eax, fs:[OffsetTib]
  213. }
  214. #pragma warning (default:4035)
  215. BOOL
  216. WinpGetAllocHandleFromStream(
  217. IN PBYTE Buffer,
  218. IN PVOID BaseOfBuffer,
  219. IN PMATCH_BUFFER MatchBuffer,
  220. IN ULONG Offset,
  221. IN ULONG * Val
  222. )
  223. /*++
  224. Routine Description:
  225. Find the address of the AllocHandle routine. This is done by searching
  226. through the code of the OpenProcess routine, looking for the third
  227. call instruction in that function. The third call calls AllocHandle().
  228. Arguments:
  229. Buffer - Buffer of instructions to search through.
  230. BaseOfBuffer - The base address of the buffer.
  231. MatchBuffer - The match buffer to compare against.
  232. Offset - The offset of call destination.
  233. Val - A buffer to return the value of AllocHandle.
  234. Return Values:
  235. TRUE - Success.
  236. FALSE - Failure.
  237. --*/
  238. {
  239. UINT i;
  240. for (i = 0; MatchBuffer [i].Offset != -1; i++) {
  241. if (Buffer [MatchBuffer[i].Offset] != MatchBuffer[i].Byte) {
  242. return FALSE;
  243. }
  244. }
  245. //
  246. // This assumes that the call instruction is a near, relative call (E8).
  247. // If this is not the case, the calculation below is incorrect.
  248. //
  249. // The calculation gives us the destination relative to the next
  250. // instruction after the call.
  251. //
  252. *Val = (ULONG) BaseOfBuffer + Offset + *(PLONG) &Buffer [Offset] + 4;
  253. return TRUE;
  254. }
  255. ULONG
  256. WinGetModuleSize(
  257. PVOID Base
  258. )
  259. /*++
  260. Routine Description:
  261. Get the SizeOfImage field given the base address of a module.
  262. Return Values:
  263. SizeOfImage field of the specified module on success.
  264. NULL on failure.
  265. --*/
  266. {
  267. ULONG Size;
  268. PIMAGE_NT_HEADERS NtHeaders;
  269. NtHeaders = GenImageNtHeader ( Base, NULL );
  270. if ( NtHeaders ) {
  271. Size = NtHeaders->OptionalHeader.SizeOfImage;
  272. } else {
  273. Size = 0;
  274. }
  275. return Size;
  276. }
  277. BOOL
  278. WinpInitAllocHandle (
  279. )
  280. /*++
  281. Routine Description:
  282. Initialize the global variable WxAllocHandle to the value of the Win9x
  283. internal routine, AllocHandle.
  284. Arguments:
  285. None
  286. Return Values:
  287. TRUE - If we were able to successfully obtain a pointer to AllocHandle.
  288. FALSE - Otherwise.
  289. Comments:
  290. The client of this routine should verify that this handle is correct by
  291. calling WxCheckOpenThread() before blindly assuming the pointer is
  292. correct.
  293. --*/
  294. {
  295. ULONG i;
  296. BOOL Succ;
  297. PVOID OpenProcessPtr;
  298. ULONG Kernel32Base;
  299. ULONG Kernel32Size;
  300. ULONG AllocHandle;
  301. BYTE Buffer [ 200 ];
  302. if ( WinpAllocHandle ) {
  303. return TRUE;
  304. }
  305. Kernel32Base = (ULONG) GetModuleHandle ( "kernel32.dll" );
  306. ASSERT ( Kernel32Base );
  307. if (!Kernel32Base)
  308. {
  309. return FALSE;
  310. }
  311. Kernel32Size = WinGetModuleSize ( (PVOID) Kernel32Base );
  312. ASSERT ( Kernel32Size != 0 );
  313. OpenProcessPtr = GetProcAddress (
  314. (HINSTANCE) Kernel32Base,
  315. "OpenProcess"
  316. );
  317. if (!OpenProcessPtr)
  318. {
  319. return FALSE;
  320. }
  321. //
  322. // Win9x thunks out functions when a debugger is present. To work around
  323. // this we undo the thunk when it looks like its been thunked.
  324. //
  325. if ( (ULONG) OpenProcessPtr < Kernel32Base ||
  326. (ULONG) OpenProcessPtr > Kernel32Base + Kernel32Size ) {
  327. OpenProcessPtr = (PVOID) *(PULONG)( (PBYTE)OpenProcessPtr + 1 );
  328. }
  329. if ( (ULONG) OpenProcessPtr < Kernel32Base ||
  330. (ULONG) OpenProcessPtr > Kernel32Base + Kernel32Size ) {
  331. return FALSE;
  332. }
  333. CopyMemory (Buffer, OpenProcessPtr, sizeof (Buffer));
  334. //
  335. // Check the buffer
  336. //
  337. for ( i = 0; i < ARRAY_COUNT (SupportedSystems); i++) {
  338. Succ = WinpGetAllocHandleFromStream (
  339. Buffer,
  340. OpenProcessPtr,
  341. SupportedSystems[i].MatchBuffer,
  342. SupportedSystems[i].AllocHandleOffset,
  343. &AllocHandle
  344. );
  345. if ( Succ ) {
  346. //
  347. // Verify WinpAllocHandle within range of Kernel32.
  348. //
  349. if (AllocHandle > Kernel32Base &&
  350. AllocHandle < Kernel32Base + Kernel32Size) {
  351. WinpAllocHandle = (ALLOC_HANDLE_ROUTINE) AllocHandle;
  352. break;
  353. }
  354. }
  355. }
  356. if ( !Succ ) {
  357. WinpAllocHandle = NULL;
  358. }
  359. return Succ;
  360. }
  361. //
  362. // This value is basically FIELD_OFFSET (TDB, Tib). It is dependent on the
  363. // specific version of the OS (95, 98).
  364. //
  365. #define WIN95_TDB_OFFSET (0x10)
  366. #define WIN98_TDB_OFFSET (0x08)
  367. DWORD
  368. WinpGetObfuscator(
  369. IN BOOL Win95
  370. )
  371. /*++
  372. Routine Description:
  373. Get the Obfuscator DWORD.
  374. Arguments:
  375. None.
  376. Return Values:
  377. The Obfuscator or 0 on failure.
  378. Comments:
  379. This routine depends on internal structures from the Win9x sources. If
  380. another major revision of windows changes many of these structures, this
  381. function may break.
  382. --*/
  383. {
  384. ULONG Tib;
  385. ULONG Type;
  386. ULONG Major;
  387. if (WinpObfuscator != 0) {
  388. return WinpObfuscator;
  389. }
  390. Tib = (DWORD)WinpGetCurrentTib ();
  391. if ( Win95 ) {
  392. WinpObfuscator = (GetCurrentThreadId () ^ (Tib - WIN95_TDB_OFFSET));
  393. } else {
  394. //
  395. // If a windows-based system that is not 95 or 98 comes along,
  396. // we should make sure the WINxx_TDB_OFFSET is correct.
  397. //
  398. WinpObfuscator = (GetCurrentThreadId () ^ (Tib - WIN98_TDB_OFFSET));
  399. }
  400. return WinpObfuscator;
  401. }
  402. LPVOID
  403. WinpTidToTDB(
  404. IN BOOL Win95,
  405. IN DWORD ThreadId
  406. )
  407. {
  408. return (PVOID) (ThreadId ^ WinpGetObfuscator (Win95));
  409. }
  410. LPVOID
  411. WinpGetCurrentPdb(
  412. IN BOOL Win95
  413. )
  414. {
  415. return (LPVOID) (GetCurrentProcessId () ^ WinpGetObfuscator (Win95));
  416. }
  417. HANDLE
  418. WinpOpenThreadInternal(
  419. BOOL Win95,
  420. DWORD dwAccess,
  421. BOOL bInheritHandle,
  422. DWORD ThreadId
  423. )
  424. {
  425. HANDLE hThread;
  426. PVOID ThreadObj;
  427. ASSERT (WinpAllocHandle);
  428. //
  429. // Convert the ThreadId to a Thread Object
  430. //
  431. ThreadObj = WinpTidToTDB (Win95, ThreadId);
  432. if (ThreadObj == NULL) {
  433. return NULL;
  434. }
  435. //
  436. // NB: we do not check that the handle really is a thread handle.
  437. // The type varies from version to version of the OS, so it is not
  438. // correct to check it.
  439. //
  440. __try {
  441. hThread = WinpAllocHandle (
  442. WinpGetCurrentPdb (Win95),
  443. ThreadObj,
  444. dwAccess
  445. );
  446. }
  447. __except (EXCEPTION_EXECUTE_HANDLER) {
  448. hThread = NULL;
  449. }
  450. if (hThread == (HANDLE) (-1)) {
  451. hThread = NULL;
  452. }
  453. return hThread;
  454. }
  455. #if _MSC_FULL_VER >= 13008827
  456. #pragma warning(push)
  457. #pragma warning(disable:4715) // Not all control paths return (due to infinite loop)
  458. #endif
  459. DWORD
  460. WINAPI
  461. WinpCheckThread(
  462. PVOID unused
  463. )
  464. {
  465. for (;;) {
  466. }
  467. return 0;
  468. }
  469. #if _MSC_FULL_VER >= 13008827
  470. #pragma warning(pop)
  471. #endif
  472. BOOL
  473. WinpCheckOpenThread(
  474. IN BOOL Win95
  475. )
  476. /*++
  477. Routine Description:
  478. Check that WxOpenThread actually works.
  479. Return Values:
  480. TRUE - If WxOpenThread works properly.
  481. FALSE - Otherwise.
  482. --*/
  483. {
  484. BOOL Succ;
  485. HANDLE hThread1;
  486. HANDLE hThread2;
  487. DWORD ThreadId;
  488. CONTEXT Context1;
  489. CONTEXT Context2;
  490. LONG SuspendCount;
  491. SuspendCount = 0;
  492. hThread1 = NULL;
  493. hThread2 = NULL;
  494. hThread1 = CreateThread (NULL,
  495. 0,
  496. WinpCheckThread,
  497. 0,
  498. 0,
  499. &ThreadId
  500. );
  501. if ( hThread1 == NULL ) {
  502. return FALSE;
  503. }
  504. hThread2 = WinpOpenThreadInternal (
  505. Win95,
  506. THREAD_ALL_ACCESS,
  507. FALSE,
  508. ThreadId
  509. );
  510. if ( hThread2 == NULL ) {
  511. Succ = FALSE;
  512. goto Exit;
  513. }
  514. Succ = TRUE;
  515. __try {
  516. //
  517. // First we check that we can suspend the thread. If that is
  518. // successful, then get the context using the read thread
  519. // handle and the newly opened thread handle and check that
  520. // they are the same.
  521. //
  522. SuspendCount = SuspendThread ( hThread2 );
  523. if ( SuspendCount == -1 ) {
  524. Succ = FALSE;
  525. __leave;
  526. }
  527. Context1.ContextFlags = CONTEXT_FULL;
  528. Succ = GetThreadContext ( hThread2, &Context1 );
  529. if ( !Succ ) {
  530. __leave;
  531. }
  532. Context2.ContextFlags = CONTEXT_FULL;
  533. Succ = GetThreadContext ( hThread1, &Context2 );
  534. if ( !Succ ) {
  535. __leave;
  536. }
  537. if ( Context1.Eip != Context2.Eip ) {
  538. Succ = FALSE;
  539. __leave;
  540. }
  541. }
  542. __except ( EXCEPTION_EXECUTE_HANDLER ) {
  543. Succ = FALSE;
  544. }
  545. Exit:
  546. if ( SuspendCount > 0 ) {
  547. ResumeThread ( hThread2 );
  548. }
  549. TerminateThread ( hThread1, 0xDEAD );
  550. if ( hThread1 ) {
  551. ::CloseHandle ( hThread1 );
  552. }
  553. if ( hThread2 ) {
  554. ::CloseHandle ( hThread2 );
  555. }
  556. return Succ;
  557. }
  558. BOOL
  559. WinInitialize(
  560. IN BOOL Win95
  561. )
  562. {
  563. if ( WinpAllocHandle == NULL ) {
  564. if (!WinpInitAllocHandle ()) {
  565. SetLastError (ERROR_NOT_SUPPORTED);
  566. return FALSE;
  567. }
  568. if (!WinpCheckOpenThread (Win95)) {
  569. SetLastError (ERROR_NOT_SUPPORTED);
  570. return FALSE;
  571. }
  572. }
  573. return TRUE;
  574. }
  575. VOID
  576. WinFree(
  577. )
  578. {
  579. WinpAllocHandle = NULL;
  580. WinpObfuscator = 0;
  581. }
  582. HANDLE
  583. WINAPI
  584. WinOpenThread(
  585. BOOL Win95,
  586. DWORD dwAccess,
  587. BOOL bInheritHandle,
  588. DWORD ThreadId
  589. )
  590. /*++
  591. Routine Description:
  592. Obtain a thread handle from a thread id on Win9x platform.x
  593. Arguments:
  594. dwAccess - Thread access requested.
  595. bInheritHandle - ALWAYS IGNORED.
  596. ThreadId - The identifier of the thread for which a handle is to
  597. be returned.
  598. Return Values:
  599. A handle to the open thread on success or NULL on failure.
  600. --*/
  601. {
  602. HANDLE Handle;
  603. //
  604. // It is necessary to call WinInitialize() before calling this function.
  605. // If this was not called, return failure.
  606. //
  607. if ( WinpAllocHandle == NULL ) {
  608. SetLastError ( ERROR_DLL_INIT_FAILED );
  609. return FALSE;
  610. }
  611. Handle = WinpOpenThreadInternal (
  612. Win95,
  613. dwAccess,
  614. bInheritHandle,
  615. ThreadId
  616. );
  617. return Handle;
  618. }
  619. //----------------------------------------------------------------------------
  620. //
  621. // Win9xWin32LiveSystemProvider.
  622. //
  623. //----------------------------------------------------------------------------
  624. class Win9xWin32LiveSystemProvider : public Win32LiveSystemProvider
  625. {
  626. public:
  627. Win9xWin32LiveSystemProvider(ULONG BuildNumber);
  628. ~Win9xWin32LiveSystemProvider(void);
  629. virtual void Release(void);
  630. virtual HRESULT OpenThread(IN ULONG DesiredAccess,
  631. IN BOOL InheritHandle,
  632. IN ULONG ThreadId,
  633. OUT PHANDLE Handle);
  634. virtual HRESULT GetTeb(IN HANDLE Thread,
  635. OUT PULONG64 Offset,
  636. OUT PULONG Size);
  637. virtual HRESULT GetThreadInfo(IN HANDLE Process,
  638. IN HANDLE Thread,
  639. OUT PULONG64 Teb,
  640. OUT PULONG SizeOfTeb,
  641. OUT PULONG64 StackBase,
  642. OUT PULONG64 StackLimit,
  643. OUT PULONG64 StoreBase,
  644. OUT PULONG64 StoreLimit);
  645. virtual HRESULT GetPeb(IN HANDLE Process,
  646. OUT PULONG64 Offset,
  647. OUT PULONG Size);
  648. protected:
  649. BOOL m_WinInit;
  650. };
  651. Win9xWin32LiveSystemProvider::Win9xWin32LiveSystemProvider(ULONG BuildNumber)
  652. : Win32LiveSystemProvider(VER_PLATFORM_WIN32_WINDOWS, BuildNumber)
  653. {
  654. m_WinInit = FALSE;
  655. }
  656. Win9xWin32LiveSystemProvider::~Win9xWin32LiveSystemProvider(void)
  657. {
  658. if (m_WinInit) {
  659. WinFree();
  660. }
  661. }
  662. void
  663. Win9xWin32LiveSystemProvider::Release(void)
  664. {
  665. delete this;
  666. }
  667. HRESULT
  668. Win9xWin32LiveSystemProvider::OpenThread(IN ULONG DesiredAccess,
  669. IN BOOL InheritHandle,
  670. IN ULONG ThreadId,
  671. OUT PHANDLE Handle)
  672. {
  673. BOOL Win95;
  674. if (m_OpenThread) {
  675. // OS supports regular Win32 OpenThread, so try it.
  676. *Handle = m_OpenThread(DesiredAccess, InheritHandle, ThreadId);
  677. if (*Handle) {
  678. return S_OK;
  679. }
  680. }
  681. Win95 = m_BuildNumber < 1998;
  682. if (!m_WinInit) {
  683. m_WinInit = WinInitialize(Win95);
  684. if (!m_WinInit) {
  685. return E_FAIL;
  686. }
  687. }
  688. *Handle = WinOpenThread(Win95, DesiredAccess, InheritHandle, ThreadId);
  689. return *Handle ? S_OK : E_FAIL;
  690. }
  691. HRESULT
  692. Win9xWin32LiveSystemProvider::GetTeb(IN HANDLE Thread,
  693. OUT PULONG64 Offset,
  694. OUT PULONG Size)
  695. {
  696. BOOL Succ;
  697. ULONG Addr;
  698. LDT_ENTRY Ldt;
  699. CONTEXT Context;
  700. Context.ContextFlags = CONTEXT_SEGMENTS;
  701. Succ = ::GetThreadContext (Thread, &Context);
  702. if ( !Succ ) {
  703. return WIN32_LAST_STATUS();
  704. }
  705. Succ = GetThreadSelectorEntry (Thread,
  706. Context.SegFs,
  707. &Ldt);
  708. if ( !Succ ) {
  709. return WIN32_LAST_STATUS();
  710. }
  711. Addr = (Ldt.HighWord.Bytes.BaseHi << 24) |
  712. (Ldt.HighWord.Bytes.BaseMid << 16) |
  713. (Ldt.BaseLow);
  714. *Offset = (LONG_PTR)Addr;
  715. *Size = sizeof(NT_TIB);
  716. return S_OK;
  717. }
  718. HRESULT
  719. Win9xWin32LiveSystemProvider::GetThreadInfo(IN HANDLE Process,
  720. IN HANDLE Thread,
  721. OUT PULONG64 Teb,
  722. OUT PULONG SizeOfTeb,
  723. OUT PULONG64 StackBase,
  724. OUT PULONG64 StackLimit,
  725. OUT PULONG64 StoreBase,
  726. OUT PULONG64 StoreLimit)
  727. {
  728. HRESULT Status;
  729. if ((Status = GetTeb(Thread, Teb, SizeOfTeb)) != S_OK) {
  730. return Status;
  731. }
  732. return TibGetThreadInfo(Process, *Teb,
  733. StackBase, StackLimit,
  734. StoreBase, StoreLimit);
  735. }
  736. HRESULT
  737. Win9xWin32LiveSystemProvider::GetPeb(IN HANDLE Process,
  738. OUT PULONG64 Offset,
  739. OUT PULONG Size)
  740. {
  741. // Win9x doesn't have a PEB.
  742. *Offset = 0;
  743. *Size = 0;
  744. return S_OK;
  745. }
  746. Win32LiveSystemProvider*
  747. NewWin9xWin32LiveSystemProvider(ULONG BuildNumber)
  748. {
  749. // Win9x keeps the build number in the low 16 bits.
  750. return new Win9xWin32LiveSystemProvider(BuildNumber & 0xffff);
  751. }
  752. #else // #ifdef _X86_
  753. Win32LiveSystemProvider*
  754. NewWin9xWin32LiveSystemProvider(ULONG BuildNumber)
  755. {
  756. return NULL;
  757. }
  758. #endif // #ifdef _X86_