İster oyun hileleri geliştiriyor olun, ister bir EDR (Uç Nokta Tespiti ve Yanıtı) çözümü yazıyor olun, ister hata ayıklama (debugging) araçları inşa ediyor olun; çalışan başka bir sürecin (process) içinde kendi kodunuzu yürütme yeteneği temel bir beceridir. Windows ekosisteminde bunun için en yaygın teknik DLL Injection'dır. Kulağa kara büyü gibi gelse de, özünde sadece dört spesifik Windows API çağrısının ardışık bir dizisidir.
Enjeksiyonun Anatomisi
Bir DLL enjekte etmek için, hedef sürecin bellek alanıyla etkileşime girmeli ve onu özel DLL'imizin yoluyla birlikte LoadLibraryA fonksiyonunu çalıştırmaya zorlamalıyız. İşte kesin iş akışı:
- OpenProcess: Hedef süreç için
PROCESS_ALL_ACCESS(veya en azından bellek yazma ve iş parçacığı oluşturma hakları) ile bir handle (tutamaç) isteriz. - VirtualAllocEx: Hedef sürecin içinde bir bellek bloğu tahsis ederiz. Bu alan, DLL'imizin dosya yolunu içeren dizgiyi (string) tutacaktır.
- WriteProcessMemory: Gerçek dizgiyi (örneğin,
"C:\\my_hook.dll") yeni tahsis edilen o bellek bloğuna yazarız. - CreateRemoteThread: Bu tetikleyicidir. Hedef süreçte yeni bir iş parçacığı (thread) başlatırız.
kernel32.dll Hilesi
Standart DLL injection'ın dehası, CreateRemoteThread'i nasıl kullandığımızda yatar. Bu fonksiyon bir başlangıç adresi işaretçisi (pointer) bekler. Peki ama hedef sürecin içindeki LoadLibraryA'nın adresini nasıl biliyoruz?
Windows yükleyicisinin belleği optimize etme şekli nedeniyle, kernel32.dll gibi çekirdek sistem DLL'leri, belirli bir önyükleme oturumundaki (boot session) tüm süreçlerde tam olarak aynı taban adrese (base address) yüklenir. Bu nedenle, kendi enjektör sürecimizde LoadLibraryA'nın adresini bulursak, bu adresi hedef süreç için CreateRemoteThread'e güvenle aktarabiliriz.
// The crux of DLL Injection in C++
LPVOID pAllocatedMem = VirtualAllocEx(hTargetProcess, NULL, dllPathLen, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
WriteProcessMemory(hTargetProcess, pAllocatedMem, dllPath, dllPathLen, NULL);
// Get local address of LoadLibraryA, which matches the remote address
LPVOID pLoadLibrary = (LPVOID)GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA");
// Trigger execution
HANDLE hThread = CreateRemoteThread(hTargetProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pLoadLibrary, pAllocatedMem, 0, NULL);Modern Önlemler (Mitigation)
Bu teknik akademik olarak mükemmel olsa da, bugün CreateRemoteThread kullanmak, modern bir Anti-Virüs veya EDR tarafından mimlenmenin kesin bir yoludur. Güvenlik çözümleri bu API'yi agresif bir şekilde hook'lar. Sonuç olarak, modern sistem programcıları ve zararlı yazılım geliştiricileri APC Injection (QueueUserAPC), Thread Hijacking (SetThreadContext) veya manuel eşleme (Windows yükleyicilerini hiç kullanmadan PE dosyasını belleğe yazma) gibi daha gizli (stealth) yöntemlere yönelmektedir.
Sonuç Yerine
DLL injection'ı anlamak, size Windows çekirdeğinin süreçleri nasıl izole ettiğini ve bu sınırların yasal olarak nasıl aşılabileceğini tam olarak öğretir. Sanal bellek, handle'lar ve sistem mimarisini anlamak için mükemmel bir egzersizdir.