Регистрация Главная Пользователи Все разделы прочитаны
Сообщения за день Справка Регистрация

Чтож вы такое, Оффсеты?

-

Разработка ПО для Perfect World

- Бюро разработчиков Zhyk.Ru: создание ботов, снифферов и прочих программ для Perfect World

Ответ
 
Опции темы Опции просмотра
Старый 18.10.2020, 05:25   #1
 Пехотинец
Аватар для dwa83
 
dwa83 лучик света в грозовом небеdwa83 лучик света в грозовом небеdwa83 лучик света в грозовом небеdwa83 лучик света в грозовом небеdwa83 лучик света в грозовом небеdwa83 лучик света в грозовом небеdwa83 лучик света в грозовом небе
Регистрация: 21.03.2012
Сообщений: 83
Популярность: 727
Сказал(а) спасибо: 18
Поблагодарили 99 раз(а) в 53 сообщениях
 
По умолчанию Чтож вы такое, Оффсеты?

Очень часто на форуме встречаются посты, из которых видно, что многие не могут понять, что такое офсеты.
И я подумал, если попробовать "разжевать" данную тему, вопросов будет меньше.
Я не профессионал в программировании(просто хобби), потому, если будут недочёты, прошу извинить и поправить.

Для понимания попробуем подробно рассмотреть небольшой пример. Я думаю все понимают, что почти в любой программе существует динамическое выделение памяти.
Примером может быть программа, которая работает с различными массивами, размерность которых не всегда одна и та же. Например с массивом типа "вектор", в котором может быть заранее неизвестное количество элементов, и которые будут туда добавляться и удаляться динамически.

Для работы с динамически созданными экземплярами данных и нужны указатели.

Предлагаю написать простенькую программу, и на примере её разобрать что к чему.
Я буду использовать C++Builder6.

Создадим новый проект и сохраним в отдельную папку. Так же для удобства создадим два файла в папке проекта с названиями structs.h и structs.cpp. В них напишем наши тестовые структуры, которые и будем рассматривать.

Тут тестовая структура Party, содержащая указатель на цепочку добавляемых элементов, описывающих параметры членов пати PartyMember.

structs.h
Код:
#ifndef STRUCTS_H
#define STRUCTS_H

#include <vcl.h>


//структура члена пати
class PartyMember
{
public:
    PartyMember();		//конструктор

	int	level;			//уровень
    int hp;				//жизни
    PartyMember * next;	//указатель на следующего члена пати, или NULL, если последний
};

// структура пати
class Party
{
public:
	Party();					//конструктор
    ~Party();					//деструктор
    void AddRandomMember();		//добавление рандомного члена в пати
    void Clear(PartyMember * m);//очистка
    void DecHP(PartyMember * m);//уменьшение на 1 ХП всех членов пати
    void GetInfo(TListBox * lb);//вывод инфы о всех членах
	int	count;					//количество сопартийцев
    PartyMember * chain;		//указатель(адрес) на первого члена пати, либо NULL, если их нет

};

#endif //STRUCTS_H
structs.cpp
Код:
#include "structs.h"

//конструктор структуры пати
Party::Party()
{
	count = 0;		//в начале ни одного члена нет
    chain = NULL;	//обнулим адрес первого члена
}

//деструктор пати
Party::~Party()
{
	if (chain != NULL) Clear(chain); //удалим цепочку членов, если она не пуста
    count = 0;
}

//добавление члена в конец цепочки
void Party::AddRandomMember()
{
	if (chain == NULL)	//если в пати ещё нет членов
    {
    	//динамически выделим память, chain будет содержать адрес первого
    	chain = new PartyMember(); //тут вызовется конструктор члена пати
        count++;
        return;
    }
    //если это не первый член, "присоединим" его к последнему
	PartyMember * m = chain;
    while (m->next != NULL) m = m->next;
    m->next = new PartyMember();
    count++;
}

//очистка пати
void Party::Clear(PartyMember * m)
{
	//рекурсивно удалим членов
	if (m == NULL) return;
    Clear(m->next);
    delete m;	//освободим память, занятую текущим членом
    m = NULL;	//адрес обнулим, чтоб не указывал на уже свободные адреса
}

//уменьшение ХП всех членов в цепочке
void Party::DecHP(PartyMember * m)
{
	if (m == NULL) return;
	DecHP(m->next);
    if (m->hp > 0) m->hp--;
}

void Party::GetInfo(TListBox * lb)
{
	lb->Clear();
	PartyMember * curent = chain;

    int num = 0;
    while (curent != NULL)
    {
    	lb->Items->Add("№" + IntToStr(num) + " Level - " + IntToStr(curent->level) + " HP - " + IntToStr(curent->hp)+ " ADDR - " + IntToStr(int(curent)));
        curent = curent->next;
		num++;
    }
}

//конструктор члена пати
PartyMember::PartyMember()
{
	level = 10 + 90*(rand()/float(RAND_MAX));
    hp = 1000 + 9000*(rand()/float(RAND_MAX));
    next = NULL;	//адрес следущего члена пока обнулён
}

На форму кинем ListBox, в который будем выводить данные по персонажам. А так же адрес переменной структуры пати.
И одну кнопку, при нажатии на которую у членов пати будут убывать ХП и обновляться информация в листбоксе.
Подключим наш заголовочник в главном модуле, а так же подключим файл реализации к проекту.

Код:
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"

#include "structs.h"



//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;




Party party;
...
Тут же в главном модуле объявим глобальную переменную paty.

В событии создания формы мы должны добавить туда к примеру 3 члена, и вывести инфо о них.
Код:
void __fastcall TForm1::FormCreate(TObject *Sender)
{
	party.AddRandomMember();
    party.AddRandomMember();
    party.AddRandomMember();
    party.GetInfo(ListBox1);
    ListBox1->Items->Add("party ADDR = " + IntToStr(int(&party)));
}
А в событии кнопки вызовем функцию уменьшения хп и опять же обновим инфо в листбоксе.
Код:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
	party.DecHP(party.chain);
    party.GetInfo(ListBox1);
    ListBox1->Items->Add("party ADDR = " + IntToStr(int(&party)));
}
Тестовая программка будет представлять собой примерно такое.


Теперь давайте запустим её, подцепимся к ней с помощью Cheat Engine и с помощью темы https://zhyk.ru/forum/showthread.php?t=116666 попытаемся найти базовый адрес(и не только).
Сначала найдём ХП последнего члена в списке(если не с первого раза нашли, кнопкой уменьшаем ХП и отсеиваем, пока не останется одно значение).

В поле Description лучше сразу писать те значения, которые прибавляются к значениям регистров в окошке MoreInformation

И далее как в вышеуказаной теме ищем адреса, пока не доберёмся до базового адреса(в данном случае базового адреса модуля Project1.exe, который кстати меняется после перезапуска).

Получится примерно такая картина.

В итоге мы добравшись до базового адреса нашли эту самую цепочку офсетов(смещений), которая ведёт до значения ХП третьего члена пати.
BA + 48C4 + 8 + 8 + 4 = HP
Но что это за значения, и откуда они взялись? Давайте разбираться.

Сначала переведём значение адреса party ADDR (последняя строчка листбокса нашей программки) в HEX и получим 004048C0.
А как мы помним, в программе это адрес нашей глобальной переменной Paty.
Но последняя строчка списке адресов Cheat Engine имеет значение 004048C4.
Ага, почти тоже самое, но на 4 больше. Смотрим на структуру нашей Paty и видим, первое поле int count; 4 байта - это значение лежит в начале нашей структуры(на объявления функций не смотрим), то-есть по адресу 004048C0.
А за ней на 4 байта дальше(по адресу 004048C4) находится PartyMember * chain.
Так как наша переменная party - глобальная, её адрес всегда будет один и тот же, и смещение от базового адреса до неё будет одно и то же. Делаем вывод, что + 48C4 - это и есть оффсет(смещение) до структуры party от базового адреса, но не до начала, а до второго её поля. A там лежит адрес структуры первого члена.

Далее по всей логике стройкой выше идёт смещение +8 от начала структуры первого члена. Смотрим в код и видим, что от начала структуры члена пати на 8 байт у нас описано PartyMember * next - указатель на начало структуры следущего члена. То-есть по этим последовательным смещениям мы идём по цепочке адресов членов пати, но последняя строчка со смещением +04. А в структуре на 4 от начала у нас описано int hp;

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

Чтоб было нагладнее, можно проилюстрировать наш примёр.
________________
╔═╗
ˑ ˑ ╬ ╬
╚═╝

Последний раз редактировалось dwa83; 22.10.2020 в 01:51. Причина: ранее "Делаем вывод, что BA + 48C4 - это и есть оффсет(смещение) до структуры party" - некорректно
  Ответить с цитированием
2 пользователя(ей) сказали cпасибо:
qqsda (18.10.2020), ScythLab (18.10.2020)
Ответ

Опции темы
Опции просмотра

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход

Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
оффсеты mskarlik Общение и обсуждение Perfect World 0 10.12.2012 22:33
Оффсеты sasha257 Общение и обсуждение Perfect World 1 13.08.2012 21:49
[Помогите!] Оффсеты firuzikh10 Общение разработчиков 1 21.04.2012 18:03

www.webmoney.ru
Заявление об ответственности / Список мошенников

Часовой пояс GMT +4, время: 01:56.

Пишите нам: [email protected]
Copyright © 2020 vBulletin Solutions, Inc.
Translate: zCarot. Webdesign by DevArt (Fox)
G-gaMe! Team production | Since 2008
Hosted by GShost.net