Fix thread support (#640)

This PR fixes several things related to threads emulation:

1. Support `SameTebFlags.InitialThread`
This flag is needed to support emulation of .net executables (not yet
fully supported) that don't have an entry point set in `PE` header. This
applies to both `PE32` and `PE64` executables. If `InitialThread` is set
the loader substitutes an entry point of the .net executable with
`mscoree.dll!_CorExeMain`.

2. Fix static thread local storage for `WOW64`
This fix resolves `shell32.dll` initialization on `WOW64`. This fix also
uses correct structure and field names that are obtained from the
corresponding `.pdb` files.

3. Fix dynamic thread local storage for `WOW64`

4. Fix setting argument of a `WOW64` thread start proc

5. Fix creating suspended thread and parse create_flags
Currently creating suspended thread doesn't work because
`NtCreateThreadEx` handler uses invalid flag `CREATE_SUSPENDED`. This PR
fixes that, and moreover it carefully parses create_flags of the
`NtCreateThreadEx` call.

6. Fix `FS` and `GS` handling
This PR fixes several problems with `GS` and `FS` segments:

    * Wrong GDT descriptor for selector 0x53
* Update GDT descriptor for selector 0x53 for a `WOW64` process every
context switch like Windows does
* Set `GS` base when `GS` segment register is updated in 64-bit code
(code selector is `0x33`). When `GS` segment register is loaded with
correct selector (`0x2b`) `GS` base is set to 0. So, when the code
accesses something like `gs:[0]`, a page fault occurs. `KiPageFault`
handles this situation and sets correct `GS` base.

Also, take into account that `teb64.ExceptionList` initially contains
`teb32` address for `WOW64` process. This is used to setup `FS` base
when `wrfsbase` instruction is available. We can enable this instruction
using `kusd.ProcessorFeatures.arr[PF_RDWRFSGSBASE_AVAILABLE] = 1;` and
this work perfectly with `unicorn` backend. Unfortunately `icicle`
backend does not support `wrfsbase`, so I don't enable this instruction
by default.
This commit is contained in:
Maurice Heumann
2025-12-30 17:56:30 +01:00
committed by GitHub
14 changed files with 241 additions and 159 deletions

View File

@@ -21,6 +21,7 @@
#define WIN32_CLIENT_INFO_LENGTH 62
#define STATIC_UNICODE_BUFFER_LENGTH 261
#define TLS_MINIMUM_AVAILABLE 64
#define TLS_EXPANSION_SLOTS 1024
#ifndef OS_WINDOWS
#define PF_FLOATING_POINT_PRECISION_ERRATA 0
@@ -970,6 +971,13 @@ union TEB_CROSS_TEB_FLAGS_UNION
USHORT SpareCrossTebBits : 16;
};
constexpr auto THREAD_CREATE_FLAGS_CREATE_SUSPENDED = 0x1;
constexpr auto THREAD_CREATE_FLAGS_SKIP_THREAD_ATTACH = 0x2;
constexpr auto THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER = 0x4;
constexpr auto THREAD_CREATE_FLAGS_LOADER_WORKER = 0x10;
constexpr auto THREAD_CREATE_FLAGS_SKIP_LOADER_INIT = 0x20;
constexpr auto THREAD_CREATE_FLAGS_BYPASS_PROCESS_FREEZE = 0x40;
union TEB_SAME_TEB_FLAGS_UNION
{
USHORT SameTebFlags;
@@ -1671,45 +1679,45 @@ typedef struct _KERNEL_USER_TIMES
LARGE_INTEGER UserTime;
} KERNEL_USER_TIMES, *PKERNEL_USER_TIMES;
struct THREAD_TLS_INFO
struct THREAD_TLS_INFORMATION
{
ULONG Flags;
uint32_t _Padding;
union
{
EmulatorTraits<Emu64>::PVOID TlsVector;
EmulatorTraits<Emu64>::PVOID TlsModulePointer;
EmulatorTraits<Emu64>::PVOID NewTlsData;
EmulatorTraits<Emu64>::PVOID OldTlsData;
};
EMULATOR_CAST(std::uint64_t, ULONG_PTR) ThreadId;
uint64_t ThreadId;
};
static_assert(sizeof(THREAD_TLS_INFO) == 0x18);
static_assert(sizeof(THREAD_TLS_INFORMATION) == 0x18);
typedef enum _PROCESS_TLS_INFORMATION_TYPE
enum PROCESS_TLS_INFORMATION_TYPE
{
ProcessTlsReplaceIndex,
ProcessTlsReplaceVector,
MaxProcessTlsOperation
} PROCESS_TLS_INFORMATION_TYPE, *PPROCESS_TLS_INFORMATION_TYPE;
};
struct PROCESS_TLS_INFO
struct PROCESS_TLS_INFORMATION
{
ULONG Unknown;
PROCESS_TLS_INFORMATION_TYPE TlsRequest;
ULONG Flags;
PROCESS_TLS_INFORMATION_TYPE OperationType;
ULONG ThreadDataCount;
union
{
ULONG TlsIndex;
ULONG TlsVectorLength;
ULONG PreviousCount;
};
THREAD_TLS_INFO ThreadData[1];
THREAD_TLS_INFORMATION ThreadData[1];
};
static_assert(sizeof(PROCESS_TLS_INFO) - sizeof(THREAD_TLS_INFO) == 0x10);
static_assert(sizeof(PROCESS_TLS_INFORMATION) == 0x28);
struct EMU_GENERIC_MAPPING
{