Стратегии победы над редакторами памяти для обмана - настольные игры [закрыто]

35

Я предполагаю, что мы говорим о настольных играх - то, что игрок загружает и запускает на своем локальном компьютере. Многие из них являются редакторами памяти, которые позволяют вам определять и фиксировать значения, например, здоровье вашего игрока.

Как вы предотвращаете мошенничество с помощью модификации памяти? Какие стратегии эффективны для борьбы с этим видом мошенничества?

Для справки, я знаю, что игроки могут: - искать что-то по значению или диапазону - искать что-то, что изменило значение - установить значения памяти - заморозить значения памяти

Я ищу хорошие. Два, которые я использую, являются посредственными:

  • Отображение значений в процентах вместо числа (например, 46/50 = 92% здоровья)
  • Класс низкого уровня, который содержит значения в массиве и перемещает их при каждом изменении. (Например, вместо int у меня есть класс, представляющий собой массив целых чисел, и всякий раз, когда значение изменяется, я использую другой, случайно выбранный элемент массива для хранения значения)

Игра оффлайн, бесплатная и для одного игрока.

Изменить: для потомков, я решил это (в C #) и разместил свое решение здесь , в моем блоге.

ashes999
источник

Ответы:

21

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

Так что представьте, что вы получили health, вы бы тоже healthComplement. Ваша реализация может выглядеть так:

// setter sets value and complement
void setHealth(int value){
    health = value;
    healthComplement = ~value;
}

// getter checks if value was changed outside of the setter
int getHealth(){
    if(value != ~healthComplement){
        // launch some cheat-counter-measure, like crashing the game?
        exit;
    }
    return health;
}

Кто-то, кто хочет обмануть, должен будет правильно установить health и healthComplement, иначе игра вылетит.

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

bummzack
источник
12

Вот одна из схем, которую я придумал, когда кто-то давно просил об этом на доске. Использование процентов или удвоенных переменных на самом деле не работает, так как вы можете искать «любые» значения и фиксировать их.

Вместо этого сделайте монстра типа данных.

В основном, храните ваши важные ценности как структуру с:

  • 32 указателя на биты
  • Для быстрого чтения сделайте так, чтобы структура включала текущее значение как обычный int

Для манипуляций соберите текущее значение из отдельно выделенных битов (которые могут быть целыми числами true / false), измените значение и сохраните их обратно.

Вот неприятный момент: каждый раз, когда вы манипулируете значением, освобождаете и снова распределяете биты. Распределение должно происходить в случайном порядке , поэтому данные перемещаются в памяти и не могут быть легко заморожены.

Дополнительные меры предосторожности заключаются в хранении контрольных сумм значений (а также "обычного" int) и их сравнении во время вызовов манипуляции. Если обнаружено несоответствие, сделайте что-нибудь неуловимое, например, удалите случайный ключ, необходимый для открытия дверей, чтобы прогрессировать в игре.

Изменить: Для дальнейшего движения памяти, убедитесь, что вы распределили новые «биты», прежде чем освободить старые.

Редактирование: для многопользовательских игр также возможно сериализовать структуру данных, сжать ее и отправить по сети. Не самое эффективное использование сети, но определенно сложнее разобраться с помощью перехвата пакетов.

Яри ​​Комппа
источник
9

Как насчет того, чтобы хранить здоровье, дополненное случайным значением, генерируемым каждый раз, когда вы сохраняете его? Это, по крайней мере, сломало бы простой механизм поиска увеличения / уменьшения значений в памяти, чтобы найти здоровье.

class Player
{
  int m_Health;
  int m_RandomHealth;
  Random m_Rnd = new Random();

  public int Health {
    get
    {
      return m_Health ^ m_RandomHealth;
    }

    set
    {
      m_RandomHealth = m_Rnd.Next();
      m_Health = value ^ m_RandomHealth;
    }
  }
}

Кроме того, вы можете сбросить значение каждого кадра, даже если состояние не меняется. Это не позволит людям искать измененные адреса, когда их здоровье меняется, и они остаются прежними, если их здоровье остается прежним.

Бонус: создайте новый объект каждый раз, когда он изменяется, чтобы изменить адрес памяти, и установите работоспособность для изменения случайного числа, сохраненного значения и адреса в памяти каждый раз, когда вы читаете его:

class Player
{
  int [] m_HealthArray; // [0] is random int, [1] is xored health
  Random m_Rnd = new Random();

  public Player() {
    this.Health = 100;
  }

  public int Health {
    get
    {
      int health = m_HealthArray[0] ^ m_HealthArray[1];
      Health = health; // reset to move in memory and change xor value
      return health;
    }

    set
    {
      m_HealthArray = new int[2];
      m_HealthArray[0] = m_Rnd.Next();
      m_HealthArray[1] = m_HealthArray[0] ^ value;
    }
  }
}
Джейсон Гомаат
источник
8

Хотя я сделал первый комментарий, ставя под сомнение точку зрения ухудшения восприятия части вашей аудитории без видимой выгоды, я все же нахожу это интересным вопросом с технической точки зрения.

У меня просто возникла идея: обманщики находят изменяющие ценности и замораживают их. Поиск будет происходить только между смертями или событиями, которые изменили здоровье игрока. Более того, мошенник мог уточнить поиск, отфильтровывая то, что изменилось, когда он «не умирал».

Что если счетчик «здоровья» постоянно меняется? Сделайте его указателем и перераспределите его каждый кадр или каждый N кадров, если производительность слишком велика. Или XOR это со случайным значением, которое изменяет каждый кадр (снова XOR против того же значения для дешифрования перед шифрованием с новым случайным значением).

Если у вас есть другие внутриигровые данные, которые также меняются все время (включая x и y позиции персонажа игрока или счетчик времени), это может затруднить определение того, какие из изменяющихся данных являются состоянием здоровья. А замораживание всего игрового состояния - мошенник.

Чтобы еще больше ввести в заблуждение, вы можете хранить состояние в простой переменной, доступной только для записи, в качестве медового банка.

Редактировать :

Тем не менее, мошенник может попытаться найти, какая из переменных, которая меняется все время, является той, которая замораживается методом проб и ошибок. Возможное решение было бы соединить переменные вместе.

Пример:

Вместо сохранения здоровья (h) и позиции (x) вы сохраняете их в двух переменных a и b, из которых вы можете получить значения позже:

a = x+h; b = x-h
x = (a+b)/2; h = (a-b)/2

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

a = x-h; b = x+h
x = (a+b)/2; h = (b-a)/2

В последовательных кадрах, и вы гарантируете, что не более чем через 2 кадра после того, как одна из переменных была заморожена, здоровье станет равным 0 в момент изменения x. Помните, что вы храните только a и b. Объедините это с непрерывным XOR, как упомянуто выше. В результате получается набор переменных, которые меняют каждый кадр на кажущиеся случайными значения, а замораживание любого отдельного или его подмножества приводит только к нежелательным побочным эффектам в игре, одним из которых является мгновенная смерть.

CeeJay
источник
7

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

Если вы обнаружили мошенничество, теперь вы можете изменять правила игры так, как считаете нужным для максимального оплакивания, если это ваше намерение. Если ваше намерение состоит в том, чтобы игнорировать читерство и заставить игру продолжать работать, перераспределите здоровье в другом месте памяти и измените ваши указатели так, чтобы новое значение использовалось, а старое игнорировалось. Повторите до бесконечности.

Джеймс
источник
6

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

Тем не менее, и вы, вероятно, не будете любить это, я думаю, вы ищете занавес памяти , который является концепцией Trusted Computing .

Сэм Хоцевар
источник
3

Один очень эффективный метод, используемый некоторыми roguelikes (DoomRL, Brogue), заключается в маскировании реальных переменных. Это означает, что вместо того, чтобы показывать здоровье как «2/10», показывайте его как «20%».

Помните, что большинство редакторов памяти хорошо работают с поиском / фильтрацией определенных значений. Если вы не знаете конкретное значение, вы все равно можете его отследить (например, искать измененные / уменьшенные значения после того, как здоровье игрока падает), хотя это займет намного больше времени.

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

ashes999
источник
2

Напишите драйвер ring 0, который перехватывает SSDT и регистрирует / блокирует при вызове ReadProcessMemory / WriteProcessMemory в вашем приложении. Было бы лучше просто войти, чтобы вы могли постепенно менять их игровое поведение с течением времени, а не просто падать.

Дуга-W
источник
Похоже, вы говорите о деталях реализации низкого уровня (Windows API?). Я спрашиваю об общих стратегиях высокого уровня.
ashes999
2

Почему вы не позволяете игрокам обманывать себя (что равно обману в одиночной игре)? В многопользовательской среде задачей сервера является обнаружение неестественных изменений и противодействие им (как правило, либо игнорируя ввод, либо полностью блокируя преступника с сервера), но в среде с одним игроком ничего не происходит, кроме мошенника, который делает сам вред.

Итак, если вы не создаете многопользовательскую игру, это пустая трата денег, а если вы думаете, то ужесточаете не то место.

jwenting
источник
2

Исследуйте известные инструменты мошенничества - и часто проверяйте, работает ли какой-либо из наиболее распространенных инструментов (проверьте имена процессов?)

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

Не остановит более решительных хакеров, но уменьшит вероятность того, что более простые читы испортят ваши таблицы лидеров.

(Возможно, раздражают кодеров, которые открыли и свернули инструменты разработчика для законных целей и делают перерыв в игре, хотя ...)

bluescrn
источник
7
Я был большим поклонником Steam как платформы для дистрибуции и пару лет назад много играл в Team Fortress II. Однажды вечером я взял перерыв в долгой сессии кодирования и оставил открытой Visual Studio и отладчик во время игры. Я оказался забаненным у TF2 за "обман". Нет апелляции, нет рамок для снятия запрета. Одно «обида» и оно постоянно для аккаунта. Я до сих пор не представляю, почему - и поверьте мне, я был в дурном настроении - за исключением того, что я увидел глубоко закопанный в FAQ вопрос о том, что наличие «редактора памяти» во время игры представляет собой мошенничество и его можно запретить. Вау.
1

Я думаю, что самое простое решение для этого - реализовать чит-опцию. Отключить подсчет очков в режиме читов.

Еще одна хорошая идея, что я понятия не имею, как бы вы реализовали. Это отключить игру, когда есть замороженная переменная памяти или что-то в этом роде :)

Удачи)

HgMerk
источник
3
Внедрение читов - хороший вариант. Выключение игры, не так уж много ... (представьте, если вы ошиблись, и закройте законного игрока.)
ashes999