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_
|