From 8bcae8acaec70dbcc64ea870534284825a4ea733 Mon Sep 17 00:00:00 2001 From: Aaron Robinson Date: Sun, 4 May 2003 19:55:25 +0000 Subject: [PATCH] Pre-Entry execution!! --- Include/Win32/CxbxKrnl/Emu.h | 7 +- Include/Win32/CxbxKrnl/EmuFS.h | 2 +- Include/Win32/CxbxKrnl/Xapi.1.0.3911.h | 1 + Source/Win32/Cxbx/EmuExe.cpp | 31 ++- Source/Win32/Cxbx/Prolog.cpp | 1 + Source/Win32/CxbxKrnl/Emu.cpp | 267 ++++++++++++++----------- Source/Win32/CxbxKrnl/EmuFS.cpp | 31 ++- Source/Win32/CxbxKrnl/EmuKrnl.cpp | 2 +- Source/Win32/CxbxKrnl/EmuXapi.cpp | 104 ---------- 9 files changed, 205 insertions(+), 241 deletions(-) diff --git a/Include/Win32/CxbxKrnl/Emu.h b/Include/Win32/CxbxKrnl/Emu.h index 780929aae..484f2fab7 100644 --- a/Include/Win32/CxbxKrnl/Emu.h +++ b/Include/Win32/CxbxKrnl/Emu.h @@ -47,7 +47,7 @@ extern "C" CXBXKRNL_API void NTAPI EmuNoFunc(); // ****************************************************************** // * func: EmuInit // ****************************************************************** -extern "C" CXBXKRNL_API void NTAPI EmuInit(Xbe::TLS *pTLS, Xbe::LibraryVersion *LibraryVersion, DebugMode DbgMode, char *szDebugFilename, Xbe::Header *XbeHeader, uint32 XbeHeaderSize, void (*Entry)()); +extern "C" CXBXKRNL_API void NTAPI EmuInit(void *pTLSData, Xbe::TLS *pTLS, Xbe::LibraryVersion *LibraryVersion, DebugMode DbgMode, char *szDebugFilename, Xbe::Header *XbeHeader, uint32 XbeHeaderSize, void (*Entry)()); // ****************************************************************** // * func: EmuCleanup @@ -74,4 +74,9 @@ extern "C" CXBXKRNL_API uint32 KernelThunkTable[367]; // ****************************************************************** extern Xbe::TLS *g_pTLS; +// ****************************************************************** +// * data: pTLSData +// ****************************************************************** +extern void *g_pTLSData; + #endif diff --git a/Include/Win32/CxbxKrnl/EmuFS.h b/Include/Win32/CxbxKrnl/EmuFS.h index 4b017b88f..475735a5e 100644 --- a/Include/Win32/CxbxKrnl/EmuFS.h +++ b/Include/Win32/CxbxKrnl/EmuFS.h @@ -83,7 +83,7 @@ static inline bool EmuIsXboxFS() // ****************************************************************** // * func: EmuGenerateFS // ****************************************************************** -void EmuGenerateFS(Xbe::TLS *pTLS); +void EmuGenerateFS(Xbe::TLS *pTLS, void *pTLSData); // ****************************************************************** // * func: EmuCleanupFS diff --git a/Include/Win32/CxbxKrnl/Xapi.1.0.3911.h b/Include/Win32/CxbxKrnl/Xapi.1.0.3911.h index c52a0904d..ee86345de 100644 --- a/Include/Win32/CxbxKrnl/Xapi.1.0.3911.h +++ b/Include/Win32/CxbxKrnl/Xapi.1.0.3911.h @@ -36,6 +36,7 @@ #include "OOVPA.h" +extern SOOVPA<9> __cinit_1_0_3911; extern OOVPATable XAPI_1_0_3911[]; extern uint32 XAPI_1_0_3911_SIZE; diff --git a/Source/Win32/Cxbx/EmuExe.cpp b/Source/Win32/Cxbx/EmuExe.cpp index 0cb592946..c875749ae 100644 --- a/Source/Win32/Cxbx/EmuExe.cpp +++ b/Source/Win32/Cxbx/EmuExe.cpp @@ -323,7 +323,9 @@ EmuExe::EmuExe(Xbe *x_Xbe, DebugMode x_debug_mode, char *x_debug_filename) : Exe // * generate .cxbxplg section virtual size / addr // ****************************************************************** { - uint32 virt_size = RoundUp(m_OptionalHeader.m_image_base + 0x100 + x_Xbe->m_Header.dwSizeofHeaders + 260 + sizeof(Xbe::LibraryVersion) * x_Xbe->m_Header.dwLibraryVersions + sizeof(Xbe::TLS), 0x1000); + uint32 virt_size = RoundUp(m_OptionalHeader.m_image_base + 0x100 + x_Xbe->m_Header.dwSizeofHeaders + 260 + + sizeof(Xbe::LibraryVersion) * x_Xbe->m_Header.dwLibraryVersions + sizeof(Xbe::TLS) + + (x_Xbe->m_TLS->dwDataEndAddr - x_Xbe->m_TLS->dwDataStartAddr), 0x1000); uint32 virt_addr = RoundUp(m_SectionHeader[i-1].m_virtual_addr + m_SectionHeader[i-1].m_virtual_size, PE_SEGM_ALIGN); m_SectionHeader[i].m_virtual_size = virt_size; @@ -514,6 +516,8 @@ EmuExe::EmuExe(Xbe *x_Xbe, DebugMode x_debug_mode, char *x_debug_filename) : Exe { memcpy(pWriteCursor, x_Xbe->m_TLS, sizeof(Xbe::TLS)); pWriteCursor += sizeof(Xbe::TLS); + memcpy(pWriteCursor, x_Xbe->GetTLSData(), (x_Xbe->m_TLS->dwDataEndAddr - x_Xbe->m_TLS->dwDataStartAddr)); + pWriteCursor += (x_Xbe->m_TLS->dwDataEndAddr - x_Xbe->m_TLS->dwDataStartAddr); } // ****************************************************************** @@ -524,24 +528,24 @@ EmuExe::EmuExe(Xbe *x_Xbe, DebugMode x_debug_mode, char *x_debug_filename) : Exe // Function Pointer *(uint32 *)((uint32)m_bzSection[i] + 1) = (uint32)EmuInit; - // Param 7 : Entry + // Param 8 : Entry *(uint32 *)((uint32)m_bzSection[i] + 6) = (uint32)ep; - // Param 6 : dwXbeHeaderSize + // Param 7 : dwXbeHeaderSize *(uint32 *)((uint32)m_bzSection[i] + 11) = (uint32)x_Xbe->m_Header.dwSizeofHeaders; - // Param 5 : pXbeHeader + // Param 6 : pXbeHeader *(uint32 *)((uint32)m_bzSection[i] + 16) = WriteCursor; WriteCursor += x_Xbe->m_Header.dwSizeofHeaders; - // Param 4 : szDebugFilename + // Param 5 : szDebugFilename *(uint32 *)((uint32)m_bzSection[i] + 21) = WriteCursor; WriteCursor += 260; - // Param 3 : DbgMode + // Param 4 : DbgMode *(uint32 *)((uint32)m_bzSection[i] + 26) = x_debug_mode; - // Param 2 : pLibraryVersion + // Param 3 : pLibraryVersion if(x_Xbe->m_LibraryVersion != 0) { *(uint32 *)((uint32)m_bzSection[i] + 31) = WriteCursor; @@ -552,7 +556,7 @@ EmuExe::EmuExe(Xbe *x_Xbe, DebugMode x_debug_mode, char *x_debug_filename) : Exe *(uint32 *)((uint32)m_bzSection[i] + 31) = 0; } - // Param 1 : pTLS + // Param 2 : pTLS if(x_Xbe->m_TLS != 0) { *(uint32 *)((uint32)m_bzSection[i] + 36) = WriteCursor; @@ -563,6 +567,17 @@ EmuExe::EmuExe(Xbe *x_Xbe, DebugMode x_debug_mode, char *x_debug_filename) : Exe *(uint32 *)((uint32)m_bzSection[i] + 36) = 0; } + // Param 1 : pTLSData + if(x_Xbe->m_TLS != 0) + { + *(uint32 *)((uint32)m_bzSection[i] + 41) = WriteCursor; + WriteCursor += (x_Xbe->m_TLS->dwDataEndAddr - x_Xbe->m_TLS->dwDataStartAddr); + } + else + { + *(uint32 *)((uint32)m_bzSection[i] + 41) = 0; + } + printf("OK\n"); } } diff --git a/Source/Win32/Cxbx/Prolog.cpp b/Source/Win32/Cxbx/Prolog.cpp index 41bc55754..55dac5ccc 100644 --- a/Source/Win32/Cxbx/Prolog.cpp +++ b/Source/Win32/Cxbx/Prolog.cpp @@ -62,6 +62,7 @@ __declspec(allocate(".cxbxplg")) uint08 Prolog[] = 0x68, 0xC3, 0xC3, 0xC3, 0xC3, // push 0xC3C3C3C3 0x68, 0xC3, 0xC3, 0xC3, 0xC3, // push 0xC3C3C3C3 0x68, 0xC3, 0xC3, 0xC3, 0xC3, // push 0xC3C3C3C3 + 0x68, 0xC3, 0xC3, 0xC3, 0xC3, // push 0xC3C3C3C3 0xFF, 0xD6, // call esi 0xC3 // ret }; diff --git a/Source/Win32/CxbxKrnl/Emu.cpp b/Source/Win32/CxbxKrnl/Emu.cpp index c932350ad..2743b5a70 100644 --- a/Source/Win32/CxbxKrnl/Emu.cpp +++ b/Source/Win32/CxbxKrnl/Emu.cpp @@ -53,12 +53,14 @@ namespace xboxkrnl // * global / static // ****************************************************************** extern Xbe::TLS *g_pTLS = 0; +extern void *g_pTLSData = 0; // ****************************************************************** // * static // ****************************************************************** -static void EmuInstallWrappers(OOVPATable *OovpaTable, uint32 OovpaTableSize, void (*Entry)(), Xbe::Header *pXbeHeader); -static int ExitException(LPEXCEPTION_POINTERS e); +static void *EmuLocateFunction(OOVPA *Oovpa, uint32 lower, uint32 upper); +static void EmuInstallWrappers(OOVPATable *OovpaTable, uint32 OovpaTableSize, void (*Entry)(), Xbe::Header *pXbeHeader); +static int ExitException(LPEXCEPTION_POINTERS e); // ****************************************************************** // * func: DllMain @@ -104,6 +106,7 @@ static void EmuCleanThread() // ****************************************************************** extern "C" CXBXKRNL_API void NTAPI EmuInit ( + void *pTLSData, Xbe::TLS *pTLS, Xbe::LibraryVersion *pLibraryVersion, DebugMode DbgMode, @@ -113,6 +116,7 @@ extern "C" CXBXKRNL_API void NTAPI EmuInit void (*Entry)()) { g_pTLS = pTLS; + g_pTLSData = pTLSData; // ****************************************************************** // * debug console allocation (if configured) @@ -157,6 +161,7 @@ extern "C" CXBXKRNL_API void NTAPI EmuInit printf("Emu: EmuInit\n" "(\n" + " pTLSData : 0x%.08X\n" " pTLS : 0x%.08X\n" " pLibraryVersion : 0x%.08X\n" " DebugConsole : 0x%.08X\n" @@ -165,7 +170,7 @@ extern "C" CXBXKRNL_API void NTAPI EmuInit " pXBEHeaderSize : 0x%.08X\n" " Entry : 0x%.08X\n" ");\n", - pTLS, pLibraryVersion, DbgMode, szDebugFilename, pXbeHeader, dwXbeHeaderSize, Entry); + pTLSData, pTLS, pLibraryVersion, DbgMode, szDebugFilename, pXbeHeader, dwXbeHeaderSize, Entry); #else printf("CxbxKrnl (0x%.08X): _DEBUG_TRACE disabled.\n", GetCurrentThreadId()); @@ -190,8 +195,6 @@ extern "C" CXBXKRNL_API void NTAPI EmuInit memcpy(&MemXbeHeader->dwInitFlags, &pXbeHeader->dwInitFlags, sizeof(pXbeHeader->dwInitFlags)); - printf("pXbeHeader->dwCertificateAddr : 0x%.08X -> 0x%.08X\n", pXbeHeader->dwCertificateAddr, pXbeHeader->dwCertificateAddr + sizeof(Xbe::Certificate)); - memcpy((void*)pXbeHeader->dwCertificateAddr, &((uint08*)pXbeHeader)[pXbeHeader->dwCertificateAddr - 0x00010000], sizeof(Xbe::Certificate)); } @@ -201,7 +204,7 @@ extern "C" CXBXKRNL_API void NTAPI EmuInit { EmuInitFS(); - EmuGenerateFS(pTLS); + EmuGenerateFS(pTLS, pTLSData); } // ****************************************************************** @@ -210,6 +213,9 @@ extern "C" CXBXKRNL_API void NTAPI EmuInit if(pLibraryVersion == 0) printf("Emu: Detected OpenXDK application...\n"); + uint32 xca; + uint32 xcz; + // ****************************************************************** // * Initialize Microsoft XDK emulation // ****************************************************************** @@ -249,11 +255,50 @@ extern "C" CXBXKRNL_API void NTAPI EmuInit if(!found) printf("Skipped\n"); + + if(strcmp("XAPILIB", szLibraryName) == 0 && MajorVersion == 1 && MinorVersion == 0 && (BuildVersion == 4627 || BuildVersion == 4361 || BuildVersion == 4034 || BuildVersion == 3911)) + { + printf("Emu: Locating Pre-Entry Execution..."); + + uint32 lower = pXbeHeader->dwBaseAddr; + uint32 upper = pXbeHeader->dwBaseAddr + pXbeHeader->dwSizeofImage; + + void *pFunc = EmuLocateFunction((OOVPA*)&__cinit_1_0_3911, lower, upper); + + if(pFunc == 0) + printf("Skipped\n"); + else + { + xca = *(uint32*)((uint32)pFunc + 0x32); + xcz = *(uint32*)((uint32)pFunc + 0x39); + + printf("Found! @ 0x%.08X -> 0x%.08X\n", xca, xcz); + } + } } EmuD3DInit(pXbeHeader, dwXbeHeaderSize); } + // ****************************************************************** + // * Static/Constructors + // ****************************************************************** + for(uint32 v=xca;vCount; + + // ****************************************************************** + // * Large + // ****************************************************************** + if(Oovpa->Large == 1) + { + LOOVPA<1> *Loovpa = (LOOVPA<1>*)Oovpa; + + upper -= Loovpa->Lovp[count-1].Offset; + + // ****************************************************************** + // * Search all of the image memory + // ****************************************************************** + for(uint32 cur=lower;curLovp[v].Offset; + uint32 Value = Loovpa->Lovp[v].Value; + + uint08 RealValue = *(uint08*)(cur + Offset); + + if(RealValue != Value) + break; + } + + // ****************************************************************** + // * success if we found all pairs + // ****************************************************************** + if(v == count) + return (void*)cur; + } + } + // ****************************************************************** + // * Small + // ****************************************************************** + else + { + SOOVPA<1> *Soovpa = (SOOVPA<1>*)Oovpa; + + upper -= Soovpa->Sovp[count-1].Offset; + + // ****************************************************************** + // * Search all of the image memory + // ****************************************************************** + for(uint32 cur=lower;curSovp[v].Offset; + uint32 Value = Soovpa->Sovp[v].Value; + + uint08 RealValue = *(uint08*)(cur + Offset); + + if(RealValue != Value) + break; + } + + // ****************************************************************** + // * success if we found all pairs + // ****************************************************************** + if(v == count) + return (void*)cur; + } + } + + return 0; +} + // ****************************************************************** // * func: EmuInstallWrappers // ****************************************************************** void EmuInstallWrappers(OOVPATable *OovpaTable, uint32 OovpaTableSize, void (*Entry)(), Xbe::Header *pXbeHeader) { + uint32 lower = pXbeHeader->dwBaseAddr; + uint32 upper = pXbeHeader->dwBaseAddr + pXbeHeader->dwSizeofImage; + // ****************************************************************** // * traverse the full OOVPA table // ****************************************************************** @@ -362,127 +495,19 @@ void EmuInstallWrappers(OOVPATable *OovpaTable, uint32 OovpaTableSize, void (*En OOVPA *Oovpa = OovpaTable[a].Oovpa; - uint32 count = Oovpa->Count; - uint32 lower = pXbeHeader->dwBaseAddr; - uint32 upper = pXbeHeader->dwBaseAddr + pXbeHeader->dwSizeofImage; + void *pFunc = EmuLocateFunction(Oovpa, lower, upper); - // ****************************************************************** - // * Large - // ****************************************************************** - if(Oovpa->Large == 1) + if(pFunc != 0) { - LOOVPA<1> *Loovpa = (LOOVPA<1>*)Oovpa; + #ifdef _DEBUG_TRACE + printf("Found @ 0x%.08X\n", pFunc); + #endif - upper -= Loovpa->Lovp[count-1].Offset; - - bool found = false; - - // ****************************************************************** - // * Search all of the image memory - // ****************************************************************** - for(uint32 cur=lower;curLovp[v].Offset; - uint32 Value = Loovpa->Lovp[v].Value; - - uint08 RealValue = *(uint08*)(cur + Offset); - - if(RealValue != Value) - break; - } - - // ****************************************************************** - // * success if we found all pairs - // ****************************************************************** - if(v == count) - { - #ifdef _DEBUG_TRACE - printf("Found! (0x%.08X)\n", cur); - #endif - - EmuInstallWrapper((void*)cur, OovpaTable[a].lpRedirect); - - found = true; - - break; - } - } - - // ****************************************************************** - // * not found - // ****************************************************************** - if(!found) - { - #ifdef _DEBUG_TRACE - printf("None (OK)\n"); - #endif - } + EmuInstallWrapper(pFunc, OovpaTable[a].lpRedirect); } - // ****************************************************************** - // * Small - // ****************************************************************** else { - SOOVPA<1> *Soovpa = (SOOVPA<1>*)Oovpa; - - upper -= Soovpa->Sovp[count-1].Offset; - - bool found = false; - - // ****************************************************************** - // * Search all of the image memory - // ****************************************************************** - for(uint32 cur=lower;curSovp[v].Offset; - uint32 Value = Soovpa->Sovp[v].Value; - - uint08 RealValue = *(uint08*)(cur + Offset); - - if(RealValue != Value) - break; - } - - // ****************************************************************** - // * success if we found all pairs - // ****************************************************************** - if(v == count) - { - #ifdef _DEBUG_TRACE - printf("Found! (0x%.08X)\n", cur); - #endif - - EmuInstallWrapper((void*)cur, OovpaTable[a].lpRedirect); - - found = true; - - break; - } - } - - // ****************************************************************** - // * not found - // ****************************************************************** - if(!found) - { - #ifdef _DEBUG_TRACE - printf("None (OK)\n"); - #endif - } + printf("None (OK)\n"); } } } diff --git a/Source/Win32/CxbxKrnl/EmuFS.cpp b/Source/Win32/CxbxKrnl/EmuFS.cpp index dc0aae99b..7bcfaab48 100644 --- a/Source/Win32/CxbxKrnl/EmuFS.cpp +++ b/Source/Win32/CxbxKrnl/EmuFS.cpp @@ -60,13 +60,36 @@ void EmuInitFS() // ****************************************************************** // * func: EmuGenerateFS // ****************************************************************** -void EmuGenerateFS(Xbe::TLS *pTLS) +void EmuGenerateFS(Xbe::TLS *pTLS, void *pTLSData) { NT_TIB *OrgNtTib; xboxkrnl::KPCR *NewPcr; uint16 NewFS = -1, OrgFS = -1; + // ****************************************************************** + // * Dump Raw TLS data + // ****************************************************************** + { + #ifdef _DEBUG_TRACE + printf("CxbxKrnl (0x%.08X) : Dumping TLS Raw Data... \n 0x%.08X: ", GetCurrentThreadId(), pTLSData); + + uint32 stop = (pTLS->dwDataEndAddr - pTLS->dwDataStartAddr); + + for(uint32 v=0;vPrcb = &NewPcr->PrcbData; - NewPcr->PrcbData.CurrentThread->TlsData = (void*)pTLS->dwTLSIndexAddr; + NewPcr->PrcbData.CurrentThread->TlsData = (void*)pTLSData; } // ****************************************************************** @@ -148,11 +171,9 @@ void EmuGenerateFS(Xbe::TLS *pTLS) // * Save "TLSPtr" inside NewFS.StackBase // ****************************************************************** { - uint32 dwTLSIndexAddr = pTLS->dwTLSIndexAddr; - __asm { - mov eax, dwTLSIndexAddr + mov eax, pTLSData mov fs:[0x04], eax } } diff --git a/Source/Win32/CxbxKrnl/EmuKrnl.cpp b/Source/Win32/CxbxKrnl/EmuKrnl.cpp index 43ab5268b..43fe9d08e 100644 --- a/Source/Win32/CxbxKrnl/EmuKrnl.cpp +++ b/Source/Win32/CxbxKrnl/EmuKrnl.cpp @@ -115,7 +115,7 @@ static DWORD WINAPI PCSTProxy } #endif - EmuGenerateFS(g_pTLS); + EmuGenerateFS(g_pTLS, g_pTLSData); // ****************************************************************** // * use the special calling convention diff --git a/Source/Win32/CxbxKrnl/EmuXapi.cpp b/Source/Win32/CxbxKrnl/EmuXapi.cpp index d2cff42d0..1c02bb08a 100644 --- a/Source/Win32/CxbxKrnl/EmuXapi.cpp +++ b/Source/Win32/CxbxKrnl/EmuXapi.cpp @@ -50,56 +50,6 @@ namespace xapi #include "EmuD3D8.h" #include "EmuDInput.h" -// ****************************************************************** -// * EmuCreateThreadProxyParam -// ****************************************************************** -typedef struct _EmuCreateThreadProxyParam -{ - LPVOID lpParameter; - LPTHREAD_START_ROUTINE lpStartAddress; -} -EmuCreateThreadProxyParam; - -// ****************************************************************** -// * func: EmuCreateThreadProxy -// ****************************************************************** -static DWORD WINAPI EmuCreateThreadProxy -( - LPVOID lpParameter -) -{ - EmuCreateThreadProxyParam *iEmuCreateThreadProxyParam = (EmuCreateThreadProxyParam*)lpParameter; - - LPTHREAD_START_ROUTINE ilpStartAddress = iEmuCreateThreadProxyParam->lpStartAddress; - LPVOID ilpParam = iEmuCreateThreadProxyParam->lpParameter; - - delete iEmuCreateThreadProxyParam; - - EmuGenerateFS(g_pTLS); - - // ****************************************************************** - // * debug trace - // ****************************************************************** - #ifdef _DEBUG_TRACE - { - printf("EmuXapi (0x%.08X): EmuCreateThreadProxy\n" - "(\n" - " lpParameter : 0x%.08X\n" - ");\n", - GetCurrentThreadId(), lpParameter); - - } - #endif - - EmuSwapFS(); // XBox FS - - DWORD ret = ilpStartAddress(ilpParam); - - EmuSwapFS(); // Win2k/XP FS - - return ret; -} - // ****************************************************************** // * func: EmuXInitDevices // ****************************************************************** @@ -287,60 +237,6 @@ DWORD WINAPI xapi::EmuXInputGetState return ret; } -// ****************************************************************** -// * func: EmuCreateThread -// ****************************************************************** -HANDLE WINAPI xapi::EmuCreateThread -( - LPSECURITY_ATTRIBUTES lpThreadAttributes, - DWORD dwStackSize, - LPTHREAD_START_ROUTINE lpStartAddress, - LPVOID lpParameter, - DWORD dwCreationFlags, - LPDWORD lpThreadId -) -{ - EmuSwapFS(); // Win2k/XP FS - - // ****************************************************************** - // * debug trace - // ****************************************************************** - #ifdef _DEBUG_TRACE - { - printf("EmuXapi (0x%.08X): EmuCreateThread\n" - "(\n" - " lpThreadAttributes : 0x%.08X\n" - " dwStackSize : 0x%.08X\n" - " lpStartAddress : 0x%.08X\n" - " lpParameter : 0x%.08X\n" - " dwCreationFlags : 0x%.08X\n" - " lpThreadId : 0x%.08X\n" - ");\n", - GetCurrentThreadId(), lpThreadAttributes, dwStackSize, lpStartAddress, - lpParameter, dwCreationFlags, lpThreadId); - } - #endif - - EmuCreateThreadProxyParam *iEmuCreateThreadProxyParam = new EmuCreateThreadProxyParam(); - - iEmuCreateThreadProxyParam->lpParameter = lpParameter; - iEmuCreateThreadProxyParam->lpStartAddress = lpStartAddress; - - HANDLE RetHandle = CreateThread - ( - NULL, - dwStackSize, - EmuCreateThreadProxy, - iEmuCreateThreadProxyParam, - dwCreationFlags, - lpThreadId - ); - - EmuSwapFS(); // XBox FS - - return RetHandle; -} - // ****************************************************************** // * func: EmuCloseHandle // ******************************************************************