Как вычисляются статичные оффсеты? С++

Начинающий
Статус
Оффлайн
Регистрация
20 Ноя 2021
Сообщения
14
Реакции[?]
0
Поинты[?]
0
Я уже задавал похожий вопрос, однако столкнулся с проблемой. Есть вот такая простая программа на которой я тестирую поиск оффсетов:
Код:
#include <iostream>

int main() {

    int c = 80;
    int* ptr = &c;

    bool keep_going = true;

    while (keep_going) {

        std::cout << "Var by " << ptr << " = " << c << " ptr: " << &ptr << std::endl;
        std::cout << "Enter: ";
        std::cin >> с;

    }

    return 0;

}
Загвоздка в том, что при перезапуске этой программы и адрес переменной "с", и оффсет меняются. При этом никаких указателей на эту переменную в регионах памяти с правами доступа на чтение/запись нет. Так как получают оффсеты от базового адреса процесса?

Возможно проблема в самом алгоритме вычисления оффсета. Я его вычислял как "базовый адрес процесса - адрес переменной".
Также столкнулся с тем, что базовый адрес процесса почему-то больше, чем адрес самой переменной. Как решать эту проблему?
 
Pa$$ter
Пользователь
Статус
Оффлайн
Регистрация
9 Июн 2020
Сообщения
237
Реакции[?]
83
Поинты[?]
12K
В твоём случае переменная будет аллокатся на стэк, а не статически т.к. она находится внутри функции и не имеет модификатора static, поэтому ты не найдёшь её по оффсету.
Пример:

C++:
volatile void func1()
{
    int e = 0; //Переменная для указателя на стэк
    __asm { mov e, esp }; //Присвоим ей значение
    int c = 0; //Инициализируем переменную на стэке.
    std::cout << std::hex << "esp:" << e << " func:" << func1 << " var:" << &c << std::endl;
}

volatile void func2()
{
    int e = 0; //Переменная для указателя на стэк
    __asm { mov e, esp }; //Присвоим ей значение
    static int c = 0; //Инициализируем переменную статически.
    std::cout << std::hex << "esp:" << e << " func:" << func2 << " var:" << &c << std::endl;
}

int main(int argc, char* argv[])
{
    func1();
    func2();
    system("pause");
}
1640174275978.png
 
Начинающий
Статус
Оффлайн
Регистрация
20 Ноя 2021
Сообщения
14
Реакции[?]
0
Поинты[?]
0
В твоём случае переменная будет аллокатся на стэк, а не статически т.к. она находится внутри функции и не имеет модификатора static, поэтому ты не найдёшь её по оффсету.
Пример:

C++:
volatile void func1()
{
    int e = 0; //Переменная для указателя на стэк
    __asm { mov e, esp }; //Присвоим ей значение
    int c = 0; //Инициализируем переменную на стэке.
    std::cout << std::hex << "esp:" << e << " func:" << func1 << " var:" << &c << std::endl;
}

volatile void func2()
{
    int e = 0; //Переменная для указателя на стэк
    __asm { mov e, esp }; //Присвоим ей значение
    static int c = 0; //Инициализируем переменную статически.
    std::cout << std::hex << "esp:" << e << " func:" << func2 << " var:" << &c << std::endl;
}

int main(int argc, char* argv[])
{
    func1();
    func2();
    system("pause");
}
Посмотреть вложение 185299
Благодарю. Но как тогда вычисляются по оффсету например здоровье игрока? Эти ведь поля точно не могут иметь модификатора static. Точнее если внутри самого класса игрока оффсет статичен, то самого игрока-то получить по оффсету не выйдет
 
Pa$$ter
Пользователь
Статус
Оффлайн
Регистрация
9 Июн 2020
Сообщения
237
Реакции[?]
83
Поинты[?]
12K
Благодарю. Но как тогда вычисляются по оффсету например здоровье игрока? Эти ведь поля точно не могут иметь модификатора static. Точнее если внутри самого класса игрока оффсет статичен, то самого игрока-то получить по оффсету не выйдет
Как правило сами игроки (энтити, игровые обьекты или ещё что-то) находятся в куче (аллоцированы динамически с помощью malloc() или new), и на них есть статический указатель. Если же статического указателя нет прийдётся или искать по паттерну сам класс, или функцию и уже из неё брать указатель. Если что

C++:
int var = 0; //Эта переменная тоже статическая.

int main(int argc, char* argv[]) {
    return var;
}
 
Начинающий
Статус
Оффлайн
Регистрация
20 Ноя 2021
Сообщения
14
Реакции[?]
0
Поинты[?]
0
Как правило сами игроки (энтити, игровые обьекты или ещё что-то) находятся в куче (аллоцированы динамически с помощью malloc() или new), и на них есть статический указатель. Если же статического указателя нет прийдётся или искать по паттерну сам класс, или функцию и уже из неё брать указатель. Если что

C++:
int var = 0; //Эта переменная тоже статическая.

int main(int argc, char* argv[]) {
    return var;
}
Слабо себе представляю возможность использования в играх статического указателя для объекта игрока. Игрок же может быть не один или любой другой объект. Однако понятно, спасибо за ответы. Как я понял, кроме паттерна, выхода для поиска обычной переменной нет
 
Pa$$ter
Пользователь
Статус
Оффлайн
Регистрация
9 Июн 2020
Сообщения
237
Реакции[?]
83
Поинты[?]
12K
Слабо себе представляю возможность использования в играх статического указателя для объекта игрока. Игрок же может быть не один или любой другой объект. Однако понятно, спасибо за ответы. Как я понял, кроме паттерна, выхода для поиска обычной переменной нет
Пример: в кс есть статический указатель на entity list, в котором первые 64 - игроки.
 
Олдфаг
Статус
Оффлайн
Регистрация
4 Янв 2020
Сообщения
2,994
Реакции[?]
1,275
Поинты[?]
19K
Слабо себе представляю возможность использования в играх статического указателя для объекта игрока. Игрок же может быть не один или любой другой объект. Однако понятно, спасибо за ответы. Как я понял, кроме паттерна, выхода для поиска обычной переменной нет
Жаль, но неправильно понял. Обычно оффсет это адрес поля в классе, а к классу можно придти разными способами используя любые указатели на него, класс также может быть структурой, разницы нет, но факт остается фактом.
 
Начинающий
Статус
Оффлайн
Регистрация
20 Ноя 2021
Сообщения
14
Реакции[?]
0
Поинты[?]
0
Жаль, но неправильно понял. Обычно оффсет это адрес поля в классе, а к классу можно придти разными способами используя любые указатели на него, класс также может быть структурой, разницы нет, но факт остается фактом.
Да я так и понял в принципе. До того, как создал тему, я думал, что к каждой переменной есть некий статический оффсет, что противоречило уже имеющимся знаниям об организации памяти процесса. Поэтому и возник такой тупняк)
 
Олдфаг
Статус
Оффлайн
Регистрация
4 Янв 2020
Сообщения
2,994
Реакции[?]
1,275
Поинты[?]
19K
Да я так и понял в принципе. До того, как создал тему, я думал, что к каждой переменной есть некий статический оффсет, что противоречило уже имеющимся знаниям об организации памяти процесса. Поэтому и возник такой тупняк)
Смотри. К примеру в играх используют классы для всей рутинной движухи по типу хп, ника и прочего стаффа от игрока. Все что тебе нужно просто отыскать указатель / ссылку на этот класс / структуру и оттуда просто прочитать адрес поля в классе, который обычно выглядит вот так 0xABC
 
Начинающий
Статус
Оффлайн
Регистрация
20 Ноя 2021
Сообщения
14
Реакции[?]
0
Поинты[?]
0
Смотри. К примеру в играх используют классы для всей рутинной движухи по типу хп, ника и прочего стаффа от игрока. Все что тебе нужно просто отыскать указатель / ссылку на этот класс / структуру и оттуда просто прочитать адрес поля в классе, который обычно выглядит вот так 0xABC
Да я это понимаю. Но, как я понял, это сработает только при условии, что указатель статичен. Например, как сказал человек выше, если есть статичная таблица с указателями на игроков. Если же у нас такой таблицы нет или она выделяется динамически на стеке/в куче, то и находить их придется каждый раз после перезапуска, ибо оффсеты к ней и ее адрес будет меняться. Так?
 
Олдфаг
Статус
Оффлайн
Регистрация
4 Янв 2020
Сообщения
2,994
Реакции[?]
1,275
Поинты[?]
19K
Да я это понимаю. Но, как я понял, это сработает только при условии, что указатель статичен. Например, как сказал человек выше, если есть статичная таблица с указателями на игроков. Если же у нас такой таблицы нет или она выделяется динамически на стеке/в куче, то и находить их придется каждый раз после перезапуска, ибо оффсеты к ней и ее адрес будет меняться. Так?
я бы конечно поспорил, но не охота
поинтер скан в cheat engine в принципе может это опровергнуть
 
Pa$$ter
Пользователь
Статус
Оффлайн
Регистрация
9 Июн 2020
Сообщения
237
Реакции[?]
83
Поинты[?]
12K
Да я это понимаю. Но, как я понял, это сработает только при условии, что указатель статичен. Например, как сказал человек выше, если есть статичная таблица с указателями на игроков. Если же у нас такой таблицы нет или она выделяется динамически на стеке/в куче, то и находить их придется каждый раз после перезапуска, ибо оффсеты к ней и ее адрес будет меняться. Так?
Верно.
я бы конечно поспорил, но не охота
поинтер скан в cheat engine в принципе может это опровергнуть
Не может, он находит статические указатели внутри функций или просто как глобальные переменные. Т.е. :
функция + оффсет ->
функция + оффсет ->
функция + оффсет ->
искомое значение.
 
Последнее редактирование:
Начинающий
Статус
Оффлайн
Регистрация
20 Ноя 2021
Сообщения
14
Реакции[?]
0
Поинты[?]
0
я бы конечно поспорил, но не охота
поинтер скан в cheat engine в принципе может это опровергнуть
Я буду только за, если вы выскажете свою точку зрения. Я в любом случае свой путь в изучении памяти процессов только начинаю, так что за любую информацию скажу спасибо
Верно.

Не может, он находит статические указатели внутри функций или просто как глобальные переменные. Т.е. :
функция + оффсет ->
функция + оффсет ->
функция + оффсет ->
искомое значение.
Тоже так думаю, поэтому и хочется услышать другую точку зрения. Все таки полностью достоверную информацию сложно искать и ее нужно собирать из многих кусочков :)
Верно.

Не может, он находит статические указатели внутри функций или просто как глобальные переменные. Т.е. :
функция + оффсет ->
функция + оффсет ->
функция + оффсет ->
искомое значение.
Такой вопрос появился. Если оффсет переменной внутри функции от адреса самой функции всегда одинаков, то почему меняется адрес самой функции? Разве код при загрузке в память загружается не последовательно? Или тут постаралась рандомизация адресов / ASLR?
 
Последнее редактирование:
Pa$$ter
Пользователь
Статус
Оффлайн
Регистрация
9 Июн 2020
Сообщения
237
Реакции[?]
83
Поинты[?]
12K
Такой вопрос появился. Если оффсет переменной внутри функции от адреса самой функции всегда одинаков, то почему меняется адрес самой функции? Разве код при загрузке в память загружается не последовательно? Или тут постаралась рандомизация адресов / ASLR?
Он может и не менятся, я никогда не задумывался над причиной на самом деле.
1640181625725.png
Здесь я три раза запустил код сверху, и получил одинаковые адреса функций при разном расположении стэка.
 
Олдфаг
Статус
Оффлайн
Регистрация
4 Янв 2020
Сообщения
2,994
Реакции[?]
1,275
Поинты[?]
19K
Pa$$ter
Пользователь
Статус
Оффлайн
Регистрация
9 Июн 2020
Сообщения
237
Реакции[?]
83
Поинты[?]
12K
если функция находится в классе, то ее адрес не меняется, также ее вроде как можно вызвать не из класса
Функция внутри класса на самом деле после компиляции просто принимает this (указатель на класс) первым аргументом, и в остальном компилируется как обычная функция. Если ей что-то нужно из класса, это берётся по оффсету от this.
 
Последнее редактирование:
Начинающий
Статус
Оффлайн
Регистрация
20 Ноя 2021
Сообщения
14
Реакции[?]
0
Поинты[?]
0
Функция внутри класса на самом теле после компиляции просто принимает this (указатель на класс) первым аргументом, и в остальном компилируется как обычная функция. Если ей что-то нужно из класса, это берётся по оффсету от this.
Именно так. Тогда до сих пор не могу понять одну вещь. Если у вас одинаковый адрес функций, то, выходит, что адрес переменной меняется лишь из-за того, что стек каждый раз располагается в разных местах? И, по сути, если мы знаем оффсет переменной от адреса функции и сам адрес функции, то задача сводится к тому, чтобы узнать адрес начала стека?
---
Сейчас понял, что снова ошибся в понимании структуры памяти. У нас ведь код хранится отдельно от стека, а не в нем. А значит, если мы знаем адрес функции и оффсет от нее, то и переменную найти сможем? И функции как раз таки статичны в памяти?
 
Последнее редактирование:
Pa$$ter
Пользователь
Статус
Оффлайн
Регистрация
9 Июн 2020
Сообщения
237
Реакции[?]
83
Поинты[?]
12K
Именно так. Тогда до сих пор не могу понять одну вещь. Если у вас одинаковый адрес функций, то, выходит, что адрес переменной меняется лишь из-за того, что стек каждый раз располагается в разных местах? И, по сути, если мы знаем оффсет переменной от адреса функции и сам адрес функции, то задача сводится к тому, чтобы узнать адрес начала стека?
Верно, но не совсем.
Да, действительно, адрес переменной может быть разным или из-за расположения стека (если она в нём) или из-за того что она динамически была аллоцирована в куче.
Нет, если переменная находится в стеке ты ничего с ней не сделаешь просто меняя память т.к. она будет автоматически уничтожена после выхода из функции, в таком случае единственное что можно сделать чтобы поменять её значение это хукнуть/пропатчить функцию в нужном месте, чтобы значение менялось так как тебе надо.

Пример:

C++:
#pragma optimize("", off)
int* func()
{
    int e = 1337;
    return &e;
}

int main(int argc, char* argv[])
{
    int* e = func();
    std::cout << *e << std::endl;;
    system("pause");
}
#pragma optimize("", on)
1640184086877.png
 
Начинающий
Статус
Оффлайн
Регистрация
20 Ноя 2021
Сообщения
14
Реакции[?]
0
Поинты[?]
0
Верно, но не совсем.
Да, действительно, адрес переменной может быть разным или из-за расположения стека (если она в нём) или из-за того что она динамически была аллоцирована в куче.
Нет, если переменная находится в стеке ты ничего с ней не сделаешь просто меняя память т.к. она будет автоматически уничтожена после выхода из функции, в таком случае единственное что можно сделать чтобы поменять её значение это хукнуть/пропатчить функцию в нужном месте, чтобы значение менялось так как тебе надо.

Пример:

C++:
#pragma optimize("", off)
int* func()
{
    int e = 1337;
    return &e;
}

int main(int argc, char* argv[])
{
    int* e = func();
    std::cout << *e << std::endl;;
    system("pause");
}
#pragma optimize("", on)
Посмотреть вложение 185321
Благодарю за ответ. Чтобы не создавать новую тему спрошу здесь. Предположим, есть некая структура. Например такая:

C++:
struct Foo {
   
    uint64_t id; // 0x00
    int any_variable; // 0x08
    int health; //0x0C
    bool is_dead; // 0x0D
   
}
Допустим, есть адрес переменной health. Если узнать смещение, относительно структуры - 0х0С, то мы можем найти и адрес самой структуры. Вопрос: как узнать смещение относительно структуры? Потыкал WinAPI, единственное, что пришло в голову - ставить точки останова в функциях, которые вызывают значение health и как-то через них уже смотреть адреса. Но я почти уверен, что есть более простой способ найти оффсеты
 
Последнее редактирование:
Pa$$ter
Пользователь
Статус
Оффлайн
Регистрация
9 Июн 2020
Сообщения
237
Реакции[?]
83
Поинты[?]
12K
Благодарю за ответ. Чтобы не создавать новую тему спрошу здесь. Предположим, есть некая структура. Например такая:

C++:
struct Foo {
  
    uint64_t id; // 0x00
    int any_variable; // 0x08
    int health; //0x0C
    bool is_dead; // 0x0D
  
}
Допустим, есть адрес переменной health. Если узнать смещение, относительно структуры - 0х0С, то мы можем найти и адрес самой структуры. Вопрос: как узнать смещение относительно структуры? Потыкал WinAPI, единственное, что пришло в голову - ставить точки останова в функциях, которые вызывают значение health и как-то через них уже смотреть адреса. Но я почти уверен, что есть более простой способ найти оффсеты
Пожалуйста, авторизуйтесь для просмотра ссылки.
А вообще, довольно несложно просто запомнить размер каждого типа и просто прибавлять размеры всех предыдущих полей структуры.
Пожалуйста, авторизуйтесь для просмотра ссылки.
 
Сверху Снизу