чтение TLS переменных другого потока

Тема в разделе "WASM.WIN32", создана пользователем 63F45EF45RB65R6VR, 18 ноя 2011.

  1. 63F45EF45RB65R6VR

    63F45EF45RB65R6VR New Member

    Публикаций:
    0
    Регистрация:
    26 окт 2011
    Сообщения:
    70
    Всем привет

    есть несколько TLS переменных dwTlsRet dwTlsRetAddr создаваемых с помощью TlsAlloc в которых потоки сохраняют указатель на адрес возврата если он в хук зашел и обнуляют их если из хука вышел потом в любой момент времени все они усыпляются NtSuspendProcess создается новый поток ему надо просмотреть TLS переменные замароженных потоков и пофиксить адреса возврата для некоторых суть в том как прочитать эти самые TLS переменные для другого потока ?

    Windows XP x86 (32-bit)
     
  2. punxer

    punxer Андрей

    Публикаций:
    0
    Регистрация:
    16 окт 2006
    Сообщения:
    1.327
    Адрес:
    Ржев
    Да никак вроде если документировано и без костылей. Коли уж пошли грабли то SetThreadContext на ваш кусок кода читающий TLS может быть
     
  3. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.323
    могу ошибаться, но мне казалось, что в TEB'е потока хранятся ссылки на TLS-переменные... попробуй пошарить по структуре, поискать... указатель на TEB можно как обычно получить из контекста потока (SegFs для x86, SegGs для x64)...
     
  4. punxer

    punxer Андрей

    Публикаций:
    0
    Регистрация:
    16 окт 2006
    Сообщения:
    1.327
    Адрес:
    Ржев
    Rel
    Да есть.
    Забыл.
    Тогда GetThreadContext
     
  5. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.323
  6. 63F45EF45RB65R6VR

    63F45EF45RB65R6VR New Member

    Публикаций:
    0
    Регистрация:
    26 окт 2011
    Сообщения:
    70
    дизассемблировал TlsGetValue от windows xp и vista алгоритм и ограничения идентичные теперь надо попробовать GetThreadContext SegFs для каждого потока а потом выполнить
    поиск по этом алгоритму

    Код (Text):
    1. код для windows xp
    2. LPVOID __stdcall TlsGetValue(DWORD dwTlsIndex)
    3. {
    4.   unsigned __int32 v1; // eax@1
    5.   int v3; // eax@7
    6.  
    7.   v1 = __readfsdword(24);
    8.   if ( dwTlsIndex < 0x40 ) // 0x40 TLS_MINIMUM_AVAILABLE
    9.   {
    10.     *(_DWORD *)(v1 + 52) = 0;
    11.     return *(LPVOID *)(v1 + 4 * dwTlsIndex + 3600);
    12.   }
    13.   if ( dwTlsIndex >= 0x440 ) // maximum 1088 indexes per process
    14.   {
    15.     sub_7C80937B(-1073741811); // error report
    16.     return 0;
    17.   }
    18.   *(_DWORD *)(v1 + 52) = 0;
    19.   v3 = *(_DWORD *)(v1 + 3988);
    20.   if ( !v3 )
    21.     return 0;
    22.   return *(LPVOID *)(v3 + 4 * dwTlsIndex - 256);
    23. }
    24.  
    25. код для vista
    26. LPVOID __stdcall TlsGetValue(DWORD dwTlsIndex)
    27. {
    28.   int v1; // eax@5
    29.   unsigned __int32 v2; // eax@1
    30.  
    31.   v2 = __readfsdword(24);
    32.   *(_DWORD *)(v2 + 52) = 0;
    33.   if ( dwTlsIndex < 0x40 ) // 0x40 TLS_MINIMUM_AVAILABLE
    34.     return *(LPVOID *)(v2 + 4 * dwTlsIndex + 3600);
    35.   if ( dwTlsIndex >= 0x440 ) // maximum 1088 indexes per process
    36.   {
    37.     sub_77E3C58C(-1073741811); // error report
    38.   }
    39.   else
    40.   {
    41.     v1 = *(_DWORD *)(v2 + 3988);
    42.     if ( v1 )
    43.       return *(LPVOID *)(v1 + 4 * dwTlsIndex - 256);
    44.   }
    45.   return 0;
    46. }
    и еще попробовал получить код с windows 7 но там с kernel32.dll вызовы уходят в разные длл типа миниподсистем так вот они все размером 4 - 5 кб пример
    Код (Text):
    1. kernel32.dll!TlsGetValue
    2. LPVOID __stdcall TlsGetValue(DWORD dwTlsIndex)
    3. {
    4.   return TlsGetValue_0(dwTlsIndex); // Imports from API-MS-Win-Core-ProcessThreads-L1-1-0.dll
    5. }
    6.  
    7. но API-MS-Win-Core-ProcessThreads-L1-1-0.dll всего 5 кб там есть только
    8. TlsGetValue и выглядит она так
    9.  
    10. LPVOID __stdcall TlsGetValue(DWORD dwTlsIndex)
    11. {
    12.   return 0;
    13. }
    ну и где собственно сам код искать ?
    [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):
    1. LPVOID __stdcall TlsGetValue(DWORD dwTlsIndex)
    2. {
    3.   unsigned __int32 v1; // eax@1
    4.   LPVOID result; // eax@2
    5.   int v3; // eax@5
    6.  
    7.   v1 = __readfsdword(24);
    8.   *(_DWORD *)(v1 + 52) = 0;
    9.   if ( dwTlsIndex >= 0x40 )
    10.   {
    11.     if ( dwTlsIndex >= 0x440 )
    12.     {
    13.       sub_DCE6AF5(-1073741811);
    14.       JUMPOUT(loc_DCE8AC6);
    15.     }
    16.     v3 = *(_DWORD *)(v1 + 3988);
    17.     JUMPOUT(v3, 0, loc_DCE8AC6);
    18.     result = *(LPVOID *)(v3 + 4 * dwTlsIndex - 256);
    19.   }
    20.   else
    21.   {
    22.     result = *(LPVOID *)(v1 + 4 * dwTlsIndex + 3600);
    23.   }
    24.   return result;
    25. }
    как видим алгоритм не меняется на всей линейке от nt 5.1 до nt 6.1 значит можно и самодельный алгоритм поиска запилить (через GetThreadContext SegFs) в надежде на переносимость
     
  7. punxer

    punxer Андрей

    Публикаций:
    0
    Регистрация:
    16 окт 2006
    Сообщения:
    1.327
    Адрес:
    Ржев
  8. 63F45EF45RB65R6VR

    63F45EF45RB65R6VR New Member

    Публикаций:
    0
    Регистрация:
    26 окт 2011
    Сообщения:
    70
    накидал простенький код проверить работает или нет
    в том то и дело что SegFs имеет значение 0x0000003b для всех потоков как его преобразовать
    в адрес TEB типа 0x7ffdf000 не совсем понятно этот код не работает
    Код (Text):
    1. #include <stdio.h>
    2. #include <windows.h>
    3. #include <intrin.h>
    4.  
    5. LPVOID WINAPI TlsGetValueEx(DWORD SegFs, DWORD dwTlsIndex)
    6. {
    7.   int v1; // eax@5
    8.   unsigned __int32 v2; // eax@1
    9.  
    10.   v2 = *(DWORD *)(SegFs + 24);
    11.   *(DWORD *)(v2 + 52) = 0;
    12.   if ( dwTlsIndex < 0x40 ) // 0x40 TLS_MINIMUM_AVAILABLE
    13.     return *(LPVOID *)(v2 + 4 * dwTlsIndex + 3600);
    14.   if ( dwTlsIndex >= 0x440 ) // maximum 1088 indexes per process
    15.   {
    16.     __asm int 3; // bad index
    17.   }
    18.   else
    19.   {
    20.     v1 = *(DWORD *)(v2 + 3988);
    21.     if ( v1 )
    22.       return *(LPVOID *)(v1 + 4 * dwTlsIndex - 256);
    23.   }
    24.   return 0;
    25. }
    26.  
    27. DWORD dwTlsIndex;
    28. volatile LONG var = 0xdeadbeef;
    29.  
    30. DWORD WINAPI TestTls(LPVOID)
    31. {
    32.     InterlockedIncrement(&var);
    33.     TlsSetValue(dwTlsIndex, (LPVOID)var);
    34.     Sleep(-1);
    35.     return 0;
    36. }
    37.  
    38. int main()
    39. {
    40.     dwTlsIndex = TlsAlloc();
    41.     HANDLE th1 = CreateThread(0, 0, TestTls, 0, 0, 0);
    42.     HANDLE th2 = CreateThread(0, 0, TestTls, 0, 0, 0);
    43.     Sleep(5000);
    44.     CONTEXT ctx1, ctx2;
    45.     SuspendThread(th1);
    46.     SuspendThread(th2);
    47.     ctx1.ContextFlags = ctx2.ContextFlags = CONTEXT_FULL;
    48.     GetThreadContext(th1, &ctx1);
    49.     GetThreadContext(th2, &ctx2);
    50.     LPVOID v1 = TlsGetValueEx(ctx1.SegFs, dwTlsIndex); // SegFs == 0x0000003b
    51.     LPVOID v2 = TlsGetValueEx(ctx2.SegFs, dwTlsIndex); // SegFs == 0x0000003b
    52.     printf("%p %p\n", v1, v2);
    53. }
    по сути задача свелась к тому что бы по id потока получить указатель на его TEB
     
  9. punxer

    punxer Андрей

    Публикаций:
    0
    Регистрация:
    16 окт 2006
    Сообщения:
    1.327
    Адрес:
    Ржев
    Код (Text):
    1. GetThreadSelectorEntry([b]hThread[/b],ctx.SegFs,LDTE)
    Код (Text):
    1. typedef struct _LDT_ENTRY {
    2.   WORD  LimitLow;
    3.   WORD  BaseLow;
    4.   union {
    5.     struct {
    6.       BYTE BaseMid;
    7.       BYTE Flags1;
    8.       BYTE Flags2;
    9.       BYTE BaseHi;
    10.     } Bytes;
    11.     struct {
    12.       DWORD BaseMid  :8;
    13.       DWORD Type  :5;
    14.       DWORD Dpl  :2;
    15.       DWORD Pres  :1;
    16.       DWORD LimitHi  :4;
    17.       DWORD Sys  :1;
    18.       DWORD Reserved_0  :1;
    19.       DWORD Default_Big  :1;
    20.       DWORD Granularity  :1;
    21.       DWORD BaseHi  :8;
    22.     } Bits;
    23.   } HighWord;
    24. } LDT_ENTRY, *PLDT_ENTRY;
     
  10. punxer

    punxer Андрей

    Публикаций:
    0
    Регистрация:
    16 окт 2006
    Сообщения:
    1.327
    Адрес:
    Ржев
     
  11. 63F45EF45RB65R6VR

    63F45EF45RB65R6VR New Member

    Публикаций:
    0
    Регистрация:
    26 окт 2011
    Сообщения:
    70
    все задача решена код заработал тестил только на windows xp
    так как остальные сейчас не загрузить (если не трудно проверьте на висте и семерке и в тему отпишитесь) всем кто помогал спасибо указатель на TEB конкретного потока вылавливается через
    NtQueryInformationThread с классом ThreadBasicInformation
    заполняется такая структурка
    Код (Text):
    1.  
    2. typedef struct _THREAD_BASIC_INFORMATION {
    3.     NTSTATUS ExitStatus;
    4.     PTEB TebBaseAddress;
    5.     CLIENT_ID ClientID;
    6.     KAFFINITY AffinityMask;
    7.     KPRIORITY BasePriority;
    8.     KPRIORITY Priority;
    9. } THREAD_BASIC_INFORMATION, *PTHREAD_BASIC_INFORMATION;
    вот полный рабочий код
    Код (Text):
    1. #include <stdio.h>
    2. #include <windows.h>
    3. #include <intrin.h>
    4. #include <ntdll1.h>
    5.  
    6. LPVOID WINAPI TlsGetValueEx(DWORD SegFs, DWORD dwTlsIndex)
    7. {
    8.   int v1; // eax@5
    9.   unsigned __int32 v2; // eax@1
    10.  
    11.   v2 = *(DWORD *)(SegFs + 24);
    12.   *(DWORD *)(v2 + 52) = 0;
    13.   if ( dwTlsIndex < 0x40 ) // 0x40 TLS_MINIMUM_AVAILABLE
    14.     return *(LPVOID *)(v2 + 4 * dwTlsIndex + 3600);
    15.   if ( dwTlsIndex >= 0x440 ) // maximum 1088 indexes per process
    16.   {
    17.     __asm int 3; // bad index
    18.   }
    19.   else
    20.   {
    21.     v1 = *(DWORD *)(v2 + 3988);
    22.     if ( v1 )
    23.       return *(LPVOID *)(v1 + 4 * dwTlsIndex - 256);
    24.   }
    25.   return 0;
    26. }
    27.  
    28. DWORD dwTlsIndex;
    29. volatile LONG var = 0xdeadbeef;
    30.  
    31. DWORD WINAPI TestTls(LPVOID)
    32. {
    33.     InterlockedIncrement(&var);
    34.     TlsSetValue(dwTlsIndex, (LPVOID)var);
    35.     Sleep(-1);
    36.     return 0;
    37.  
    38. }
    39.  
    40. extern "C" NTSYSAPI
    41. NTSTATUS
    42. NTAPI
    43. NtQueryInformationThread(
    44.  
    45.   IN HANDLE               ThreadHandle,
    46.   IN THREADINFOCLASS ThreadInformationClass,
    47.   OUT PVOID               ThreadInformation,
    48.   IN ULONG                ThreadInformationLength,
    49.   OUT PULONG              ReturnLength OPTIONAL );
    50.  
    51.  
    52.  
    53. int main()
    54. {
    55.     THREAD_BASIC_INFORMATION dd;
    56.     dwTlsIndex = TlsAlloc();
    57.     HANDLE th1 = CreateThread(0, 0, TestTls, 0, 0, 0);
    58.     HANDLE th2 = CreateThread(0, 0, TestTls, 0, 0, 0);
    59.     Sleep(5000);
    60.    
    61.     NtQueryInformationThread(th1, ThreadBasicInformation, &dd, sizeof(dd), 0);
    62.     LPVOID v1 = TlsGetValueEx((DWORD)dd.TebBaseAddress, dwTlsIndex);
    63.     NtQueryInformationThread(th2, ThreadBasicInformation, &dd, sizeof(dd), 0);
    64.     LPVOID v2 = TlsGetValueEx((DWORD)dd.TebBaseAddress, dwTlsIndex);
    65.     printf("%p %p\n", v1, v2);
    66. }
     
  12. punxer

    punxer Андрей

    Публикаций:
    0
    Регистрация:
    16 окт 2006
    Сообщения:
    1.327
    Адрес:
    Ржев
    UPD: ПроститеПростите
    x32 W7