Вопрос Как получать динамические адреса?

Начинающий
Статус
Оффлайн
Регистрация
27 Дек 2023
Сообщения
15
Реакции[?]
0
Поинты[?]
0
Добрый день, коллеги!
Требуется помощь с улучшением Dota 2. Модифицирую поведение команды host_timescale. В изначальную команду добавлен намордник, ограничивающий таймскейл значением x10.
Через CheatEngine нашел два нужных мне адреса: значение float текущего таймскейла и значение float максимального таймскейла.
Изменяя их через CE добиваюсь нужного поведения.
Но адреса не зеленые (динамические) и при каждом запуске они отличаются.
Как мне автоматизировать поиск адреса в моей программе? (например на C/С++, но это не принципиально)
Если кинете ссылкой с обучающим материалом - даже лучше.
 
Начинающий
Статус
Оффлайн
Регистрация
30 Мар 2020
Сообщения
324
Реакции[?]
24
Поинты[?]
12K
А что оно вообще тебе дает эта команда?

Ну крч смотри тебе надо найти статический указатель на это значение, если он имеется(ну это впринципе конвар поэтому должен быть)

Можешь поискать видосы по поиску указателей static pointer.

Вот типа такого : 1)
Пожалуйста, авторизуйтесь для просмотра ссылки.

2)
Пожалуйста, авторизуйтесь для просмотра ссылки.


Можешь конечно поиграть с Конварами и как-то получать через класс ConVarGetter или что-то в этом роде, как в гайде от Liberalist
 
Начинающий
Статус
Оффлайн
Регистрация
27 Дек 2023
Сообщения
15
Реакции[?]
0
Поинты[?]
0
А что оно вообще тебе дает эта команда?

Ну крч смотри тебе надо найти статический указатель на это значение, если он имеется(ну это впринципе конвар поэтому должен быть)

Можешь поискать видосы по поиску указателей static pointer.

Вот типа такого : 1)
Пожалуйста, авторизуйтесь для просмотра ссылки.

2)
Пожалуйста, авторизуйтесь для просмотра ссылки.


Можешь конечно поиграть с Конварами и как-то получать через класс ConVarGetter или что-то в этом роде, как в гайде от Liberalist
Спасибо за ответ!
То есть мне надо найти указатель со статическим адресом на мой динамический адрес, верно? А то гуглинг повел меня в сторону поиска сигнатур и т.п.

Я делаю RL AI-Bot'а для кастомки и мне нужно ускорять клиент по максимуму, чтобы бот быстрее обучился.
А можешь еще, пожалуйста, кинуть ссылкой с базовыми вещами на C - как лучше подсосаться к памяти процесса и как получить адрес dll'ки в нем.
 
Пользователь
Статус
Оффлайн
Регистрация
8 Апр 2022
Сообщения
663
Реакции[?]
104
Поинты[?]
67K
Спасибо за ответ!
То есть мне надо найти указатель со статическим адресом на мой динамический адрес, верно? А то гуглинг повел меня в сторону поиска сигнатур и т.п.

Я делаю RL AI-Bot'а для кастомки и мне нужно ускорять клиент по максимуму, чтобы бот быстрее обучился.
А можешь еще, пожалуйста, кинуть ссылкой с базовыми вещами на C - как лучше подсосаться к памяти процесса и как получить адрес dll'ки в нем.
всмысле? нахуя ты вообще по адресу делаешь? он же тебе скинул ссылку на гайд по конварам,их можно менять в разы проще через интерфейс
 
Ревёрсер среднего звена
Пользователь
Статус
Оффлайн
Регистрация
24 Ноя 2022
Сообщения
303
Реакции[?]
108
Поинты[?]
57K
Добрый день, коллеги!
Требуется помощь с улучшением Dota 2. Модифицирую поведение команды host_timescale. В изначальную команду добавлен намордник, ограничивающий таймскейл значением x10.
Через CheatEngine нашел два нужных мне адреса: значение float текущего таймскейла и значение float максимального таймскейла.
Изменяя их через CE добиваюсь нужного поведения.
Но адреса не зеленые (динамические) и при каждом запуске они отличаются.
Как мне автоматизировать поиск адреса в моей программе? (например на C/С++, но это не принципиально)
Если кинете ссылкой с обучающим материалом - даже лучше.
Пожалуйста, авторизуйтесь для просмотра ссылки.
Пожалуйста, авторизуйтесь для просмотра ссылки.

Вот куски на тему получения конваров
 
Начинающий
Статус
Оффлайн
Регистрация
27 Дек 2023
Сообщения
15
Реакции[?]
0
Поинты[?]
0
всмысле? нахуя ты вообще по адресу делаешь? он же тебе скинул ссылку на гайд по конварам,их можно менять в разы проще через интерфейс
Спасибо за ответ. Не очень понял твой агрессии. Я делаю через адреса, т.к. host_timescale limiter - это не конвар, а внутреннее значение, вероятно захардкоженное. Можешь пояснить? Я не очень разбираюсь в теме.
Пожалуйста, авторизуйтесь для просмотра ссылки.
Пожалуйста, авторизуйтесь для просмотра ссылки.

Вот куски на тему получения конваров
Спасибо! Ознакомлюсь.
Пока все получилось по первой ссылке из первого ответа, через указатели.
 
Начинающий
Статус
Оффлайн
Регистрация
27 Дек 2023
Сообщения
15
Реакции[?]
0
Поинты[?]
0
Мужики, а где взять memory.h и memory type, как вот здесь, например?
Создал проект на C++14, у меня такого нет в стандартной поставке.
 
Участник
Статус
Оффлайн
Регистрация
23 Май 2019
Сообщения
779
Реакции[?]
331
Поинты[?]
63K
основной принцип реверса в том что кто-то что-то уже и так делает(игра), тебе осталось только понять как откуда почему зачем и тд
игра считывает твой текущий host_timescale? считывает. ограничивает до лимита в 10? ограничивает. ну так возьми да найди где это происходит.
хвбп ставишь на рид дворда(флоат и дворд одинакового размера - 32 бита) значения твоего таймскейла(в чит енджине этот функционал называется Find out what accesses this address или чето такое). это тебе дает увидеть где игра считывает эти данные(и что потом с ними делает)
1704395203622.png
и смотришь кто считывает и ищешь вокруг проверки связанные с регистром в котором этот флоат лежит
вот например одно из мест(их несколько) где считывает
1704395411509.png
тут проверка на 0.001 сначала, а потом проверка на 10, еще и проверка на 0. это то что тебе и надо.
00007FFAD9970023 | minss xmm0, dword ptr ds:[0x00007FFAD9BB0BC4]
твоя десятка лежит в этой 0x00007FFAD9BB0BC4(это .rdata т.е. константа, ридонли, нужно права на запись включать(VirtualProtect) либо WriteProcessMemory юзать который и так их уже под колпаком включает)
делаешь сигнатуру просто на эти инструкции и потом уже берешь адрес с этой minss. сам таймскейл тоже там есть чуть выше
зеленые адреса(RVA) это хуйня которая поменяется при следующем апдейте. юзай сигскан. если мы говорим про чит енджин то там этот функционал AOBScan называется, так же там есть поиск типа Array of byte который то же самое делает.
инструкции кодируются байтами, ищи в памяти эти байты(заменяя ненужное нестабильное говно(регистры, значения операндов и тд) универсальными символами, например вопросиками). нашел инструкции, берешь их операнды считываешь и потом используешь их.
например нашел инструкцию свою
minss xmm0, dword ptr ds:[0x00007FFAD9BB0BC4]
забрал оттуда эту 0x00007FFAD9BB0BC4 и кайфуешь.
разве что инструкция будет в байтах
F3 0F 5D 05 99 0B 24 00
где 99 0B 24 00 это 32 битное значение операнда, в литтл ендиане, и к нему надо прибавить адрес следующей инструкции(ну т.е. адрес текущей инструкции + размер текущей инструкции(8 байт)), на скрине это 00007FFAD9970023 + 8 = 00007FFAD997002B
00007FFAD997002B + 00240B99 = 00007FFAD9BB0BC4
если тебе все таки нужна RVA(мало ли) то это оффсет от ImageBase где модуль загружен.
например у меня адрес 00007FFAD9BB0BC4, имейджбейз engine2.dll у меня 00007FFAD9790000.
00007FFAD9BB0BC4 - 00007FFAD9790000 = 420BC4. т.е. "зеленый адрес" будет engine2.dll + 420BC4 (это тот самый лимит в десятку)
на данные которые лежат вне модуля(например само значение этого квара таймскейла) зеленых адресов не бывает. но как правило в модуле лежат какието ссылочки/упомянания этого места(или места рядом) где лежат эти данные. например в доте в модуле лежит указатель на сам квар(на engine2.dll + 5414C0), а его значение лежит на +0x40 от этого места(т.е. [engine2.dll + 5414C0] + 0x40). только эти оффсеты поменяются при следующем апдейте, поэтому делай сигу, находи инструкции в памяти(которые при апдейте вряд ли сильно поменяются) и из значений операндов бери эти адреса
 
Последнее редактирование:
Начинающий
Статус
Оффлайн
Регистрация
30 Мар 2020
Сообщения
324
Реакции[?]
24
Поинты[?]
12K
Мужики, а где взять memory.h и memory type, как вот здесь, например?
Создал проект на C++14, у меня такого нет в стандартной поставке.
Если тебе лень читать документацию на майкросотовских сайтах (MSDN), и гуглить, то оч рекомендую спрашивать у chatgpt. Я не говорю, что ты нуль в с++ или геймхакинге, я просто пример навожу полезности нейронных сетей. Только не говори

Вот ты кинул тему, и там вот такой код:

C++:
#include "memory.h"
...
int main()
{
...
ReadProcessMemory(mem.pHandle, reinterpret_cast<LPVOID>(baseAddr), &baseAddr, sizeof(baseAddr), 0);
...
}
Спроси у того же чатжпт что за функция ReadProcessMemory, что она дает ? что она делает ?зачем она нужна ? как её использовать.
Скажу сразу, что больше юзается в экстернале(External) хацках. Для сохранения своей нервной психики рекомендую идти internal, и там не нужна херня типа RPM(ReadProcessMemory)/WPM(WriteProcessMemory) .Там намного легче (мейби и опасно но похуй ваще, советую чекнуть гайдики Господина Liberalist )
 
Начинающий
Статус
Оффлайн
Регистрация
27 Дек 2023
Сообщения
15
Реакции[?]
0
Поинты[?]
0
основной принцип реверса в том что кто-то что-то уже и так делает(игра), тебе осталось только понять как откуда почему зачем и тд
игра считывает твой текущий host_timescale? считывает. ограничивает до лимита в 10? ограничивает. ну так возьми да найди где это происходит.
хвбп ставишь на рид дворда(флоат и дворд одинакового размера - 32 бита) значения твоего таймскейла(в чит енджине этот функционал называется Find out what accesses this address или чето такое). это тебе дает увидеть где игра считывает эти данные(и что потом с ними делает)
Посмотреть вложение 267752
и смотришь кто считывает и ищешь вокруг проверки связанные с регистром в котором этот флоат лежит
вот например одно из мест(их несколько) где считывает
Посмотреть вложение 267753
тут проверка на 0.001 сначала, а потом проверка на 10, еще и проверка на 0. это то что тебе и надо.
00007FFAD9970023 | minss xmm0, dword ptr ds:[0x00007FFAD9BB0BC4]
твоя десятка лежит в этой 0x00007FFAD9BB0BC4(это .rdata т.е. константа, ридонли, нужно права на запись включать(VirtualProtect) либо WriteProcessMemory юзать который и так их уже под колпаком включает)
делаешь сигнатуру просто на эти инструкции и потом уже берешь адрес с этой minss. сам таймскейл тоже там есть чуть выше
зеленые адреса(RVA) это хуйня которая поменяется при следующем апдейте. юзай сигскан. если мы говорим про чит енджин то там этот функционал AOBScan называется, так же там есть поиск типа Array of byte который то же самое делает.
инструкции кодируются байтами, ищи в памяти эти байты(заменяя ненужное нестабильное говно(регистры, значения операндов и тд) универсальными символами, например вопросиками). нашел инструкции, берешь их операнды считываешь и потом используешь их.
например нашел инструкцию свою
minss xmm0, dword ptr ds:[0x00007FFAD9BB0BC4]
забрал оттуда эту 0x00007FFAD9BB0BC4 и кайфуешь.
разве что инструкция будет в байтах
F3 0F 5D 05 99 0B 24 00
где 99 0B 24 00 это 32 битное значение операнда, в литтл ендиане, и к нему надо прибавить адрес следующей инструкции(ну т.е. адрес текущей инструкции + размер текущей инструкции(8 байт)), на скрине это 00007FFAD9970023 + 8 = 00007FFAD997002B
00007FFAD997002B + 00240B99 = 00007FFAD9BB0BC4
если тебе все таки нужна RVA(мало ли) то это оффсет от ImageBase где модуль загружен.
например у меня адрес 00007FFAD9BB0BC4, имейджбейз engine2.dll у меня 00007FFAD9790000.
00007FFAD9BB0BC4 - 00007FFAD9790000 = 420BC4. т.е. "зеленый адрес" будет engine2.dll + 420BC4 (это тот самый лимит в десятку)
на данные которые лежат вне модуля(например само значение этого квара таймскейла) зеленых адресов не бывает. но как правило в модуле лежат какието ссылочки/упомянания этого места(или места рядом) где лежат эти данные. например в доте в модуле лежит указатель на сам квар(на engine2.dll + 5414C0), а его значение лежит на +0x40 от этого места(т.е. [engine2.dll + 5414C0] + 0x40). только эти оффсеты поменяются при следующем апдейте, поэтому делай сигу, находи инструкции в памяти(которые при апдейте вряд ли сильно поменяются) и из значений операндов бери эти адреса
Спасибо за развернутый ответ! У меня получились почти такие же статические адреса, только я оба относительно engine2.dll получил, выше уже писал, что успешно их нашел.
Сейчас пытаюсь понять, как их использовать в проге на C++, смотрю в сторону Write/ReadProcessMemory, т.к. это максимально похоже на функционал CheatEngine.
 
Начинающий
Статус
Оффлайн
Регистрация
27 Дек 2023
Сообщения
15
Реакции[?]
0
Поинты[?]
0
Коллеги, всем спасибо, вы очень мне помогли.
Застопорился сейчас на обновлении значений, код прикладываю ниже.
Timescale успешно обновляется, а timescale_limit остается прежним, ошибка при этом такая: "Invalid access to memory location."
Я так понимаю, моему процессу не хватает прав, чтобы писать в какое-то более защищенное место другого процесса? Или не в ту сторону рою?

C++:
int main() {
    auto phandle = GetProcessByName("dota2.exe");
    auto pid = GetProcessId(phandle);

    std::cout << "PID: " << pid << std::endl;

    uintptr_t BaseAddress;
    BaseAddress = dwGetModuleBaseAddress(pid, (TCHAR *) "engine2.dll");

    std::cout << "Module base address: " << std::hex << BaseAddress << std::endl;

    auto timescale_ptr_addr = BaseAddress + 0x5414B0;
    auto timescale_limiter_addr = BaseAddress + 0x420BC4;

    float timescale_limiter = 0;
    uintptr_t timescale_addr = 0;
    float timescale = 0;
    float new_timescale = 0;
    float new_timescale_limit = 1000;

    ReadProcessMemory(phandle, reinterpret_cast<LPVOID>(timescale_limiter_addr), &timescale_limiter, sizeof(timescale_limiter), nullptr);
    ReadProcessMemory(phandle, reinterpret_cast<LPVOID>(timescale_ptr_addr), &timescale_addr, sizeof(timescale_addr), nullptr);
    ReadProcessMemory(phandle, reinterpret_cast<LPVOID>(timescale_addr + 0x90), &timescale, sizeof(timescale), nullptr);
    std::cout << "Current timescale limit: " << timescale_limiter << std::endl;
    std::cout << "Timescale addr: " << timescale_addr << std::endl;
    std::cout << "Current timescale: " << timescale << std::endl;

    std::cout << "Please enter new timescale: ";
    std::cin >> new_timescale;
    std::cout << std::endl;

    WriteProcessMemory(phandle, reinterpret_cast<LPVOID>(timescale_limiter_addr), &new_timescale_limit, sizeof(timescale_limiter), nullptr);
    WriteProcessMemory(phandle, reinterpret_cast<LPVOID>(timescale_addr + 0x90), &new_timescale, sizeof(timescale), nullptr);

    ReadProcessMemory(phandle, reinterpret_cast<LPVOID>(timescale_limiter_addr), &timescale_limiter, sizeof(timescale_limiter), nullptr);
    ReadProcessMemory(phandle, reinterpret_cast<LPVOID>(timescale_addr + 0x90), &timescale, sizeof(timescale), nullptr);
    std::cout << "New timescale limit: " << timescale_limiter << std::endl;
    std::cout << "New timescale: " << timescale << std::endl;

    std::cout << GetLastErrorAsString();
}
 
Начинающий
Статус
Оффлайн
Регистрация
27 Дек 2023
Сообщения
15
Реакции[?]
0
Поинты[?]
0
Коллеги, всем спасибо, вы очень мне помогли.
Застопорился сейчас на обновлении значений, код прикладываю ниже.
Timescale успешно обновляется, а timescale_limit остается прежним, ошибка при этом такая: "Invalid access to memory location."
Я так понимаю, моему процессу не хватает прав, чтобы писать в какое-то более защищенное место другого процесса? Или не в ту сторону рою?

C++:
int main() {
    auto phandle = GetProcessByName("dota2.exe");
    auto pid = GetProcessId(phandle);

    std::cout << "PID: " << pid << std::endl;

    uintptr_t BaseAddress;
    BaseAddress = dwGetModuleBaseAddress(pid, (TCHAR *) "engine2.dll");

    std::cout << "Module base address: " << std::hex << BaseAddress << std::endl;

    auto timescale_ptr_addr = BaseAddress + 0x5414B0;
    auto timescale_limiter_addr = BaseAddress + 0x420BC4;

    float timescale_limiter = 0;
    uintptr_t timescale_addr = 0;
    float timescale = 0;
    float new_timescale = 0;
    float new_timescale_limit = 1000;

    ReadProcessMemory(phandle, reinterpret_cast<LPVOID>(timescale_limiter_addr), &timescale_limiter, sizeof(timescale_limiter), nullptr);
    ReadProcessMemory(phandle, reinterpret_cast<LPVOID>(timescale_ptr_addr), &timescale_addr, sizeof(timescale_addr), nullptr);
    ReadProcessMemory(phandle, reinterpret_cast<LPVOID>(timescale_addr + 0x90), &timescale, sizeof(timescale), nullptr);
    std::cout << "Current timescale limit: " << timescale_limiter << std::endl;
    std::cout << "Timescale addr: " << timescale_addr << std::endl;
    std::cout << "Current timescale: " << timescale << std::endl;

    std::cout << "Please enter new timescale: ";
    std::cin >> new_timescale;
    std::cout << std::endl;

    WriteProcessMemory(phandle, reinterpret_cast<LPVOID>(timescale_limiter_addr), &new_timescale_limit, sizeof(timescale_limiter), nullptr);
    WriteProcessMemory(phandle, reinterpret_cast<LPVOID>(timescale_addr + 0x90), &new_timescale, sizeof(timescale), nullptr);

    ReadProcessMemory(phandle, reinterpret_cast<LPVOID>(timescale_limiter_addr), &timescale_limiter, sizeof(timescale_limiter), nullptr);
    ReadProcessMemory(phandle, reinterpret_cast<LPVOID>(timescale_addr + 0x90), &timescale, sizeof(timescale), nullptr);
    std::cout << "New timescale limit: " << timescale_limiter << std::endl;
    std::cout << "New timescale: " << timescale << std::endl;

    std::cout << GetLastErrorAsString();
}
Вопрос снят - для следующих поколений: используйте
C++:
VirtualProtectEx(phandle, reinterpret_cast<LPVOID>(timescale_limiter_addr), sizeof(new_timescale_limit), PAGE_READWRITE,&nothing);
 
Участник
Статус
Оффлайн
Регистрация
23 Май 2019
Сообщения
779
Реакции[?]
331
Поинты[?]
63K
твоя десятка лежит в этой 0x00007FFAD9BB0BC4(это .rdata т.е. константа, ридонли, нужно права на запись включать(VirtualProtect) либо WriteProcessMemory юзать который и так их уже под колпаком включает)
напиздел немножко впм только для PAGE_EXECUTE / PAGE_EXECUTE_READ страничек врайт права включает(и наверно не на всех версиях винды) и то это не задокументировано + в доках написано
The entire area to be written to must be accessible or the operation fails.
так что не стоит на это полагаться. я так понимаю это сделано для дебагеров которые инт3 ставят через впм в .text чтобы им легче жить было и винда сама бы снимала/восстанавливала протект
C++:
    auto timescale_ptr_addr = BaseAddress + 0x5414B0;
    auto timescale_limiter_addr = BaseAddress + 0x420BC4;
у тебя это завтра перестанет работать делай сигу
 
Начинающий
Статус
Оффлайн
Регистрация
27 Дек 2023
Сообщения
15
Реакции[?]
0
Поинты[?]
0
напиздел немножко впм только для PAGE_EXECUTE / PAGE_EXECUTE_READ страничек врайт права включает(и наверно не на всех версиях винды) и то это не задокументировано + в доках написано
The entire area to be written to must be accessible or the operation fails.
так что не стоит на это полагаться. я так понимаю это сделано для дебагеров которые инт3 ставят через впм в .text чтобы им легче жить было и винда сама бы снимала/восстанавливала протект

у тебя это завтра перестанет работать делай сигу
Для моей задачи некритично зафризить версию доты и в ней обучать.
Для саморазвития попробую сделать сигу, как дойдут руки. Есть гайд какой-то на это?
Еще раз спасибо!
 
Участник
Статус
Оффлайн
Регистрация
23 Май 2019
Сообщения
779
Реакции[?]
331
Поинты[?]
63K
Для моей задачи некритично зафризить версию доты и в ней обучать.
Для саморазвития попробую сделать сигу, как дойдут руки. Есть гайд какой-то на это?
Еще раз спасибо!
инструкции чекаешь, смотришь как они кодируются, выписываешь байтики, заменяешь операнды(и регистры но это уже сложнее) на вопросики.
вот у тебя есть инструкция скажем "прибавить к регистру 123". у тебя тут сама инструкция это "прибавить к регистру какое-нибудь число", а операнд это и есть то самое число с которым инструкция работает, т.е. 123. вот это 123 может поменяться при апдейте, поэтому ты ищешь инструкцию типа "прибавить к регистру ?", т.е. игноришь 123 или что угодно там может быть. а потом уже когда ты нашел что надо ты эту 123(или другое что там может быть) спокойно можешь забирать если надо из памяти
операнды в некоторых инструментах и так уже выделены но зачастую они очевидны из инструкции. например вот у тебя место
1704478661158.png
в х64дбг например операнды выделены пробелом(на скрине там красную полоску нарисовал где пробелы), но они и так очевидны
jne 0x00007FF9DA9D000C - прыжок куда? на сколько-то байт вперед(до 0x00007FF9DA9D000C). тут операнд очевиден это 0xB(прыжок на 11 байт вперед после данной инструкции. это и есть место 0x00007FF9DA9D000C)
mov rax, qword ptr ds:[0x00007FF9DAD314C0] - засунуть в регистр rax что? вот эту хуйню с адреса 0x00007FF9DAD314C0. тут тоже очевиден операнд это b8 14 36 00 это оффсет от места после данной инструкции(00007FF9DA9D0001 + 7 + 003614b8 = 00007FF9DAD314C0)
mov rax, qword ptr ds:[rax+0x8] - засунуть в регистр rax что? вот эту хуйню с + 8. тут операнд и есть эта 8
movss xmm1, dword ptr ds:[rax] - ну тут операнда нет(ну точнее он тут есть, это регистр rax(и еще xmm1), но он прямо в инструкцию закодирован похуй на него в большинстве случаев оно меняться не будет)
xorps xmm7, xmm7 - тут тоже похуй все в инструкцию закодировано напрямую
movss xmm0, dword ptr ds:[0x00007FF9DAC10A74] - засунуть в регистр xmm0 что? вот эту хуйню с адреса 0x00007FF9DAC10A74. тут операнд 59 0A 24 00(опять таки оффсет от места после данной инструкции(00007FF9DA9D0013 + 8 + 00240A59 = 00007FF9DAC10A74))
все эти операнды могут меняться при апдейте, поэтому ты их заменяешь на универсальные символы(т.е. игнорируешь при поиске), получается что тебе нужно найти последовательность инструкций
jne ?
mov rax, qword ptr ds:[?]
mov rax, qword ptr ds:[rax + ?]
movss xmm1, dword ptr ds:[rax]
xorps xmm7, xmm7
movss xmm0, dword ptr ds:[?]
тебе похуй что там в вопросиках главное чтобы внешний вид более менее совпадал
jne ? это в байтах 75 ??
mov rax, qword ptr ds:[?] это в байтах 48 8b 05 ?? ?? ?? ??
mov rax, qword ptr ds:[rax + ?] это в байтах 48 8b 40 ??
movss xmm1, dword ptr ds:[rax] это в байтах f3 0f 10 08
xorps xmm7, xmm7 это в байтах 0f 57 ff
movss xmm0, dword ptr ds:[?] это в байтах f3 0f 10 05 ?? ?? ?? ??
в итоге твоя сига это 75 ?? 48 8b 05 ?? ?? ?? ?? 48 8b 40 ?? f3 0f 10 08 0f 57 ff f3 0f 10 05 ?? ?? ?? ??
вопросики в конце можно убрать т.к. смысла от них нету(вопросик = игнор при поиске. зачем нам игнорить то что на конце если мы можем это лишнее говно просто не искать), т.е. 75 ?? 48 8b 05 ?? ?? ?? ?? 48 8b 40 ?? f3 0f 10 08 0f 57 ff f3 0f 10 05
сига должна быть уникальной, т.е. либо достаточно длинной, либо косвенной(сига на ссылку на место, а не на само место например. например вместо сиги на функцию можно сделать сигу на место где функция вызывается и оттуда уже этот адрес функции забрать)
теперь когда ты нашел в памяти такое место, ты идешь смотреть что же там на месте вопросиков(среди того что тебе интересно), т.е. считываешь память оттуда где надо. например от места где нашел + 5 до места где нашел + 9(т.е. 4 вопросика эти 75 ?? 48 8b 05 ?? ?? ?? ??). это будет твой адрес квара(относительно следующей инструкции. т.е. ты берешь ее адрес(это место где нашел + 9) и прибавляешь туда эту хуйню которая в вопросиках)
например я по шаблону
75 ?? 48 8B 05 ?? ?? ?? ?? 48 8B 40 ?? F3 0F 10 08 0F 57 FF F3 0F 10 05 нашел
75 0B 48 8B 05 B8 14 36 00 48 8B 40 08 F3 0F 10 08 0F 57 FF F3 0F 10 05
вот у меня например интересующие меня данные это B8 14 36 00(литтл ендиан. перевернутое в оперативке хранится. если ты литтл ендиан процессором(а он у тебя литтл ендиан) из оперативки считывать будешь то оно само автоматически перевернется(при условии что ты считываешь инструкцией mov dword(ну т.е. работаешь с типом std::int32_t, т.е. с числом а не с кучей байт) а не по каждому байту отдельно) не надо париться. это я тут вручуню считаю поэтому надо переворачивать). беру адрес где нашел, прибавляю 9(потому что именно там следующая инструкция начинается, на +9) и 003614b8, 00007FF9DA9CFFFF + 9 + 3614b8 = 00007FF9DAD314C0
ну погугли кароче signature scanning, pattern matching и тд на анноунчитс каком-нибудь или где-нибудь еще. считай ты просто ищешь в некой строке некую последовательность(например в строке "привет андрей" ищешь слово "андрей", т.е. то что после пробела, будет у тебя шаблон допустим \s(.*), т.е. самый последний пробел и после него захват всего что дальше) только тут более ограниченный набор, ты ищешь только конкретные байтики либо игноришь любые байтики поштучно. а игноришь ты операнды(т.е. то что при апдейте может поменяться). регистры и сами инструкции как правило не меняются при апдейте(т.к. компилятор которым доту собирают одной и той же версии и настройки никто не меняет и код по сто раз не переписывает)
 
Начинающий
Статус
Оффлайн
Регистрация
27 Дек 2023
Сообщения
15
Реакции[?]
0
Поинты[?]
0
инструкции чекаешь, смотришь как они кодируются, выписываешь байтики, заменяешь операнды(и регистры но это уже сложнее) на вопросики.
вот у тебя есть инструкция скажем "прибавить к регистру 123". у тебя тут сама инструкция это "прибавить к регистру какое-нибудь число", а операнд это и есть то самое число с которым инструкция работает, т.е. 123. вот это 123 может поменяться при апдейте, поэтому ты ищешь инструкцию типа "прибавить к регистру ?", т.е. игноришь 123 или что угодно там может быть. а потом уже когда ты нашел что надо ты эту 123(или другое что там может быть) спокойно можешь забирать если надо из памяти
операнды в некоторых инструментах и так уже выделены но зачастую они очевидны из инструкции. например вот у тебя место
Посмотреть вложение 267809
в х64дбг например операнды выделены пробелом(на скрине там красную полоску нарисовал где пробелы), но они и так очевидны
jne 0x00007FF9DA9D000C - прыжок куда? на сколько-то байт вперед(до 0x00007FF9DA9D000C). тут операнд очевиден это 0xB(прыжок на 11 байт вперед после данной инструкции. это и есть место 0x00007FF9DA9D000C)
mov rax, qword ptr ds:[0x00007FF9DAD314C0] - засунуть в регистр rax что? вот эту хуйню с адреса 0x00007FF9DAD314C0. тут тоже очевиден операнд это b8 14 36 00 это оффсет от места после данной инструкции(00007FF9DA9D0001 + 7 + 003614b8 = 00007FF9DAD314C0)
mov rax, qword ptr ds:[rax+0x8] - засунуть в регистр rax что? вот эту хуйню с + 8. тут операнд и есть эта 8
movss xmm1, dword ptr ds:[rax] - ну тут операнда нет(ну точнее он тут есть, это регистр rax(и еще xmm1), но он прямо в инструкцию закодирован похуй на него в большинстве случаев оно меняться не будет)
xorps xmm7, xmm7 - тут тоже похуй все в инструкцию закодировано напрямую
movss xmm0, dword ptr ds:[0x00007FF9DAC10A74] - засунуть в регистр xmm0 что? вот эту хуйню с адреса 0x00007FF9DAC10A74. тут операнд 59 0A 24 00(опять таки оффсет от места после данной инструкции(00007FF9DA9D0013 + 8 + 00240A59 = 00007FF9DAC10A74))
все эти операнды могут меняться при апдейте, поэтому ты их заменяешь на универсальные символы(т.е. игнорируешь при поиске), получается что тебе нужно найти последовательность инструкций
jne ?
mov rax, qword ptr ds:[?]
mov rax, qword ptr ds:[rax + ?]
movss xmm1, dword ptr ds:[rax]
xorps xmm7, xmm7
movss xmm0, dword ptr ds:[?]
тебе похуй что там в вопросиках главное чтобы внешний вид более менее совпадал
jne ? это в байтах 75 ??
mov rax, qword ptr ds:[?] это в байтах 48 8b 05 ?? ?? ?? ??
mov rax, qword ptr ds:[rax + ?] это в байтах 48 8b 40 ??
movss xmm1, dword ptr ds:[rax] это в байтах f3 0f 10 08
xorps xmm7, xmm7 это в байтах 0f 57 ff
movss xmm0, dword ptr ds:[?] это в байтах f3 0f 10 05 ?? ?? ?? ??
в итоге твоя сига это 75 ?? 48 8b 05 ?? ?? ?? ?? 48 8b 40 ?? f3 0f 10 08 0f 57 ff f3 0f 10 05 ?? ?? ?? ??
вопросики в конце можно убрать т.к. смысла от них нету(вопросик = игнор при поиске. зачем нам игнорить то что на конце если мы можем это лишнее говно просто не искать), т.е. 75 ?? 48 8b 05 ?? ?? ?? ?? 48 8b 40 ?? f3 0f 10 08 0f 57 ff f3 0f 10 05
сига должна быть уникальной, т.е. либо достаточно длинной, либо косвенной(сига на ссылку на место, а не на само место например. например вместо сиги на функцию можно сделать сигу на место где функция вызывается и оттуда уже этот адрес функции забрать)
теперь когда ты нашел в памяти такое место, ты идешь смотреть что же там на месте вопросиков(среди того что тебе интересно), т.е. считываешь память оттуда где надо. например от места где нашел + 5 до места где нашел + 9(т.е. 4 вопросика эти 75 ?? 48 8b 05 ?? ?? ?? ??). это будет твой адрес квара(относительно следующей инструкции. т.е. ты берешь ее адрес(это место где нашел + 9) и прибавляешь туда эту хуйню которая в вопросиках)
например я по шаблону
75 ?? 48 8B 05 ?? ?? ?? ?? 48 8B 40 ?? F3 0F 10 08 0F 57 FF F3 0F 10 05 нашел
75 0B 48 8B 05 B8 14 36 00 48 8B 40 08 F3 0F 10 08 0F 57 FF F3 0F 10 05
вот у меня например интересующие меня данные это B8 14 36 00(литтл ендиан. перевернутое в оперативке хранится. если ты литтл ендиан процессором(а он у тебя литтл ендиан) из оперативки считывать будешь то оно само автоматически перевернется(при условии что ты считываешь инструкцией mov dword(ну т.е. работаешь с типом std::int32_t, т.е. с числом а не с кучей байт) а не по каждому байту отдельно) не надо париться. это я тут вручуню считаю поэтому надо переворачивать). беру адрес где нашел, прибавляю 9(потому что именно там следующая инструкция начинается, на +9) и 003614b8, 00007FF9DA9CFFFF + 9 + 3614b8 = 00007FF9DAD314C0
ну погугли кароче signature scanning, pattern matching и тд на анноунчитс каком-нибудь или где-нибудь еще. считай ты просто ищешь в некой строке некую последовательность(например в строке "привет андрей" ищешь слово "андрей", т.е. то что после пробела, будет у тебя шаблон допустим \s(.*), т.е. самый последний пробел и после него захват всего что дальше) только тут более ограниченный набор, ты ищешь только конкретные байтики либо игноришь любые байтики поштучно. а игноришь ты операнды(т.е. то что при апдейте может поменяться). регистры и сами инструкции как правило не меняются при апдейте(т.к. компилятор которым доту собирают одной и той же версии и настройки никто не меняет и код по сто раз не переписывает)
Обнял, спасибо за такой развернутый ответ!
Сделаю.
 
Сверху Снизу