mirror of
https://github.com/ApfelTeeSaft/reactos.git
synced 2026-08-26 19:33:31 +00:00
[NTDLL_APITEST] Add more tests for NtCreateThread
This commit is contained in:
@@ -156,11 +156,13 @@ if(ARCH STREQUAL "i386")
|
||||
add_asm_files(ntdll_apitest_asm
|
||||
../crt/i386/setjmp_helper.s
|
||||
i386/NtContinue.S
|
||||
i386/NtCreateThread.S
|
||||
)
|
||||
elseif(ARCH STREQUAL "amd64")
|
||||
add_asm_files(ntdll_apitest_asm
|
||||
../crt/amd64/setjmp_helper.s
|
||||
amd64/NtContinue.S
|
||||
amd64/NtCreateThread.S
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -3,16 +3,139 @@
|
||||
* LICENSE: See COPYING in the top level directory
|
||||
* PURPOSE: Test for NtCreateThread
|
||||
* PROGRAMMER: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
* PROGRAMMER: Timo Kreuzer <[email protected]>
|
||||
*/
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
PVOID TestThreadProcPtr;
|
||||
CONTEXT TestThreadStartupContext;
|
||||
DECLSPEC_ALIGN(16) UCHAR TestThreadStartupStack[PAGE_SIZE];
|
||||
BOOLEAN TestThreadFunctionCalled;
|
||||
extern void ThreadStartupThunk(void*);
|
||||
|
||||
#define RPL_MASK 0x0003
|
||||
#define MODE_MASK 0x0001
|
||||
#define EFLAGS_INTERRUPT_MASK 0x200L
|
||||
#define KGDT_R3_CODE 0x0018
|
||||
#define KGDT_R3_DATA 0x0020
|
||||
#define KGDT_R3_TEB 0x0038
|
||||
#define KGDT64_R3_CMCODE 0x0020
|
||||
#define KGDT64_R3_DATA 0x0028
|
||||
#define KGDT64_R3_CODE 0x0030
|
||||
#define KGDT64_R3_CMTEB 0x0050
|
||||
|
||||
static
|
||||
VOID
|
||||
InitializeTestContext(PCONTEXT Context)
|
||||
{
|
||||
RtlFillMemory(Context, sizeof(*Context), 0xAA);
|
||||
|
||||
Context->ContextFlags = CONTEXT_ALL;
|
||||
|
||||
#ifdef _M_AMD64
|
||||
|
||||
/* Control */
|
||||
Context->Rsp = (ULONG64)(TestThreadStartupStack + PAGE_SIZE - 16);
|
||||
Context->Rip = (ULONG64)ThreadStartupThunk;
|
||||
|
||||
/* Set Eflags. These get sanitized, but 0x100 (trap flag) makes it trap instantly. */
|
||||
Context->EFlags = 0xFFFFFFFF;
|
||||
Context->EFlags &= ~0x100;
|
||||
|
||||
/* Integer (these are copied) */
|
||||
Context->Rax = 0xF000000000000000;
|
||||
Context->Rcx = 0xF000000000000001;
|
||||
Context->Rdx = 0xF000000000000002;
|
||||
Context->Rbx = 0xF000000000000003;
|
||||
Context->Rbp = 0xF000000000000005;
|
||||
Context->Rsi = 0xF000000000000006;
|
||||
Context->Rdi = 0xF000000000000007;
|
||||
Context->R8 = 0xF000000000000008;
|
||||
Context->R9 = 0xF000000000000009;
|
||||
Context->R10 = 0xF00000000000000A;
|
||||
Context->R11 = 0xF00000000000000B;
|
||||
Context->R12 = 0xF00000000000000C;
|
||||
Context->R13 = 0xF00000000000000D;
|
||||
Context->R14 = 0xF00000000000000E;
|
||||
Context->R15 = 0xF00000000000000F;
|
||||
|
||||
#elif defined(_M_IX86)
|
||||
|
||||
/* Control */
|
||||
Context->Esp = (ULONG)(TestThreadStartupStack + PAGE_SIZE - 16);
|
||||
Context->Eip = (ULONG)ThreadStartupThunk;
|
||||
|
||||
/* Set Eflags. These get sanitized, but 0x100 (trap flag) makes it trap instantly. */
|
||||
Context->EFlags = 0xFFFFFFFF;
|
||||
Context->EFlags &= ~0x100; // Disable trap flag, because it would make the thread trap instantly
|
||||
Context->EFlags &= ~0x00020000; // Disable V86 flag
|
||||
|
||||
/* Integer (these are copied) */
|
||||
Context->Eax = 0xF0000000;
|
||||
Context->Ecx = 0xF0000001;
|
||||
Context->Edx = 0xF0000002;
|
||||
Context->Ebx = 0xF0000003;
|
||||
Context->Ebp = 0xF0000005;
|
||||
Context->Esi = 0xF0000006;
|
||||
Context->Edi = 0xF0000007;
|
||||
|
||||
/* FIXME: Initialize segments to prevent ReactOS from crashing in the kernel */
|
||||
Context->SegCs = KGDT_R3_CODE | RPL_MASK;
|
||||
Context->SegSs = KGDT_R3_DATA | RPL_MASK;
|
||||
Context->SegDs = KGDT_R3_DATA | RPL_MASK;
|
||||
Context->SegEs = KGDT_R3_DATA | RPL_MASK;
|
||||
Context->SegFs = KGDT_R3_TEB | RPL_MASK;
|
||||
Context->SegGs = 0;
|
||||
|
||||
#else
|
||||
|
||||
#pragma message("Missing CONTEXT setup in NtCreateThread test")
|
||||
ASSERT(FALSE);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
TestThreadProc(IN PVOID StartContext)
|
||||
{
|
||||
TestThreadFunctionCalled = TRUE;
|
||||
|
||||
#if defined(_M_IX86) || defined(_M_AMD64)
|
||||
CONTEXT Context;
|
||||
|
||||
/* Get the debug registers and floating point */
|
||||
Context.ContextFlags = CONTEXT_DEBUG_REGISTERS | CONTEXT_FLOATING_POINT;
|
||||
GetThreadContext(NtCurrentThread(), &Context);
|
||||
TestThreadStartupContext.Dr0 = Context.Dr0;
|
||||
TestThreadStartupContext.Dr1 = Context.Dr1;
|
||||
TestThreadStartupContext.Dr2 = Context.Dr2;
|
||||
TestThreadStartupContext.Dr3 = Context.Dr3;
|
||||
TestThreadStartupContext.Dr6 = Context.Dr6;
|
||||
TestThreadStartupContext.Dr7 = Context.Dr7;
|
||||
#if defined(_M_IX86)
|
||||
TestThreadStartupContext.FloatSave = Context.FloatSave;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Terminate current thread */
|
||||
NtTerminateThread(NtCurrentThread(), STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
START_TEST(NtCreateThread)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
INITIAL_TEB InitialTeb;
|
||||
HANDLE ThreadHandle;
|
||||
OBJECT_ATTRIBUTES Attributes;
|
||||
DECLSPEC_ALIGN(16) ULONG_PTR Stack[128];
|
||||
PULONG_PTR StackPtr = &Stack[ARRAYSIZE(Stack) - 2];
|
||||
CONTEXT Context;
|
||||
CLIENT_ID ClientId;
|
||||
|
||||
BOOL IsWow64 = FALSE;
|
||||
IsWow64Process(GetCurrentProcess(), &IsWow64);
|
||||
|
||||
InitializeObjectAttributes(&Attributes, NULL, 0, NULL, NULL);
|
||||
ZeroMemory(&InitialTeb, sizeof(INITIAL_TEB));
|
||||
@@ -27,4 +150,196 @@ START_TEST(NtCreateThread)
|
||||
FALSE);
|
||||
|
||||
ok_hex(Status, STATUS_ACCESS_VIOLATION);
|
||||
|
||||
InitialTeb.PreviousStackBase = NULL;
|
||||
InitialTeb.PreviousStackLimit = NULL;
|
||||
InitialTeb.StackBase = StackPtr;
|
||||
InitialTeb.StackLimit = Stack;
|
||||
InitialTeb.AllocatedStackBase = Stack;
|
||||
|
||||
TestThreadProcPtr = TestThreadProc;
|
||||
|
||||
RtlFillMemory(&TestThreadStartupContext, sizeof(TestThreadStartupContext), 0xCC);
|
||||
InitializeTestContext(&Context);
|
||||
|
||||
Status = NtCreateThread(&ThreadHandle,
|
||||
THREAD_ALL_ACCESS,
|
||||
NULL,
|
||||
NtCurrentProcess(),
|
||||
&ClientId,
|
||||
&Context,
|
||||
&InitialTeb,
|
||||
TRUE);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
|
||||
NtResumeThread(ThreadHandle, NULL);
|
||||
WaitForSingleObject(ThreadHandle, INFINITE);
|
||||
CloseHandle(ThreadHandle);
|
||||
|
||||
ok_eq_bool(TestThreadFunctionCalled, TRUE);
|
||||
TestThreadFunctionCalled = FALSE;
|
||||
|
||||
#ifdef _M_AMD64
|
||||
|
||||
/* Control */
|
||||
ok_eq_hex64(TestThreadStartupContext.Rsp, Context.Rsp - 0x28);
|
||||
ok_eq_hex64(TestThreadStartupContext.SegCs, 0x0033);
|
||||
ok_eq_hex64(TestThreadStartupContext.EFlags, 0x200ED7);
|
||||
ok_eq_hex(TestThreadStartupContext.SegSs, 0x0002B);
|
||||
|
||||
/* Integer (copied) */
|
||||
ok_eq_hex64(TestThreadStartupContext.Rax, Context.Rax);
|
||||
ok_eq_hex64(TestThreadStartupContext.Rcx, Context.Rcx);
|
||||
ok_eq_hex64(TestThreadStartupContext.Rdx, Context.Rdx);
|
||||
ok_eq_hex64(TestThreadStartupContext.Rbx, Context.Rbx);
|
||||
ok_eq_hex64(TestThreadStartupContext.Rbp, (GetNTVersion() >= _WIN32_WINNT_WIN10) ? Context.Rbp : 0);
|
||||
ok_eq_hex64(TestThreadStartupContext.Rsi, Context.Rsi);
|
||||
ok_eq_hex64(TestThreadStartupContext.Rdi, Context.Rdi);
|
||||
ok_eq_hex64(TestThreadStartupContext.R8, Context.R8);
|
||||
ok_eq_hex64(TestThreadStartupContext.R9, Context.R9);
|
||||
ok_eq_hex64(TestThreadStartupContext.R10, Context.R10);
|
||||
ok_eq_hex64(TestThreadStartupContext.R11, Context.R11);
|
||||
ok_eq_hex64(TestThreadStartupContext.R12, Context.R12);
|
||||
ok_eq_hex64(TestThreadStartupContext.R13, Context.R13);
|
||||
ok_eq_hex64(TestThreadStartupContext.R14, Context.R14);
|
||||
ok_eq_hex64(TestThreadStartupContext.R15, Context.R15);
|
||||
|
||||
/* Segments (hardcoded) */
|
||||
ok_eq_hex(TestThreadStartupContext.SegDs, KGDT64_R3_DATA | RPL_MASK);
|
||||
ok_eq_hex(TestThreadStartupContext.SegEs, KGDT64_R3_DATA | RPL_MASK);
|
||||
ok_eq_hex(TestThreadStartupContext.SegFs, KGDT64_R3_CMTEB | RPL_MASK);
|
||||
ok_eq_hex(TestThreadStartupContext.SegGs, KGDT64_R3_DATA | RPL_MASK);
|
||||
|
||||
/* Floating point (hardcoded) */
|
||||
ok_eq_hex64(TestThreadStartupContext.MxCsr, INITIAL_MXCSR);
|
||||
ok_eq_hex(TestThreadStartupContext.FltSave.ControlWord, INITIAL_FPCSR);
|
||||
ok_eq_hex(TestThreadStartupContext.FltSave.StatusWord, 0x0000);
|
||||
ok_eq_hex(TestThreadStartupContext.FltSave.TagWord, 0x00);
|
||||
ok_eq_hex(TestThreadStartupContext.FltSave.Reserved1, 0x00);
|
||||
ok_eq_hex(TestThreadStartupContext.FltSave.ErrorOpcode, 0x0000);
|
||||
ok_eq_hex(TestThreadStartupContext.FltSave.ErrorOffset, 0x00000000);
|
||||
ok_eq_hex(TestThreadStartupContext.FltSave.ErrorSelector, 0x0000);
|
||||
ok_eq_hex(TestThreadStartupContext.FltSave.Reserved2, 0x0000);
|
||||
ok_eq_hex(TestThreadStartupContext.FltSave.DataOffset, 0x00000000);
|
||||
ok_eq_hex(TestThreadStartupContext.FltSave.DataSelector, 0x0000);
|
||||
ok_eq_hex(TestThreadStartupContext.FltSave.Reserved3, 0x0000);
|
||||
ok_eq_hex(TestThreadStartupContext.FltSave.MxCsr, INITIAL_MXCSR);
|
||||
ok_eq_hex(TestThreadStartupContext.FltSave.MxCsr_Mask, 0x0002FFFF);
|
||||
for (ULONG i = 0; i < ARRAYSIZE(TestThreadStartupContext.FltSave.FloatRegisters); i++)
|
||||
{
|
||||
ok_eq_hex64(TestThreadStartupContext.FltSave.FloatRegisters[i].Low, 0x0000000000000000ull);
|
||||
ok_eq_hex64(TestThreadStartupContext.FltSave.FloatRegisters[i].High, 0x0000000000000000ull);
|
||||
}
|
||||
PM128A XmmRegisters = &TestThreadStartupContext.Xmm0;
|
||||
for (ULONG i = 0; i < 16; i++)
|
||||
{
|
||||
ok_eq_hex64(XmmRegisters[i].Low, 0x0000000000000000ull);
|
||||
ok_eq_hex64(XmmRegisters[i].High, 0x0000000000000000ull);
|
||||
}
|
||||
for (ULONG i = 0; i < ARRAYSIZE(TestThreadStartupContext.VectorRegister); i++)
|
||||
{
|
||||
ok_eq_hex64(TestThreadStartupContext.VectorRegister[i].Low, 0xCCCCCCCCCCCCCCCCull);
|
||||
ok_eq_hex64(TestThreadStartupContext.VectorRegister[i].High, 0xCCCCCCCCCCCCCCCCull);
|
||||
}
|
||||
|
||||
/* Debug registers (reset to 0) */
|
||||
ok_eq_hex64(TestThreadStartupContext.Dr0, 0x0000000000000000ull);
|
||||
ok_eq_hex64(TestThreadStartupContext.Dr1, 0x0000000000000000ull);
|
||||
ok_eq_hex64(TestThreadStartupContext.Dr2, 0x0000000000000000ull);
|
||||
ok_eq_hex64(TestThreadStartupContext.Dr3, 0x0000000000000000ull);
|
||||
ok_eq_hex64(TestThreadStartupContext.Dr6, 0x0000000000000000ull);
|
||||
ok_eq_hex64(TestThreadStartupContext.Dr7, 0x0000000000000000ull);
|
||||
|
||||
#elif defined(_M_IX86)
|
||||
|
||||
/* Control */
|
||||
ok_eq_hex(TestThreadStartupContext.Esp, Context.Esp);
|
||||
ok_eq_hex(TestThreadStartupContext.EFlags, IsWow64 ? 0x00240ED7 : 0x003C4ED7);
|
||||
|
||||
/* Integer (copied) */
|
||||
ok_eq_hex(TestThreadStartupContext.Eax, Context.Eax);
|
||||
ok_eq_hex(TestThreadStartupContext.Ecx, Context.Ecx);
|
||||
ok_eq_hex(TestThreadStartupContext.Edx, Context.Edx);
|
||||
ok_eq_hex(TestThreadStartupContext.Ebx, Context.Ebx);
|
||||
ok_eq_hex(TestThreadStartupContext.Ebp, Context.Ebp);
|
||||
ok_eq_hex(TestThreadStartupContext.Esi, Context.Esi);
|
||||
ok_eq_hex(TestThreadStartupContext.Edi, Context.Edi);
|
||||
|
||||
/* Segments (hardcoded, the upper 16 bits are left uninitialized by RtlCaptureContext) */
|
||||
ok_eq_hex((USHORT)TestThreadStartupContext.SegCs, IsWow64 ? KGDT64_R3_CMCODE | RPL_MASK : KGDT_R3_CODE | RPL_MASK);
|
||||
ok_eq_hex((USHORT)TestThreadStartupContext.SegDs, IsWow64 ? KGDT64_R3_DATA | RPL_MASK : KGDT_R3_DATA | RPL_MASK);
|
||||
ok_eq_hex((USHORT)TestThreadStartupContext.SegEs, IsWow64 ? KGDT64_R3_DATA | RPL_MASK : KGDT_R3_DATA | RPL_MASK);
|
||||
ok_eq_hex((USHORT)TestThreadStartupContext.SegFs, IsWow64 ? KGDT64_R3_CMTEB | RPL_MASK : KGDT_R3_TEB | RPL_MASK);
|
||||
ok_eq_hex((USHORT)TestThreadStartupContext.SegGs, IsWow64 ? KGDT64_R3_DATA | RPL_MASK : 0x0000);
|
||||
ok_eq_hex((USHORT)TestThreadStartupContext.SegSs, IsWow64 ? KGDT64_R3_DATA | RPL_MASK : KGDT_R3_DATA | RPL_MASK);
|
||||
|
||||
/* Floating point (hardcoded) */
|
||||
ok_eq_hex(TestThreadStartupContext.FloatSave.ControlWord, IsWow64 ? 0x27F : 0xFFFF0A6A);
|
||||
ok_eq_hex(TestThreadStartupContext.FloatSave.StatusWord, IsWow64 ? 0 : 0xFFFF2A2A);
|
||||
ok_eq_hex(TestThreadStartupContext.FloatSave.TagWord, IsWow64 ? 0x0000FFFF : 0xFFFF0000);
|
||||
ok_eq_hex(TestThreadStartupContext.FloatSave.ErrorOffset, IsWow64 ? 0 : 0xAAAAAAAA);
|
||||
ok_eq_hex(TestThreadStartupContext.FloatSave.ErrorSelector, IsWow64 ? 0 : 0x02AAAAAA);
|
||||
ok_eq_hex(TestThreadStartupContext.FloatSave.DataOffset, IsWow64 ? 0 : 0xAAAAAAAA);
|
||||
ok_eq_hex(TestThreadStartupContext.FloatSave.DataSelector, IsWow64 ? 0 : 0xFFFFAAAA);
|
||||
|
||||
/* Debug registers (reset to 0) */
|
||||
ok_eq_hex(TestThreadStartupContext.Dr0, 0x00000000);
|
||||
ok_eq_hex(TestThreadStartupContext.Dr1, 0x00000000);
|
||||
ok_eq_hex(TestThreadStartupContext.Dr2, 0x00000000);
|
||||
ok_eq_hex(TestThreadStartupContext.Dr3, 0x00000000);
|
||||
ok_eq_hex(TestThreadStartupContext.Dr6, 0x00000000);
|
||||
ok_eq_hex(TestThreadStartupContext.Dr7, 0x00000000);
|
||||
|
||||
#else
|
||||
|
||||
#pragma message("Missing CONTEXT validation in NtCreateThread test")
|
||||
ASSERT(FALSE);
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(_M_AMD64) || defined(_M_IX86)
|
||||
/* Test Eflags set to 0 */
|
||||
Context.EFlags = 0;
|
||||
TestThreadStartupContext.EFlags = 0xCCCCCCCC;
|
||||
Status = NtCreateThread(&ThreadHandle,
|
||||
THREAD_ALL_ACCESS,
|
||||
NULL,
|
||||
NtCurrentProcess(),
|
||||
&ClientId,
|
||||
&Context,
|
||||
&InitialTeb,
|
||||
TRUE);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
NtResumeThread(ThreadHandle, NULL);
|
||||
WaitForSingleObject(ThreadHandle, INFINITE);
|
||||
CloseHandle(ThreadHandle);
|
||||
ok_eq_hex(TestThreadStartupContext.EFlags, 0x202);
|
||||
#endif
|
||||
|
||||
#if !defined(_M_IX86) // FIXME: This crashes on x86
|
||||
/* Test different InitialTeb values */
|
||||
InitialTeb.PreviousStackBase = Stack;
|
||||
InitialTeb.PreviousStackLimit = NULL;
|
||||
Status = NtCreateThread(&ThreadHandle,
|
||||
THREAD_ALL_ACCESS,
|
||||
NULL,
|
||||
NtCurrentProcess(),
|
||||
&ClientId,
|
||||
&Context,
|
||||
&InitialTeb,
|
||||
FALSE);
|
||||
ok_eq_hex(Status, (GetNTVersion() >= _WIN32_WINNT_WIN10) ? STATUS_NOT_SUPPORTED : STATUS_SUCCESS);
|
||||
|
||||
InitialTeb.PreviousStackBase = NULL;
|
||||
InitialTeb.PreviousStackLimit = Stack;
|
||||
Status = NtCreateThread(&ThreadHandle,
|
||||
THREAD_ALL_ACCESS,
|
||||
NULL,
|
||||
NtCurrentProcess(),
|
||||
&ClientId,
|
||||
&Context,
|
||||
&InitialTeb,
|
||||
FALSE);
|
||||
ok_eq_hex(Status, (GetNTVersion() >= _WIN32_WINNT_WIN10) ? STATUS_NOT_SUPPORTED : STATUS_SUCCESS);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* PROJECT: ReactOS API tests
|
||||
* LICENSE: MIT (https://spdx.org/licenses/MIT)
|
||||
* PURPOSE: Helper functions for NtCreateThread test
|
||||
* COPYRIGHT: Copyright 2026 Timo Kreuzer <timo.kreuzer@reactos.org>
|
||||
*/
|
||||
|
||||
#include <asm.inc>
|
||||
#include <ksamd64.inc>
|
||||
|
||||
.code64
|
||||
|
||||
EXTERN RtlCaptureContext:PROC
|
||||
EXTERN TestThreadProcPtr:QWORD
|
||||
EXTERN TestThreadStartupContext:QWORD
|
||||
|
||||
PUBLIC ThreadStartupThunk
|
||||
.PROC ThreadStartupThunk
|
||||
|
||||
pushfq
|
||||
push rcx
|
||||
sub rsp, 5 * 8
|
||||
.ENDPROLOG
|
||||
|
||||
lea rcx, TestThreadStartupContext[rip]
|
||||
call RtlCaptureContext
|
||||
|
||||
/* Save original rcx */
|
||||
mov rcx, [rsp + 5 * 8]
|
||||
mov TestThreadStartupContext[rip + CxRcx], rcx
|
||||
|
||||
/* Save original eflags */
|
||||
mov rcx, [rsp + 6 * 8]
|
||||
mov TestThreadStartupContext[rip + CxEFlags], rcx
|
||||
|
||||
/* Fix Rsp */
|
||||
lea rcx, [rsp + 7 * 8]
|
||||
mov qword ptr TestThreadStartupContext[rip + CxRsp], rcx
|
||||
|
||||
add rsp, 7 * 8
|
||||
jmp qword ptr TestThreadProcPtr[rip]
|
||||
|
||||
.ENDP
|
||||
|
||||
END
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* PROJECT: ReactOS API tests
|
||||
* LICENSE: MIT (https://spdx.org/licenses/MIT)
|
||||
* PURPOSE: Helper functions for NtCreateThread test
|
||||
* COPYRIGHT: Copyright 2026 Timo Kreuzer <timo.kreuzer@reactos.org>
|
||||
*/
|
||||
|
||||
#include <asm.inc>
|
||||
#include <ks386.inc>
|
||||
|
||||
.code
|
||||
|
||||
EXTERN _RtlCaptureContext@4:PROC
|
||||
EXTERN _TestThreadProcPtr:DWORD
|
||||
EXTERN _TestThreadStartupContext:DWORD
|
||||
|
||||
TempEflags:
|
||||
.long 0
|
||||
|
||||
PUBLIC _ThreadStartupThunk
|
||||
.PROC _ThreadStartupThunk
|
||||
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
|
||||
/* Save EFlags */
|
||||
pushfd
|
||||
|
||||
/* Clear direction flag */
|
||||
cld
|
||||
|
||||
/* Capture the context */
|
||||
push offset _TestThreadStartupContext
|
||||
call _RtlCaptureContext@4
|
||||
|
||||
/* Fix up control registers */
|
||||
pop eax
|
||||
mov [_TestThreadStartupContext + CsEflags], eax
|
||||
lea eax, [esp + 4]
|
||||
mov [_TestThreadStartupContext + CsEsp], eax
|
||||
lea eax, _ThreadStartupThunk
|
||||
mov [_TestThreadStartupContext + CsEip], eax
|
||||
|
||||
pop ebp
|
||||
jmp dword ptr [_TestThreadProcPtr]
|
||||
|
||||
.ENDP
|
||||
|
||||
END
|
||||
Reference in New Issue
Block a user