Всем привет есть несколько TLS переменных dwTlsRet dwTlsRetAddr создаваемых с помощью TlsAlloc в которых потоки сохраняют указатель на адрес возврата если он в хук зашел и обнуляют их если из хука вышел потом в любой момент времени все они усыпляются NtSuspendProcess создается новый поток ему надо просмотреть TLS переменные замароженных потоков и пофиксить адреса возврата для некоторых суть в том как прочитать эти самые TLS переменные для другого потока ? Windows XP x86 (32-bit)
Да никак вроде если документировано и без костылей. Коли уж пошли грабли то SetThreadContext на ваш кусок кода читающий TLS может быть
могу ошибаться, но мне казалось, что в TEB'е потока хранятся ссылки на TLS-переменные... попробуй пошарить по структуре, поискать... указатель на TEB можно как обычно получить из контекста потока (SegFs для x86, SegGs для x64)...
дизассемблировал TlsGetValue от windows xp и vista алгоритм и ограничения идентичные теперь надо попробовать GetThreadContext SegFs для каждого потока а потом выполнить поиск по этом алгоритму Код (Text): код для windows xp LPVOID __stdcall TlsGetValue(DWORD dwTlsIndex) { unsigned __int32 v1; // eax@1 int v3; // eax@7 v1 = __readfsdword(24); if ( dwTlsIndex < 0x40 ) // 0x40 TLS_MINIMUM_AVAILABLE { *(_DWORD *)(v1 + 52) = 0; return *(LPVOID *)(v1 + 4 * dwTlsIndex + 3600); } if ( dwTlsIndex >= 0x440 ) // maximum 1088 indexes per process { sub_7C80937B(-1073741811); // error report return 0; } *(_DWORD *)(v1 + 52) = 0; v3 = *(_DWORD *)(v1 + 3988); if ( !v3 ) return 0; return *(LPVOID *)(v3 + 4 * dwTlsIndex - 256); } код для vista LPVOID __stdcall TlsGetValue(DWORD dwTlsIndex) { int v1; // eax@5 unsigned __int32 v2; // eax@1 v2 = __readfsdword(24); *(_DWORD *)(v2 + 52) = 0; if ( dwTlsIndex < 0x40 ) // 0x40 TLS_MINIMUM_AVAILABLE return *(LPVOID *)(v2 + 4 * dwTlsIndex + 3600); if ( dwTlsIndex >= 0x440 ) // maximum 1088 indexes per process { sub_77E3C58C(-1073741811); // error report } else { v1 = *(_DWORD *)(v2 + 3988); if ( v1 ) return *(LPVOID *)(v1 + 4 * dwTlsIndex - 256); } return 0; } и еще попробовал получить код с windows 7 но там с kernel32.dll вызовы уходят в разные длл типа миниподсистем так вот они все размером 4 - 5 кб пример Код (Text): kernel32.dll!TlsGetValue LPVOID __stdcall TlsGetValue(DWORD dwTlsIndex) { return TlsGetValue_0(dwTlsIndex); // Imports from API-MS-Win-Core-ProcessThreads-L1-1-0.dll } но API-MS-Win-Core-ProcessThreads-L1-1-0.dll всего 5 кб там есть только TlsGetValue и выглядит она так LPVOID __stdcall TlsGetValue(DWORD dwTlsIndex) { return 0; } ну и где собственно сам код искать ? [append] насчет замарочек в windows 7 с импортом http://www.nirsoft.net/articles/windows_7_kernel_architecture_changes.html а вот и код выдранный из windows 7 там TlsGetValue находится в kernelbase.dll причем все хитро сделано kernel32.dll ссылается на "пустую" API-MS-Win-Core-ProcessThreads-L1-1-0.dll а загрузчик подставляет адрес из kernelbase.dll по ссылке подробно описано Код (Text): LPVOID __stdcall TlsGetValue(DWORD dwTlsIndex) { unsigned __int32 v1; // eax@1 LPVOID result; // eax@2 int v3; // eax@5 v1 = __readfsdword(24); *(_DWORD *)(v1 + 52) = 0; if ( dwTlsIndex >= 0x40 ) { if ( dwTlsIndex >= 0x440 ) { sub_DCE6AF5(-1073741811); JUMPOUT(loc_DCE8AC6); } v3 = *(_DWORD *)(v1 + 3988); JUMPOUT(v3, 0, loc_DCE8AC6); result = *(LPVOID *)(v3 + 4 * dwTlsIndex - 256); } else { result = *(LPVOID *)(v1 + 4 * dwTlsIndex + 3600); } return result; } как видим алгоритм не меняется на всей линейке от nt 5.1 до nt 6.1 значит можно и самодельный алгоритм поиска запилить (через GetThreadContext SegFs) в надежде на переносимость
http://msdn.microsoft.com/ru-ru/magazine/cc301808(en-us).aspx она в NTDLL UPD: обманул kernelbase.dll
накидал простенький код проверить работает или нет в том то и дело что SegFs имеет значение 0x0000003b для всех потоков как его преобразовать в адрес TEB типа 0x7ffdf000 не совсем понятно этот код не работает Код (Text): #include <stdio.h> #include <windows.h> #include <intrin.h> LPVOID WINAPI TlsGetValueEx(DWORD SegFs, DWORD dwTlsIndex) { int v1; // eax@5 unsigned __int32 v2; // eax@1 v2 = *(DWORD *)(SegFs + 24); *(DWORD *)(v2 + 52) = 0; if ( dwTlsIndex < 0x40 ) // 0x40 TLS_MINIMUM_AVAILABLE return *(LPVOID *)(v2 + 4 * dwTlsIndex + 3600); if ( dwTlsIndex >= 0x440 ) // maximum 1088 indexes per process { __asm int 3; // bad index } else { v1 = *(DWORD *)(v2 + 3988); if ( v1 ) return *(LPVOID *)(v1 + 4 * dwTlsIndex - 256); } return 0; } DWORD dwTlsIndex; volatile LONG var = 0xdeadbeef; DWORD WINAPI TestTls(LPVOID) { InterlockedIncrement(&var); TlsSetValue(dwTlsIndex, (LPVOID)var); Sleep(-1); return 0; } int main() { dwTlsIndex = TlsAlloc(); HANDLE th1 = CreateThread(0, 0, TestTls, 0, 0, 0); HANDLE th2 = CreateThread(0, 0, TestTls, 0, 0, 0); Sleep(5000); CONTEXT ctx1, ctx2; SuspendThread(th1); SuspendThread(th2); ctx1.ContextFlags = ctx2.ContextFlags = CONTEXT_FULL; GetThreadContext(th1, &ctx1); GetThreadContext(th2, &ctx2); LPVOID v1 = TlsGetValueEx(ctx1.SegFs, dwTlsIndex); // SegFs == 0x0000003b LPVOID v2 = TlsGetValueEx(ctx2.SegFs, dwTlsIndex); // SegFs == 0x0000003b printf("%p %p\n", v1, v2); } по сути задача свелась к тому что бы по id потока получить указатель на его TEB
Код (Text): GetThreadSelectorEntry([b]hThread[/b],ctx.SegFs,LDTE) Код (Text): typedef struct _LDT_ENTRY { WORD LimitLow; WORD BaseLow; union { struct { BYTE BaseMid; BYTE Flags1; BYTE Flags2; BYTE BaseHi; } Bytes; struct { DWORD BaseMid :8; DWORD Type :5; DWORD Dpl :2; DWORD Pres :1; DWORD LimitHi :4; DWORD Sys :1; DWORD Reserved_0 :1; DWORD Default_Big :1; DWORD Granularity :1; DWORD BaseHi :8; } Bits; } HighWord; } LDT_ENTRY, *PLDT_ENTRY;
все задача решена код заработал тестил только на windows xp так как остальные сейчас не загрузить (если не трудно проверьте на висте и семерке и в тему отпишитесь) всем кто помогал спасибо указатель на TEB конкретного потока вылавливается через NtQueryInformationThread с классом ThreadBasicInformation заполняется такая структурка Код (Text): typedef struct _THREAD_BASIC_INFORMATION { NTSTATUS ExitStatus; PTEB TebBaseAddress; CLIENT_ID ClientID; KAFFINITY AffinityMask; KPRIORITY BasePriority; KPRIORITY Priority; } THREAD_BASIC_INFORMATION, *PTHREAD_BASIC_INFORMATION; вот полный рабочий код Код (Text): #include <stdio.h> #include <windows.h> #include <intrin.h> #include <ntdll1.h> LPVOID WINAPI TlsGetValueEx(DWORD SegFs, DWORD dwTlsIndex) { int v1; // eax@5 unsigned __int32 v2; // eax@1 v2 = *(DWORD *)(SegFs + 24); *(DWORD *)(v2 + 52) = 0; if ( dwTlsIndex < 0x40 ) // 0x40 TLS_MINIMUM_AVAILABLE return *(LPVOID *)(v2 + 4 * dwTlsIndex + 3600); if ( dwTlsIndex >= 0x440 ) // maximum 1088 indexes per process { __asm int 3; // bad index } else { v1 = *(DWORD *)(v2 + 3988); if ( v1 ) return *(LPVOID *)(v1 + 4 * dwTlsIndex - 256); } return 0; } DWORD dwTlsIndex; volatile LONG var = 0xdeadbeef; DWORD WINAPI TestTls(LPVOID) { InterlockedIncrement(&var); TlsSetValue(dwTlsIndex, (LPVOID)var); Sleep(-1); return 0; } extern "C" NTSYSAPI NTSTATUS NTAPI NtQueryInformationThread( IN HANDLE ThreadHandle, IN THREADINFOCLASS ThreadInformationClass, OUT PVOID ThreadInformation, IN ULONG ThreadInformationLength, OUT PULONG ReturnLength OPTIONAL ); int main() { THREAD_BASIC_INFORMATION dd; dwTlsIndex = TlsAlloc(); HANDLE th1 = CreateThread(0, 0, TestTls, 0, 0, 0); HANDLE th2 = CreateThread(0, 0, TestTls, 0, 0, 0); Sleep(5000); NtQueryInformationThread(th1, ThreadBasicInformation, &dd, sizeof(dd), 0); LPVOID v1 = TlsGetValueEx((DWORD)dd.TebBaseAddress, dwTlsIndex); NtQueryInformationThread(th2, ThreadBasicInformation, &dd, sizeof(dd), 0); LPVOID v2 = TlsGetValueEx((DWORD)dd.TebBaseAddress, dwTlsIndex); printf("%p %p\n", v1, v2); }