Hafıza Tarayıcılar Oyunlarınıza Nasıl Zarar Verir ve Nasıl Engellenirler?
- Tolga Karanlikoglu
- 14 Eyl 2023
- 2 dakikada okunur
İngilizce dilinde "Memory scanner" olarak geçen bu tür programlar sizin oyununuz açık olduğu bir anda hafızadaki belirli değerleri tarayarak onları başka değerlerle değiştirebilirler. Örneğin oyununuzda aşağıdaki resimde olduğu gibi $12,345 var diyelim.

Bir hafıza tarayıcı programı (örneğin Cheat Engine) oyununuzun işlemine erişip 12345 sayısını aratarak onun hangi hafıza konumlarında bulunduğunu tespit eder. Sonrasında 12345 sayısını diyelim ki 999999 ile değiştirdiğinizde sonuç şu şekilde görünecektir:

Bir anda oyundaki bakiyeniz uçtu :) Fakat bu hiç de hayırlı bir uçuş olmadı takdir edeceğiniz gibi. Bir kez oyuncu sizden satın alabileceği oyun parasını kolayca bedavaya ürettiğini gördükten sonra bir daha sizden bir şey satın almasının imkanı kalmadı. Üstelik daha da kötüsü haksız bir şekilde elde ettiği oyun parasını başka oyunculara sizin fiyatınızın altında satarak hem sizin kazancınızı engelledi hem de sizin sırtınızdan haksız bir para kazancı da yaptı.
Durun hemen üzülmeyin, bu konunun birden fazla çözümü var. Eğer oyununuz sunucu tabanlı bir oyunsa ve oyun mantığı tamamen sunucu tarafında işletiliyorsa (örneğin bir poker oyunu) o zaman endişelenmenize gerek yok. Çünkü oyuncu parasının artması veya azalması sunucu tarafında yapılıyorsa o zaman saldırganlar sadece kendi bilgisayarlarındaki bir tabelayı değiştirmiş olurlar, oyun parasının miktarı aslında değişmez.
Fakat o şekilde değilse, oyun mantığı kullanıcının cihazında işletiliyorsa işte o noktada işi koddan çözmek zorundasınız demektir. Koddan çözmenin yolu ise kolay. Hafızada saklamak istediğiniz veri tiplerini belirsizleştirilmiş (obscured) tiplerle değiştirmeniz gerekiyor. Özet olarak obscured tipler şu şekilde çalışıyor:
* Tipin içinde sayısal değerin belirli bir farkla arttırılmış hali
* Değişkenin gerçek değeri
* Değişkenin gerçek değeri ve arttırılmış hali arasındaki fark
Bu obscured tipin C# kodu şu şekilde görüntülenebilir:
public class ObscuredInt
{
int realValue;
int obscuredValue;
int obscuredDiff;
}
Burayı bir parça açıklayalım. Bu işlemi neden yaptık? Çünkü bu tipin değerinin değiştirilip değiştirilmediğini anlamak istiyoruz. Değeri belirlendiği anda realValue değişkenine yazılacak ve rasgele bir fark belirlenip obscuredDiff alanına yazılacak. Sonra da obscuredValue değişkeninin değeri realValue+obscuredDiff olarak belirlenecek. Peki bu toplama çıkarmayı neden yapıyoruz?
Burada amacımız realValue alanındaki değerin değişip değişmediğini anlamak. Kullanmadan önce eğer realValue'ya obscuredDiff'i eklediğinizde ortaya obscuredValue değişkeninde tutulan sayı çıkmıyorsa o zaman realValue değeri değiştirilmiş demektir. Peki saldırganlar obscuredDiff ve obscuredValue alanlarını neden değiştiremiyor? Çünkü saldırganlar değişkenlere sadece değerinden bulabilir, bu iki alanın da değerini bilmedikleri için onlara ulaşamıyorlar.
Şimdi kodumuzun son halini şöyle görüntüleyelim:
using UnityEngine;
public class ObscuredInt
{
int realValue;
int obscuredValue;
int obscuredDiff;
public ObscuredInt(int value)
{
realValue = value;
obscuredDiff = UnityEngine.Random(13, 9013);
obscuredValue = realValue + obscuredDiff;
}
}
Şimdi bunun için bir get fonksiyonu tanımlayıp bir de OnChangeDetected isminde bir event yapacağız. Bu event'i yapmanız şart değil, ben genel amaçlı bir kod yazdığım için bunu koymayı uygun gördüm, fakat siz değer değiştiğinde bir faaliyette bulunmayacaksanız bu kısmı kullanmanıza gerek yok.
Kodun son hali:
using UnityEngine;
public class ObscuredInt
{
int realValue;
int obscuredValue;
int obscuredDiff;
public delegate void ChangeDetectedEvent();
public ChangeDetectedEvent ChangeDetected = null;
public ObscuredInt(int value)
{
realValue = value;
obscuredDiff = UnityEngine.Random(13, 9013);
obscuredValue = realValue + obscuredDiff;
}
public int Get()
{
if(obscuredValue - obscuredDiff != realValue)
{
ChangeDetected?.Invoke();
realValue = obscuredValue - obscuredDiff
}
return obscuredValue - obscuredDiff;
}
}
Bu koda ilave olarak +, -, = ve diğer matematiksel operatörleri overload edip doğruca int yerine kendi class'ınızın kullanılmasını sağlayabilirsiniz.
Dikkat! 13 ve 9013 arasında rasgele sayılar belirlemek konusunda bir risk vardır, eğer ki realValue değeri int.MaxValue - obscuredDiff değerinden büyük olursa muhtemelen bir hatayla karşılaşacaksınız. O nedenle bu kodu oyununuza kopyalarken bu konuya karşı bir önlem kodlayın, veya en azından bu kodu try..catch içinde çalıştırmayı deneyin.
Peki o zaman bu hatayı niye gidermedin? dediğinizi duyar gibiyim. Çünkü bu bir öğretici yazısı ve bu tür yazılarda konunun özünde gerekli olmayan ne kadar çok şey koyarsam okuyucunun anlaması o kadar zorlaşıyor. Burada anlatılan yöntemi anlayacak kadar programlama bilgisi olan kişilerin bu hatayı da çabucak giderecek bilgileri olacağı kesindir. |
Aynı yöntemle float, double, byte, vs. tüm sayısal tipleri belirsizleştirip saldırganlardan koruyabilirsiniz. Peki string için bunu nasıl yapabilirsiniz? O konuya başka bir yazıda değineceğim.
Hocam çok önemli bir konu, özellikle de multiplayer oyunlar için. Zamanında Cheat Engine ile oyunları az kurcalamadım asdasd :D