[internal]zulu Dinamik Fonksiyon Tabanlı EntityList Döngüsü ve Pattern Scanning

Onaylı Üye
Katılım
30 May 2026
Mesajlar
75
Tepki puanı
2
Yaş
19
Sosyal
Selam millet, bugün sizlere zulu da yeni geliştirdiğim* bir yöntemi sizlerle paylaşmak istiyorum.

Bu yöntem eski entitylist mantığını tamamen çöpe atıyor.
Peki nedir bu yöntem? Gelin anlatayım;

acknex.dll de (zulunun oyun motoru) statik bir şekilde tek offstele çekebileceğiniz bir entitylist bulunmamaktadır. entitylist başka fonksiyonların ardına gizlenmiştir.
entitylist'i projenize eklemenin yolları oldukça sınırlıdır.

Eski Yöntem (String Tabanlı): Oyun motorunun belleğe yüklediği 3B modellerin (Mesh) dosya adlarını kontrol eder. Kod, bellekteki her nesnenin adını (örneğin, bir karakter modelinin adını) bir dize olarak okur. Model adı "FPS_..._MESH.M" içeriyorsa, yerel bir oyuncu olarak kabul edilir; "CHAR_HALIL" içeriyorsa, bir Zulu takım üyesi olarak kabul edilir.

bu yöntemin dezavantajları saymakla bitmez. Fakat yinede birkaç örnek vermek gerekirse;
Bazı durumlarda kasma/donma, işlemciye daha fazla yük bindirme, karaktere bir kostüm geldiğinde kodun çalışmaması, yeni karakter eklendiğinde hilenin algılayamaması, oyuna güncelleme geldiğinde tüm meshlerin çöp olması...

fakat size şimdi vereceğim yöntemde oyuna güncelleme geldiğinde dahi hilenizin sorunsuz bir şekilde çalışma ihtimali mevcut.
öyleyse yönteme geçelim;

Yeni yöntem: Doğrudan oyun motorunun bellek tabanlı beyin fonksiyonlarına bağlanır ( zulu için sub_10003EB0). Nesne adlarıyla veya karakterlerin şu anda hangi kostümü/karakteri giydiğiyle ilgilenmez. Oyun motorun kendi listesinden canlı bellek adreslerini çeker.

Bu yöntemin avantajları: Tek tek offset/mesh bulmanıza gerek yoktur, işlemciye çok daha az yük bindirir, hileden kaynaklı kasma donma sorunları yaşatmaz...

şimdi kod bloklarının arasına bolca yorum satırı koyarak açıkladığım kodumu sizlerle paylaşıyorum;
C++:
#include <windows.h>
#include <psapi.h> // İşlem belleğini ayrıştırmak için gereken MODULEINFO ve GetModuleInformation için gereklidir
#include <iostream>
 
// Dinamik bellek eşlemesi için gereken Process Status API kitaplığını otomatik olarak bağlar
#pragma comment(lib, "psapi.lib")
 
/**
 *  @brief Belirli bir modülün bellek alanında bir bayt deseni arayan dinamik imza tarayıcı.
 *  @Param moduleName İşlem alanına yüklenen hedef DLL dosyası ("acknex.dll").
 *  @Param pattern Aranacak makine kodu baytlarının (opcode) belirli dizisi.
 *  @Param mask Kesin bayt eşleşmeleri için 'x' ve dinamik/joker baytlar için '?' içeren bir dize.
 *  @returN Bulunan desenin mutlak bellek adresi veya bulunamazsa 0.
 */
uintptr_t DynamicPatternScan(const char* moduleName, const char* pattern, const char* mask) {
    // Hedef modülün temel yükleme adresini alır (ASLR'yi dinamik olarak yönetir)
    uintptr_t base = (uintptr_t)GetModuleHandleA(moduleName);
    if (!base) return 0;
 
    // Modülün bellek sınırları hakkında genişletilmiş bilgileri tutacak yapı
    MODULEINFO modInfo = { 0 };
    HMODULE hModule = GetModuleHandleA(moduleName);
    
    // İşletim sisteminden modülün boyutunu ve görüntü bilgilerini güvenli bir şekilde alır
    if (!GetModuleInformation(GetCurrentProcess(), hModule, &modInfo, sizeof(MODULEINFO)))
        return 0;
 
    size_t size = modInfo.SizeOfImage; // Modül tarafından kaplanan toplam bellek boyutu
    size_t patternLength = strlen(mask); // İmza maskesinin toplam uzunluğu
 
    // Modülün yürütme bellek alanını bayt bayt tarar
    for (size_t i = 0; i < size - patternLength; i++) {
        bool found = true;
        
        // İmzanın her bir baytını mevcut bellek akışı ile karşılaştırır
        for (size_t j = 0; j < patternLength; j++) {
            // Maske bir joker karakter '?' değilse ve baytlar eşleşmiyorsa, iç döngüyü kırar
            if (mask[j] != '?' && pattern[j] != *(char*)(base + i + j)) {
                found = false;
                break;
            }
        }
        // Eksiksiz imza dizisi başarıyla eşleşirse, kesin bellek adresini döndürür
        if (found) return base + i;
    }
    return 0; // İmza güncel değilse veya mevcut değilse 0 döndürür
}
 
// Derleyicinin yerel Microsoft __thiscall çağrı kuralını yansıtan fonksiyon göstericisi prototipi.
// __thiscall, nesne örneği göstericisini ('this' anahtar kelimesi) ECX kaydı içinde iletir.
typedef uintptr_t(__thiscall* GetEntityFromList_t)(void* thisPtr, int entityId);
 
/**
 *  @brief Dinamik desenler aracılığıyla zulu'nın gizli varlık (entity) alt sistemini bulur ve tüm aktif oyun varlıklarını döngüye alır.
 */
void EntityListPatternScanning() {
    //----------------------------------------------------------------------------------
    // 1. VARLIK LİSTESİ ARAMA FONKSİYONUNU DİNAMİK OLARAK BUL (sub_10003EB0)
    //----------------------------------------------------------------------------------
    // Döngü içindeki komut bloğunu tarar: mov ecx, [ebp+8] / push esi / call sub_10003EB0
    uintptr_t listFunctionInstruction = DynamicPatternScan("acknex.dll", "\x8B\x4D\x08\x56\xE8", "xxxxx");
 
    if (!listFunctionInstruction) {
        std::cout << "[-] Failed to locate Entity List function signature!" << std::endl;
        return;
    }
 
    // E8 (CALL) işlem kodunun (opcode) göreli atlama/yer değiştirme ofsetini çözer.
    // E8 işlem kodu, bir SONRAKİ komut adresine göre 4 baytlık bir göreli yer değiştirme değeri alır.
    int relativeAddr = *(int*)(listFunctionInstruction + 5);
    
    // Mutlak hedef bellek adresini hesaplar: Mevcut Komut Adresi + Komut Boyutu (9 bayt) + Göreli Ofset
    uintptr_t finalListFunctionAddress = listFunctionInstruction + 9 + relativeAddr;
    
    // Hesaplanan ham bellek adresini açıkça yürütülebilir __thiscall fonksiyon göstericimize dönüştürür
    GetEntityFromList_t GetEntityById = (GetEntityFromList_t)finalListFunctionAddress;
 
    //----------------------------------------------------------------------------------
    // 2. KÜRESEL MOTOR YÖNETİCİSİ ÖRNEĞİNİ DİNAMİK OLARAK BUL (dword_10237EE4)
    //----------------------------------------------------------------------------------
    // Şu diziyi tarar: mov ecx, dword_10237EE4 / mov edx, [ecx] / mov edx, [edx+8]
    uintptr_t managerInstruction = DynamicPatternScan("acknex.dll", "\x8B\x0D\x00\x00\x00\x00\x8B\x11\x8B\x52\x08", "xx????xxxxx");
 
    if (!managerInstruction) {
        std::cout << "[-] Failed to locate Global Manager signature!" << std::endl;
        return;
    }
 
    // 'mov ecx, [adres]' komutunun 2 bayt derinliğinde bulunan gömülü statik gösterici adresini çıkarır
    uintptr_t globalManagerRegister = *(uintptr_t*)(managerInstruction + 2);
    
    // Veri segmentinden gerçek temel nesne örneği adresini yakalamak için gösterici kaydının değerini alır (dereference)
    uintptr_t globalManagerPtr = *(uintptr_t*)globalManagerRegister;
    if (!globalManagerPtr) return;
 
    // Yuvalanmış 'engineManager' sınıfı örneğine adım atmak için '[ebp+8]' montaj (assembly) komutunu kopyalar
    void* engineManager = *(void**)(globalManagerPtr + 0x8);
    if (!engineManager) return;
 
    //----------------------------------------------------------------------------------
    // 3. zulu'NIN FONKSİYON TABANLI VARLIK HATTI ÜZERİNDE GÜVENLİ DÖNGÜ YÜRÜT
    //----------------------------------------------------------------------------------
    // 0x0C [ecx+0Ch] ofsetinde güvenle saklanan aktif dinamik varlık sayısı değişkenini okur
    int entityCount = *(int*)((uintptr_t)engineManager + 0x0C);
 
    std::cout << "[+] Entity List parsed successfully. Active entities count: " << entityCount << std::endl;
 
    // Oyun motorunun dahili işleme döngüsü (rendering loop) yapısını taklit eden standart yinelemeli döngü
    for (int i = 0; i < entityCount; i++) {
        // Yerel kodu yürüten güvenli dahili çağrı; 'engineManager' göstericisini ECX kaydına otomatik olarak iter (push)
        uintptr_t currentEntity = GetEntityById(engineManager, i);
        if (!currentEntity) continue; // Nesne yuvası atanmamışsa, boşsa veya yok edilmişse atla
 
        // 'currentEntity' artık bellekteki oyuncu nesnesi örneğinin ham temel adresini içerir.
        // Daha fazla görsel özellik bağlantısı için hazırdır (örneğin, acknex.dll+0x243F10 adresindeki oyuncu adlarını ayrıştırmak)
        std::cout << "Player [" << i << "] Base Address: 0x" << std::hex << currentEntity << std::endl;
    }
}
 
/**
 *  @brief Başarılı DLL enjeksiyonunun ardından eşzamansız olarak yürütülen iş parçacığı (thread) giriş noktası.
 */
DWORD WINAPI MainThread(LPVOID lpParam) {
    // Oyunun aktif çalışma zamanı alanına bir hata ayıklama konsolu hattı tahsis eder
    AllocConsole();
    freopen_s((FILE**)stdin, "CONIN$", "r", stdin);
    freopen_s((FILE**)stdout, "CONOUT$", "w", stdout);
 
    std::cout << "[+] zulu Internal Hook module initialized successfully." << std::endl;
 
    // Motor durumunu sorgulamak için sonsuz yürütme döngüsü
    while (true) {
        EntityListPatternScanning(); // Varlık alt sistemini dinamik olarak ayrıştırır
        Sleep(500); // Doğrulama testleri sırasında sıfır CPU yükü sağlamak için sınırlandırılmış döngü zamanlaması (500ms gecikme)
    }
    return 0;
}
 
/**
 *  @brief İşletim sistemi yükleyicisi tarafından çağrılan standart dinamik kütüphane giriş noktası.
 */
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
    // Kod rutinini yalnızca modül işlem alanına tamamen eklendiğinde yürütür
    if (ul_reason_for_call == DLL_PROCESS_ATTACH) {
        // Yerel işletim sistemi yükleyici kilidi iş parçacığının (loader lock thread) engelini kaldırmak ve baypas etmek için bağımsız bir yürütme iş parçacığı oluşturur
        CreateThread(NULL, 0, MainThread, NULL, 0, NULL);
    }
    return TRUE;
}

umarım faydalı olmuştur, sonraki konularda görüşmek üzere!
Hoşçakalın.

DC: lyr1ca.x4n
*şuana kadar hiçbir zulu projesinde rastlamadım buyüzden en azından zulu için yöntemi ben bulmuş oluyorum :)

NOT: yorum satırlarının orijinalini ingilizce hazırlamıştım tekrar türkçeye çevirirken üşendiğim için çeviriden kopy paste yaptım bu yüzden bazı terimlerin türkçesi yabancı geldiyse üzgünüm
Coffee Time Cute Cat GIF by ErlebnisMalerei
 
Son düzenleme:
Üst