Перейти к содержанию

Проблема с видовой матрицей [Phasmophobia]


Рекомендуемые сообщения

Всем привет!

Не давно тут решил поиграться с такой замечательной вещью как видовая матрица. В качестве подопытной игры выбрал Call of Duty: Modern Warfare 2. В качестве инструмента выбрал язык C# и сканер памяти Cheat Engine.

 

Соответственно нашёл адрес игрового объекта к примеру вертолёт, хранящий ось X и далее по смещениям в 4 байта нашёл Y и Z. Использовал Win API функцию ReadProccessMemory, предварительно описав её:

 

[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr OpenProcess(int processAccess, bool bInheritHandle, int processId);

[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CloseHandle(IntPtr hObject);

[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool ReadProcessMemory(IntPtr pHandle, IntPtr Address, ref float Buffer, int Size, IntPtr NumberofBytesRead);

Читаю байты из памяти:

/// <summary>
/// Reads bytes from the specified address in the proccess memory, saves bytes to the buffer
/// </summary>
private void ReadBytes()
{
      ReadProcessMemory(handle, (IntPtr)BaseAddress, ref tempCoord, size, (IntPtr)bytesRead);
      objCoord[0] = tempCoord; //X coordinate
      ReadProcessMemory(handle, (IntPtr)(BaseAddress + 4), ref tempCoord, size, (IntPtr)bytesRead);
      objCoord[1] = tempCoord; //Y coordinate
      ReadProcessMemory(handle, (IntPtr)(BaseAddress + 4 + 4), ref tempCoord, size, (IntPtr)bytesRead);
      objCoord[2] = tempCoord; //Z coordinate
}

В общем по игрался с координатами всё замечательно работает, потом решил поискать видовую матрицу. Само собой искал неизвестное значение в диапазоне от -1.0 до 1.0

Нашёл, это матрица 4 на 4 = всего 16 байт для чтения, записал в массив:

/// <summary>
/// Reads bytes for the view matrix, saves it to the buffer
/// </summary>
private void GetViewMatrix()
{
	for (int i = 0; i < 16; i++)
	{
		ReadProcessMemory(handle, (IntPtr)(VMBaseAddress + (i * 4)), ref tempCoord, size, (IntPtr)bytesRead);
		view_matrix[i] = tempCoord;
	}
}

А затем преобразовывал их в координаты на экране и писал результат (x, y координаты) в поля моей структуры, чтобы потом использовать их для рисования объекта, который как раз таки будет отображать игровой объект подобно ESP хакам:

/// <summary>
/// Converts coordinates from 3D world of the game to 2D coordinates for the Form, sets Indicator position using converted 2D coordinates, returns 1 - object is visible on form; 0 - otherwise
/// </summary>
/// <returns>integer value 1 - object is visible on form; 0 - otherwise</returns>
private int WorldToScreen()
{
	screenCoords[0] = objCoord[0] * view_matrix[0] + objCoord[1] * view_matrix[1] + objCoord[2] * view_matrix[2] + view_matrix[3];
	screenCoords[1] = objCoord[0] * view_matrix[4] + objCoord[1] * view_matrix[5] + objCoord[2] * view_matrix[6] + view_matrix[7];
	screenCoords[2] = objCoord[0] * view_matrix[8] + objCoord[1] * view_matrix[9] + objCoord[2] * view_matrix[10] + view_matrix[11];
	screenCoords[3] = objCoord[0] * view_matrix[12] + objCoord[1] * view_matrix[13] + objCoord[2] * view_matrix[14] + view_matrix[15];
	if (screenCoords[3] < 0.1f)
	{
		return 0;
	}
	ndc[0] = screenCoords[0] / screenCoords[3];
	ndc[1] = screenCoords[1] / screenCoords[3];
	ndc[2] = screenCoords[2] / screenCoords[3];
	strucPoint.X = Convert.ToInt32((this.Width / 2 * ndc[0]) + (ndc[0] + this.Width / 2));
	strucPoint.Y = Convert.ToInt32(-(this.Height / 2 * ndc[1]) + (ndc[1] + this.Height / 2));
	return 1;
}

Всё прекрасно работало, но потом решил сделать тоже самое для игры Phasmophobia, и так, сперва нашёл адрес объекта, в данном случае баскетбольный мяч (его можно найти на карте главного меню), читаю значения из адреса с координатами. Координаты там представлены довольно "маленькими значениями" типа float (для сравнения: 324.5643 - Cod:MW2; 1.0344543533 - Phasmophobia).

К тому же адреса довольно длинные (больше 8 символов в HEX формате) для этого мне пришлось использовать тип данных структуры System.Int64 (тип long) для хранения адресов, и запускать проект в x64 сборке чтобы преобразование (IntPtr)(VMBaseAddress) было рабочим при передаче аргумента в функцию ReadProccessMemory.

 

Учитывая то что игра написана на движке Unity, координата по оси Z находится второй по счёту (после первого смещения в 4 байта), а не третьей (после второго смещения в 4 байта) как в остальных играх, ведь в Unity немного по другому расположены координатные прямые.

 

И так нашёл адреса и значения всё также по смещениям в 4 байта, пришло время искать видовую матрицу. И вот тут собственно начались проблемы, я нашёл очень похожый массив байт в 16 элементов как в предыдущей игре и попытался преобразовать и нарисовать объект на экране, но годного ESP не получилось, вместо этого объект рисовался вокруг да около нужного места.

 

Вот по этому прошу помощи в поиске и разъяснение касательно именно для Unity:

Может ли быть такое, что подобное преобразование (описано в методе WorldToScreen() см. код выше) может являться некорректным, учитывая особенность координат в Unity, ведь я записывал координаты в том порядке в котором они представлены в игре, то есть Z во вторую ячейку, а Y в третью??

Изменено пользователем Sergey99
Ссылка на комментарий
Поделиться на другие сайты

Привет, мне тоже очень интересны тему касающиеся координат и матриц.

Только я не совсем понял цели описанного. У тебя есть видео работы этого мода для Call of Duty: Modern Warfare 2?

 

В свое время я делал неверно что-то подобное. Отображал через D3D положение машин опопнентов относительно моей.

Ссылка на комментарий
Поделиться на другие сайты

6 часов назад, Antonshka сказал:

Привет, мне тоже очень интересны тему касающиеся координат и матриц.

Только я не совсем понял цели описанного. У тебя есть видео работы этого мода для Call of Duty: Modern Warfare 2?

 

В свое время я делал неверно что-то подобное. Отображал через D3D положение машин опопнентов относительно моей.

 

Конечно видео есть, вот:

 

 

Всё довольно просто, использую конвертированные в 2D координаты из 3D для рисования зелёного текста с чёрным фоном. То же самое и для Phasmophobia хочется реализовать, но как я описывал в теме, возникли некоторые трудности.

 

  • Плюс 1
Ссылка на комментарий
Поделиться на другие сайты

Отлично получилось на видео.

У меня гораздо проще все было. Такого преобразования я не делал. Я просто брал две координаты из трех (кроме высоты), и использовал их для расчета положения в плоскости относительно моих.

 

Такой вещи как на видео я еще ни разу не делал.

Поделись источником как делать преобразование из 3D в 2D.

Ссылка на комментарий
Поделиться на другие сайты

Сейчас ещё параллельно пытаюсь найти видовую матрицу в Amnesia - The Dark Descent. Тут также как в Phasmophobia координата Z вторая по счёту, а не третья. Ищу видовую матрицу, описание с рисунком есть здесь: https://www.3dgep.com/understanding-the-view-matrix/

 

Поэтому я сравниваю, вот нахожу нечто похожее (самая нижняя строка также представлена как 0, 0, 0, 1), но один из элементов в матрице не меняется, а точнее Y для right вектора, соответственно преобразование не работает, хотя в CoD:MW2 точно также ведёт себя X для forward вектора (выделен красным) 1.png

Ссылка на комментарий
Поделиться на другие сайты

9 минут назад, Antonshka сказал:

Отлично получилось на видео.

У меня гораздо проще все было. Такого преобразования я не делал. Я просто брал две координаты из трех (кроме высоты), и использовал их для расчета положения в плоскости относительно моих.

 

Такой вещи как на видео я еще ни разу не делал.

Поделись источником как делать преобразование из 3D в 2D.

Тут просто обычная функция, или метод (если ты в классе реализуешь это), вот пример где всё хранится в массивах:

private int WorldToScreen()
{
	screenCoords[0] = objCoord[0] * view_matrix[0] + objCoord[1] * view_matrix[1] + objCoord[2] * view_matrix[2] + view_matrix[3];
	screenCoords[1] = objCoord[0] * view_matrix[4] + objCoord[1] * view_matrix[5] + objCoord[2] * view_matrix[6] + view_matrix[7];
	screenCoords[2] = objCoord[0] * view_matrix[8] + objCoord[1] * view_matrix[9] + objCoord[2] * view_matrix[10] + view_matrix[11];
	screenCoords[3] = objCoord[0] * view_matrix[12] + objCoord[1] * view_matrix[13] + objCoord[2] * view_matrix[14] + view_matrix[15];
	if (screenCoords[3] < 0.1f)
	{
		return 0;
	}
	ndc[0] = screenCoords[0] / screenCoords[3];
	ndc[1] = screenCoords[1] / screenCoords[3];
	ndc[2] = screenCoords[2] / screenCoords[3];
	strucPoint.X = Convert.ToInt32((this.Width / 2 * ndc[0]) + (ndc[0] + this.Width / 2));
	strucPoint.Y = Convert.ToInt32(-(this.Height / 2 * ndc[1]) + (ndc[1] + this.Height / 2));
	return 1;
}

А вот источник где также описаны функции WorldToScreen, только для хранения они используют поля структур или классов: https://guidedhacking.com/threads/world2screen-direct3d-and-opengl-worldtoscreen-functions.8044/

Как найти видовую матрицу от туда же: https://guidedhacking.com/threads/how-to-get-started-with-learning-viewmatrix.13663/

Но я использовал метод поиска между -1.0 и 1.0

Изменено пользователем Sergey99
  • Плюс 1
Ссылка на комментарий
Поделиться на другие сайты

Спасибо за ссылки!

 

А ты пробовал нопить пишущие в эти адреса инструкции и смотреть, перестала вращаться камера или нет? Чтобы удостовериться, что это верные адреса.

Ссылка на комментарий
Поделиться на другие сайты

2 минуты назад, Antonshka сказал:

Спасибо за ссылки!

 

А ты пробовал нопить пишущие в эти адреса инструкции и смотреть, перестала вращаться камера или нет? Чтобы удостовериться, что это верные адреса.

Есть вероятность того, что игра обидится и закроется, если наткнусь на не те адреса и установлю инструкцию nop. Но попробовать стоит.

Ссылка на комментарий
Поделиться на другие сайты

1 минуту назад, Sergey99 сказал:

Есть вероятность того, что игра обидится и закроется, если наткнусь на не те адреса и установлю инструкцию nop. Но попробовать стоит.

У тебя на скрине первое значение матрицы -1,06. Скорее всего в этом проблема. Значение не должно быть больше 1 или меньше -1.

Тебе нужно просто нормализовать эту матрицу.

1 - Получить из неё Yaw, Pitch, Roll

2 - Проверить что они правильно отрабатывают, показывают правильные углы

3 - Из них же сделать преобразование уже в нормализованную матрицу

 

Ссылка на комментарий
Поделиться на другие сайты

3 минуты назад, Antonshka сказал:

У тебя на скрине первое значение матрицы -1,06. Скорее всего в этом проблема. Значение не должно быть больше 1 или меньше -1.

Тебе нужно просто нормализовать эту матрицу.

1 - Получить из неё Yaw, Pitch, Roll

2 - Проверить что они правильно отрабатывают, показывают правильные углы

3 - Из них же сделать преобразование уже в нормализованную матрицу

 

Это для CoD:MW2 я уже nop'ы поставил и проверил, изображение становится плоским + на видео я показывал, что там работает всё. Сейчас буду тоже самое пробовать для Amnesia и Phasmophobia. Так как там координаты немного местами поменяли разработчики

Изменено пользователем Sergey99
Ссылка на комментарий
Поделиться на другие сайты

1 час назад, Sergey99 сказал:

Это для CoD:MW2 я уже nop'ы поставил и проверил, изображение становится плоским + на видео я показывал, что там работает всё. Сейчас буду тоже самое пробовать для Amnesia и Phasmophobia. Так как там координаты немного местами поменяли разработчики

Изображение становиться плоским если занопить только часть инструкций. То есть если из девяти адресов видовой матрицы некоторые останутся задействованными.

 

Тот адрес, который выделен красным, и который не меняется (0,00),, - это адрес Roll. В игре камера не наклоняется влево-право, потому он всегда имеет значение 0.

Ссылка на комментарий
Поделиться на другие сайты

Нашёл видовую матрицу для Amnesia, в конце можно увидеть куда деваются все объекты после "неожиданного исчезновения":

 

 

Как выясняется расположение координат в адресном пространстве не влияет на обработку видовой матрицы:

amns.png - Amnesia, адрес со значением Roll (выделен красным), находится во втором столбце

cod.png - CoD:MW2, адрес со значением Roll (выделен красным), находится в третьем столбце, подобно адресу, хранящим координату Z в структуре объекта. Что же, раз положение Roll, зависит от порядка следования координат, сейчас пойду искать в игре Phasmophobia, сообщу как результат.

Ссылка на комментарий
Поделиться на другие сайты

1 час назад, Antonshka сказал:

Изображение становиться плоским если занопить только часть инструкций. То есть если из девяти адресов видовой матрицы некоторые останутся задействованными.

 

Тот адрес, который выделен красным, и который не меняется (0,00),, - это адрес Roll. В игре камера не наклоняется влево-право, потому он всегда имеет значение 0.

В Phasmophobia смещение между адресами с координатами игрока = 8 байт, всё из-за того что между каждыми этими адресами есть ещё один, где хранится коке-то значение, которое мне не интересно и оно тоже занимает 4 байта памяти. Может ли в таком случае структура видовой матрицы изменится как-нибудь или же она всегда 4x4 = 16 байт и каждый столбец - это X, Y, Z для определённого вектора?

Ссылка на комментарий
Поделиться на другие сайты

Да уж спустя столько времени я так и не нашёл матрицу, проверял даже банально подстановкой в код для преобразования, чтобы сразу проверять правильные ли байты или нет. Интересно почему так, может я не там ищу?

Ссылка на комментарий
Поделиться на другие сайты

1 час назад, trickster сказал:

Почему ты просто не используешь крючки?

Что такое крючки?

 

6 часов назад, Sergey99 сказал:

Да уж спустя столько времени я так и не нашёл матрицу, проверял даже банально подстановкой в код для преобразования, чтобы сразу проверять правильные ли байты или нет. Интересно почему так, может я не там ищу?

Может там значения координат и матрицы в типе Double, а не Float.

 

 

9 часов назад, Sergey99 сказал:

всё из-за того что между каждыми этими адресами есть ещё один, где хранится коке-то значение, которое мне не интересно и оно тоже занимает 4 байта памяти.

Возможно что это вторые половинки числа типа Double. Просто ты смотришь на них как на тип Float.

Ссылка на комментарий
Поделиться на другие сайты

А что мешает взять dnSpy и просто найти, в каком методе используется видовая  матрица? Затем взять CE Mono и перейти по методу найденному в dnSpy.
Поиск можно начать с Camera, тем более, в зависимости от игры камер может быть несколько и у каждой будет своя матрица.

Изменено пользователем ChestGlaring
Ссылка на комментарий
Поделиться на другие сайты

10 часов назад, Antonshka сказал:

Возможно что это вторые половинки числа типа Double. Просто ты смотришь на них как на тип Float.

Я сомневаюсь что координаты представлены как тип Double

1.png

Но попробую поискать видовую матрицу как Double между -1.0 и 1.0

Ссылка на комментарий
Поделиться на другие сайты

6 часов назад, ChestGlaring сказал:

А что мешает взять dnSpy и просто найти, в каком методе используется видовая  матрица? Затем взять CE Mono и перейти по методу найденному в dnSpy.
Поиск можно начать с Camera, тем более, в зависимости от игры камер может быть несколько и у каждой будет своя матрица.

Да, идея хорошая, учитывая то что игра на Unity с использование скриптинга на C#, но не каждая же игра написана на таких общедоступных движках, к примеру CoD:MW2 была написана на C++ и "IW Engine" (движок разработчиков - они сами его написали и сами же модернизировали).

Изменено пользователем Sergey99
Ссылка на комментарий
Поделиться на другие сайты

15 минут назад, Sergey99 сказал:

Да, идея хорошая, учитывая то что игра на Unity с использование скриптинга на C#, но не каждая же игра написана на таких общедоступных движках, к примеру CoD:MW2 была написана на C++ и "IW Engine" (движок разработчиков - они сами его написали и сами же модернизировали).

Ну если игра не на юнити, то тогда и нужно искать видовую матрицу
Для юнити довольно просто все писать. Берешь саму dll, которая Assembly-csharp из папки manage.
Это считай твоя "основная библиотека классов" для модификаций чего угодно. После написания инжектируешь как mono библиотеку

Ссылка на комментарий
Поделиться на другие сайты

45 минут назад, roma912 сказал:

Ну если игра не на юнити, то тогда и нужно искать видовую матрицу
Для юнити довольно просто все писать. Берешь саму dll, которая Assembly-csharp из папки manage.
Это считай твоя "основная библиотека классов" для модификаций чего угодно. После написания инжектируешь как mono библиотеку

А может быть такое что байты видовой матрица перевёрнуты? то есть порядок столбцов тот же, а вот строки снизу вверх?

Ссылка на комментарий
Поделиться на другие сайты

2 минуты назад, Sergey99 сказал:

А может быть такое что байты видовой матрица перевёрнуты? то есть порядок столбцов тот же, а вот строки снизу вверх?

Ну... Я с видовыми матрицами работал совсем немного
Но перевернутых никаких мне не встречалось.
Да и если посмотреть как формируется н-мерный массив, то он останется таким же и в памяти.
Т.е. как он был записан в коде, так должен и выглядеть в памяти. Разве что в CE выбрать неправильное отображение (Оно и может наверное запутать)

Ссылка на комментарий
Поделиться на другие сайты

1 час назад, Sergey99 сказал:

но не каждая же игра написана на таких общедоступных движках

 

Но ведь и ты не спрашиваешь про общие принципы нахождения видовой матрицы. Какой вопрос - такой ответ. А в той игре, которая указана в названии темы, 3 видовых матрицы, для игрока, камеры и еще какой-то штуки.

Изменено пользователем ChestGlaring
Ссылка на комментарий
Поделиться на другие сайты

17 минут назад, ChestGlaring сказал:

 

Но ведь и ты не спрашиваешь про общие принципы нахождения видовой матрицы. Какой вопрос - такой ответ. А в той игре, которая указана в названии темы, 3 видовых матрицы, для игрока, камеры и еще какой-то штуки.

Ищу я видовую матрицу для игрока, вот как он смотрит на 3D мир (вид от первого лица, никакого геймплея через "камеру" нет, просто грубо говоря глаза игрока), а вообще выше по теме было целых два видео где я её использую так что думаю очевидно что я ищу в этой игре.

Изменено пользователем Sergey99
Ссылка на комментарий
Поделиться на другие сайты

×
×
  • Создать...

Важная информация

Находясь на нашем сайте, Вы автоматически соглашаетесь соблюдать наши Условия использования.