Isse Kun
Emektar Üye
Hedef: Bu laboratuvar için hedefimiz Assault Cube 1.2.0.2 olacak.
Tanımlama: Bu laboratuvardaki amacımız, radarda hem düşmanları hem de dost oyuncuları görüntüleyen bir tür hack olan bir radar hack'i oluşturmaktır.
Anlatım: Birçok FPS oyununda, mevcut haritanın küçültülmüş bir versiyonunun üstünde her oyuncu için bir simge görüntüleyecek bir radar bulunur. Takımlarla bir oyunda oynarken, bu radarlar yalnızca aktif oyuncuyla aynı takımdaki oyuncuları gösterecektir. Çoğu oyunun kodu, radarda bir oyuncunun simgesini çizerken, aşağıdaki bloğa benzer şekilde bu liste üzerinde yinelenir:
Bu kodu bulursak, takımdan bağımsız olarak oyuncuyu her zaman radara çekmek için if koşulunu değiştirebiliriz. Kodu bulmak için öncelikle oyuncu yapımızdaki takım üyesini tanımlamamız gerekecek. Ardından, bu üyeye kodda nerede erişildiğini belirlemek için erişimde bir kesme noktası ayarlayabiliriz.
Oyuncunun Takımını Bulma: Oyuncunun takımını oyuncu yapısında bulmak için iki yaklaşım kullanabiliriz:
Tanımlama: Bu laboratuvardaki amacımız, radarda hem düşmanları hem de dost oyuncuları görüntüleyen bir tür hack olan bir radar hack'i oluşturmaktır.
Anlatım: Birçok FPS oyununda, mevcut haritanın küçültülmüş bir versiyonunun üstünde her oyuncu için bir simge görüntüleyecek bir radar bulunur. Takımlarla bir oyunda oynarken, bu radarlar yalnızca aktif oyuncuyla aynı takımdaki oyuncuları gösterecektir. Çoğu oyunun kodu, radarda bir oyuncunun simgesini çizerken, aşağıdaki bloğa benzer şekilde bu liste üzerinde yinelenir:
C++:
void draw_radar() {
for(int i = 0; i < max_players; i++) {
if(player_list[i]->team == current_player->team) {
//draw on radar
}
}
}
Bu kodu bulursak, takımdan bağımsız olarak oyuncuyu her zaman radara çekmek için if koşulunu değiştirebiliriz. Kodu bulmak için öncelikle oyuncu yapımızdaki takım üyesini tanımlamamız gerekecek. Ardından, bu üyeye kodda nerede erişildiğini belirlemek için erişimde bir kesme noktası ayarlayabiliriz.
Oyuncunun Takımını Bulma: Oyuncunun takımını oyuncu yapısında bulmak için iki yaklaşım kullanabiliriz:
- Hile Motoru'nu kullanın ve Bilinmeyen bir başlangıç değeri arayın. Ardından, takımlar arasında geçiş yapın ve Değiştirilen değeri arayın.
- x64dbg kullanın ve oynatıcının yapısını bir dökümde bulun. Ardından, ekipler arasında geçiş yapın ve değişen bir üye arayın.
Bu yaklaşımların her ikisini de geçmiş laboratuvarlarda ele aldık. Daha önce tartışılan teknikleri kullanarak, ekibinize bağlı olarak 0 ile 1 arasında değişen bir üyeyi tanımlayabilmeniz gerekir. Bu üye, oyuncunun hayatta olup olmadığını tutan daha önce belirlediğimiz üyeye nispeten yakındır.
Radar İşlevini Bulun: Radar fonksiyonunun oyuncunun takımına erişmesi gerektiğini biliyoruz. Bu nedenle, az önce tanımladığımız ekip üyesine erişim için bir kesme noktası yerleştirebiliriz. Hemen, kesme noktası açılmalıdır. Ancak, yürütmeye birkaç kez devam ederseniz, kesme noktasının kodun tamamen farklı bölümlerinde açıldığını görmeniz gerekir. Bunun nedeni büyük olasılıkla kodun birkaç bölümünün bu üyeye erişmesidir. Bir sonraki adımımız, radarın çizilmesinden sorumlu kod bölümünü belirlemektir.
Yukarıda açıkladığımız sahte koda dayanarak, aradığımız kod hakkında birkaç şey varsayabiliriz:
Radar İşlevini Bulun: Radar fonksiyonunun oyuncunun takımına erişmesi gerektiğini biliyoruz. Bu nedenle, az önce tanımladığımız ekip üyesine erişim için bir kesme noktası yerleştirebiliriz. Hemen, kesme noktası açılmalıdır. Ancak, yürütmeye birkaç kez devam ederseniz, kesme noktasının kodun tamamen farklı bölümlerinde açıldığını görmeniz gerekir. Bunun nedeni büyük olasılıkla kodun birkaç bölümünün bu üyeye erişmesidir. Bir sonraki adımımız, radarın çizilmesinden sorumlu kod bölümünü belirlemektir.
Yukarıda açıkladığımız sahte koda dayanarak, aradığımız kod hakkında birkaç şey varsayabiliriz:
- Bir cmp (veya test) talimatı ve ardından koşullu bir sıçrama (je, jne, jg, vb.)
- İlgili birçok işlem nedeniyle ya bir işlevi çağıracak ya da adil miktarda koda sahip olacaktır.
- Büyük olasılıkla simgeyi radara yerleştirmek için kayan nokta işlemlerinden (fld, fstp) yararlanacaktır.
Bu özellikleri, kodda hangi konuma önem verdiğimizi belirlememize yardımcı olması için kullanabiliriz.
Program yürütmeyi kesintiye uğrattığımız için, kesme noktaları tutarlı bir şekilde ortaya çıkmaz. Bu laboratuvarda, her bir kod parçasını laboratuvarı yazarken karşılaştıkları sırayla inceleyeceğiz. Ortamınızda, popların sırası büyük olasılıkla farklı olacaktır.
İlk pop aşağıdaki kodda oluşur:
Bu başlangıçta önemsediğimiz koşulların birkaçını kontrol ediyor gibi görünüyor. Ancak, jne talimatını 'de nop edersek, oyunda bir değişiklik olmadığını fark ederiz. Çağrıyı şu adreste keşfederseniz, aşağıdaki kodu görmeniz gerekir: 0x4153220x415326
Bu dize sabitinden, bu kodun radardaki sesli sohbet (veya iletişim) sembollerini çizmekle bir ilgisi olduğunu varsayabiliriz. Şimdi bir sonraki konuma geçeceğiz:
Hemen tersine çevirme amacımız için, bir kaydı kendisine karşı test etmek, kaydı 0 ile karşılaştırmakla aynıdır. Burada, oyuncunun takımı 0 veya CLA takımı olarak ayarlanmışsa kodun bir dal yürüttüğünü görüyoruz. Radar çizim işlemi, statik bir değere göre değil, oyuncunun yapısında saklanan değere göre yürütülmelidir. Şimdi bir sonraki konuma geçebiliriz:
Bu kodu incelediğimizde bir önceki koda benzer bir işlem yaptığını görüyoruz. Oyuncunun takımının değerini ecx'e yükledikten sonra, kod bu değeri 1 ile veya RSVF takımını test cl, 1 talimatıyla karşılaştırır. Aynı mantık, yukarıdaki paragrafta olduğu gibi burada da geçerlidir, bu yüzden bir sonraki konumu inceleyelim:
En üstteki cmp talimatı, mevcut oyuncumuzun takımını, aynı takım ofsetini başka bir veri yapısından, potansiyel olarak başka bir oyuncudan yüklüyor gibi görünen eax ile karşılaştırır. Ayrıca, simgenin radara yerleştirilmesinden sorumlu olabilecek birkaç kayan nokta işlemi de görüyoruz. Bakalım jne talimatını çıkarırsak ne olacak:
Assault Cube'a geri dönerseniz, artık ekibinizde olmayanlar da dahil olmak üzere radardaki her oyuncuyu görebildiğinizi fark etmelisiniz. Sorumlu radar kodumuzu bulduk.
Kodu Değiştirme: Bu hack yalnızca bir bellek adresine bayt yazmamızı gerektirmektedir.
Program yürütmeyi kesintiye uğrattığımız için, kesme noktaları tutarlı bir şekilde ortaya çıkmaz. Bu laboratuvarda, her bir kod parçasını laboratuvarı yazarken karşılaştıkları sırayla inceleyeceğiz. Ortamınızda, popların sırası büyük olasılıkla farklı olacaktır.
İlk pop aşağıdaki kodda oluşur:
Bu başlangıçta önemsediğimiz koşulların birkaçını kontrol ediyor gibi görünüyor. Ancak, jne talimatını 'de nop edersek, oyunda bir değişiklik olmadığını fark ederiz. Çağrıyı şu adreste keşfederseniz, aşağıdaki kodu görmeniz gerekir: 0x4153220x415326
Bu dize sabitinden, bu kodun radardaki sesli sohbet (veya iletişim) sembollerini çizmekle bir ilgisi olduğunu varsayabiliriz. Şimdi bir sonraki konuma geçeceğiz:
Hemen tersine çevirme amacımız için, bir kaydı kendisine karşı test etmek, kaydı 0 ile karşılaştırmakla aynıdır. Burada, oyuncunun takımı 0 veya CLA takımı olarak ayarlanmışsa kodun bir dal yürüttüğünü görüyoruz. Radar çizim işlemi, statik bir değere göre değil, oyuncunun yapısında saklanan değere göre yürütülmelidir. Şimdi bir sonraki konuma geçebiliriz:
Bu kodu incelediğimizde bir önceki koda benzer bir işlem yaptığını görüyoruz. Oyuncunun takımının değerini ecx'e yükledikten sonra, kod bu değeri 1 ile veya RSVF takımını test cl, 1 talimatıyla karşılaştırır. Aynı mantık, yukarıdaki paragrafta olduğu gibi burada da geçerlidir, bu yüzden bir sonraki konumu inceleyelim:
En üstteki cmp talimatı, mevcut oyuncumuzun takımını, aynı takım ofsetini başka bir veri yapısından, potansiyel olarak başka bir oyuncudan yüklüyor gibi görünen eax ile karşılaştırır. Ayrıca, simgenin radara yerleştirilmesinden sorumlu olabilecek birkaç kayan nokta işlemi de görüyoruz. Bakalım jne talimatını çıkarırsak ne olacak:
Assault Cube'a geri dönerseniz, artık ekibinizde olmayanlar da dahil olmak üzere radardaki her oyuncuyu görebildiğinizi fark etmelisiniz. Sorumlu radar kodumuzu bulduk.
Kodu Değiştirme: Bu hack yalnızca bir bellek adresine bayt yazmamızı gerektirmektedir.
C++:
#include <Windows.h>
unsigned char new_bytes[5] = { 0x90, 0x90, 0x90, 0x90, 0x90 };
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
DWORD old_protect;
unsigned char* hook_location = (unsigned char*)0x409FB3;
if (fdwReason == DLL_PROCESS_ATTACH) {
VirtualProtect((void*)hook_location, 5, PAGE_EXECUTE_READWRITE, &old_protect);
for (int i = 0; i < sizeof(new_bytes); i++) {
*(hook_location + i) = new_bytes[i];
}
}
return true;
}