Помогите, пожалуйста, решить следующую проблему: Процесс А вызывает функцию GetTlsValue. Соответственно выполняется команда mov eax, large fs:18h. Может ли другой процесс (моя программа) прочитать это значение? Если да, то как это сделать. Перебор значений 7FFDF000, 7FFDE000 и т.д. не подходит.
Через NativeAPI - можно, NtQueryInformationThread с классом информации ThreadBasicInformation=0 возвращает по хэндлу потока в числе прочего TebBaseAddress (поле по смещению +4). Далее - ReadProcessMemory. Через WinAPI - можно, если "другой процесс" - отладчик для процесса A: отладчику приходят извещения, в том числе о создании потоков; в числе прочего в этом извещении опять же содержится lpThreadLocalBase - то же, что и TebBaseAddress.
2diamond: Откуда импортировать NtQueryInformationThread и какой индекс не подскажите? Может есть другие решения? Неужели только ОС может получить доступ к fs? TlsIndex известен. Всё упирается в fs:18h! Внедряться в процесс в моем случае недопустимо, можно только читать RAM.
Из ntdll.lib - можно найти в куче мест, начиная с DDK. На всякий случай предупреждаю, что NativeAPI - это такая вещь, которая, с одной стороны, довольно полезна, а с другой, сильно связана с внутренностями системы и не рекомендуется Microsoft к использованию (теоретически может меняться в следующих версиях системы, хотя на практике довольно стабильно). Кроме того, их нет под линейкой 9x, хотя вряд ли это сейчас кого-то интересует. Как уже посоветовал leo, можно GetThreadContext + GetThreadSelectorEntry.
А Microsoft не документирует, как именно она работает. Сегодня, в XP и Vista, она сводится к NtGetContextThread, а завтра, в Windows 7, Microsoft может NativeAPI переделать - все "честные" программы, использующие документированную GetThreadContext, останутся работать, а всё, использующее NtGetContextThread, перестанет. P.S. Я в курсе, что это исключительно маловероятно и на практике можно ими пользоваться.
2diamond: А можно примерный код чтения fs:18h другого процесса через GetThreadContext + GetThreadSelectorEntry?
Ну, например, так (fasm): Код (Text): TlsGetValueEx: ; in: ebx=thread handle, ; edi=process handle, ; esi=tls index ; out: eax=tls value, CF cleared if OK ; allocate CONTEXT structure sub esp, 2CCh-4 push 10004h ; CONTEXT_SEGMENTS ; get FS value push esp push ebx call [GetThreadContext] test eax, eax jz .error ; [esp+90h] = FS; get FS base push esp push dword [esp+4+90h] ; CONTEXT.SegFs push ebx call [GetThreadSelectorEntry] test eax, eax jz .error mov ah, [esp+7] mov al, [esp+4] shl eax, 16 mov ax, [esp+2] ; eax = FS base = [fs:18h]; now get TLS value cmp esi, 40h jae .1 lea eax, [eax+esi*4+0xE10] .doread: call .read_dword jc .error .ok: add esp, 2CCh ret .error: add esp, 2CCh xor eax, eax stc ret .1: cmp esi, 440h jae .error add eax, 0xF94 call .read_dword jc .error test eax, eax jz .ok lea eax, [eax+esi*4-0x100] jmp .doread .read_dword: ; in: eax = address, edi = process handle ; out: eax = value, CF set if error push eax mov ecx, esp push eax push esp push 4 push ecx push eax push edi call [ReadProcessMemory] test eax, eax pop ecx pop eax jz .readerr cmp ecx, 4 jnz .readerr ret .readerr: stc ret Замечания: 1. Это код-аналог TlsGetValue, ему нужен tls index и работает он с динамическим TLS; ещё бывает статический TLS (который обходится без Tls*-функций и работает через [fs:2Ch] - для него подход такой же). 2. Нужно иметь открытые хэндлы процесса, в котором всё это происходит, и потока, у которого считывается TLS (на то он и Thread Local Storage, чтобы быть зависимым от потока). Получить их можно кучей разных способов, в том числе OpenProcess/OpenThread по известным идентификаторам, Process32First/Process32Next/Thread32First/Thread32Next из toolhelp API, GetWindowThreadProcessId по хэндлу окна, созданного потоком. 3. Константы 0xE10 и 0xF94 вообще-то потенциально могут меняться в будущих версиях (в 2k, XP, Vista - значения одинаковые), но вряд ли будут; для точности можно либо проверять работоспособность в будущих версиях, либо прямо на месте встраивать в прогу дизассемблирование (либо сигнатурный поиск, это детали реализации) и поиск этих констант в функции TlsGetValue из текущей работающей системы). Кроме того, в Win64 для 64-битных процессов они другие (равно как и tls-данные занимают по 8 байт вместо 4), для обычных 32-битных - такие же. Кстати, их можно вытащить из winternl.h из SDK - соответственно offsetof(TEB, TlsSlots) и offsetof(TEB, TlsExpansionSlots).
2diamond: Спасибо огромное! Никак не мог закончить проект из-за проблемы чтения fs:18h. Надеюсь, теперь всё будет в порядке. Сейчас занимаюсь дизассемблированием win32 приложений. А о TLS так мало полезной инфы. Может посоветуете, где почитать?
diamond Да будет вам известно что нормальное приложение не должно юзать GetThreadContext(), GetThreadSelectorEntry() -темболее и выполнять операции с блоком потока недолжно напрямую обращаясь к нему, минуя функционал винапи.
Угу, мне это известно. Равно как и то, что нормальное приложение не должно быть написано на ассемблере и даже иметь ассемблерные вставки - ведь это (о ужас!) приводит к потере переносимости (дважды ужас!) Если серьёзно - я ведь не говорил, что NativeAPI использовать нельзя; иногда их и знания внутренней структуры использовать просто необходимо. Я всего лишь предупредил, чем это может быть чревато. Ну а использование архитектурно-зависимой GetThreadContext() на ассемблерном форуме, да ещё и в топике про [fs:18h], не должно смущать читателей С точки зрения высокоуровневого программиста (что это вообще такое и как его использовать) - как и о многом другом, об этом хорошо написано у Рихтера (в 4-м издании "Создание эффективных Win32-приложений..." это глава 21). Что находится под капотом - здесь есть статья http://www.wasm.ru/print.php?article=tls (общая теория там тоже есть, но у Рихтера IMHO лучше).