Я работаю над обратным проектированием игры, которая использует указатель локального хранилища потока из NTCurrentTeb для инициализации указателя на игровой объект.
Вывод IDA выглядит следующим образом:
bool sub_51C3CC()
{
int v0; // eax
_BYTE *v1; // rdx
v0 = 0;
v1 = *(_BYTE **)(*(_QWORD *)NtCurrentTeb()->ThreadLocalStoragePointer + 568i64);
...
В настоящее время я реализовал это как
#include <cstdint>
#include <windows.h>
bool AcademyWon()
{
int hasWon;
uint8_t *threadPointer;
hasWon = 0;
threadPointer = *(uint8_t **)(*(intptr_t *)NtCurrentTeb()->ThreadLocalStoragePointer + 568);
}
Приведенный выше код выдает ошибку «указатель или ссылка на неполный тип «_TEB» не разрешен», поскольку _TEB определен следующим образом в winnt.h:
struct _TEB *
NtCurrentTeb (
VOID
)
{
return (struct _TEB *)__readgsqword(FIELD_OFFSET(NT_TIB, Self));
}
Нужно ли мне полностью переопределить _TEB, чтобы он указывал на него? Или есть ли способ добиться того же результата, не прикасаясь к нему?
C или C++ здесь имеют значение. Это следует общей схеме введения псевдонима типа для struct: typedef struct _TEB { ... } TEB;. В C++ вы можете использовать либо _TEB, либо TEB. В C вам нужно использовать struct _TEB или TEB. Это определено в Winternl.h. Включенный вами код не определяет структуру. Он определяет функцию NtCurrentTeb(), которая возвращает struct _TEB, то есть TEB.
Спасибо! Кажется, я неправильно понял функцию, думая, что она определяет структуру, а не возвращает ее. Итак, теоретически определение структуры _TEB до ThreadLocalStoragePointer в файле заголовка, а затем ее включение должно решить эту проблему?
Или вместо того, чтобы переходить на низкий уровень, просто используйте TlsAlloc и связанные с ним функции (TlsFree, TlsGetValue, TlsSetValue) или даже реализацию компилятора. Есть большая вероятность, что исходный код не затрагивал TEB напрямую.
Это абсолютно не касалось ТЭБ напрямую. Это стандартный способ доступа к статически выделенному значению TLS, и весь этот код был сгенерирован компилятором. В исходном коде это был просто стандартный доступ к глобальной переменной thread_local. Проблема в том, что ОП, вероятно, хочет сохранить функциональность на 100%, чтобы некоторые части исходного кода можно было заменить новым кодом, и все это по-прежнему работало.





К сожалению, вы не можете просто получить доступ к _TEB::ThreadLocalStoragePointer, поскольку это поле не задокументировано и не предусмотрено в Windows SDK. И вы не можете переопределить _TEB, поскольку он, вероятно, уже определен (а вам это не очень-то и хочется).
Я вижу здесь два общих подхода.
struct MY_TEB { // or take a complete definition from Wine headers
LPVOID Reserved[11];
LPVOID ThreadLocalStoragePointer;
}
LPVOID tls = ((struct MY_TEB*)NtCurrentTeb())->ThreadLocalStoragePointer;
LPVOID tls = NtCurrentTeb())->Reserved1[11];
Нет необходимости определять тип структуры для создания/возврата указателей на этот тип (например, нулевые указатели). Однако необходимо определить этот тип, чтобы разыменовать такой указатель или создать экземпляр этого типа. Ваша функция
AcademyWon()выполняет разыменование с помощьюNtCurrentTeb()->ThreadLocalStoragePointer + 568). Оператор->— это оператор разыменования указателя. Обычный способ обработки таких вещей — поместить определение структуры в заголовок (а не просто прямое объявление) и#includeэтот заголовок, чтобы разыменовать такие указатели.