public static IntPtr GetTlsPointer(int threadId) { IntPtr threadHandle = IntPtr.Zero; try { threadHandle = OpenThread(ThreadAccess.QUERY_INFORMATION, false, threadId); THREAD_BASIC_INFORMATION threadInfo = new THREAD_BASIC_INFORMATION(); int status = NtQueryInformationThread(threadHandle, 0, &threadInfo, (ulong)sizeof(THREAD_BASIC_INFORMATION), null); if (status != 0) { Rage.Game.LogTrivialDebug($"Thread Invalid Query Status: {status}"); return(IntPtr.Zero); } TEB *teb = (TEB *)threadInfo.TebBaseAddress; return(teb->ThreadLocalStoragePointer); } finally { if (threadHandle != IntPtr.Zero) { CloseHandle(threadHandle); } } }
public static void CopyTlsValues(IntPtr sourceThreadHandle, IntPtr targetThreadHandle, params int[] valuesOffsets) { THREAD_BASIC_INFORMATION sourceThreadInfo = new THREAD_BASIC_INFORMATION(); THREAD_BASIC_INFORMATION targetThreadInfo = new THREAD_BASIC_INFORMATION(); int sourceStatus = NtQueryInformationThread(sourceThreadHandle, 0, &sourceThreadInfo, (ulong)sizeof(THREAD_BASIC_INFORMATION), null); if (sourceStatus != 0) { Rage.Game.LogTrivialDebug($"Source Thread Invalid Query Status: {sourceStatus}"); return; } int targetStatus = NtQueryInformationThread(targetThreadHandle, 0, &targetThreadInfo, (ulong)sizeof(THREAD_BASIC_INFORMATION), null); if (targetStatus != 0) { Rage.Game.LogTrivialDebug($"Target Thread Invalid Query Status: {targetStatus}"); return; } TEB *sourceTeb = (TEB *)sourceThreadInfo.TebBaseAddress; TEB *targetTeb = (TEB *)targetThreadInfo.TebBaseAddress; foreach (int offset in valuesOffsets) { *(long *)(*(byte **)(targetTeb->ThreadLocalStoragePointer) + offset) = *(long *)(*(byte **)(sourceTeb->ThreadLocalStoragePointer) + offset); } }
public static void CopyTlsValues(IntPtr sourceThreadHandle, IntPtr targetThreadHandle, params int[] valuesOffsets) { THREAD_BASIC_INFORMATION sourceThreadInfo, targetThreadInfo; if (!threadInformationDictionary.TryGetValue(sourceThreadHandle, out sourceThreadInfo)) { sourceThreadInfo = new THREAD_BASIC_INFORMATION(); int sourceStatus = Win32Native.NtQueryInformationThread(sourceThreadHandle, 0, &sourceThreadInfo, (ulong)sizeof(THREAD_BASIC_INFORMATION), null); if (sourceStatus != 0) { ScriptCore.Logger.Log($"Source Thread Invalid Query Status: {sourceStatus}"); return; } threadInformationDictionary[sourceThreadHandle] = sourceThreadInfo; } if (!threadInformationDictionary.TryGetValue(targetThreadHandle, out targetThreadInfo)) { targetThreadInfo = new THREAD_BASIC_INFORMATION(); int sourceStatus = Win32Native.NtQueryInformationThread(targetThreadHandle, 0, &targetThreadInfo, (ulong)sizeof(THREAD_BASIC_INFORMATION), null); if (sourceStatus != 0) { ScriptCore.Logger.Log($"Source Thread Invalid Query Status: {sourceStatus}"); return; } threadInformationDictionary[targetThreadHandle] = targetThreadInfo; } TEB *sourceTeb = (TEB *)sourceThreadInfo.TebBaseAddress; TEB *targetTeb = (TEB *)targetThreadInfo.TebBaseAddress; foreach (int offset in valuesOffsets) { *(long *)(*(byte **)(targetTeb->ThreadLocalStoragePointer) + offset) = *(long *)(*(byte **)(sourceTeb->ThreadLocalStoragePointer) + offset); } }