Unity Mono tarafını anlattıktan sonra ORGA Hub’da kullandığım bir diğer ilginç sisteme geçelim: Unreal Engine Reflection.
Özellikle Unreal Engine kullanan oyunlarda her şeyi sabit adresler, pointer zincirleri veya tek tek AOB imzalarıyla çözmek zorunda değiliz.
Unreal Engine kendi içerisinde nesneleri, sınıfları ve property’leri tanımlayan oldukça geniş bir runtime yapısına sahip.
Eğer bu yapıya doğru şekilde ulaşabilirsek bazı değerleri:
Player + 0x3A8
gibi anlamsız bir offset üzerinden değil,
Şu sınıftaki şu property
mantığıyla bulabiliriz.
ORGA Hub’da Subnautica 2 traineri için geliştirdiğim sistem de büyük ölçüde bu mantıktan faydalanıyor.
🟪 Önce Unreal Engine Reflection Nedir?Reflection kelimesini basitçe:
Programın çalışma sırasında kendi yapısı hakkında bilgi verebilmesi
şeklinde düşünebilirsiniz.
Unreal Engine içerisinde sınıflar, nesneler ve property’lerle ilgili metadata bulunuyor.
Örneğin oyun tarafında şöyle bir yapı olduğunu düşünelim:
PlayerCharacter
ve bunun içerisinde:
Health
Oxygen
MovementSpeed
gibi property’ler var.
Klasik memory trainer yaklaşımında bunların adreslerini ve offsetlerini tek tek bulmaya çalışabiliriz.
Reflection tarafında ise uygun yapıya ulaşabilirsek:
PlayerCharacter içerisindeki Health property’sini bul.
gibi çok daha anlamlı bir yaklaşım kullanabiliriz.
🧠 Neden Bu Kadar Değerli?Çünkü sabit offsetler her zaman stabil değil.
Örneğin eski sürümde:
Health = Player + 0x2F0
olsun.
Geliştirici yeni güncellemede sınıfa birkaç yeni property ekledi.
Artık Health:
Player + 0x308
olabilir.
Hardcoded olarak 0x2F0 kullanıyorsak trainer yanlış yere bakmaya başlar.
Ama trainer runtime sırasında:
Health property’sinin gerçek offset’ini
bulabiliyorsa bu tarz değişikliklerden bazıları bizi hiç etkilemeyebilir.
Tabii bu sistem traineri tamamen güncellemelerden bağımsız yapmıyor.
Ama sabit adres bağımlılığını azaltabiliyor.
🏗️ Unreal Engine’de Nesne MantığıUnreal Engine oyunlarında dünyadaki birçok şey bir UObject yapısından türeyebilir.
Örneğin:
Oyuncu
Silah
Envanter
Araç
Yaratık
Component
Attribute sistemi
farklı UObject tabanlı yapılardan oluşabilir.
Bir trainer geliştirirken sadece değeri değil, o değerin hangi gerçek nesneye ait olduğunu bulmak önemli.
Çünkü bellekte aynı sayı yüzlerce farklı yerde bulunabilir.
Mesela oyuncunun canı:
100
olsun.
Bellekte 100 aradığımızda:
düşmanın canı,
item miktarı,
UI değeri,
maksimum stamina,
animasyon parametresi
gibi yüzlerce farklı sonuç çıkabilir.
Ama:
PlayerHealthComponent → Health
yapısına ulaşırsak hangi 100’ü değiştirdiğimiz çok daha net olur.
🔎 ORGA Hub’daki UE RTTI KatmanıORGA Hub içerisinde Unreal Engine oyunları için geliştirdiğim ayrı bir UE RTTI / reflection katmanı bulunuyor.
Buradaki amaç runtime sırasında oyunun Unreal yapısını çözerek trainer özelliklerinin kullanabileceği sınıf ve field bilgilerine ulaşmak.
Sistem sayesinde bazı trainer işlemlerini doğrudan:
sınıf,
property,
attribute,
runtime field
üzerinden tanımlayabiliyorum.
Bu özellikle Subnautica 2 tarafında kullandığım sistemin temelini oluşturuyor.
🌊 Neden Subnautica 2?Subnautica 2 Unreal Engine tabanlı olduğu için klasik Subnautica oyunlarından teknik olarak farklı bir yapıya sahip.
Trainer geliştirirken de bunu dikkate almak gerekiyor.
Oyunun Unreal tarafındaki runtime yapılarını kullanabildiğim için birçok özelliği klasik pointer scan yaklaşımından farklı şekilde hazırladım.
Subnautica 2 trainerinde ORGA Hub tarafında şu tarz özel işlemler bulunuyor:
ueAttrFreezeueFieldSetueTimeFreezeuePos
Bunların her biri Unreal yapısını farklı amaçlarla kullanıyor.
❤️ ueAttrFreeze Nedir?Bazı Unreal Engine oyunlarında karakter istatistikleri normal bir float field’dan daha karmaşık tutulabiliyor.
Özellikle attribute sistemlerinde bir değerin:
Current
Base
Max
gibi birden fazla bölümü olabilir.
Örneğin can:
Current Health: 80
Base Health: 100
Max Health: 100
şeklinde tutulabilir.
Trainer sadece ekranda gördüğümüz Current değerini değiştirirse oyun bir sonraki hesaplamada bunu tekrar Base veya başka bir sistem üzerinden değiştirebilir.
Bu yüzden ORGA Hub’daki ueAttrFreeze işlemi attribute yapısını daha doğru şekilde ele almak için geliştirdiğim yöntemlerden biri.
Trainer ilgili attribute’u bulup gerekli bölümlerini kontrol altında tutabiliyor.
Kullanıcı açısından sonuç örneğin:
Sınırsız can
oluyor.
Ama arka tarafta sadece rastgele bir float değeri 999’a sabitlemekten daha kontrollü bir işlem yapılabiliyor.
📌 ueFieldSet Nedir?Bazı özelliklerde sürekli freeze yapmak gerekmiyor.
Sadece ilgili Unreal property’sini bulup bir değer yazmak yeterli.
Burada ueFieldSet kullanabiliyorum.
Örneğin:
şu nesneyi bul
şu property’yi çöz
şu değeri yaz
mantığında ilerliyor.
Bu bir buton işlemi de olabilir veya trainer özelliğinin ihtiyaç duyduğu başka bir ayar olabilir.
Yine avantaj aynı:
Hardcoded adres yerine mümkün olduğunca Unreal’ın kendi property yapısından faydalanmak.
⏱️ ueTimeFreezeZamanla ilgili sistemler oyunlarda bazen düşündüğümüzden daha karmaşık oluyor.
Bir değeri doğrudan bellekte freeze etmek her zaman yeterli olmayabiliyor.
Subnautica 2 trainerinde zamanla ilişkili özellikler için Unreal tarafına özel ayrı bir yöntem de bulunuyor.
ueTimeFreeze işlemi oyunun runtime yapısındaki ilgili zaman değerlerini kontrol altında tutmak için kullanılıyor.
Buradaki amaç yine aynı:
Oyunun kendi yapısına mümkün olduğunca yakın noktadan müdahale etmek.
📍 uePos ve Pozisyon SistemiTrainerlerde en sevdiğim özelliklerden biri teleport. 😄
Ama teleport yapmak için önce oyuncunun gerçek dünya pozisyonunu güvenilir şekilde bulmanız gerekiyor.
Unreal Engine’de karakterlerin transform ve location bilgileri motorun kendi nesne yapıları üzerinden yönetiliyor.
Subnautica 2 tarafında geliştirdiğim uePos sistemi de oyuncunun konum bilgisine ulaşabilmek için bu Unreal yapısından faydalanıyor.
Böylece trainer:
mevcut pozisyonu okuyabiliyor,
pozisyon kaydedebiliyor,
gerektiğinde tekrar aynı noktaya taşıyabiliyor
gibi işlemler gerçekleştirebiliyor.
Bu tarz sistemlerde doğrudan rastgele X/Y/Z float değerlerini aramaktansa gerçek oyuncu nesnesinin konum yapısını bulmak çok daha sağlıklı.
🧩 Property İsmiyle Bulmak Ne Kazandırıyor?Diyelim geliştirici sınıf yapısını değiştirdi.
Eski sürüm:
Health = +0x310
Yeni sürüm:
Health = +0x328
Eğer trainer:
+0x310
kullanıyorsa özellik kırılır.
Ama runtime’da:
Health
property’sini bulup gerçek offset’i çözüyoruz diyelim.
Property adı ve genel yapı aynı kaldığı sürece yeni offset otomatik olarak bulunabilir.
Bu da trainer güncelleme işini bazı durumlarda ciddi şekilde kolaylaştırabiliyor.
⚠️ Reflection Kullanmak Traineri Ölümsüz YapmıyorBunu özellikle belirtmek lazım.
Reflection kullanıyorsak:
Oyun bir daha ne kadar güncellenirse güncellensin trainer bozulmaz.
gibi bir durum yok.
Geliştirici:
sınıf adını değiştirebilir,
property adını değiştirebilir,
sistemi başka component’e taşıyabilir,
veri tipini değiştirebilir,
attribute sistemini yeniden yazabilir,
Unreal sürümünü değiştirebilir,
runtime yapısını ciddi şekilde değiştirebilir.
Bu durumda trainer yine güncellenmek zorunda kalabilir.
Ama küçük yapısal değişikliklerde hardcoded offset kullanmaya göre daha dayanıklı olma ihtimali yüksek.
🔍 Peki Her Property Reflection ile Bulunabilir mi?Hayır.
Unreal Engine’de gördüğümüz her değer mutlaka trainer tarafından kolayca isim üzerinden çözülebilecek bir property olmak zorunda değil.
Bazı şeyler:
native kod içerisinde hesaplanabilir,
local değişken olabilir,
optimize edilmiş olabilir,
runtime’da farklı bir yapıya dönüşebilir,
doğrudan uygun metadata sunmayabilir.
Böyle durumlarda yine klasik yöntemlere dönmek gerekebilir.
Mesela:
AOB
pointer
code cave
runtime capture
hala gerekli olabilir.
Yani Reflection çok güçlü bir sistem ama yine bütün problemlerin tek çözümü değil.
🆚 Unreal Reflection ile Pointer Arasındaki FarkPointer yaklaşımı genellikle:
Şu adres zincirini takip ederek değere ulaş.
der.
Reflection ise daha çok:
Oyunun kendi nesne sisteminden şu sınıfı/property’yi çöz.
mantığında çalışır.
Pointer:
Game.exe + X → Y → Z → +0x328
gibi olabilir.
Reflection tarafında ise daha anlamlı şekilde:
Player → HealthComponent → Health
gibi düşünebiliriz.
İkisi sonunda aynı değere çıkabilir ama oraya ulaşma yöntemleri farklı.
🆚 Unreal Reflection ile AOB Arasındaki FarkAOB:
makine kodu veya byte desenini arar.
Reflection:
oyunun nesne/property metadata’sını kullanır.
Örneğin hasar fonksiyonunun davranışını değiştireceksem AOB + Code Cave daha uygun olabilir.
Ama sadece oyuncunun bir property’sini okuyup yazmam gerekiyorsa Reflection daha mantıklı olabilir.
Bu yüzden çoğu trainer tek bir yöntemden oluşmaz.
🔥 Birlikte Kullanmak da MümkünAslında en güçlü taraf burada.
Diyelim Unreal reflection üzerinden oyuncu nesnesini bulabiliyorum.
Ama yapmak istediğim özellik için belirli bir native fonksiyonu hooklamam gerekiyor.
O zaman:
Reflection → Player nesnesi
ve:
AOB → ilgili native fonksiyon
birlikte kullanılabilir.
Trainer geliştirirken yöntemleri birbirine rakip sistemler olarak değil, elimizdeki farklı araçlar olarak görüyorum.
🎮 Subnautica 2 Trainerinde Bunun AvantajıSubnautica 2 tarafında bu sistem sayesinde trainerin önemli bölümünü oyunun Unreal yapısına özel hazırlayabildim.
Bu hem trainer tanımlarını daha anlaşılır hale getiriyor hem de bazı işlemleri klasik memory yöntemlerine göre daha temiz yapmamı sağlıyor.
Örneğin:
Attribute Freeze
normal freeze’den farklı davranabiliyor.
Position
doğrudan Unreal’ın gerçek konum yapısı üzerinden yönetilebiliyor.
Field Set
property çözümü üzerinden çalışabiliyor.
Böylece trainer engine içerisinde:
Bu oyun Unreal Engine, o zaman onun yapısını kullan.
diyebildiğimiz ayrı bir katman oluşuyor.
🧠 Neden ORGA Hub’da Motorlara Özel Sistemler Geliştiriyorum?Çünkü bütün oyunları aynı memory engine ile zorlamaya çalışmak bana mantıklı gelmiyor.
Unity Mono bize metadata veriyorsa kullanmak lazım.
Unreal Engine bize reflection yapısı sunuyorsa değerlendirmek lazım.
CryEngine’in kendi console sistemi varsa bundan yararlanabiliriz.
The Sims 4 zaten Python çalıştırıyorsa Python tarafıyla iletişim kurmak daha mantıklı olabilir.
Benim ORGA Hub trainer sisteminde yapmak istediğim şey tam olarak bu:
Oyunu kendi yapısına göre ele almak.
Her oyunda illa aynı yöntem kullanılacak diye bir kural koymamak.
🔄 Güncelleme Geldiğinde Ne Kontrol Ediyorum?Subnautica 2 gibi Reflection kullanan bir trainer güncellendiğinde genel olarak:
Aradığımız sınıflar hâlâ var mı?
Property isimleri değişmiş mi?
Property tipleri aynı mı?
Attribute yapısı değişmiş mi?
Oyuncu nesnesine ulaşma yolu değişmiş mi?
Position sistemi aynı mı?
Trainer özellikleri hâlâ doğru nesne üzerinde çalışıyor mu?
gibi şeylere bakmak gerekiyor.
Sadece:
Trainer açıldı, crash olmadı.
demek yeterli değil.
Her özelliği tekrar oyun içinde test etmek gerekiyor.
❤️ Kısaca ÖzetlersekUnreal Engine Reflection bize bazı trainer özelliklerinde oyunun kendi runtime yapısını kullanma imkanı veriyor.
Yani:
Sabit offset kullanmak yerine → Property çöz.
Rastgele değer aramak yerine → Gerçek nesneyi bul.
Her şeyi pointer scan ile çözmek yerine → Unreal metadata’dan faydalan.
ORGA Hub’daki Subnautica 2 trainerinde de bu nedenle Unreal’a özel ayrı bir altyapı kullanıyorum.
Ama yine temel prensip aynı:
Tek bir yönteme bağlı kalmak yerine oyun hangi yönteme uygunsa onu kullanmak.
Bazı oyunlarda AOB en iyi yöntem.
Bazılarında Mono.
Bazılarında Unreal Reflection.
Bazılarında ise oyunun kendi script veya konsol sistemi.
Bence trainer geliştirmeyi ilginç yapan taraflardan biri de bu. Her oyun farklı bir problem ve her oyunun çözümü aynı değil.
Gringos