892 lines
18 KiB
C
892 lines
18 KiB
C
|
||
/*++
|
||
|
||
Copyright (c) 1999-2001 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
win.c
|
||
|
||
Abstract:
|
||
|
||
This module exports windows specific apis
|
||
|
||
Algorithm:
|
||
|
||
Unfortunately, implementing OpenThread cannot be done in a simple
|
||
manner. What follows is a very system dependent hack. If the structure
|
||
of the TDB or the implementation of OpenProcess change very much, this
|
||
function will break.
|
||
|
||
To have any idea of what we are doing here, you should be familiar with
|
||
Win9x internals. If you are not familiar with the Win9x source, consult
|
||
the book "Windows 95 System Programming SECRETS" by Matt Pietrek. Things
|
||
are not exactly the same for Win98 -- but pretty close.
|
||
|
||
OpenThread is a very simple function. If we were compiled withing the
|
||
Win9x source code base, the code would be simple:
|
||
|
||
OpenThread:
|
||
|
||
pObj = TidToTDB (dwThreadId);
|
||
|
||
return AllocHandle (GetCurrentPdb(), pObj, Flags);
|
||
|
||
Since we are not, the challenge is implementing the functions TidToTDB()
|
||
and AllocHandle().
|
||
|
||
Our approach is as follows:
|
||
|
||
1) We reverse-engineer TidToTDB since it is simple. TidToTDB is just
|
||
the thread-id xor'd with the Win9x Obfuscator.
|
||
|
||
2) We search through the code of OpenProcess until we find the address
|
||
of AllocHandle. We use this to allocate new handles in the
|
||
process's handle database.
|
||
|
||
3) OpenThread is then implemented in terms of the above primitives.
|
||
|
||
Author:
|
||
|
||
Matthew D Hendel (math) 01-Sept-1999
|
||
|
||
Revision History:
|
||
|
||
|
||
--*/
|
||
|
||
#include "pch.h"
|
||
|
||
#include "impl.h"
|
||
|
||
//
|
||
// Windows 9x support is x86 only.
|
||
//
|
||
|
||
#ifdef _X86_
|
||
|
||
typedef struct _MATCH_BUFFER {
|
||
ULONG Offset;
|
||
BYTE Byte;
|
||
} MATCH_BUFFER, *PMATCH_BUFFER;
|
||
|
||
typedef struct _OS_INFORMATION {
|
||
PMATCH_BUFFER MatchBuffer;
|
||
ULONG AllocHandleOffset;
|
||
} OS_INFORMATION, POS_INFORMATION;
|
||
|
||
|
||
/*++
|
||
|
||
Operating System:
|
||
|
||
Win95
|
||
|
||
Description:
|
||
|
||
This is the disasm of the OpenProcess routine on Win95. We attempt to
|
||
match this routine and pull out the value for AllocHandle from the code
|
||
for this routine. In this case, AllocHande is called by the third call in
|
||
this function.
|
||
|
||
The instructions marked by '*' are those we use for matching.
|
||
|
||
OpenProcess:
|
||
|
||
* BFF9404C: FF 74 24 0C push dword ptr [esp+0Ch]
|
||
* BFF94050: E8 2D 87 FE FF call BFF7C782
|
||
BFF94055: 85 C0 test eax,eax
|
||
BFF94057: 75 04 jne BFF9405D
|
||
BFF94059: 33 C0 xor eax,eax
|
||
BFF9405B: EB 56 jmp BFF940B3
|
||
BFF9405D: 83 38 05 cmp dword ptr [eax],5
|
||
BFF94060: 74 0E je BFF94070
|
||
BFF94062: 6A 57 push 57h
|
||
* BFF94064: E8 BC 68 FE FF call BFF7A925
|
||
BFF94069: B9 FF FF FF FF mov ecx,0FFFFFFFFh
|
||
BFF9406E: EB 33 jmp BFF940A3
|
||
BFF94070: B9 00 00 00 00 mov ecx,0
|
||
BFF94075: 8B 54 24 04 mov edx,dword ptr [esp+4]
|
||
BFF94079: 83 7C 24 08 01 cmp dword ptr [esp+8],1
|
||
BFF9407E: 83 D1 FF adc ecx,0FFFFFFFFh
|
||
BFF94081: 81 E2 BF FF 1F 00 and edx,1FFFBFh
|
||
BFF94087: 81 E1 00 00 00 80 and ecx,80000000h
|
||
BFF9408D: 0B CA or ecx,edx
|
||
BFF9408F: 8B 15 7C C2 FB BF mov edx,dword ptr ds:[BFFBC27Ch]
|
||
BFF94095: 80 C9 40 or cl,40h
|
||
BFF94098: 51 push ecx
|
||
BFF94099: 50 push eax
|
||
BFF9409A: FF 32 push dword ptr [edx]
|
||
* BFF9409C: E8 6E 76 FE FF call BFF7B70F
|
||
BFF940A1: 8B C8 mov ecx,eax
|
||
BFF940A3: 8D 41 01 lea eax,[ecx+1]
|
||
BFF940A6: 83 F8 01 cmp eax,1
|
||
BFF940A9: B8 00 00 00 00 mov eax,0
|
||
BFF940AE: 83 D0 FF adc eax,0FFFFFFFFh
|
||
BFF940B1: 23 C1 and eax,ecx
|
||
BFF940B3: C2 0C 00 ret 0Ch
|
||
|
||
--*/
|
||
|
||
MATCH_BUFFER Win95AllocHandleMatch [] = {
|
||
|
||
//
|
||
// ret 0x0C at offset 103
|
||
//
|
||
|
||
{ 103, 0xC2 },
|
||
{ 104, 0x0C },
|
||
{ 105, 0x00 },
|
||
|
||
//
|
||
// push dword ptr [exp 0x0C] at offset 0
|
||
//
|
||
|
||
{ 0, 0xFF },
|
||
{ 1, 0x74 },
|
||
{ 2, 0x24 },
|
||
{ 3, 0x0C },
|
||
|
||
//
|
||
// call at offset 4
|
||
//
|
||
|
||
{ 4, 0xE8 },
|
||
|
||
//
|
||
// call at offset 24
|
||
//
|
||
|
||
{ 24, 0xE8 },
|
||
|
||
//
|
||
// call at offset 80
|
||
//
|
||
|
||
{ 80, 0xE8 },
|
||
|
||
//
|
||
// End of match list.
|
||
//
|
||
|
||
{ -1, -1 }
|
||
};
|
||
|
||
|
||
/*++
|
||
|
||
Operating system:
|
||
|
||
Win98
|
||
|
||
Description:
|
||
|
||
See comments above regarding OpenProcess.
|
||
|
||
OpenProcess:
|
||
|
||
* BFF95C4D: FF 74 24 0C push dword ptr [esp+0Ch]
|
||
* BFF95C51: E8 C9 8E FE FF call BFF7EB1F
|
||
BFF95C56: 85 C0 test eax,eax
|
||
BFF95C58: 75 04 jne BFF95C5E
|
||
BFF95C5A: 33 C0 xor eax,eax
|
||
BFF95C5C: EB 53 jmp BFF95CB1
|
||
BFF95C5E: 80 38 06 cmp byte ptr [eax],6
|
||
BFF95C61: 74 0E je BFF95C71
|
||
BFF95C63: 6A 57 push 57h
|
||
* BFF95C65: E8 27 6D FE FF call BFF7C991
|
||
BFF95C6A: B9 FF FF FF FF mov ecx,0FFFFFFFFh
|
||
BFF95C6F: EB 30 jmp BFF95CA1
|
||
BFF95C71: B9 00 00 00 00 mov ecx,0
|
||
BFF95C76: 8B 54 24 04 mov edx,dword ptr [esp+4]
|
||
BFF95C7A: 83 7C 24 08 01 cmp dword ptr [esp+8],1
|
||
BFF95C7F: 83 D1 FF adc ecx,0FFFFFFFFh
|
||
BFF95C82: 81 E2 FF 0F 1F 00 and edx,1F0FFFh
|
||
BFF95C88: 81 E1 00 00 00 80 and ecx,80000000h
|
||
BFF95C8E: 0B CA or ecx,edx
|
||
BFF95C90: 8B 15 DC 9C FC BF mov edx,dword ptr ds:[BFFC9CDCh]
|
||
BFF95C96: 51 push ecx
|
||
BFF95C97: 50 push eax
|
||
BFF95C98: FF 32 push dword ptr [edx]
|
||
* BFF95C9A: E8 5A 7E FE FF call BFF7DAF9
|
||
BFF95C9F: 8B C8 mov ecx,eax
|
||
BFF95CA1: 8D 41 01 lea eax,[ecx+1]
|
||
BFF95CA4: 83 F8 01 cmp eax,1
|
||
BFF95CA7: B8 00 00 00 00 mov eax,0
|
||
BFF95CAC: 83 D0 FF adc eax,0FFFFFFFFh
|
||
BFF95CAF: 23 C1 and eax,ecx
|
||
* BFF95CB1: C2 0C 00 ret 0Ch
|
||
|
||
--*/
|
||
|
||
MATCH_BUFFER Win98AllocHandleMatch [] = {
|
||
|
||
//
|
||
// ret 0x0C at offset 100
|
||
//
|
||
|
||
{ 100, 0xC2 },
|
||
{ 101, 0x0C },
|
||
{ 102, 0x00 },
|
||
|
||
//
|
||
// push dword ptr [exp 0x0C] at offset 0
|
||
//
|
||
|
||
{ 0, 0xFF },
|
||
{ 1, 0x74 },
|
||
{ 2, 0x24 },
|
||
{ 3, 0x0C },
|
||
|
||
//
|
||
// call at offset 4
|
||
//
|
||
|
||
{ 4, 0xE8 },
|
||
|
||
//
|
||
// call at offset 24
|
||
//
|
||
|
||
{ 24, 0xE8 },
|
||
|
||
//
|
||
// call at offset 77
|
||
//
|
||
|
||
{ 77, 0xE8 },
|
||
|
||
//
|
||
// End of match list.
|
||
//
|
||
|
||
{ -1, -1 }
|
||
};
|
||
|
||
|
||
OS_INFORMATION SupportedSystems [] =
|
||
{
|
||
{ Win95AllocHandleMatch, 81 },
|
||
{ Win98AllocHandleMatch, 78 }
|
||
};
|
||
|
||
typedef
|
||
HANDLE
|
||
(__stdcall * ALLOC_HANDLE_ROUTINE) (
|
||
PVOID Pdb,
|
||
PVOID Obj,
|
||
DWORD Flags
|
||
);
|
||
|
||
//
|
||
// Global variables
|
||
//
|
||
|
||
ALLOC_HANDLE_ROUTINE WinpAllocHandle = NULL;
|
||
DWORD WinpObfuscator = 0;
|
||
|
||
|
||
#pragma warning (disable:4035)
|
||
|
||
//
|
||
// OffsetTib is NOT dependent on the OS. The compiler uses this value.
|
||
//
|
||
|
||
#define OffsetTib 0x18
|
||
|
||
_inline
|
||
PVOID
|
||
WinpGetCurrentTib(
|
||
)
|
||
{
|
||
#if defined(_X86_)
|
||
__asm mov eax, fs:[OffsetTib]
|
||
#else
|
||
return NULL;
|
||
#endif
|
||
}
|
||
|
||
#pragma warning (default:4035)
|
||
|
||
|
||
BOOL
|
||
WinpGetAllocHandleFromStream(
|
||
IN PBYTE Buffer,
|
||
IN PVOID BaseOfBuffer,
|
||
IN PMATCH_BUFFER MatchBuffer,
|
||
IN ULONG Offset,
|
||
IN ULONG * Val
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Find the address of the AllocHandle routine. This is done by searching
|
||
through the code of the OpenProcess routine, looking for the third
|
||
call instruction in that function. The third call calls AllocHandle().
|
||
|
||
Arguments:
|
||
|
||
Buffer - Buffer of instructions to search through.
|
||
|
||
BaseOfBuffer - The base address of the buffer.
|
||
|
||
MatchBuffer - The match buffer to compare against.
|
||
|
||
Offset - The offset of call destination.
|
||
|
||
Val - A buffer to return the value of AllocHandle.
|
||
|
||
|
||
Return Values:
|
||
|
||
TRUE - Success.
|
||
|
||
FALSE - Failure.
|
||
|
||
--*/
|
||
|
||
|
||
{
|
||
UINT i;
|
||
|
||
for (i = 0; MatchBuffer [i].Offset != -1; i++) {
|
||
|
||
if (Buffer [MatchBuffer[i].Offset] != MatchBuffer[i].Byte) {
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
//
|
||
// This assumes that the call instruction is a near, relative call (E8).
|
||
// If this is not the case, the calculation below is incorrect.
|
||
//
|
||
// The calculation gives us the destination relative to the next
|
||
// instruction after the call.
|
||
//
|
||
|
||
*Val = (ULONG) BaseOfBuffer + Offset + *(PLONG) &Buffer [Offset] + 4;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
|
||
ULONG
|
||
WinGetModuleSize(
|
||
PVOID Base
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Get the SizeOfImage field given the base address of a module.
|
||
|
||
Return Values:
|
||
|
||
SizeOfImage field of the specified module on success.
|
||
|
||
NULL on failure.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG Size;
|
||
PIMAGE_NT_HEADERS NtHeaders;
|
||
|
||
NtHeaders = ImageNtHeader ( Base );
|
||
if ( NtHeaders ) {
|
||
Size = NtHeaders->OptionalHeader.SizeOfImage;
|
||
} else {
|
||
Size = 0;
|
||
}
|
||
|
||
return Size;
|
||
}
|
||
|
||
|
||
BOOL
|
||
WinpInitAllocHandle (
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Initialize the global variable WxAllocHandle to the value of the Win9x
|
||
internal routine, AllocHandle.
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Values:
|
||
|
||
TRUE - If we were able to successfully obtain a pointer to AllocHandle.
|
||
|
||
FALSE - Otherwise.
|
||
|
||
Comments:
|
||
|
||
The client of this routine should verify that this handle is correct by
|
||
calling WxCheckOpenThread() before blindly assuming the pointer is
|
||
correct.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG i;
|
||
BOOL Succ;
|
||
PVOID OpenProcessPtr;
|
||
ULONG Kernel32Base;
|
||
ULONG Kernel32Size;
|
||
ULONG AllocHandle;
|
||
BYTE Buffer [ 200 ];
|
||
|
||
if ( WinpAllocHandle ) {
|
||
return TRUE;
|
||
}
|
||
|
||
Kernel32Base = (ULONG) GetModuleHandle ( "kernel32.dll" );
|
||
ASSERT ( Kernel32Base );
|
||
if (!Kernel32Base)
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
Kernel32Size = WinGetModuleSize ( (PVOID) Kernel32Base );
|
||
ASSERT ( Kernel32Size != 0 );
|
||
|
||
OpenProcessPtr = GetProcAddress (
|
||
(HINSTANCE) Kernel32Base,
|
||
"OpenProcess"
|
||
);
|
||
if (!OpenProcessPtr)
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
//
|
||
// Win9x thunks out functions when a debugger is present. To work around
|
||
// this we undo the thunk when it looks like its been thunked.
|
||
//
|
||
|
||
if ( (ULONG) OpenProcessPtr < Kernel32Base ||
|
||
(ULONG) OpenProcessPtr > Kernel32Base + Kernel32Size ) {
|
||
|
||
OpenProcessPtr = (PVOID) *(PULONG)( (PBYTE)OpenProcessPtr + 1 );
|
||
}
|
||
|
||
if ( (ULONG) OpenProcessPtr < Kernel32Base ||
|
||
(ULONG) OpenProcessPtr > Kernel32Base + Kernel32Size ) {
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
CopyMemory (Buffer, OpenProcessPtr, sizeof (Buffer));
|
||
|
||
//
|
||
// Check the buffer
|
||
//
|
||
|
||
for ( i = 0; i < ARRAY_COUNT (SupportedSystems); i++) {
|
||
|
||
Succ = WinpGetAllocHandleFromStream (
|
||
Buffer,
|
||
OpenProcessPtr,
|
||
SupportedSystems[i].MatchBuffer,
|
||
SupportedSystems[i].AllocHandleOffset,
|
||
&AllocHandle
|
||
);
|
||
|
||
if ( Succ ) {
|
||
|
||
//
|
||
// Verify WinpAllocHandle within range of Kernel32.
|
||
//
|
||
|
||
if (AllocHandle > Kernel32Base &&
|
||
AllocHandle < Kernel32Base + Kernel32Size) {
|
||
|
||
WinpAllocHandle = (ALLOC_HANDLE_ROUTINE) AllocHandle;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
if ( !Succ ) {
|
||
WinpAllocHandle = NULL;
|
||
}
|
||
|
||
return Succ;
|
||
}
|
||
|
||
|
||
//
|
||
// This value is basically FIELD_OFFSET (TDB, Tib). It is dependent on the
|
||
// specific version of the OS (95, 98).
|
||
//
|
||
|
||
#define WIN95_TDB_OFFSET (0x10)
|
||
#define WIN98_TDB_OFFSET (0x08)
|
||
|
||
DWORD
|
||
WinpGetObfuscator(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Get the Obfuscator DWORD.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Values:
|
||
|
||
The Obfuscator or 0 on failure.
|
||
|
||
Comments:
|
||
|
||
This routine depends on internal structures from the Win9x sources. If
|
||
another major revision of windows changes many of these structures, this
|
||
function may break.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG Tib;
|
||
ULONG Type;
|
||
ULONG Major;
|
||
|
||
|
||
if (WinpObfuscator != 0) {
|
||
return WinpObfuscator;
|
||
}
|
||
|
||
GenGetSystemType (&Type, &Major, NULL, NULL, NULL);
|
||
|
||
ASSERT ( Type == Win9x );
|
||
|
||
Tib = (DWORD)WinpGetCurrentTib ();
|
||
|
||
if ( Major == 95 ) {
|
||
|
||
WinpObfuscator = (GetCurrentThreadId () ^ (Tib - WIN95_TDB_OFFSET));
|
||
|
||
} else {
|
||
|
||
//
|
||
// If a windows-based system that is not 95 or 98 comes along,
|
||
// we should make sure the WINxx_TDB_OFFSET is correct.
|
||
//
|
||
|
||
ASSERT ( Major == 98 );
|
||
WinpObfuscator = (GetCurrentThreadId () ^ (Tib - WIN98_TDB_OFFSET));
|
||
}
|
||
|
||
return WinpObfuscator;
|
||
}
|
||
|
||
|
||
LPVOID
|
||
WinpTidToTDB(
|
||
IN DWORD ThreadId
|
||
)
|
||
{
|
||
return (PVOID) (ThreadId ^ WinpGetObfuscator ());
|
||
}
|
||
|
||
LPVOID
|
||
WinpGetCurrentPdb(
|
||
)
|
||
{
|
||
return (LPVOID) (GetCurrentProcessId () ^ WinpGetObfuscator ());
|
||
}
|
||
|
||
HANDLE
|
||
WinpOpenThreadInternal(
|
||
DWORD dwAccess,
|
||
BOOL bInheritHandle,
|
||
DWORD ThreadId
|
||
)
|
||
{
|
||
HANDLE hThread;
|
||
PVOID ThreadObj;
|
||
|
||
ASSERT (WinpAllocHandle);
|
||
|
||
//
|
||
// Convert the ThreadId to a Thread Object
|
||
//
|
||
|
||
ThreadObj = WinpTidToTDB (ThreadId);
|
||
|
||
if (ThreadObj == NULL) {
|
||
return NULL;
|
||
}
|
||
|
||
//
|
||
// NB: we do not check that the handle really is a thread handle.
|
||
// The type varies from version to version of the OS, so it is not
|
||
// correct to check it.
|
||
//
|
||
|
||
try {
|
||
|
||
hThread = WinpAllocHandle (
|
||
WinpGetCurrentPdb (),
|
||
ThreadObj,
|
||
dwAccess
|
||
);
|
||
}
|
||
|
||
except (EXCEPTION_EXECUTE_HANDLER) {
|
||
|
||
hThread = NULL;
|
||
}
|
||
|
||
if (hThread == (HANDLE) (-1)) {
|
||
hThread = NULL;
|
||
}
|
||
|
||
return hThread;
|
||
}
|
||
|
||
|
||
#if _MSC_FULL_VER >= 13008827
|
||
#pragma warning(push)
|
||
#pragma warning(disable:4715) // Not all control paths return (due to infinite loop)
|
||
#endif
|
||
|
||
DWORD
|
||
WINAPI
|
||
WinpCheckThread(
|
||
PVOID unused
|
||
)
|
||
{
|
||
for (;;) {
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
#if _MSC_FULL_VER >= 13008827
|
||
#pragma warning(pop)
|
||
#endif
|
||
|
||
|
||
|
||
BOOL
|
||
WinpCheckOpenThread(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Check that WxOpenThread actually works.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Values:
|
||
|
||
TRUE - If WxOpenThread works properly.
|
||
|
||
FALSE - Otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
BOOL Succ;
|
||
HANDLE hThread1;
|
||
HANDLE hThread2;
|
||
DWORD ThreadId;
|
||
CONTEXT Context1;
|
||
CONTEXT Context2;
|
||
LONG SuspendCount;
|
||
|
||
|
||
SuspendCount = 0;
|
||
hThread1 = NULL;
|
||
hThread2 = NULL;
|
||
|
||
|
||
hThread1 = CreateThread (NULL,
|
||
0,
|
||
WinpCheckThread,
|
||
0,
|
||
0,
|
||
&ThreadId
|
||
);
|
||
|
||
if ( hThread1 == NULL ) {
|
||
return FALSE;
|
||
}
|
||
|
||
hThread2 = WinpOpenThreadInternal (
|
||
THREAD_ALL_ACCESS,
|
||
FALSE,
|
||
ThreadId
|
||
);
|
||
|
||
if ( hThread2 == NULL ) {
|
||
Succ = FALSE;
|
||
goto Exit;
|
||
}
|
||
|
||
Succ = TRUE;
|
||
try {
|
||
|
||
//
|
||
// First we check that we can suspend the thread. If that is
|
||
// successful, then get the context using the read thread
|
||
// handle and the newly opened thread handle and check that
|
||
// they are the same.
|
||
//
|
||
|
||
SuspendCount = SuspendThread ( hThread2 );
|
||
|
||
if ( SuspendCount == -1 ) {
|
||
Succ = FALSE;
|
||
leave;
|
||
}
|
||
|
||
Context1.ContextFlags = CONTEXT_FULL;
|
||
Succ = GetThreadContext ( hThread2, &Context1 );
|
||
|
||
if ( !Succ ) {
|
||
leave;
|
||
}
|
||
|
||
Context2.ContextFlags = CONTEXT_FULL;
|
||
Succ = GetThreadContext ( hThread1, &Context2 );
|
||
|
||
if ( !Succ ) {
|
||
leave;
|
||
}
|
||
|
||
if ( Context1.Eip != Context2.Eip ) {
|
||
Succ = FALSE;
|
||
leave;
|
||
}
|
||
}
|
||
|
||
except ( EXCEPTION_EXECUTE_HANDLER ) {
|
||
|
||
Succ = FALSE;
|
||
}
|
||
|
||
Exit:
|
||
|
||
if ( SuspendCount > 0 ) {
|
||
ResumeThread ( hThread2 );
|
||
}
|
||
|
||
TerminateThread ( hThread1, 0xDEAD );
|
||
|
||
if ( hThread1 ) {
|
||
CloseHandle ( hThread1 );
|
||
}
|
||
|
||
if ( hThread2 ) {
|
||
CloseHandle ( hThread2 );
|
||
}
|
||
|
||
return Succ;
|
||
}
|
||
|
||
|
||
BOOL
|
||
WinInitialize(
|
||
)
|
||
{
|
||
if ( WinpAllocHandle == NULL ) {
|
||
|
||
if (!WinpInitAllocHandle ()) {
|
||
SetLastError (ERROR_NOT_SUPPORTED);
|
||
return FALSE;
|
||
}
|
||
|
||
if (!WinpCheckOpenThread ()) {
|
||
SetLastError (ERROR_NOT_SUPPORTED);
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
return TRUE;
|
||
|
||
}
|
||
|
||
VOID
|
||
WinFree(
|
||
)
|
||
{
|
||
WinpAllocHandle = NULL;
|
||
WinpObfuscator = 0;
|
||
|
||
}
|
||
|
||
HANDLE
|
||
WINAPI
|
||
WinOpenThread(
|
||
DWORD dwAccess,
|
||
BOOL bInheritHandle,
|
||
DWORD ThreadId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Obtain a thread handle from a thread id on Win9x platform.x
|
||
|
||
Arguments:
|
||
|
||
dwAccess - Thread access requested.
|
||
|
||
bInheritHandle - ALWAYS IGNORED.
|
||
|
||
ThreadId - The identifier of the thread for which a handle is to
|
||
be returned.
|
||
|
||
Return Values:
|
||
|
||
A handle to the open thread on success or NULL on failure.
|
||
|
||
--*/
|
||
|
||
{
|
||
HANDLE Handle;
|
||
|
||
//
|
||
// It is necessary to call WinInitialize() before calling this function.
|
||
// If this was not called, return failure.
|
||
//
|
||
|
||
if ( WinpAllocHandle == NULL ) {
|
||
|
||
SetLastError ( ERROR_DLL_INIT_FAILED );
|
||
return FALSE;
|
||
}
|
||
|
||
Handle = WinpOpenThreadInternal (
|
||
dwAccess,
|
||
bInheritHandle,
|
||
ThreadId
|
||
);
|
||
|
||
return Handle;
|
||
}
|
||
|
||
#endif // _X86_
|