|
Authenticator Code |
Thread Tools |
Finding Offsets Using Cheat Engine |
|
#1 |
computation 1337 H4x0!2 Join Date: Jan 2016
Reputation: 2724 |
Finding Offsets Using Cheat Engine Hello everyone. Many people have trouble finding offsets in games and understanding what an offset is (talking to beginners here not you leet haxors). So I want to make an over kill tutorial to clear any confusions on offsets and a simple way to find them. This tutorial is aimed at the very beginner who is just looking to get into hacking but doesn’t know the basics of offsets and is having trouble starting off. This tutorial is not designed to target internal or external game hacking specifically but general(and simple) memory concepts. You should have an understanding of programming (I will be using C++ in the short code examples) or else this will be useless. What Is An Offset? Code: struct player { int health; int ammo; float x; float y; float z; }; So here we have a struct. Now when we create a variable of a struct in memory a very awesome and simple thing happens. Every member in the struct gets created in memory back to back to back. Meaning our z coordinate is always the same distance to the beginning of the struct. The struct might start at a different memory address every time you run an application BUT the members in the struct are always the same distance away relative to each other. ammo will always come after health and nothing is declared in between them and so on and so forth. So what is an offset. An offset is just how far away something is (in bytes) relative to something else. In game hacking when we say offset we are often referring about offset from the start of our player (if we are talking about our player of course). Lets look at the struct but lets comment in the offsets that each member is. Code: struct player { int health; //0x0 int ammo; //0x4 float x; //0x8 float y; //0xC float z; //0x10 }; how do we know what the offsets are though? Well think about this for a second. If all of these members are in a struct, they will be allocated in memory right next to each other. If you know how many bytes each data type is we can do some simple addition. The first member in the struct is where the struct starts. So health is offset 0 bytes from the start of the struct because it is the start. And the next member is 4 bytes away from that (since health takes 4 bytes because its an int) so it is said to be offset 4 bytes. As long as you know the data type you can simply add how many bytes it is away from your reverence point (which is the start of the struct for us also called the start of local player). So an offset is just the number of bytes away from a reference point and in this case that’s the start of player. This is extremely simple but many «programmers» who make hacks use offsets but don’t understand what it actually is. Pointer To Local Player And Local Player Finding Offsets The Bigger Picture
|
computation is offline |
|
|
#2 |
|||||||||||
WasserEsser Site Administrator Join Date: Jun 2013
Reputation: 122812 Recognitions (43) (4)
(1) Points: 236,129, Level: 59 Level up: 20%, 257,871 Points needed Activity: 42.9% Last Achievements Award-Showcase |
@computation Use the direct links to the images. (Rightclick on the image and copy the direct link) __________________
|
|||||||||||
WasserEsser is online now |
|
|
#3 |
computation 1337 H4x0!2
Join Date: Jan 2016
Reputation: 2724 |
Quote:
Originally Posted by WasserEsser @computation Use the direct links to the images. (Rightclick on the image and copy the direct link) Sorry about that. Thanks for the fix! |
computation is offline |
|
|
#4 |
|||||||||||
Slayer Master Contributor Join Date: Jan 2016 Location: USA
Reputation: 17363 Recognitions
(2) Points: 37,008, Level: 29 Level up: 29%, 1,792 Points needed Activity: 2.1% Last Achievements |
Looks neat, but definitely add or update this and touch on finding pointers. Very important skills. Otherwise, this was simple and neat, great explanation! Kudos, ~Slayer1250~ __________________ Quote:
Originally Posted by Synraw Don’t blame me, blame the japanese. Nuke them once and they fight back with a weapon far more dangerous Quote:
Originally Posted by gorkx Bluntly: WHAT FUCK IS YOU PEOPLES GOD DAMN PROPBLEM? you are the most disterbingly egotistical little-endian bags ever! This isn’t…don farmer going ooff to risk jail time to further chaos,and market theory. this is a gots damn video game motherfuckers. jesus fucking christ. |
|||||||||||
Slayer is offline |
|
|
#5 |
|||||||||||
vergil250493 n00bie Join Date: Aug 2014
Reputation: -37 Points: 6,013, Level: 8 Level up: 56%, 487 Points needed Activity: 2.3% Last Achievements |
Thanks for the tutorial to beginners ! you could also add on how to find pointers |
|||||||||||
vergil250493 is offline |
|
|
#6 |
computation 1337 H4x0!2
Join Date: Jan 2016
Reputation: 2724 |
Quote:
Originally Posted by vergil250493 Thanks for the tutorial to beginners ! you could also add on how to find pointers thanks. there is so much on finding pointers that I feel it is not worth the time to say what can easily be found with a quick search. |
computation is offline |
|
|
#7 |
ccurtis20 h4x0!2 Join Date: Jan 2013
Reputation: 955 |
Thanks for the tutorial/info. +Rep |
ccurtis20 is offline |
|
|
#8 |
|||||||||||
wtffwtf Junior Member Join Date: Jun 2017
Reputation: 162 Points: 4,738, Level: 7 Level up: 27%, 662 Points needed Activity: 8.6% Last Achievements |
How do you find the address of sth that is not changeable (not like the ammo or health) easily? I want to find the address of unlocking all guns for example, how is this possible? |
|||||||||||
wtffwtf is offline |
|
|
#9 |
|||||||||||
Lawlessvictory n00bie Join Date: Dec 2017
Reputation: 23 Points: 1,061, Level: 2 Level up: 33%, 339 Points needed Activity: 1.3% Last Achievements |
Thanks for taking the time to write this, things like this help a lot. |
|||||||||||
Lawlessvictory is offline |
|
|
#10 |
chubbyH n00bie Join Date: Jan 2018
Reputation: 10 |
Thinks for sharing |
chubbyH is offline |
|
|
#11 |
|||||||||||
hieu832 n00bie Join Date: Jan 2018 Location: HA NOI
Reputation: 10 Points: 2,131, Level: 4 Level up: 5%, 669 Points needed Activity: 1.8% Last Achievements |
you can tutorial video plz. |
|||||||||||
hieu832 is offline |
|
|
#12 |
|||||||||||
jahaha A God Join Date: Jul 2007
Reputation: 858 Points: 15,227, Level: 16 Level up: 17%, 1,173 Points needed Activity: 4.8% Last Achievements |
Quote:
Originally Posted by hieu832 you can tutorial video plz. There’s many videos on this already, just open up youtube and search. Good guide btw. +rep |
|||||||||||
jahaha is offline |
|
|
#13 |
tsunaweak n00bie Join Date: Feb 2018
Reputation: 10 |
very helpful thank you so much ^_^ |
tsunaweak is offline |
|
|
#14 |
|||||||||||
Phnmz Senior Member Join Date: Feb 2015
Reputation: 132 Points: 5,101, Level: 7 Level up: 67%, 299 Points needed Activity: 2.3% Last Achievements |
Good explanation, still need to know how to find pointers, and it would be about time someone explain how to do this on a game that has a simple anti-cheat at least, cause once you learn that from Assault Cube and try another game, you’re pretty much fucked as a beginner. (including myself) |
|||||||||||
Phnmz is offline |
|
Similar Threads |
||||
Thread | Thread Starter | Forum | Replies | Last Post |
[Tutorial] Cheat Engine — Finding Base Address w/ Pointer Scan | xenocidewiki | Programming for Beginners | 16 | 26th June 2019 05:06 AM |
[Question] Finding offsets using IDA. | Articxslack | DayZ SA | 7 | 22nd July 2016 09:51 AM |
[Help] Cheat Engine not finding Rsc | nrodway11 | ARMA 3 | 3 | 27th March 2015 04:12 AM |
[Discuss] Is Finding Transformation Pointer Possible With Cheat Engine? | Falchon | DayZ SA | 1 | 22nd May 2014 08:52 AM |
Help with using OllyDBG finding adresses and offsets | traplol2 | ARMA 2 | 9 | 11th August 2012 10:13 AM |
Tags |
address, struct, player, offset, memory, ammo, bytes, local, offsets, start |
«
Previous Thread
|
Next Thread
»
Forum Jump |
All times are GMT. The time now is 10:52 AM.
Contact Us —
Toggle Dark Theme
Terms of Use Information Privacy Policy Information
Copyright ©2000-2023, Unknowncheats� UKCS #312436
no new posts
Step 1: Find the current address for whatever you want to get the pointer & offset of.
In this tutorial, I’ll be using max HP as an example. I first found my max HP by searching my current max HP, adding/removing equipment with + Max HP on it, and filtering the results.
Add that address to your address list (the bottom section in Cheat Engine).
Step 2: Find out what accesses that address
Now right click on the newly added address, and select «Find what accesses this address.» You will be prompted if you want to attach the debugger; select yes.
You may need to go back into the game and wait a few seconds before anything is added to the opcode box. After a few results turn up, cycle through them look for an entry that is labled as «Copy memory» on the right side below the buttons.
Step 3: Get the offset, and probable address to search for
Double click on this entry, and you will receive another window with detailed information in it. This window contains two very important pieces of information: the offset, and address to search for. The red text shows us the offset in hex. It will look something like this: >>004971b0 — mov ecx, [esi+0000012c]
From this, we can tell that 12C is our offset. Write this down.
The second important line contains the address we need to search for. It will say «The value of the pointer needed to find this address is pobably <address>». Write down the address, and you can now close this window.
Step 4: Searching the address
Now go back to the Cheat Engine main window, and begin a new scan. You will have the «Hex» checkbox checked, have the value set to the probable address to search for, scan type as Exact Value, and value type as 4 bytes. Click First Scan.
Now we should have a few results. You hopefully won’t have more than a few. Most likely, the address you want to use will appear green in the found list. The green text means that it is a static pointer (it will not change when you restart the game).
Now that you’ve found the pointer, you can put it to use. To add it into Cheat Engine, click the «Add address manually» button. Check Pointer, and copy the address from the green result in the address list (make sure it’s the address, and NOT the value!), and type in the offset you wrote down earlier from step 3. You’ve now got your full pointer and offset.
If the green results do not appear to work, or you do not see any green results, it is possible that the game uses a double pointer to access this specific variable, and you will need to run another pointer-offset lookup on the already found pointer and offset. A quick explanation of what this is all about can be found here.
Сегодня я вам расскажу в статье как найти оффсет gameobjectmanager (gom) для игры Rust, для этого нам нужна программа IDA и сама папка с игрой где будет лежать файл UnityPlayer.dll и давайте приступим! Для начало мы сделаем следующее
Открываем IDA и кидаем туда файл UnityPlayer.dll
После зажимаем комбинацию клавиш Alt + B и в строке String вставляем следующее:
48 8B 0D ? ? ? ? 48 85 C9 74 17 41 B9 ? ? ? ? 4C 8D 05 ? ? ? ? BA ? ? ? ? E8 ? ? ? ? 48 C7 05 ? ? ? ? ? ? ? ? 48 83 C4 28 C3 CC CC CC CC CC CC CC CC CC 40 53
это необходимый паттерн который ищет значение, но при глобальном апдейте он может изменится, если он нашелся у вас то значит все отлично
Нас перебросило на необходимую область она будет выделенная и мы видем такое значение:
cs:qword_1817C1F18
Нам нужно убрать до cs:qword_18 и у нас получится значение 17C1F18
после добавляем 0x и получаем такое значение 0x17C1F18 — это и есть наш оффсет GameObjectManager
Источник: anonymcheats.ru
Как искать оффсеты | Cheat Engine | Читаем значения csgo на C++ | Урок 1 | Создание читов на ПК
Что такое Оффсеты? Как найти и обновить?
Что такое Оффсеты?
Оффсет (Offset) — на простом языке, это смещение адреса в памяти . Например, в ячейке памяти есть игрок, по адресу 0x5100 (или любому другому), соответственно что этот объект содержит несколько ячеек данных: количество HP, процент брони, местоположение — координаты нахождения на карте, а также и другую информацию.
Как их найти и произвести обновление?
Вероятно вы зададитесь вопросом, как их найти и извлечь? Постараемся немного объяснить, на примере одновременно популярной и простой в этом плане игре Counter Strike: Global Offensive. Игровой движок Source имеет есть так называемые глобальные значения «Networked Variables» или же Netvar, сокращенный вариант. По сути, это обширные таблицы для каждого типа объекта . За известный адрес игрока, возьмем 0x5100, переносим игровой client.dll и загружаем в IDA- интерактивный дизассемблер. После открываем список строк через комбинацию клавиш Shitf + F12, в открывшимся окне и делаем поиск по строке , вписываем «Health» в переводе Здоровье (Игрока), после этого появится целый список с результатами.
На изображении выше, в после String есть много префиксов, но нужен именно тот, который имеет в начале «m_» — это член класса, в полном названии member. Для примера возьмем m_iHealth, который имеет следующий код:
class CBasePlayer < pad; pad; pad; int m_iHealth; // 0xFC >
- int — integer «целое число»;
- float — число с плавающей запятой;
- etc — оператор.
Как пользоваться IDA PRO. Как найти оффсеты в любой игре
Два раза кликаем по любому из столбиков, и перед глазами появляется очередная таблица:
Этими действиями, удалось найти Оффсет, который равен значению — 0xFC. Но на этом еще не все, осталось еще одно незаконченное действие, чтобы узнать внутренние значение, нужно выполнить код ниже, применяем его, так как тип данных integer:
void * player = getentity(. ); int health = *(int*)((DWRD)player + 0xFC); print( health );
- 10.08.2021
- 6 641
- 5
Источник: cheats.lol
Поиск поинтеов и оффсетов
7. Открываем, калькулятор и настраиваем «Вид -> Инженерный», потом выбираем Hex.
8. Возвращаемся к Cheat Engine и копируем значение поля «Address».
9. Возвращаемся к калькулятору и вставляем значение сюда. После этого вычисляем (-) 500.
10. Получившийся результат копируем на поле»Address» и нажимаем OK
11. В Address list смотрим и видим, добавилось новое значение. Нажимаем ПКМ и выбираем»Pointer scan for this address».
12. Появиться окно. В настройках ставим Max level на 1 и галочку на»Improve pointerscan with gathered heap data» потом жмем OK и ожидаем окончание загрузки.
13. Должно, появится что-то вроде PointBlank.i3exec+123123123, на него 2 раза кликнем и закрываем окно.
14. В Address listнажимаем на новое значение ПКМ и выбираем»Change -> Address». В окне поле «Address of pointer» это Pointer.
15. Около него должен быть поле»Offset (Hex)» копируем данное поле и вставляем на калькулятор и сложим (+) на 500. Получившийся результат это оффсет.
Чтобы искать новый оффсет и не проделывать все пункты сначала:
16. Нажимаем на «Add address manually»,ставим галочку на «Pointer» и в поле «Address of pointer» пишем наш Pointer (например: PointBlank.i3exec+123123123). Нажимаем Ок.
17. В Address list нажимаем на новое значение ПКМ и выбираем «Change -> Address». Над полей «Address of pointer» есть текст вида «This pointer points to address 123123123» здесь «123123123» адрес, с которого будем искать другие оффсеты.
18. Выполняем пункт с 1-9. НО (!) вместо того чтобы вычислят (-) 500, мы будем, вычислят значение которое нашли недавно. Получившийся результат это — ОффСет.
2-ой способ я выложуtxt файлом т.к там очень много писать..прочитав,вы всё поймёте…
Источник: www.rf-cheats.ru
Теоретическая часть для понимания сути процесса
Как доподлинно известно, адрес в оперативной памяти — некий условный шестнадцатеричный идентификатор (а еще проще — обычное число) для взаимодействия программы с реальной физической памятью. По конкретному адресу всегда расположен ровно 1 байт информации. При этом значение любой переменной в программе хранится по какому-то адресу, даже у переменной, для которой выделено больше 1 байта. Например, если по адресу 0CC9B840 хранится переменная в 2 байта со значением в 10000, то в памяти по адресу 0CC9B840 будет храниться 10h, а по адресу 0CC9B841 будет храниться 27h (10000 в hex-кодировке будет выглядеть как 1027 с учетом обратного порядка чередования байтов). Но для программы важен именно начальный адрес всего блока из 2 байтов. Просто программа знает, что нужно использовать последовательно 2 байта информации, начиная с байта по искомому адресу — соответствующий тип переменной использовался разъеботчиком при написании исходного кода.
Каждый кулхацкер сталкивается с тем, что ранее найденный адрес со значением здоровья, патронов или выпусков журнала «Горячие попки ванамингосов» после перезапуска игры, уровня, а то и вовсе ВНЕЗАПНО становится нерабочим — теперь в нем хранится какое-то другое значение или вообще мусор (так называемый garbage — данные, на которые больше нет никаких ссылок). И нужно, превозмогая боль и страх, со штангенциркулем искать новый вожделенный адрес. Происходит сие непотребство из-за так называемого динамического распределения памяти — механизма создания и хранения программами данных в оперативной памяти непосредственно в процессе работы самой программы (называется «в рантайме»). Нужно игре выделить какой-то диапазон адресного пространства под свои данные? Да пожалуйста. Во время своей работы игра жонглирует данными постоянно, выделяя и освобождая память по необходимости. Создался новый враг? Отлично, под его данные выделено N байт. Враг получил передозировку киберсвинца в организьме и больше он нам и нахуй не нужон, враг ваш? Память, ранее выделенную под него, можно освободить и сделать доступной для записи каких-то иных данных, например, для спавна другого врага.
И, собственно, из-за этого блядского цирка с пересозданием объектов и происходит переезд данных на новые адреса в памяти, например, при переходе на новый уровень — игре нужно заново создать уровень и наполнить его объектами. При этом игре лишь нужно знать, с какого адреса будут начинаться данные нового уровня (увязать все это взаимодействие — задача компилятора, программист и в страшном сне заниматься этим не захочет), а относительно этого адреса игра будет пользоваться так называемыми указателями (pointers) на адреса — ссылками на начальные адреса вновь создаваемых объектов согласно принятой иерархии или на адреса, по которым располагаются конкретные значения.
Исходя из сказанного, можно сделать следующие выводы:
1. Память однородна. Ячейка памяти может хранить как исполняемый код, так и какие-то данные.
2. Если данные хранятся непосредственно по какому-то адресу в памяти, доступ к ним осуществляется напрямую при обращении к этому адресу.
3. По какому-то адресу в памяти можно разместить не конечные данные, а указатель — ссылку на какой-то другой адрес, где хранятся нужные данные.
4. Если указатель ссылается на другой указатель, то такой указатель будет называться многоуровневым. Времена одноуровневых указателей давно в прошлом, поэтому 99% нужных нам указателей будут многоуровневыми.
Тут надо сделать маленькое лирическое отступление о причинах возникновения такого порядка вещей. Всему виной повсеместное использование ООП — объектно-ориентированного программирования. Такой подход позволяет оперировать объектами игры как с некими абстрактными структурами данных, и хранить однотипные данные не в обособленных переменных, а в заранее определенном формате. Например, при создании нового объекта типа пони можно последовательно хранить имя пони, тип пони (обычная поня, пегас, единорог, аликорн и т.д.), цвет пони в кодировке RGB, тип кьютимарка (отличительный знак на ляжке — пояснение для жалких унтерменшей, не смотревших прогрессивные мультики про поней). Таким образом, когда будет создан новый объект типа пони, информация о нем будет заранее определенным образом упорядочена при описании структуры или класса объекта.
На абстрактном языке погромирования это может выглядеть следующим образом:
struct Pony
{
char name[10]; // 10 байт под имя
short type; // 2 байта под тип пони
byte color[3]; // 3 байта под цвет
byte cutiemark; // 1 байт под тип кьютимарка
}
Возможность создавать такие однотипные структуры данных позволяет экономить сотни времени, наделяя объекты общими данными и методами работы с ними.
Теперь представим, что мы как-то адекватно хотим описать в коде игры возможность пегасов летать. Создадим некую структуру данных и назовем ее PonyType. Пусть другие типы, кроме пегасов, нас сейчас не волнуют, и мы просто хотим в один байт уместить информацию о возможности или невозможности пони летать.
Для этого объявим в этой структуре логическую переменную canFly типа bool, которая может принимать значения true либо false, занимая при этом ровно 1 байт. Также добавим еще 1 байт под запас энергии для полета.
struct PonyType
{
bool canFly;
byte energy;
}
А теперь начинается интеграционная дружбомагия. В исходную структуру типа Pony поместим указатель на структуру типа PonyType:
struct Pony
{
char name[10];
PonyType* type; // тот самый указатель на тип в виде звездочки *
byte color[3];
byte cutiemark;
}
Таким образом, при создании нового объекта типа Pony информация о возможности летать и запасе энергии будет передаваться через указатель на структуру PonyType. Чсх, в памяти это будет занимать те же самые 2 байта, как если бы использовали ранее применявшийся целочисленный тип short.
Для программиста, который занимается разработкой структуры типа Pony, теперь не имеет значения, что там внедряет другой программист, занимающийся разработкой структуры PonyType. При правильной организации кода игры любые изменения в структуре PonyType никак не отразятся на работоспособности структуры Pony. Собственно, ради этого все и затевалось. Конечно, на таком простом примере сложно ощутить все преимущества ООП, но мейнстримом он стал не за красивые глаза.
И теперь уже совсем нетрудно построить некоторую цепочку указателей, начиная от создания мира.
Остальные данные структур не отображены для экономии пространства:
// структура лучезарного эквестрийского мира с множеством локаций
struct Equestria
{
.. // какие-то другие данные
City* city[36]; // для выделения памяти под 36 объектов типа City
}
// структура уютненького Понивилля с множеством поняшек
struct City
{
..
Pony* pony[100]; // для выделения памяти под 100 объектов типа Pony
}
// структура няшечки Рейнбоу и любой другой пони
struct Pony
{
..
PonyType* type; // для выделения памяти под 1 объект типа PonyType
}
// структура типа пони
struct PonyType
{
..
byte energy; // для выделения 1 байта памяти под значение энергии
}
Таким образом, например, при перезапуске игры нужно вновь создать объект типа Equestria, записав его начало по новому адресу, а дальше последовательно будет выделена память под 36 объектов типа City, для каждого и которых будет последовательно выделено место под 100 объектов типа Pony, в каждом из которых, в свою очередь, будет выделено место под 1 объект типа PonyType.
Адресация во всех этой махине зависит полностью от одного адреса — адреса начала объекта типа Equestria. И если нас интересует конечный адрес количества энергии на полет конкретной пони, то он каждый раз будет новый. Но с точки зрения игры все остается по прежнему:
→ Она знает начальный адрес, по которому прописался исполняемый код игры.
→ От него она отсчитывает известное количество байт, занимаемое исполняемым кодом и не относящимися к генерации уровня данными, и там начинает записывать данные, уже относящиеся к генерации уровня — то есть создает объект типа Equestria.
→ Далее по системе указателей она доходит до конечного пункта — количества энергии у конкретной пони — и использует его.
На слове последовательно я акцентирую внимание по той причине, что по нашей схеме будет использовано сквозное заполнение адресного пространства оперативной памяти: сначала будут созданы какие-то исходные данные объекта типа Equestria, затем создан первый объект типа City и все объекты типа Pony, затем второй объект типа City и все объекты типа Pony и так далее.
Собственно, зная адрес начала объекта типа Equestria и последовательность смещений до энергии конкретной пони, мы всегда может восстановить искомый адрес энергии. Задача поиска рабочего адреса энергии возлагается на рабочий указатель.
В рассматриваемом случае буквально получается, что объект типа Equestria создается по адресу, по которому была записана в оперативную память сама игра (ее исполняемый файл Game.exe) плюс некоторое смещение 10EF0C, необходимое игре для записи своего исполняемого кода и каких-то иных данных.
Относительно адреса объекта типа Equestria на значение C0 смещено расположение конкретного объекта типа City, относительно которого на значение FAD8 смещено расположение конкретного объекта типа Pony, относительно которого на значение 02FF смещено расположение конкретного объекта типа PonyType, относительно которого на значение 01 смещено расположение искомого значения энергии.
Обладая этой информацией, мы почти всегда однозначно можем определить истинный адрес искомого значения энергии.
И все это благолепие справедливо, конечно же, в том случае, если нужный нам город и нужная нам поня создаются первыми (вторыми, десятыми, главное — стабильность положения относительно начала) во всем массиве объектов (что часто бывает, поскольку именно относящиеся к игроку данные загружаются первыми). Также нужно уточнить, что адрес объекта типа Equestria может и не быть статическим (то есть неизменным от загрузки к загрузке — в нашем случае это Game.exe + 10EF0C), если не предопределен конечный объем данных перед его загрузкой. В этом случае адрес начала ключевого объекта должен быть найден способами, не входящими в данный гайд (через поиск так называемых сигнатур — уникальных последовательностей байтов). О сигнатурах мы тоже когда-то обязательно поговорим.
Резюмируя затянувшуюся вводную часть, подчеркну, что никакой мистики тут нет. С точки зрения кулхацкерства указатель — всего лишь ссылка на начальный адрес объекта внутри адресного пространства другого объекта либо непосредственно на адрес, по которому расположены требуемые данные.
Для успешного кулхацкерства достаточно знать, как вся система примерно работает в целом, а также владеть автоматизированными средствами поиска и ручными методами контроля правильности указателей.
К этому и приступим.
Автоматический поиск указателей
Практическая часть для формирования навыков
Если речь идет не об эрпогэ, где достаточно один раз взломать значение каких-нибудь скиллпоинтов, а затем тупо вкачать героя на полный фарш, поиск указателей является обязательной процедурой. Играя в шутер или РТС, хочется всегда иметь под рукой возможность поковырять ресурсы, здоровье или боезапас, не утруждая себя подчас утомительной процедурой поиска нового адреса. Да и в пошаговой эрпогэ каждый бой искать количество очков действия, если их всего два, а то и одно — нахуй так жыдь?
Но на помощь кулхацкерам приходят средства автоматизации СЕ, благодаря которым поиск рабочих указателей является ничуть не более сложной процедурой, чем стандартный поиск адреса.
Процесс поиска предлагаю рассмотреть на примере первой Мафии. Если при взгляде на главное меню у тебя заиграла в голове та самая музыка, а сердце защемило тоской по былому — я тебя понимаю!
Ну что ж, искать мы будем указатель на адрес, по которому хранится количество патронов в магазине оружия, находящегося в руках у игрока. Это весьма полезный указатель, позволяющий нам забыть про необходимость перезарядки абсолютно любого вооружения. Здесь и далее я считаю, что поиск соответствующего адреса не вызывает проблем. Если таковые имеются, можно либо перечитать вступительный гайд по СЕ, либо задать вопрос тут в каментах.
Значение патронов в текущем оружии хранится в обычной целочисленной переменной 4 байта, никаких трудностей при поиске и отсеве возникнуть не должно даже у новичков в использовании СЕ.
Итак, значение найдено. Действующий адрес 16В4744С.
Жмакаем правой кнопкой по адресу и выбираем пункт Pointer scan for this address.
Вылезет окошко опций сканирования, в котором ничего не нужно трогать, а только проконтролировать корректность адреса.
Далее СЕ попросит указать расположение файла результатов сканирования указателей в формате PTR.
После появится окно прогресса сканирования.
И завершится все феерическим количеством найденных указателей (результаты уже сохранены в файл 111.PTR). Предлагаю внимательно изучить результаты.
Сверху слева в выпадающем списке указан формат представления данных по конечному адресу, на который ссылается указатель. В нашем случае это 4 байта целочисленное. Конечный адрес указан в крайнем правом столбце Points to.
Сверху по центру указано общее количество найденных указателей: 26769689. 26 мульёнов — шутка ли?
В крайнем левом столбце Base Address указывается базовый статический адрес, относительно которого выстраивается многоуровневый указатель.
В столбцах Offset 0 – Offset 6 указывается смещение на каждом уровне многоуровневого указателя.
Если перенести даблкликом найденный указатель в рабочее поле СЕ и даблкликом же в поле Address открыть окно редактирования Change address, можно будет детально изучить всю структуру добавленного указателя. В рабочем поле указатель помечается префиксом P->.
В окне Change address снизу по центру указаны по порядку все уровни указателя, начиная со статического базового адреса. Справа приводится результат по каждому смещению. Результат по предыдущему вычислению становится исходным адресом для следующего уровня.
Если говорить совсем в открытую, уже сейчас, несмотря на дикое количество результатов, с ними можно работать. Но мы из вредности проведем еще один цикл поиска и отсева. Главное правило при отсеве указателей заключается в максимальном смещении всего адресного пространства, выделяемого под игру. Чаще всего, правда, достаточно игру просто перезапустить, но можно и поизъёбствываться, запустив перед загрузкой игры пару «тяжелых» приложений.
Но мы ограничимся перезапуском самой игры и загрузкой другого уровня. Окно СЕ с результатами поиска указателей по старому адресу остается открытым.
В открытом окне СЕ снова выбираем процесс игры. Проводим поиск нужного адреса. Готово.
В окне поиска указателей можно обратить внимание на то, что ранее найденные указатели, отображенные в данный момент на экране, уже не ссылаются на нужный адрес в памяти игры.
Теперь достаточно скопировать новый найденный адрес (даблклик по полю Address откроет окно редактирования), затем в окне поиска указателей нужно выбрать пункт меню Pointer scanner > Rescan memory — Removes pointers not pointing to the right address.
В появившемся окне нужно проконтролировать корректность введенного адреса и отметить чекбоксик Only filter out invalid pointers.
После установки чекбоксика изменение адреса и типа отсева станет недоступно.
Снова СЕ предложит нам сохранить результаты отсева указателей в файле PTR. Я рекомендую каждый этап сохранять в отдельной файле, ибо в случае каких-то проблем можно будет без труда загрузить предыдущие результаты. Из окна результатов сканирования Pointer scan это можно сделать через пункт меню File > Open.
Результатом предыдущего этапа являются 3кк указателей, что почти на порядок меньше, чем при первом поиске.
С этими результатами уже точно можно работать, но для подстраховки мы проведеи еще и третий цикл.
И четвертый цикл отсева произведем не по результатам поиска нового адреса, а по результатам сравнения в текущей сессии значений по адресам, на которые ссылаются найденные указатели. В этом случае нужно изменить тип отсева на Value to find, указать тип значения 4 байта целочисленное и снять чекбоксик Only filter out invalid pointers.
Как видно из количества отсеянных указателей на третьем и четвертом этапах, эти этапы можно было смело пропустить.
И вот здесь кулхацкер задаст себе резонный вопрос: как же работать с тремя миллионами (Карл!) найденных указателей? На помощь пытливому уму придет логика и здравый смысл:
1. Нужно проанализировать базовые адреса в колонке Base Address. Всякие мутные ddl-ки и прочие модули нам вряд ли подойдут. Нужен исполняемый файл или, на крайний случай, какая-то базовая библиотека. В случае с Мафией ориентироваться на Game.exe более чем разумно.
2. Если после очередного отсева есть указатели, ссылающиеся на адрес с некорректным значением (при условии правильно указанного типа значения — целочисленного или с плавающей точкой!), то такие указатели нам явно не подходят.
3. Чем меньше уровней в многоуровневом указателе, тем надежнее будет его использование. Иногда, конечно, и двухуровневые указатели могут отваливаться, но желательно стремиться к меньшему числу уровней.
И именно на этом этапе анализа достаточно кликнуть по заголовку столбца Offset 6, чтобы указатели были рассортированы по количеству уровней.
Теперь нужно легко и непринужденно даблкликом накидать скопом в рабочее поле СЕ указатели второго-пятого уровня различными базовыми адресами и первыми смещениями. В нашем примере очевидно, что Game.exe + 00246D4C является, скорее всего, тем самым правильным базовым адресом, но вот иерархия уровней указателей может не обязательно говорить в пользу меньшего количества уровней. Строго говоря, для точного ответа необходим ручной анализ структур данных, но это уже более комплексный вопрос. Поэтому надо накидать в рабочее поле штук по пять указателей каждого уровня и получить в итоге целую батарею предварительных результатов. В рабочем поле они все выглядят одинаково, но при редактировании можно будет увидеть всю структуру уровней каждого указателя.
Торжественный момент! Настало время проверить работоспособность найденных указателей.
Как всегда перезапускаем игру и загружаем другой уровень.
Выбираем в открытом окне СЕ процесс игры и — вуаля. Все найденные указатели являются рабочими. Удалять их из экономии пространства я пока не советую, ибо в разных условиях какие-то могут отвалиться и перестать работать, но в целом всё получилось. Можно объединить все указатели в группу в рабочем поле СЕ, выделив их и выбрав в контекстном меню по правой кнопке мыши Add to new group, озаглавив группу и выбрав уверенное No в вопросе «Do you want «address» version?». В настройках группы Group config в контекстном меню можно выбрать Hide children when deactivated и сворачивать всю группу пробелом или кликом по чекбоксу заморозки значения в левой части строки. Табличку можно сохранять и жить припеваючи.
Анализ дампа в окрестностях найденного адреса показал, что за 4 байта до нашего адреса хранится тип оружия, а через 4 байта после — общее количество патронов к данному оружию.
Что же нам теперь, повторять эту возню с поиском указателей еще и на эти адреса? Разумеется, нет.
Достаточно скопировать рабочем поле какой-нибудь корректный указатель с помощью Ctrl + C или пункта контекстного меню Copy, после чего вставить его здесь же по Ctrl + V (Paste).
Откроется небольшое окно, позволяющее указать требуемое смещение.
Альтернативный вариант заключается в копировании всего указателя без изменений и последующего редактирования копии в общем порядке.
Вот и все. Получается уютненькая табличка, которой можно пользоваться в том числе и тогда, когда оружия на миссию вообще не выдают, а покувыркаться с Сарочкой очень хочется — достаточно выставить тип оружия на 10 (томми-ган) и досыпать патронов, не забывая выкинуть его и поднять для корректной обработки появления оружия в руках у персонажа.
P.S. Ежели гранд-мастера погромирования меня поправят в чем-то и подскажут более корректные формулировки, буду крайне благодарен. В рассматриваемых теоретических вопросах я дилетант, поэтому здоровая критика моего взгляда на проблему будет очень пользительной.
Всем привет. Я пишу ботов для MMORPG Guild Wars. Занимаюсь этим год — полтора. Все это не слишком сложно, потому что существует такой скрипт как GWA2.au3, данный скрипт был написан не мной, он находится в публичном доступе, каждый может его скачать и заниматься бытописанием для Guild Wars. В данном скрипте прописаны многие пути расположения тех или иных значений, такие как количество здоровья, координаты персонажа, место нахождение и тд, все это можно определить используя ту или иную функцию. Но увы всех функций не достаточно что бы писать новых ботов. Ниже приведу пример, нескольких функций.
; Пример первой функции
Func GetPartySize()
Local $lOffset[5] = [0, 0x18, 0x4C, 0x64, 0x24]
Local $lPartyPtr = MemoryReadPtr($mBasePointer, $lOffset)
Local $lReturn = MemoryRead($lPartyPtr[0], 'long') ; henchmen
Return $lReturn
EndFunc ;==>GetPartySize
; Пример первой 2 функции
Func GetMissionStartDelay()
Local $lOffset = [0, 0x18, 0x44, 0x9C, 0]
Return MemoryReadPtr($mBasePointer, $lOffset)[1]
EndFunc
Первая функция определяет количество персонажей в команде. Второй определяет статус команды (лидер команды, начата ли миссия и тд.)
Ниже MemoryReadPtr и MemoryRead.
;~ Description: Internal use only.
Func MemoryReadPtr($aAddress, $aOffset, $aType = 'dword')
Local $lPointerCount = UBound($aOffset) - 2
Local $lBuffer = DllStructCreate('dword')
For $i = 0 To $lPointerCount
$aAddress += $aOffset[$i]
DllCall($mKernelHandle, 'int', 'ReadProcessMemory', 'int', $mGWProcHandle, 'int', $aAddress, 'ptr', DllStructGetPtr($lBuffer), 'int', DllStructGetSize($lBuffer), 'int', '')
$aAddress = DllStructGetData($lBuffer, 1)
If $aAddress == 0 Then
Local $lData[2] = [0, 0]
Return $lData
EndIf
Next
$aAddress += $aOffset[$lPointerCount + 1]
$lBuffer = DllStructCreate($aType)
DllCall($mKernelHandle, 'int', 'ReadProcessMemory', 'int', $mGWProcHandle, 'int', $aAddress, 'ptr', DllStructGetPtr($lBuffer), 'int', DllStructGetSize($lBuffer), 'int', '')
Local $lData[2] = [$aAddress, DllStructGetData($lBuffer, 1)]
Return $lData
EndFunc ;==>MemoryReadPtr
;~ Description: Internal use only.
Func MemoryRead($aAddress, $aType = 'dword')
Local $lBuffer = DllStructCreate($aType)
DllCall($mKernelHandle, 'int', 'ReadProcessMemory', 'int', $mGWProcHandle, 'int', $aAddress, 'ptr', DllStructGetPtr($lBuffer), 'int', DllStructGetSize($lBuffer), 'int', '')
Return DllStructGetData($lBuffer, 1)
EndFunc ;==>MemoryRead
Соответственно вопрос таков. Как я могу найти такие значения как $lOffset[5] = [0, 0x18, 0x4C, 0x64, 0x24] (первый пример) и $lOffset = [0, 0x18, 0x44, 0x9C, 0] (второе значение)???
Эти значения уже найдены, но я хочу их найти самостоятельно, что бы потом я так же смог найти другие, которые отсутствуют в скрипте. Я понимаю что для это мне нужно использовать OllyDbg или Cheat Engine. Так же у меня есть инструмент для получения отправленных и полученных пакетов из сервера до шифрования. Фото ниже.
То есть это ряд мне выдает программа, которая получила пакет от сервера. Вторая функция GetMissionStartDelay() возвращает тоже значение. 0x100 Integer => …..
Я попытался сравнить $lOffset и hex ряд на фото, к сожаления сходств я не нашел. Пытался найти этот hex ряд с помощью OllyDgb и тоже без результатной. Буду рад получить любые советы для решения данного вопроса.
И да, сам GWA2.au3 выложу ниже.