Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

BTRisk Zararlı Yazılım Analizi Eğitimi Sunumu - Bölüm 2

1,423 views

Published on

BTRisk Zararlı Yazılım Analizi Eğitimi Sunumu - Bölüm 2

Published in: Education

BTRisk Zararlı Yazılım Analizi Eğitimi Sunumu - Bölüm 2

  1. 1. ZARARLI YAZILIM ANALİZİ EĞİTİMİ BÖLÜM 2 İSTANBUL blog.btrisk.com @btrisk /btrisktv /btrisk
  2. 2. BTRİSK HAKKINDA TANIŞMA Pentest & BT Denetimi ISO27001 Danışmanlık Hizmetleri BG Operasyon Hizmetleri
  3. 3. ANALİZ STATİK ANALİZ [Import Address Table] Bir uygulamanın Import ettiği fonksiyonlar o uygulamanın fonksiyonalitesine ilişkin bize fikir verebilirler
  4. 4. ANALİZ STATİK ANALİZ [Import Address Table] Import edilen fonksiyon adlarını kopyalayarak bir şüpheli fonksiyon listesiyle karşılaştırabilmek için IDA Pro'nun Imports penceresinde sağ klikleyerek Copy seçeneğini seçelim
  5. 5. ANALİZ STATİK ANALİZ [Import Address Table] Kopyaladığımız listeyi Notepad++'a yapıştırarak arama yapabiliriz
  6. 6. ANALİZ STATİK ANALİZ [Import Address Table] Şüpheli API listemizle Import adres tablosunu karşılaştırmak için MS Excel'in VLOOKUP fonksiyonunu da kullanabiliriz
  7. 7. ANALİZ STATİK ANALİZ [Import Address Table] Bunun için fonksiyon adlarını ayrı kolona bölmek amacıyla Text to Columns özelliğini kullanalım ve delimiter olarak "Space"i seçelim
  8. 8. ŞÜPHELİ WINDOWS API'LERİ Windows API Fonksiyonları • Windows API fonksiyonlarına baktığımızda bazılarının “A” ile, bazılarının ise “W” ile bittiğini görürüz. Bu fonksiyonlardan A ile bitenler “string” veri tipinde aldıkları parametreleri ANSI (ASCII değil) string’leri olarak, W ile bitenler ise Unicode (Wide Character) string’leri olarak kabul ederler. • Bazı fonksiyonların sonu da “Ex” olarak bitmektedir (bu fonksiyonlarda da W ve A ekleri görülebilir, yani “Ex” ekinden sonra W veya A gelebilir). Bu fonksiyonlar da benzer isimli önceki fonksiyonların yerini almış ancak eski fonksiyonların sahip oldukları fonksiyonaliteyi de destekleyen “Extended” fonksiyonlardır.
  9. 9. ŞÜPHELİ WINDOWS API'LERİ Şüphe Doğurabilecek API’ler • Zararlı yazılımların genellikle ihtiyaç duydukları ve bu yüzden şüpheli olabilecek API’lere sonraki sayfalardaki örnekleri verebiliriz. Elbette API’lerin birden fazla kullanım amacı olabilir ve liste daha da genişletilebilir, ancak kullanım amaçları ile ilgili fikir vermesi için bu şekilde bir gruplama yapılmıştır. • Elbette zararlının özel amaçları doğrultusunda ihtiyaç duyacağı başka API’ler de olabilir. Tüm Windows API’lerine erişmek için MSDN’den faydalanabilirsiniz.
  10. 10. ŞÜPHELİ WINDOWS API'LERİ Ağ Erişimiyle İlgili API’ler İhtiyaç: Zararlı yazılımlar veriyi dışarı sızdırmak, bir sunucuyla tünel bağlantısı kurmak, ikinci aşama payload’larını indirmek, v.b. ihtiyaçlarla ağ erişim API’lerini kullanabilirler. WinSock API • WSAStartup • getaddrinfo • socket • connect • send • recv • WSAGetLastError
  11. 11. ŞÜPHELİ WINDOWS API'LERİ Ağ Erişimiyle İlgili API’ler (devamı) WinINet API • InternetOpen • InternetConnect • InternetOpenURL • InternetReadFile • InternetWriteFile • HTTPOpenRequest • HTTPQueryInfo • HTTPSendRequest
  12. 12. ŞÜPHELİ WINDOWS API'LERİ Ağ Erişimiyle İlgili API’ler (devamı) Kernel32 API • ConnectNamedPipe • PeekNamedPipe Urlmon API • URLDownloadToFile Diğer • FtpPutFile • GetAdaptersInfo (Anti-Virtual Machine kontrolü için de kullanılabilir)
  13. 13. İhtiyaç: Zararlı yazılımlar dosya drop etmek (resource section’larındaki bir dosyayı diske yazmak), kendilerini başka bir isimle saklamak, veri sızdırmak için dosyalara erişmek, indirdiği ve ihtiyacı kalmayan dosyaları silmek v.b. amaçlarla dosya erişim API’lerini kullanabilirler. • CreateFile • ReadFile • WriteFile • FindResource • LoadResource ŞÜPHELİ WINDOWS API'LERİ Dosya Erişimiyle ve Dropper Fonksiyonalitesiyle İlgili API’ler
  14. 14. ŞÜPHELİ WINDOWS API'LERİ Registry Erişimiyle İlgili API’ler İhtiyaç: Zararlı yazılımlar kalıcılıklarını sağlamak için Autorun registry değerlerine yazmak, parola v.b. hassas verilere erişmek, varsa hedeflediği bir uygulamanın kurulu olup olmadığını anlamak, v.b. amaçlarla registry API’lerini kullanabilirler. • RegOpenKeyEx • RegSetValueEx • RegGetValue
  15. 15. ŞÜPHELİ WINDOWS API'LERİ Keylogger Fonksiyonalitesiyle İlgili API’ler İhtiyaç: Zararlı yazılımın keylogger fonksiyonalitesi var ise bu bilgileri elde etmelerine imkan veren API’lere erişebilirler. • GetAsyncKeyState • GetForegroundWindow • GetKeyState • SetWindowsHookEx • CallNextHookEx • AttachThreadInput • MapVirtualKey
  16. 16. ŞÜPHELİ WINDOWS API'LERİ Proses İşlemleri ile İlgili API’ler İhtiyaç: Zararlı yazılımlar diğer proses’lerin adres space’lerinde kod çalıştırmak için, anti-virüs v.d. proses’leri öldürmek için, dinamik analizi engellemek için v.d. amaçlarla bu API’lere ihtiyaç duyabilirler. • CreateToolhelp32Snapshot (process listesini belirlemek için kullanılır) • Process32First/Process32Next • Module32First/Module32Next • OpenProcess • VirtualAllocEx • VirtualProtectEx (bellek erişim haklarının değiştirilmesi için kullanılır) • WriteProcessMemory • AdjustTokenPrivileges • CreateRemoteThread • EnumProcesses • EnumProcessModules • IsWoW64Process • QueueUserAPC
  17. 17. ŞÜPHELİ WINDOWS API'LERİ DLL Yükleme ve Fonksiyon Adresi Bulma API’leri İhtiyaç: Zararlı yazılımlar detaylı statik analizde tespit edilebilecek olmalarına rağmen Import Address Table’larında kullandıkları kütüphane ve API’lerin görünmemesi amacıyla dinamik olarak kütüphane yükleme ve bunların Export ettikleri fonksiyonların adreslerini bulmak için gerekli API’leri kullanabilirler. • LoadLibrary • GetProcAddress • LdrLoadDll
  18. 18. ŞÜPHELİ WINDOWS API'LERİ Debug Edilip Edilmediğini Tespit Etmek için Kullanılan API’ler İhtiyaç: Zararlı yazılımlar debug edildiklerini tespit etmek ve normal davranışlarını sergilememek için çok çeşitli teknikler kullanırlar. Bunlardan bir kısmı Windows’un sağladığı debugger tespit imkanlarıdır. • IsDebuggerPresent • CheckRemoteDebuggerPresent • FindWindow (örneğin Ollydbg uygulamasının aktif olup olmadığını anlamak için) • GetTickCount • NtQueryInformationProcess • OutputDebugString
  19. 19. Servislerle ve Scheduled Task’larla Kalıcılığı Sağlamak için Kullanılabilecek API’ler ŞÜPHELİ WINDOWS API'LERİ İhtiyaç: Zararlının kalıcılık için servis veya scheduled task kullanması durumunda kullandığı API’ler • CreateService • ControlService • OpenSCManager • NetScheduleJobAdd
  20. 20. ŞÜPHELİ WINDOWS API'LERİ Diğer Dosyalara Bulaşmak için Kullanılan API’ler İhtiyaç: Zararlının diğer dosyalara da kod eklemek için kullandığı API’ler • FindFirstFile • FindNextFile • NtQueryDirectoryFile • CreateFileMapping (Disk üzerindeki PE dosyalarına kod inject etmek için bunları belleğe yükleyerek ona erişmek için kullanılan API) • MapViewOfFile
  21. 21. ŞÜPHELİ WINDOWS API'LERİ COM Nesnelerini Kullanmak için Kullanılan API’ler İhtiyaç: Zararlı yazılım Windows işletim sistemi ile gelen COM bileşenlerini kullanabilir. Bu durumda hangi COM nesnesinin ve dolayısıyla hangi fonksiyonalitenin kullanıldığını anlamak için onun class identifier’ını (CLSID) incelememiz gerekir. • OleInitialize (COM nesneleri kullanılmadan önce çağrılır) • CoInitializeEx (COM nesneleri kullanılmadan önce çağrılır)
  22. 22. ŞÜPHELİ WINDOWS API'LERİ Veri Sızdırmak, Parola Çalmak için Kullanılabilecek API’ler İhtiyaç: Zararlı yazılım sistem üzerinde tanımlı kullanıcıların parola hash’lerini SAM veritabanına erişerek, sisteme erişmiş kullanıcıların parolalarını bellekteki verilere erişerek ele geçirmek isteyebilir, sisteme map’lenmiş paylaşımlar içinde de veri arayabilir. • LsaEnumerateLogonSessions (Credential çalan zararlılar tarafından sisteme logon olmuş kullanıcıları tespit etmek için kullanılabilir) • SamIConnect (SAM veritabanına erişmek ve parola hash’lerini dump etmek için kullanılır) • SamIGetPrivateData (SAM veritabanına erişmek ve parola hash’lerini dump etmek için kullanılır) • SamQueryInformationUse (SAM veritabanına erişmek ve parola hash’lerini dump etmek için kullanılır)
  23. 23. ŞÜPHELİ WINDOWS API'LERİ Veri Sızdırmak, Parola Çalmak için Kullanılabilecek API’ler (devamı) • NetShareEnum (SAM veritabanına erişmek ve parola hash’lerini dump etmek için kullanılır) • ReadProcessMemory • Toolhelp32ReadProcessMemory
  24. 24. ŞÜPHELİ WINDOWS API'LERİ Diğer API’ler • CreateMutex (Aynı anda zararlı prosesin tek bir instance’ının çalışması için kullanılabilen bir API’dir. Mutex bir kilit gibi davranır ve bu kilide sahip olmayan proses diğerlerini bekler) • CreateProcess • ShellExecute • WinExec • System (zararlı proses drop ettiği başka bir uygulamayı veya sistem üzerindeki başka bir uygulamayı başlatmak için bu API’leri kullanabilir) • CryptAcquireContext (Kriptolama fonksiyonları zararlı tarafından çeşitli amaçlarla kullanılabilir, crypt ile başlayan pek çok fonksiyon incelenebilir) • EnableExecuteProtectionSupport (DEP kontrolünü ortadan kaldırmak için kullanılan fonksiyondur)
  25. 25. ŞÜPHELİ WINDOWS API'LERİ Diğer API’ler (devamı) • NtSetInformationProcess (Proses haklarını yükseltmek veya DEP kontrolünü ortadan kaldırmak için kullanılabilir) • GetSystemDefaultLangId (Ransomware v.b. mesaj veren zararlılar tarafından sistemin dil ayarlarını tespit etmek için kullanılır) • GetTempPath (zararlı yazılım bir takım geçici dosyaları saklamak için bu alanı kullanabilir) • SetFileTime (zararlı yazılım aktivitelerini gizleyebilmek için kullanabilir) • StartServiceCtrlDispatcher (Servis olarak başlayan bir proses’in ilk 30 sn. içinde bu fonksiyonu çağırması gerekir. Bu API’nin gözlenmesi zararlının servis olarak çalıştırılması gerektiği anlamına gelebilir.) • IsNTAdmin • IsUserAnAdmin (zararlı kullanıcının admin haklarına sahip olup olmadığını kontrol etmek için bu API’leri kullanabilir)
  26. 26. ŞÜPHELİ WINDOWS API'LERİ ÖNEMLİ • Derleyiciler bazı fonksiyonları yazılımcı bu fonksiyonu doğrudan kullanmamış olsa da uygulamaya ekleyebilmektedir. Örneğin [IsDebuggerPresent] fonksiyonunu aslında yazılımcı böyle bir kontrol yapmasa da bazı uygulamalarda mevcut olarak gözlemleyebilirsiniz. • Şüpheli bir API’nin tam olarak nasıl kullanıldığını anlayabilmek için disassembly üzerinde aldığı parametreleri incelemek ve binary debugger ile dinamik analiz ile izlemek gerekecektir. Bunu yapabilmek için de X86 mimarisi, X86 Assembly, calling conventions (fonksiyon çağırma yöntemleri) bilgilerine sahip olmak gereklidir.
  27. 27. ANALİZ STATİK ANALİZ [Import Address Table] Oluşturduğumuz şüpheli API adları listesini kopyalayarak A ve W uzantılı adlarını da türetelim
  28. 28. ANALİZ STATİK ANALİZ [Import Address Table] MS Excel'in VLOOKUP fonksiyonunu kullanarak zararlı yazılımın IAT'ından elde ettiğimiz liste ile şüpheli API listemizi karşılaştıralım
  29. 29. ANALİZ STATİK ANALİZ [Import Address Table] Henüz X86 mimarisi ile ilgili teorik bir çalışma yapmadık, ancak küçük bir tanışıklık için ilgimizi çeken bir API için [ör: RegSetValueExW] zararlımızı inceleyelim. Dinamik analiz sırasında zararlının Autorun registry key'lerine değer yazdığını görmüştük, zararlı yazılımın bu davranışını biraz daha yakından inceleyelim.
  30. 30. ANALİZ STATİK ANALİZ [Import Address Table] RegSetValueExW fonksiyonunun çağrıldığı yerleri bulmak ve bu bölümleri inceleyebilmek için IDA Pro'nun Imports penceresinden faydalanabiliriz. Bunun için bu fonksiyonun üzerinde çift tıklayalım.
  31. 31. ANALİZ STATİK ANALİZ [Import Address Table] Buradan RegSetValueExW fonksiyonunun IAT'daki yerine geliriz. Fonksiyon adına tıkladıktan sonra "X" harfine basarsak IDA bize bu adresin kullanıldığı kod bölümlerinin Cross (bu yüzden X) Reference bilgilerini verir.
  32. 32. ANALİZ STATİK ANALİZ [Import Address Table] XREF listesinde seçtiğimiz bir satıra çift tıkladığımızda ilgili kod için disassembly ekranına geçeriz. Mouse'umuzu fonksiyon adı üzerine getirdiğimizde fonksiyonun parametre yapısını görebiliriz. X86 hakkında daha detaylı çalışacağız, ancak fonksiyonların parametrelerini Stack'e yazılan değerlerden aldığını söyleyelim. Disassembly üzerinden bu değerlerin neler olduğunu anlamak güç, çünkü parametrelerin bir kısmı daha yukarıda yapılan hesaplamalar ve diğer işlemler sonucunda belirlenerek stack'e yazılıyor (push ediliyor).
  33. 33. ANALİZ STATİK ANALİZ [Import Address Table] Windows API'leri ve bu fonksiyonların alabilecekleri parametre değerleri ile ilgil detaylı bilgiyi MSDN v.d. kaynaklardan bulabilirsiniz.
  34. 34. ANALİZ DİNAMİK ANALİZ [Import Address Table] RegSetValueExW fonksiyonuna verilen parametreleri statik olarak analiz etmek zor olduğu için Immunity Debugger ile dinamik analiz yapalım ve bu fonksiyon çağrılmadan önce Stack'te bulunacak parametreleri inceleyelim.
  35. 35. ANALİZ DİNAMİK ANALİZ [Import Address Table] Uygulamanın ASLR destekli olması nedeniyle unpack edilmiş olan uygulamada da hata alıyoruz [uzun incelemeler sonrasında ulaştığım bu sonuç hakkında bana güvenin!] Ancak bu hata yüzünden olmasa da yine de ASLR desteğini kaldırmamız gerekecekti, yoksa IDA'da öğrendiğimiz adresi bellekte aynı adreste bulamayacaktık
  36. 36. ANALİZ DİNAMİK ANALİZ [Import Address Table] Unpack edilmiş zararlı yazılımımıza PEView ile göz attığımızda Image Optional Header içinde bulunan DLL Characteristics alanında ASLR desteği bulunduğunu görebiliriz [Dynamic Base özelliği] OS Loader bu özelliği dikkate alarak uygulamayı ASLR ile belleğe yükler. Bundan kaçınmak için uygulamanın ASLR'ı desteklemediğini belirtmemiz lazım. Bu alanın dosya içindeki offset'inin 0x176 byte'ta olduğunu PEView'ın pFile adres formatı ile görebiliriz.
  37. 37. ANALİZ DİNAMİK ANALİZ [Import Address Table] Uygulama dosyasını yamalamak için 010 Editör'le dosyayı açmadan önce Immunity Debugger ve PEView'ı kapatalım, aksi takdirde dosya Read Only olarak açılacaktır DLL Characteristics alanının mevcut değeri 40 81 (PEView'da little endian formatta gösterilmiştir)
  38. 38. ANALİZ DİNAMİK ANALİZ [Import Address Table] 40 değerini 00 ile değiştirerek dosyamızı Save edelim
  39. 39. ANALİZ DİNAMİK ANALİZ [Import Address Table] Yamamızdan sonra unpacked zararlı yazılım uygulamamızın ASLR (Dynamic Base) desteğinin kalktığını görebiliriz
  40. 40. ANALİZ DİNAMİK ANALİZ [Import Address Table] Uygulamamızı bu defa sorunsuz başlatabiliriz. RegSetValueExW fonksiyonunun tam çağrıldığı noktada breakpoint koymak için [b 40298f] komutunu kullanabiliriz.
  41. 41. ANALİZ DİNAMİK ANALİZ [Import Address Table] Imminuty Debugger'ın [b] düğmesiyle erişilen Breakpoints ekranına göz attığımızda breakpoint'imizin başarı ile konup konmadığını gözleyebiliriz.
  42. 42. ANALİZ DİNAMİK ANALİZ [Import Address Table] Normalde çalışan uygulamamız Immunity Debugger ile çalıştırdığımızda [Division by zero] hatası aldı Shift+F9 ile kontrolü uygulamaya iade ettiğimizde de herhangi bir ilerleme gözlemleyemedik EAX register'ının hata anındaki değeri [0]
  43. 43. ANALİZ DİNAMİK ANALİZ [Import Address Table] DIV instruction'ının açıklamasına baktığımızda EDX:EAX register'larındaki değerin EAX register'ı ile bölme işlemini gerçekleştirdiğini görebiliriz
  44. 44. DİNAMİK ANALİZ [Import Address Table] ANALİZ Hata aldığımız noktanın öncesini Immunity Debugger'ın Disassembly penceresinden de inceleyebiliriz, ama incelememizi IDA'da yapmak istersek [Jump to address] aracılığıyla ilgili adrese gidebiliriz
  45. 45. DİNAMİK ANALİZ [Import Address Table] ANALİZ Hatanın alındığı [0x401D8A] adresine gidelim
  46. 46. DİNAMİK ANALİZ [Import Address Table] ANALİZ [div eax] instruction'ından hemen önceki satıra bakarsak [xor eax, eax] instruction'ı ile EAX register'ının değerinin 0'landığını görebiliriz. Bu bilgi 0'a bölme hatasının kasten oluşturulduğu şüphesini doğuruyor. Bu satırdan hemen önce de yeni bir Exception Handler belirlenmiş. Uygulama çalışırken bu handler hatayı ele alıyor olmalı, ancak Immunity kontrolü uygulamaya devrettiğinde aynı durum gerçekleşmiyor.
  47. 47. HATA ALDIRMA ÖRNEĞİ ANTI-DEBUGGING YÖNTEMLERİ ImmunityDebugger'ın Options / Debugging options / Exceptions penceresinde istediğimiz hata kodları için kontrolün otomatik olarak uygulamaya devredilmesi ayarını yapabiliriz
  48. 48. HATA ALDIRMA ÖRNEĞİ ANTI-DEBUGGING YÖNTEMLERİ Tam hata kodunu öğrenmek için bu ekrandaki "Add last exception" düğmesini kullanabiliriz, veya bir aralık tanımlayarak 0 – FFFFFFFF aralığındaki tüm exception'ları göz ardı ettirebiliriz.
  49. 49. HATA ALDIRMA ÖRNEĞİ ANTI-DEBUGGING YÖNTEMLERİ ImmunityDebugger'ın bu özelliğini kullanarak Exception'ı uygulamaya aktarma denememiz başarılı olamadı.
  50. 50. ANTI-DEBUGGING YÖNTEMLERİ AMAÇ • Anti-Debugging yöntemleri ile zararlı yazılım geliştiren taraf dinamik analizi zorlaştırmak ister. • Ancak hemen her durumda bu kontrolün tespiti ve uygulama yamalanarak (debug kontrolü yapan instruction'ların NOP instruction'ları ile etkisiz hale getirilmesiyle) atlatılması mümkündür. • Bu kontrollerin uygulandığı noktalar tespit edildikten sonra dinamik analiz sırasında bu noktalarda registry değerleri veya belleğe manuel müdahale etme veya bu debugger'ların sağladığı bazı atlatma imkanlarının kullanılması da anti- debugging engellerini atlatmak için kullanılabilir.
  51. 51. ANTI-DEBUGGING YÖNTEMLERİ ÖRNEKLER API Metodları • [IsDebuggerPresent()] – PEB bloğundaki BeingDebugged byte'ının değerini kontrol eder • [CheckRemoteDebuggerPresent(GetCurrentProcess(), &isDebuggerPresent)] – Mevcut proses'imizin handle'ını kullarak debug edilip edilmediğini test eder • [NtQueryInformationProcess(...)] – Debug Flag'lerini verilen değişken referansına döndürür • [OutputDebugString(L"test")/GetLastError()] – proses debug edilmiyorsa GetLastError ile dönen hata kodu değişecektir • [DebugActiveProcess(pid)] – Eğer proses zaten debug ediliyorsa hata döndürecektir
  52. 52. ANTI-DEBUGGING YÖNTEMLERİ ÖRNEKLER Manuel Kontrol Yöntemleri • Debugger uygulama varlığını arama: [FindWindow(L"OLLYDBG",0)] fonksiyonu ile aktif uygulamaların adlarını inceleme, registry 'yi veya dosya sistemini debugger varlığını keşfetmek için tarama • Manuel olarak PEB bloğu içindeki BeingDebugged değerini arama
  53. 53. ANTI-DEBUGGING YÖNTEMLERİ ÖRNEKLER Breakpoint Arama ve Kod Bütünlüğünü Test Etme • Software breakpoint ve yama tespiti: Belli bir kod bölümünün byte'larını basit bir biçimde bir byte'lık bir değişkene ekleyerek hesaplanan değer önceden hesaplanmış bir değerle karşılaştırılabilir. Veya her bir byte bir değerle XOR'lanarak 0xCC olup olmadığı test edilebilir (ör: [0xCC XOR 0x55 == 0x99]) • Hardware breakpoint tespiti: [GetThreadContext(hnd, &ctx)] fonksiyonuyla DR0, DR1, DR2, DR3 register değerlerini içeren context veri yapısı incelenebilir.
  54. 54. ANTI-DEBUGGING YÖNTEMLERİ ÖRNEKLER Zaman Aralıklarını Ölçme • [GetTickCount() ], [timeGetTime()] gibi fonksiyonlarla art arda ölçülen zaman değerleri arasındaki fark test edilerek proses'in debug edilip edilmediği anlaşılmaya çalışılır.
  55. 55. ANTI-DEBUGGING YÖNTEMLERİ UYGULAMANIN YAMALANMASI Debug etmemizi engelleyen bu durumu aşmak için hata alan satırı NOP instruction'ı ile yamalayacağız. Bunun için önce Options / IDA Options / Disassembly menüsünde "Number of opcode bytes" değerini 8 yaparak Opcode'ların görünür olmasını sağlayalım.
  56. 56. ANTI-DEBUGGING YÖNTEMLERİ UYGULAMANIN YAMALANMASI "div eax" instruction'ının opcode'larının "F7 F0" olduğunu görebiliyoruz. Bu instruction'ın VA adresi de 0x401D8A
  57. 57. ANTI-DEBUGGING YÖNTEMLERİ UYGULAMANIN YAMALANMASI Hex View'a geçtiğimizde seçtiğimiz instruction'ı Hex veriler arasında da görebiliriz
  58. 58. ANTI-DEBUGGING YÖNTEMLERİ UYGULAMANIN YAMALANMASI IDA Pro'nun güncel versiyonunda disk üzerindeki dosyanın yamalanması imkanı var. Ne yazık ki ücretsiz versiyon olan IDA Pro 5'te "Patch program" seçeneği bulunmuyor.
  59. 59. ANTI-DEBUGGING YÖNTEMLERİ UYGULAMANIN YAMALANMASI Uygulamayı IDA'da yamalayamadığımız için VA ve dosya offset dönüşümünü PEView ile yapmaya çalışacağız. Bunun için önce VA adresi olarak 0x401D8A adresinin bulunduğu yeri bulalım. Yamalanacak olan [F7 F0] byte'ları işaretlenen satırın 11. ve 12. byte'ları.
  60. 60. ANTI-DEBUGGING YÖNTEMLERİ UYGULAMANIN YAMALANMASI PEView'ın adres formatını File Offset'e getirdiğimizde yamalayacağımız adresin 0x118A'da bulunduğunu görebiliriz.
  61. 61. ANTI-DEBUGGING YÖNTEMLERİ UYGULAMANIN YAMALANMASI Yamayı 010 Editör'le veya farklı bir Hex editörle uygulayabiliriz.
  62. 62. ANTI-DEBUGGING YÖNTEMLERİ UYGULAMANIN YAMALANMASI Yamalanacak [F7 F0] byte'larını [90 90] yani NOP NOP instruction'ları ile yamalayalım.
  63. 63. ANTI-DEBUGGING YÖNTEMLERİ UYGULAMANIN YAMALANMASI Değişikliğimizi dosyaya yansıtmak için Save edelim.
  64. 64. ANTI-DEBUGGING YÖNTEMLERİ UYGULAMANIN YAMALANMASI Yamalanmış uygulamayı tekrar IDA Pro'da açarak yamayı gerçekleştirdiğimiz adrese gidelim.
  65. 65. ANTI-DEBUGGING YÖNTEMLERİ UYGULAMANIN YAMALANMASI Daha önce "div eax" instruction'ının bulunduğu yerde "nop nop" instruction'larının bulunduğunu görebiliriz.
  66. 66. ANALİZ DİNAMİK ANALİZ [Import Address Table]
  67. 67. ANALİZ DİNAMİK ANALİZ [Import Address Table] Uygulama sonlandı ancak registry değerinin atandığı instruction çalışmadı. Böyle bir durum zararlının daha önce bu sistem üzerinde çalışmış olması nedeniyle tekrar sisteme bulaşmamak istemesinden kaynaklanmış olabilir. Bu nedenle infection öncesi SnapShot'a dönerek uygulamayı tekrar denemekte fayda var.
  68. 68. ANALİZ DİNAMİK ANALİZ [Import Address Table] Kurban sistemi kurulumlar sonrası aldığımız snapshot'a döndürdüğümüzde üzerinde çalıştığımız ve yamaladığımız zararlı kopyalarını da kaybedeceğiz. Bunun için snapshot'a dönmeden önce yamayı uyguladığımız fatura_pdf-decompress.exe dosyasını Host bilgisayarımıza kopyalayalım.
  69. 69. ANALİZ DİNAMİK ANALİZ [Import Address Table] Kurban sistemimizi "Kurulum Sonrası" snapshot'umuza döndürelim.
  70. 70. ANALİZ DİNAMİK ANALİZ [Import Address Table] Kurban sistemimiz kurulumlar sonrasında henüz zararlı yazılımı çalıştırmadan önceki haline dönecektir.
  71. 71. ANALİZ DİNAMİK ANALİZ [Import Address Table] Host bilgisayarımıza aldığımız Anti-Debug amaçlı kod bölümünü yamaladığımız "fatura_pdf-decompress.exe" dosyasını Host bilgisayardan kopyalayalım.
  72. 72. ANALİZ DİNAMİK ANALİZ [Import Address Table] "fatura_pdf-decompress.exe" dosyamızı kurban bilgisayara kopyalayalım.
  73. 73. ANALİZ DİNAMİK ANALİZ [Import Address Table] "fatura_pdf-decompress.exe" dosyasını Immunity Debugger ile başlatalım. Başlatır başlatmaz da 0x40298F adresine breakpoint koyalım.
  74. 74. ANALİZ DİNAMİK ANALİZ [Import Address Table] Uygulamayı devam ettirdiğimizde PDF dosyasının görüntülendiğini görüyoruz. Bu davranış son denememizden farklı, muhtemelen uygulama daha önceden bulaşmadığı bir sistem üzerinde bu şekilde davranıyor. Uygulama tanımladığımız breakpoint adresinde durdu.
  75. 75. ANALİZ DİNAMİK ANALİZ [Import Address Table] RegSetValueExW fonksiyonu çağrılmadan hemen önce Stack'te bu fonksiyona verilen parametreleri görebiliriz. Bunlardan "ValueName" parametresi Registry değerini ifade ediyor
  76. 76. ANALİZ DİNAMİK ANALİZ [Import Address Table] MSDN'den edindiğimiz bilgiye göre RegSetValueEx fonksiyonuna verilen 5. parametre Registry değerine atanacak veriye işaret eden bir pointer
  77. 77. ANALİZ DİNAMİK ANALİZ [Import Address Table] ImmunityDebugger'ın Buffer olarak adlandırdığı bu alanda belirtilen adrese giderek atanan veriyi gözlemlemek için sol alt bölümdeki Memory Dump alanında sağ klikleyerek "Go to" / "Expression" seçeneğini seçelim.
  78. 78. ANALİZ DİNAMİK ANALİZ [Import Address Table] Buffer'ın stack'te tutulduğu adresi çıkan kutuya yazalım
  79. 79. ANALİZ DİNAMİK ANALİZ [Import Address Table] Bu adreste bulunan Unicode string'i biraz daha rahat gözlemleyebilmek için dump alanında sağ klikleyerek "Hex / UNICODE (16 bytes)" seçeneğini işaretleyelim.
  80. 80. ANALİZ DİNAMİK ANALİZ [Import Address Table] Bu alanda bir exe dosya adı görüyoruz. SORU: Burada gözlemlediğimiz dosya adını daha önce nerede gözlemlemiştik?
  81. 81. ANALİZ DİNAMİK ANALİZ [Import Address Table] hKey handle'ının hangi registry key'ine ait olduğunu anlamak için daha yukarıda çağrılan RegOpenKeyExW fonksiyonunun çağrıldığı yere breakpoint koymamız lazım. Tabi bunun için sanal makinemizi yine kurulumlar sonrası snapshot'ımıza döndürmeyi unutmamalıyız.
  82. 82. EGZERSİZ DİNAMİK ANALİZ [Import Address Table] • Import Address Table'da ilginç bulduğunuz fonksiyonlar için Immunity Debugger ile benzer analizleri yapınız. • Fonksiyonun çağrıldığı adrese breakpoint koyunuz ve stack'te fonksiyon için hazırlanmış olan parametreleri inceleyiniz. Parametreler hakkında detaylı bilgi için MSDN'e başvurunuz. • Tespitlerinizi bu noktaya kadar yapmış olduğumuz strings analizleri ve capturebat ile yaptığımız dinamik analiz sonuçları ile birlikte değerlendiriniz. • Daha ileri statik ve dinamik analiz yapabilmek için gerekli X86 temel bilgileri üzerinde sonraki bölümde durulacaktır.
  83. 83. X86 MİMARİSİNE GİRİŞ İNCELEYECEĞİMİZ UYGULAMA PE dosya formatını da inceleme için kullandığımız bu basit C uygulamasından derlenmiş kodu Immunity Debugger üzerinde incelerken temel X86 bilgilerine değineceğiz.
  84. 84. X86 MİMARİSİNE GİRİŞ ANA KONULAR VE KAVRAMLAR Daha Önce Değindiklerimiz • Derleme ve linkleme • OS Loader'ın uygulamayı belleğe yüklemesi • Executable imajı, DLL modülleri, Stack ve Heap alanlarının bellekteki konumları [ASLR konusuyla bağlantıları] • Virtual Address kavramı
  85. 85. X86 MİMARİSİNE GİRİŞ ANA KONULAR VE KAVRAMLAR (DEVAMI) Bu Bölümde Değineceklerimiz • Register'lar ve kullanım amaçları • X86 instruction set'i • Stack alanının kullanımı [fonksiyon çağırma, fonksiyon içindeki ve fonksiyondan çıkış işlemleri sırasındaki olaylar] • Calling conventions [fonksiyon çağırma sırasında parametrelerin fonksiyona aktarım yöntemleri, fonksiyon dönüşünde stack'i temizleme görevleri]
  86. 86. X86 MİMARİSİNE GİRİŞ X86 hakkındaki teorik bilgiler üzerinde daha sonrak konuşmak üzere, öncelikle uygulamamızın Makine Kodu seviyesindeki işleyişini inceleyelim. Öncelikle main() fonksiyonu içindeki ilk instruction'ın adresini öğrenmek için Visual Studio'nun "Go To Assembly" özelliğini kullanacağız.
  87. 87. X86 MİMARİSİNE GİRİŞ Visual Studio'da Disassembly view'ına geçtiğimizde derleyicinin üreteceği Assembly kodlarının yanı sıra bunların adreslerini de görüyoruz. Bu bilgiye şu nedenle ihtiyacımız var: Derleyiciler kod üretmeye doğrudan main() fonksiyonundan başlamazlar ve Address of Entry Point'te main() fonksiyonuna işaret etmez. Ancak bizim X86 mimarisini anlama amaçlı incelememizi main() fonksiyonundan başlatmamız lazım. İlk instruction olan "push ebp" instruction'ının adresi 0x401060
  88. 88. X86 MİMARİSİNE GİRİŞ Uygulama belleğe yüklendiğinde de bu adreste olacağından emin olabilmek için ASLR'ı bu ayarlarla etkisiz hale getirdik.
  89. 89. X86 MİMARİSİNE GİRİŞ Address of Entry Point'e koyduğumuz breakpoint [0x401060] sonrası bir kaç defa F9 tuşuna basılarak main() fonksiyonunun başına geliyoruz.
  90. 90. X86 MİMARİSİNE GİRİŞ main() fonksiyonunun ilk instruction'ları "function prologue" adı da verilen önceki fonksiyon frame pointer'ın saklanması ve mevcut stack pointer'ın yeni fonksiyonun frame pointer'ı olarak belirlenmesidir.
  91. 91. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] STACK DEĞİŞEN REGISTER'LAR ESP 0x0018FF40 ESP Yüksek Adres Düşük Adres Buradaki stack gösterimimiz ile Immunity Debugger'ın stack penceresindeki büyüme yönleri farklı, bu nedenle biraz kafanız karışabilir !
  92. 92. X86 MİMARİSİNE GİRİŞ "function prologue"un ikinci adımında mevcut stack pointer [ESP] main() fonksiyonunun stack base pointer'ı [EBP] olarak atanıyor.
  93. 93. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] STACK EBP 0x0018FF40 ESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  94. 94. X86 MİMARİSİNE GİRİŞ main() fonksiyonunun lokal değişkenleri için stack'te 12 byte'lık [0x0C] yer ayrılıyor.
  95. 95. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] XXXXXXXX XXXXXXXX XXXXXXXX STACK ESP 0x0018FF34 ESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  96. 96. X86 MİMARİSİNE GİRİŞ [EBP-8] adresindeki lokal değişkene 10 [0x0A] değeri atanıyor.
  97. 97. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] XXXXXXXX 0x0000000A XXXXXXXX STACK ESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  98. 98. X86 MİMARİSİNE GİRİŞ [EBP-4] adresindeki lokal değişkene 20 [0x14] değeri atanıyor.
  99. 99. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A XXXXXXXX STACK ESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  100. 100. X86 MİMARİSİNE GİRİŞ [EBP-4] adresindeki lokal değişken EAX register'ına atanıyor.
  101. 101. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A XXXXXXXX STACK ESP EAX 0x00000014 DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  102. 102. X86 MİMARİSİNE GİRİŞ EAX register'ının değeri Stack'e push ediliyor. Bu değer "add" fonksiyonu için bir parametre olarak kullanılacak.
  103. 103. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A XXXXXXXX 0x00000014 [Arg 2]STACK ESP ESP 0x0018FF30 DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  104. 104. X86 MİMARİSİNE GİRİŞ [EBP-8] adresindeki lokal değişken ECX register'ına atanıyor.
  105. 105. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A XXXXXXXX 0x00000014 [Arg 2]STACK ESP ECX 0x0000000A DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  106. 106. X86 MİMARİSİNE GİRİŞ ECX register'ının değeri Stack'e push ediliyor. Bu değer "add" fonksiyonu için bir diğer parametre olarak kullanılacak.
  107. 107. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A XXXXXXXX 0x00000014 [Arg 2] 0x0000000A [Arg 1] STACK ESP ESP 0x0018FF2C DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  108. 108. X86 MİMARİSİNE GİRİŞ Immunity Debugger debug sembollerine sahip olduğu bir executable için bize fonksiyon adı ve bu fonksiyona verilen parametrelerle ilgili bilgi sağlıyor.
  109. 109. X86 MİMARİSİNE GİRİŞ "call add" instruction'ı çalıştığında EIP değeri add fonksiyonuna işaret edecek şekilde değişiyor, ancak main() fonksiyonu içindeki bir sonraki instruction'ın adresi stack'e yazılıyor.
  110. 110. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A XXXXXXXX 0x00000014 [Arg 2] 0x0000000A [Arg 1] 0x00401081 [EIP] STACK ESP ESP 0x0018FF28 DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  111. 111. X86 MİMARİSİNE GİRİŞ add() fonksiyonunun prologue'unın ilk instruction'ı çalıştığında main() fonksiyonunun stack base pointer'ı stack'e yazılıyor.
  112. 112. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A XXXXXXXX 0x00000014 [Arg 2] 0x0000000A [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] STACK ESP ESP 0x0018FF24 DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  113. 113. X86 MİMARİSİNE GİRİŞ add() fonksiyonunun prologue'unın ikinci instruction'ı çalıştığında ESP register'ının değeri add() fonksiyonunun stack base pointer'ına [EBP] yazılıyor.
  114. 114. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A XXXXXXXX 0x00000014 [Arg 2] 0x0000000A [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] STACK ESP EBP 0x0018FF24 DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  115. 115. X86 MİMARİSİNE GİRİŞ add() fonksiyonu lokal değişkenler için sadece 4 byte'lık bir alan kullandığından "push ecx" instruction'ı ile stack'te yeterli alan ayrılmış oluyor.
  116. 116. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A XXXXXXXX 0x00000014 [Arg 2] 0x0000000A [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] XXXXXXXX STACK ESP ESP 0x0018FF20 DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  117. 117. X86 MİMARİSİNE GİRİŞ add() fonksiyonunun stack'te hazır bulunan birinci parametresi [EAX] register'ına atanıyor.
  118. 118. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A XXXXXXXX 0x00000014 [Arg 2] 0x0000000A [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] XXXXXXXX STACK ESP EAX 0x0000000A DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  119. 119. X86 MİMARİSİNE GİRİŞ add() fonksiyonunun stack'te hazır bulunan ikinci parametresi [EAX] register'ına [add] instruction'ı ile ekleniyor.
  120. 120. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A XXXXXXXX 0x00000014 [Arg 2] 0x0000000A [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] XXXXXXXX STACK ESP EAX 0x0000001E DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  121. 121. X86 MİMARİSİNE GİRİŞ [EAX] register'ının değeri stack'te add() fonksiyonu için ayrılmış 4 byte'lık lokal değişken alanına atanıyor. Uygulamamızı optimizasyon ayarları ile derlemiş olsaydık muhtemelen bu adımı görmeyecektik. Çünkü zaten return değeri [EAX] register'ı ile döndürülecek.
  122. 122. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A XXXXXXXX 0x00000014 [Arg 2] 0x0000000A [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] 0x0000001E STACK ESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  123. 123. X86 MİMARİSİNE GİRİŞ Bu adımda gereksiz bir biçimde lokal değişken tekrar [EAX] register'ına atanıyor. Ancak register değeri zaten aynı olduğu için değişmiyor.
  124. 124. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A XXXXXXXX 0x00000014 [Arg 2] 0x0000000A [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] 0x0000001E STACK ESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  125. 125. X86 MİMARİSİNE GİRİŞ add() fonksiyonun epilogue'unun ilk adımında add() fonksiyonunun stack base pointer'ı [ESP] register'ına atanıyor. Bu adımda add() fonksiyonu için stack'ten almış olduğumuz alan geri veriliyor.
  126. 126. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A XXXXXXXX 0x00000014 [Arg 2] 0x0000000A [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] 0x0000001E STACK ESP 0x0018FF24 ESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  127. 127. X86 MİMARİSİNE GİRİŞ add() fonksiyonun epilogue'unun ikinci adımında main() fonksiyonunun stack'te saklanmış olan [EBP] register değeri tekrar yükleniyor. pop instruction'ı ile birlikte stack de 4 byte daha azaltılmış oluyor.
  128. 128. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A XXXXXXXX 0x00000014 [Arg 2] 0x0000000A [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] 0x0000001E STACK EBP 0x0018FF40 ESP 0x0018FF28 ESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  129. 129. X86 MİMARİSİNE GİRİŞ "retn" instruction'ı çalıştığında stack'in en üstünde bulunan saklanmış [EIP] değeri "pop" edilecek ve uygulama akışı bu adresten devam edecektir.
  130. 130. X86 MİMARİSİNE GİRİŞ "retn" instruction'ı çalıştığında sadece saklanmış EIP değerine atlamıyoruz aynı zamanda stack'de 4 byte küçültülmüş oluyor.
  131. 131. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A XXXXXXXX 0x00000014 [Arg 2] 0x0000000A [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] 0x0000001E STACK ESP 0x0018FF2C ESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  132. 132. X86 MİMARİSİNE GİRİŞ "add esp, 8" instruction'ı ile stack'te add() fonksiyon parametreleri için kullanmış olduğumuz 8 byte'lık alanı geri veriyoruz. Bu işlemde çağıran [caller] stack'i temizliyor.
  133. 133. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A XXXXXXXX 0x00000014 [Arg 2] 0x0000000A [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] 0x0000001E STACK ESP 0x0018FF34 ESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  134. 134. X86 MİMARİSİNE GİRİŞ [EAX] register'ında bulunan toplama işlemi sonucu main() fonksiyonunun lokal değişkenine atanıyor.
  135. 135. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A 0x0000001E 0x00000014 [Arg 2] 0x0000000A [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] 0x0000001E STACK ESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  136. 136. X86 MİMARİSİNE GİRİŞ Lokal değişkenimizde bulunan toplama sonucu [EDX] register'ına atanıyor.
  137. 137. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A 0x0000001E 0x00000014 [Arg 2] 0x0000000A [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] 0x0000001E STACK EDX 0x0000001E ESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  138. 138. X86 MİMARİSİNE GİRİŞ Optimizasyon uygulamadığımız için printf() fonksiyonunun ikinci parametresi olarak (parametreler yine sağdan sola doğru stack'e yazılıyor) [EDX] register'ında bulunan toplam değerini stack'e yazıyoruz (halbuki bu değer zaten stack'te mevcuttu)
  139. 139. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A 0x0000001E 0x0000001E [Arg 2] 0x0000000A [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] 0x0000001E STACK ESP 0x0018FF30 ESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres Buradaki Arg 2 printf()'in ikinci parametresi
  140. 140. X86 MİMARİSİNE GİRİŞ Bu instruction'da printf() fonksiyonu için format string'in bulunduğu adresi stack'e yazıyoruz. Stack penceresinde bu değerin Sonuc = "%d" olduğunu görebiliriz.
  141. 141. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A 0x0000001E 0x0000001E [Arg 2] 0x00403000 [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] 0x0000001E STACK ESP 0x0018FF2C ESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  142. 142. X86 MİMARİSİNE GİRİŞ printf() fonksiyonu çağrılmadan önce konsol penceresini görünteleyelim ve henüz birşey yazılmadığını görelim.
  143. 143. X86 MİMARİSİNE GİRİŞ printf fonksiyonunun içine girmeden "step over" şeklinde bu fonksiyonu çalıştırıyoruz, çünkü bu API fonksiyonunu incelemek istemiyoruz. Bu çağrıdan sonra Sonuc = 30 ifadesini görmemizin yanında ilginç olan bir nokta [EAX], [ECX] ve [EDX] register'larımızın değişmiş olması.
  144. 144. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A 0x0000001E 0x0000001E [Arg 2] 0x00403000 [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] 0x0000001E STACK EAX 0x0018FF2C ECX 0x0018FF2C EDX 0x0018FF2CESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres "caller saved" registers kavramına "calling conventions" bölümünde değineceğiz.
  145. 145. X86 MİMARİSİNE GİRİŞ printf() fonksiyonuna verilen parametreler için tüketilen stack alanı geri veriliyor.
  146. 146. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A 0x0000001E 0x0000001E [Arg 2] 0x00403000 [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] 0x0000001E STACK ESP 0x0018FF34 ESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  147. 147. X86 MİMARİSİNE GİRİŞ getchar() API fonksiyonunun çalışabilmesi için konsol penceresinden bir girdi vermemiz gerekecek. Bu yüzden "step over" komutu ile bir instruction daha atlamaya çalıştıktan sonra konsolu tekrar ön plana alalım.
  148. 148. X86 MİMARİSİNE GİRİŞ Konsol penceresinde "Enter" tuşuna bastıktan sonra getchar() fonksiyonu tamamlanarak dönüyor. [ECX] ve [EDX] register'larının değiştiğini gözlemliyoruz.
  149. 149. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A 0x0000001E 0x0000001E [Arg 2] 0x00403000 [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] 0x0000001E STACK ECX 0x683D60B0 EDX 0x0000000A ESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  150. 150. X86 MİMARİSİNE GİRİŞ main() fonksiyonundan çıkmadan önce [EAX] register'ı return değeri olarak "0"lanmak amacıyla kendisiyle XOR'lanıyor.
  151. 151. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A 0x0000001E 0x0000001E [Arg 2] 0x00403000 [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] 0x0000001E STACK EAX 0x00000000 ESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  152. 152. X86 MİMARİSİNE GİRİŞ main() fonksiyonundan çıkmadan önce epilogue adımlarından main() fonksiyonu için alınmış olan stack alanını geri veren "mov esp, ebp" instruction'ı çalıştırılıyor.
  153. 153. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A 0x0000001E 0x0000001E [Arg 2] 0x00403000 [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] 0x0000001E STACK ESP 0x0018FF40 ESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  154. 154. X86 MİMARİSİNE GİRİŞ main() fonksiyonu 2. epilogue adımında main() fonksiyonunu çağıran bir üst fonksiyonun [EBP] register'ı restore ediliyor.
  155. 155. X86 MİMARİSİNE GİRİŞ Stack ve Registry Değişim Özeti 0x0018FF88 [EBP] 0x00000014 0x0000000A 0x0000001E 0x0000001E [Arg 2] 0x00403000 [Arg 1] 0x00401081 [EIP] 0x0018FF40 [EBP] 0x0000001E STACK EBP 0x0018FF88 ESP 0x0018FF44 ESP DEĞİŞEN REGISTER'LAR Yüksek Adres Düşük Adres
  156. 156. X86 MİMARİSİNE GİRİŞ main() fonksiyonunun sonunda "retn" instruction'ı çalıştığında saklanmış olan [EIP] adresinden uygulama akışı devam ediyor.
  157. 157. X86 MİMARİSİNE GİRİŞ Uygulamanın devam etmesine izin verdiğimizde "0" exit değeri ile sonlandığını görüyoruz.
  158. 158. X86 MİMARİSİNE GİRİŞ İNCELEYEDİĞİMİZ UYGULAMA Assembly kodlarının üzerinden geçtikten sonra kaynak kodumuzu tekrar hatırlamak isteyebilirsiniz. (Aslında her aşamada bu kaynak koda göz atmak disassembly'yi anlamak için size yardımcı olabilir.)
  159. 159. X86 MİMARİSİNE GİRİŞ REGISTER'LAR VE KULLANIM AMAÇLARI EIP [Extended Instruction Pointer] Bir sonra çalışacak olan instruction’ın adresi (sadece makine tarafından değiştirilir) EBP [Extended Base Pointer] ve ESP [Extended Stack Pointer] İçinde bulunulan fonksiyonun stack frame’inin taban ve tavan adreslerini barındıran register’lar EAX, EBX, ECX, EDX, ESI, EDI Genel amaçlı register’lar (ancak geleneksel olarak belli amaçlarla kullanılabilirler) EFLAGS Çeşitli instruction’lar tarafından etkilenen ve kullanılan bayrakları barındıran 32 bit’lik bir register
  160. 160. X86 MİMARİSİNE GİRİŞ REGISTER'LAR VE KULLANIM AMAÇLARI • EAX – Accumulator Register: Genellikle fonsiyonların return değerlerini tutar. Hesaplamaların sonuçları da genellikle bu register'da tutulur. • EBX – Base Register: Genellikle belli bir özel amaç için kullanılmaz. • ECX – Counter Register: Genellikle döngülerde ve string işlemlerinde sayaç değişkenini (yani meşhur "i" değerini) tutmak için kullanılır. • EDX – Data Register: Çarpma ve bölme gibi işlemlerde EAX'in yetersiz kalması nedeniyle işlem sonuçlarının most significant bit'lerini tutmak için kullanılır. • ESI – Source Index: Genellikle string yazma işlemlerinde kopyalanacak string'den okunacak adresi tutar (read pointer). • EDI – Destination Index: Genellikle string yazma işlemlerinde yazılacak adresi tutar (write pointer). Önemli: ESP ve EBP register'ları ile birlikte yukarıdaki genel amaçlı register'lar assembly yazan uygulama geliştirici veya derleyici tarafından istenildiği gibi kullanılabilir. Ancak yukarıda belirtilen kullanımlar geleneksel kullanımlardır.
  161. 161. X86 MİMARİSİNE GİRİŞ REGISTER'LAR VE KULLANIM AMAÇLARI EAX EBX ECX EDX AX BX CX DX 078151631 32 Bit Register'lar 16 Bit Register'lar 8 Bit Register'lar Bu bölümleme sadece EAX, EBX, ECX ve EDX'e özeldir
  162. 162. X86 MİMARİSİNE GİRİŞ X86 ASSEMBLY GİRİŞ Assembly Syntax'ları Intel AT&T Prefix'ler mov eax, 1 movl $1, %eax Operand yönü instr dest, source instr source, dest Bellek operand'ları mov eax, [ebx] movl (%ebx), %eax Suffix'ler mov al, bl movb %bl, %al
  163. 163. X86 MİMARİSİNE GİRİŞ X86 ASSEMBLY GİRİŞ Bellek adresleme yöntemleri Instruction Anlamı mov eax, [ebx] EBX register'ının içerdiği adresteki 4 byte'lık değeri EAX register'ına atama mov [var], ebx EBX register'ının değerini 32bit'lik bir değişkenin içerdiği adrese yazma mov eax, [esi-4] ESI + (-4) adresindeki 4 byte'lık değeri EAX register'ına atama mov [esi+eax], cl CL register'ının taşıdığı bir byte'lık değeri ESI+EAX adresine yazma mov edx, [esi+4*ebx] ESI+4*EBX adresinde bulunan 4 byte'lık değeri EDX register'ına atama
  164. 164. X86 MİMARİSİNE GİRİŞ X86 ASSEMBLY GİRİŞ Size Directive'leri Register adlarının geçtiği instruction'lardan okunacak ve/veya yazılacak verinin büyüklüğü anlaşılabilir. Ancak immediate (sabit) verilerin yazıldığı durumlarda yazılacak verinin kaplayacağı alanın belirtilmesi gerekir. Instruction Anlamı mov BYTE PTR [ebx], 2 2 sabit değerini EBX register'ında saklı adresteki 1 byte'lık alan yaz mov WORD PTR [ebx], 2 2 sabit değerinin 16 bit'lik gösterimini EBX register'ında saklı adresten başlayan 2 byte'lık alana yaz mov DWORD PTR [ebx], 2 2 sabit değerinin 32 bit'lik gösterimini EBX register'ında saklı adresten başlayan 2 byte'lık alana yaz
  165. 165. X86 MİMARİSİNE GİRİŞ X86 ASSEMBLY GİRİŞ Instruction'lar Şu ana kadar pek çok assembly instruction'ı ile karşılaştık. Açıkçası belli bir instruction set'i kullanılan veya derleyicilerin ürettiği assembly kodlarının önemli bir bölümünü kapsar. Bu bölümde daha önce de karşılaştığımız çok kullanılan Assembly Instruction'larının üzerinden geçeceğiz.
  166. 166. X86 MİMARİSİNE GİRİŞ X86 ASSEMBLY GİRİŞ Instruction'lar [Data Movement Instruction'ları] mov Move (Opcodes: 88, 89, 8A, 8B, 8C, 8E, ...) Bellekten belleğe mov instruction'ı ile veri kopyalamak mümkün değildir. Syntax mov <reg>,<reg> mov <reg>,<mem> mov <mem>,<reg> mov <reg>,<imm> mov <mem>,<imm>
  167. 167. X86 MİMARİSİNE GİRİŞ X86 ASSEMBLY GİRİŞ Instruction'lar [Data Movement Instruction'ları] push Push stack (Opcodes: FF, 89, 8A, 8B, 8C, 8E, ...) Syntax push <reg32> push <mem> push <imm32>
  168. 168. X86 MİMARİSİNE GİRİŞ X86 ASSEMBLY GİRİŞ Instruction'lar [Data Movement Instruction'ları] pop Pop stack Syntax pop <reg32> pop <mem>
  169. 169. X86 MİMARİSİNE GİRİŞ X86 ASSEMBLY GİRİŞ Instruction'lar [Data Movement Instruction'ları] lea Load effective address Bu instruction diğerlerine nazaran biraz kafa karıştırıcı olabilir. "lea" instruction'ın da kaynak değer mutlaka köşeli parantezler arasındadır, ancak "mov" instruction'ı için bu köşeli parantezler arasında adresi bulunan bellek alanındaki değer anlamına gelirken "lea" instruction'ı doğrudan adres değerini kullanır. Bu imkan zaman zaman adres bilgisini kullanmaktan ziyade hesaplama amacıyla kullanılmaktadır. Örnek lea edi, [ebx+4*esi] - EBX+4*ESI hesaplamasının sonucu EDI register'ına atanır
  170. 170. X86 MİMARİSİNE GİRİŞ X86 ASSEMBLY GİRİŞ Instruction'lar [Aritmetik ve Mantık Instruction'ları] add Integer Addition Toplama instruction'ında en fazla bir operand bellek alanı olabilir. Syntax add <reg>,<reg> add <reg>,<mem> add <mem>,<reg> add <reg>,<imm> add <mem>,<imm>
  171. 171. X86 MİMARİSİNE GİRİŞ X86 ASSEMBLY GİRİŞ Instruction'lar [Aritmetik ve Mantık Instruction'ları] sub Integer Subtraction Toplama instruction'ında olduğu gibi çıkarma instruction'ında da en fazla bir operand bellek alanı olabilir. Syntax sub <reg>,<reg> sub <reg>,<mem> sub <mem>,<reg> sub <reg>,<imm> sub <mem>,<imm>
  172. 172. X86 MİMARİSİNE GİRİŞ X86 ASSEMBLY GİRİŞ Instruction'lar [Aritmetik ve Mantık Instruction'ları] inc, dec Increment, Decrement Artırma instruction'ı registry veya bellek alanını bir artırırken azaltma instruction'ı da tam tersini gerçekleştirir. Syntax inc <reg> inc <mem> dec <reg> dec <mem>
  173. 173. X86 MİMARİSİNE GİRİŞ X86 ASSEMBLY GİRİŞ Instruction'lar [Aritmetik ve Mantık Instruction'ları] imul Integer Multiplication 2 veya 3 operand'la çalışır. 2 operand'lı kullanımda iki değer çarpılıp sonuç birinci operand'da saklanır. 3 operand'lı kullanımda 2. ve 3. operand'lar çarpılıp sonuç birinci operand'da saklanır. Birinci operand (destination) her zaman registry olmak zorundadır, 3 operand'lı kullanımda 3. operand her zaman bir immediate (sabit) değer olmak zorundadır. Syntax imul <reg32>,<reg32> imul <reg32>,<mem> imul <reg32>,<reg32>,<imm> imul <reg32>,<mem>,<imm>
  174. 174. X86 MİMARİSİNE GİRİŞ X86 ASSEMBLY GİRİŞ Instruction'lar [Aritmetik ve Mantık Instruction'ları] idiv Integer Division EDX:EAX registerlarında bulunan 64 bit'lik integer değeri operand değerine böler. Bölüm EAX'e kalan ise EDX register'ına yazılır. Syntax idiv <reg32> idiv <mem>
  175. 175. X86 MİMARİSİNE GİRİŞ X86 ASSEMBLY GİRİŞ Instruction'lar [Aritmetik ve Mantık Instruction'ları] and, or, xor Bitwise logical and, or and exclusive or Operand'lar üzerinde belirtilen işlemleri gerçekleştirdikten sonra sonucu birinci operand'a yazarlar. Syntax and <reg>,<reg> and <reg>,<mem> and <mem>,<reg> and <reg>,<imm> and <mem>,<imm> or <reg>,<reg> or <reg>,<mem> or <mem>,<reg> or <reg>,<imm> or <mem>,<imm> xor <reg>,<reg> xor <reg>,<mem> xor <mem>,<reg> xor <reg>,<imm> xor <mem>,<imm>
  176. 176. X86 MİMARİSİNE GİRİŞ X86 ASSEMBLY GİRİŞ Instruction'lar [Aritmetik ve Mantık Instruction'ları] shl, shr Shift Left, Shift Right Birinci operand'ı sola veya sağa kaydırırken boşalan bit pozisyonlarına 0 yazılır. Kaç bit kaydırma yapılacağı 8 bit'lik bir immediate değerde veya CL register'ı ile verilir. Syntax shl <reg>,<imm8> shl <mem>,<imm8> shl <reg>,<cl> shl <mem>,<cl> shr <reg>,<imm8> shr <mem>,<imm8> shr <reg>,<cl> shr <mem>,<cl>
  177. 177. X86 MİMARİSİNE GİRİŞ X86 ASSEMBLY GİRİŞ Instruction'lar [Akış Kontrol Instruction'ları] jmp Jump Uygulama akışını koşulsuz olarak operand ile belirtilen adrese yönlendirir. Syntax jmp <label>
  178. 178. X86 MİMARİSİNE GİRİŞ X86 ASSEMBLY GİRİŞ Instruction'lar [Akış Kontrol Instruction'ları] jcondition (Conditional Jump) EFLAGS register'ında tutulan ve son aritmetik işlemin (bunlar add, sub gibi instruction'lar olabileceği gibi cmp ve test gibi çıkarma işleminin türevleri olan karşılaştırma instruction'ları da olabilir) sonuçlarına bağlı olarak uygulama akışını operand'da belirtilen adrese yönlendirir veya akışın bir sonraki instruction'dan devam etmesine izin verir. ZF - zero flag yapılan işlem veya karşılaştırmanın sonucu "0" ise "1" değerini alır. SF - sign flag yapılan işlemin sonucu negatif ise "1" değerini alır. Syntax je <label> (jump when equal) jne <label> (jump when not equal) jz <label> (jump when last result was zero) jg <label> (jump when greater than) jge <label> (jump when greater than or equal to) jl <label> (jump when less than) jle <label> (jump when less than or equal to)
  179. 179. X86 MİMARİSİNE GİRİŞ X86 ASSEMBLY GİRİŞ Instruction'lar [Akış Kontrol Instruction'ları] cmp Compare CMP instruction'ı SUB instruction'ına benzer ancak çıkartma işleminin sonucu birinci operand'a yazılmaz, sadece işlemin sonucu negatif ise Sign Flag "1" olarak işaretlenir. Syntax cmp <reg>,<reg> cmp <reg>,<mem> cmp <mem>,<reg> cmp <reg>,<imm>
  180. 180. X86 MİMARİSİNE GİRİŞ X86 ASSEMBLY GİRİŞ Instruction'lar [Akış Kontrol Instruction'ları] call, ret (Subroutine call and return) CALL instruction'ı operand ile verilen adrese uygulama akışını yönlendirirken bir yandan da kendisinden bir sonra gelen instruction'ın adresini STACK'e yazar, JMP instruction'ından temel farkı da budur. RET instruction'ı ise önce STACK'in o anda en üstünde bulunan adres değerini restore eder, yani uygulama akışını daha önce CALL instruction'ı ile saklanmış olan adrese yönlendirir. Dolayısıyla RET instruction'ından önce function epilog bölümü gerçekleştirilerek çalıştırılan fonksiyon için STACK'te ayrılmış olan tüm alanın SUB ESP, 0x??? instruction'ı veya benzeri bir işlem ile geri verilmiş olması gerekir. Syntax call <label> ret
  181. 181. X86 MİMARİSİNE GİRİŞ STACK ALANININ KULLANIMI Stack Alanının Çalışma Mekanizması • Stack yüksek bir adresten düşük adreslere doğru büyür. • Stack'e veri yazma (PUSH) ve bu veriyi bir register'a okuyarak silme (POP) işlemi LIFO (Last In First Out) yöntemiyle stack'e veri yazılması ve silinmesine yol açar. Bu stack'teki herhangi bir alan okunarak (MOV instruction'ı ile) bir register'a atanamaz ve tam tersi şekilde bir register veya immediate değeri stack'e yazılamaz anlamına gelmez, LIFO yöntemi ile sadece stack'in alan tüketimi ve iadesine ilişkin yöntemi ifade ediyoruz. • Stack sadece PUSH instruction'ı ile büyümez ve POP instruction'ı ile küçülmez. [SUB ESP, 0x20] benzeri instruction'larla ESP register değeri küçültülerek büyüyebilir ve [ADD ESP, 0x20] benzeri instruction'larla ESP değeri artırılarak küçülebilir. • Stack ASLR uygulanırsa her yüklemede farklı bir adresten başlatılır.
  182. 182. X86 MİMARİSİNE GİRİŞ STACK ALANININ KULLANIMI Stack'te Saklanan Veriler • Fonksiyon parametreleri: fastcall gibi calling convention'larda register'lar da fonksiyonlara parametre vermek için kullanılabilmekle birlikte diğer convention'larda ve bu iş için ayrılmış register'ların sayısının yetmediği durumlarda parametreler "CALL" instruction'ı ile fonksiyon çağrılmadan önce stack'e yazılır. Parametreler genellikle sağdan sola doğru stack'e PUSH edilir ("printf" gibi değişken sayıda parametre kabul eden fonksiyonlar için format string parametresinde olduğu gibi diğer parametreleri tanımlayan bir string başta olduğundan bu yaklaşım oldukça mantıklıdır).
  183. 183. X86 MİMARİSİNE GİRİŞ STACK ALANININ KULLANIMI Stack'te Saklanan Veriler [devamı] • Fonksiyon dönüş adresi: "CALL" instruction'ı çalıştığı anda bu instruction'dan bir sonraki instruction adresi fonksiyondan "RET" instruction'ı ile dönüldüğünde EIP register'ına atanmak üzere stack'te saklanır. Bellek taşma açıklıklarında uygulama akışını manipüle etmek için hedef alınan başlıca pointer değeri bu değerdir (diğerlerine SEH pointer değeri, lokal değişken olarak saklanan object veri yapılarının ilk alanında bulunan Virtual Table pointer değeri örnek verilebilir).
  184. 184. X86 MİMARİSİNE GİRİŞ STACK ALANININ KULLANIMI Stack'te Saklanan Veriler [devamı] • Bir önceki fonksiyon frame pointer'ı: Fonksiyon "prolog"larında daha önce de gördüğümüz gibi ilk yapılan işlem mevcut frame pointer değeri (EBP) yeni fonksiyonun frame pointer değeri ile ezileceği için "PUSH EBP" instruction'ı ile stack'e yazılır. Bu değer fonksiyon "epilog"unda "POP EBP" instruction'ı ile EBP pointer'ını eski frame pointer'ı haline getirmek için kullanılır. • Fonksiyon lokal değişkenleri: Fonksiyon "prolog"undan sonra genellikle fonksiyon lokal değişkenleri için ESP değeri düşürülerek yer ayrılır. Daha sonra lokal değişkenler için ayrılan bu alana lokal değişkenler yazılmaya ve bu alandan gerektiğinde okunmaya başlanır.
  185. 185. X86 MİMARİSİNE GİRİŞ CALLING CONVENTIONS CALLING CONVENTION'LARI NEDEN ANLAMALIYIZ? Calling convention'lar çağıranın mı çağrılanın mı parametreler için kullanılan alanı geri vereceği ve hangi register'ların korunmasının kimin sorumluluğunda olduğu ile ilgilidir. İyi Niyetli Cevap Bu sorunun iyi niyetli cevabı farklı compiler'ların ürettikleri kodların bir arada uyum içinde çalışabilmeleri için stack yönetimi ve register'ların korunması için aynı yaklaşımları izleme ihtiyacıdır.
  186. 186. X86 MİMARİSİNE GİRİŞ CALLING CONVENTIONS CALLING CONVENTION'LARI NEDEN ANLAMALIYIZ? [devamı] Kötü Niyetli Cevap Inline assembly ile bir kod yazarken veya virüs benzeri bir kodu mevcut bir uygulamaya yerleştirirken assembly içinden çağrılan Windows API'lerinin calling convention'ına uygun olarak hareket edilmezse Stack yapısının düzeni bozulacak, dolayısıyla da uygulama stack frame'i ile ilgili bu düzensizlikten dolayı hata alarak sonlanacaktır. Windows API'leri için "stdcall" convention'ına uygun bir biçimde stack'teki parametreleri yönetmezsek kodumuzun içinde çalıştığı proses hata alacaktır.
  187. 187. X86 MİMARİSİNE GİRİŞ CALLING CONVENTIONS stdcall Adının çağrıştırabileceğinin aksine aslında tüm derleyiciler için standart convention değildir ve Microsoft Win32 API tarafından kullanılır. İlk olarak bu convention'dan söz etmemizin sebebi de budur. • Stack'in temizlenmesinden çağırılan (callee) sorumludur. Yani çağıran (caller) parametreleri stack'e push eder, ancak temizleme işlemini gerçekleştirmez. • Parametreler stack'e sağdan sola doğru push edilir. • EAX, ECX ve EDX register'ları fonksiyon içinde kullanılır, dolayısıyla fonksiyondan geri dönüldüğünde farklılaşmış olma ihtimalleri yüksektir. Yani bunlar caller saved register'lardır. • Fonksiyon return değeri EAX register'ına yazılır.
  188. 188. X86 MİMARİSİNE GİRİŞ CALLING CONVENTIONS cdecl C declaration'ın kısaltması olan bu convention çoğu C derleyicileri tarafından kullanılır. • Stack'in temizlenmesinden çağıran (caller) sorumludur. Bu yaklaşım stdcall'unkinden farklıdır. • Parametreler stack'e sağdan sola doğru push edilir. • EAX, ECX ve EDX register'ları fonksiyon içinde kullanılır, dolayısıyla fonksiyondan geri dönüldüğünde farklılaşmış olma ihtimalleri yüksektir. Yani bunlar caller saved register'lardır. • Fonksiyon return değeri EAX register'ına yazılır.
  189. 189. X86 MİMARİSİNE GİRİŞ CALLING CONVENTIONS Microsoft fastcall Parametre aktarımında register kullanımına da bir örnek olması amacıyla fastcall convention'ından da bahsedelim. Bir fonksiyonun bu convention'a göre derlenmesi için __fastcall anahtar kelimesinin kullanılması gerekir. • Soldan sağa ilk iki parametre ECX ve EDX register'larında aktarılır. • Diğer parametreler (bu defa sağdan sola) stack'e yazılır. • Stack'in temizlenmesinden stdcall'da olduğu gibi çağırılan (callee) sorumludur.
  190. 190. ANALİZ STATİK ANALİZ [Disassembly] • X86 mimarisi ve assembly hakkında daha fazla bilgiye sahip olduğumuza göre biraz daha detaylı bir statik analiz gerçekleştirebiliriz. • İlk dinamik analiz çalışmalarımız sırasında uygulamanın bir HTTP isteğinde bulunduğunu gözlemlemiştik. Tabi bu gözlemi zararlı yazılıma herhangi bir internet erişimi vermeden gözlemlediğimiz için aslında indireceği [paket.bin] dosyasında ne olduğunu henüz bilmiyoruz. • Ancak ilginç olan konu uygulamanın Import ettiği API fonksiyonları içinde herhangi bir network veya HTTP API'sinin bulunmaması.
  191. 191. ANALİZ STATİK ANALİZ [Disassembly] Yeniden hatırlamak gerekirse Import edilen API'lerden ilgimizi çekenlerin listesini aşağıda bulabilirsiniz (aralarında bir network API'si yok!): AdjustTokenPrivileges CreateFileW CreateRemoteThread CreateToolhelp32Snapshot FindNextFileW FindResourceW GetProcAddress IsDebuggerPresent LoadResource OpenProcess Process32FirstW Process32NextW ReadFile RegOpenKeyExW RegSetValueExW ShellExecuteW VirtualAllocEx WriteFile WriteProcessMemory
  192. 192. ANALİZ STATİK ANALİZ [Disassembly] Bu API'lerden VirtualAllocEx farklı bir proses'in adres alanında yer ayırma işlevine sahip. Bu metodun çağrıldığı yeri biraz inceleyelim. AdjustTokenPrivileges CreateFileW CreateRemoteThread CreateToolhelp32Snapshot FindNextFileW FindResourceW GetProcAddress IsDebuggerPresent LoadResource OpenProcess Process32FirstW Process32NextW ReadFile RegOpenKeyExW RegSetValueExW ShellExecuteW VirtualAllocEx WriteFile WriteProcessMemory
  193. 193. ANALİZ STATİK ANALİZ [Disassembly] VirtualAllocEx metodunun kullanıldığı yerleri tespit etmek için IDA Pro'nun Imports view'ında bu metodu bularak çift tıklayalım.
  194. 194. ANALİZ STATİK ANALİZ [Disassembly] Import Address Table'da VirtualAllocEx fonksiyonuyla ilgili alana geçiyoruz. Burada VirtualAllocEx fonksiyon isminin üzerinde tıkladıktan sonra "x" tuşuna tıklayarak bu adrese referans verilen yerleri gözlemleyelim.
  195. 195. ANALİZ STATİK ANALİZ [Disassembly] VirtualAllocEx fonksiyonuna tek bir noktada referans verildiğini görüyoruz. Bu referans'a çift tıklayarak .text section'ındaki ilgili instruction'a geçelim.
  196. 196. ANALİZ STATİK ANALİZ [Disassembly] Bu alana ulaştığımızda biraz aşağıda WriteProcessMemory fonksiyonunun da çağrıldığını görebiliyoruz. VirtualAllocEx fonksiyonunun return değerinin "mov ebx, eax" instruction'ı ile "ebx" register'ına aktarıldığını görüyoruz.
  197. 197. ANALİZ STATİK ANALİZ [Disassembly] WriteProcessMemory fonksiyonunun çağrıldığı instruction'ın hemen üzerinde toplam 5 adet push instruction'ı var. Bu instruction'lar büyük ihtimallle bu fonksiyonun aldığı parametreler olmalı.
  198. 198. ANALİZ STATİK ANALİZ [Disassembly] MSDN'den WriteProcessMemory API'si ile ilgili bilgilere göz attığımızda fonksiyonun aldığı 5 parametreyi görebiliriz. Parametrelerden 3.sü diğer process'in address space'ine yazılacak içeriğin barındırıldığı alana işaret eden bir pointer. Bir zararlı yazılımı analiz ederken bizi merak ettirebilecek bir konu bu, o yüzden bu parametre'nin nereden geldiğini biraz inceleyelim.
  199. 199. ANALİZ STATİK ANALİZ [Disassembly] Disassembly ekranında WriteProcessMemory fonksiyonuna verilen 3. parametrenin dword_42FCC8 pointer'ı olarak belirtildiğini görüyoruz. Şimdi bu parametreye tıkladıktan sonra bu asrese referans veren noktaları inceleyelim.
  200. 200. ANALİZ STATİK ANALİZ [Disassembly] "x" tuşuna bastığımızda bu adrese 2 noktada referans verildiğini görüyoruz. 2. sırada bulunan referans şu anda gözlemlediğimiz alan, dolayısıyla diğerini incelememizde fayda var. 1. linke çift tıklayarak bu alanı inceleyelim.
  201. 201. ANALİZ STATİK ANALİZ [Disassembly] Bu alana geldiğimizde "eax" register değerinin bu pointer'a atandığını görüyoruz. "eax" register'ı da hemen 2 instruction yukarıdaki "call sub_402A70" instruction'ı ile belirlenmiş olmalı.
  202. 202. ANALİZ STATİK ANALİZ [Disassembly] Tekrar hatırlayalım halen diğer process'in address alanına yazılacak verinin nereden geldiğini inceliyoruz. Görünen o ki sub_402A70 adlı fonksiyon bu veriye işaret eden bir pointer döndürüyor. Şimdi çift tıklayarak bu fonksiyona göz atalım.
  203. 203. ANALİZ STATİK ANALİZ [Disassembly] Şimdi bu fonksiyonun içindeyiz.
  204. 204. ANALİZ STATİK ANALİZ [Disassembly] 1 2 3 Fonksiyonda biraz aşağıya indiğimizde deneyimli bir tersine mühendislik uzmanı tarafından normalde bir derleyici tarafından üretildiğine pek şahit olunmayacak olan bazı instruction'ları görüyoruz. Bu durum zararlı yazılımı geliştirmiş olan kişinin uygulamanın bu bölümünü bir inline assembly kodu ile geliştirmiş olma ihtimalini aklımıza getirmelidir. İlginç instruction'lardan birkaçını işaretledik. Şimdi sırasıyla bu instruction'lara anlam vermeye çalışalım.
  205. 205. ANALİZ STATİK ANALİZ [Disassembly] 1 Birinci instruction "pusha", 32 bit'lik bir uygulama için bizim ikinci satırı esas almamız lazım. Instruction'ın yaptığı işlem tüm genel amaçlı register'ları yukarıda görüldüğü sırada stack'e yazmak. Bir shellcode programcısı bu işlemi kodu gömdüğü alanda bu register'ları kullandıktan sonra "popa" instruction'ı ile kazasız belasız tekrar orijinal hallerine döndürmek amacıyla kullanabilir.
  206. 206. ANALİZ STATİK ANALİZ [Disassembly] 2 İkinci ilginç instruction ise "fs:0x30" adresindeki bir veriye işaret ediyor. "fs" register'ı Thread Environment Block [TEB] veri alanına işaret etmek için kullanılır. Bu veri yapısının 0x30 offset'inde ise Process Environment Block yer alır. Derlenmiş bir kodda böyle bir instruction'a rastlamak olası değildir.
  207. 207. ANALİZ THREAD ENVIRONMENT BLOCK (TEB) Adım-1: PEB’in adresinin bulunması 0:000> !teb TEB at 7efdd000 ExceptionList: 0026f814 StackBase: 00270000 StackLimit: 0026e000 SubSystemTib: 00000000 FiberData: 00001e00 ArbitraryUserPointer: 00000000 Self: 7efdd000 EnvironmentPointer: 00000000 ClientId: 00001920 . 00001928 RpcHandle: 00000000 Tls Storage: 7efdd02c PEB Address: 7efde000 LastErrorValue: 0 LastStatusValue: 0 Count Owned Locks: 0 HardErrorMode: 0 fs:[0] fs:[30] 0x30 kernel32.dll'in adresinin bulunması 2 WinDbg binary debugger'ı ile bazı Windows veri yapılarını kolayca inceleyebiliriz. Yukarıda böyle bir örnek verilmektedir.
  208. 208. ANALİZ STATİK ANALİZ [Disassembly] 3 Yukarıdaki instruction'lar başlangıçta biraz kafa karıştırıcı gelebilir, ancak iyi bir tersine mühendislik uzmanı bu tür instruction'lara hakim olabilmelidir. fs:30h alanında bulunan PEB referansı "esi" instruction'ına atıldıktan sonra, PEB'in 0xC offset'indeki değer tekrar "esi"a atanmakta, bu adresin de 0x1C offset'indeki değer de tekrar "esi"a atanmaktadır. Son adımda "esi" register'ının neyin adresini barındıracağını inceleyelim.
  209. 209. ANALİZ PROCESS ENVIRONMENT BLOCK (PEB) Adım-2: _PEB_LDR_DATA veri yapısının bulunması 0:000> dt nt!_peb 7efde000 ntdll!_PEB +0x000 InheritedAddressSpace : 0 '' +0x001 ReadImageFileExecOptions : 0 '' +0x002 BeingDebugged : 0x1 '' +0x003 BitField : 0x8 '' +0x003 ImageUsesLargePages : 0y0 +0x003 IsProtectedProcess : 0y0 +0x003 IsLegacyProcess : 0y0 +0x003 IsImageDynamicallyRelocated : 0y1 +0x003 SkipPatchingUser32Forwarders : 0y0 +0x003 SpareBits : 0y000 +0x004 Mutant : 0xffffffff Void +0x008 ImageBaseAddress : 0x01380000 Void +0x00c Ldr : 0x77240200 _PEB_LDR_DATA +0x010 ProcessParameters : 0x002f2178 _ .... fs:[30] 0x0c kernel32.dll'in adresinin bulunması 3 0xC offset'inde process'in address alanına yüklenmiş olan DLL'ler ile ilgili yükleme veri yapısına bir referans bulmaktayız. Shellcode geliştirme deneyimi olan bir kişi size bu adımların içinde "LoadLibrary" fonksiyonunu barındıran Kernel32.dll kütüphanesinin process'in adres alanındaki tabanını bulmak için gerekli ilk adımlardan birisi olduğunu söyleyecektir. LoadLibrary fonksiyonu uygulama içinde dinamik olarak farklı DLL'lerin yüklenebilmesi için kullanılır.
  210. 210. ANALİZ kernel32.dll'in adresinin bulunması _PEB_LDR_DATA Adım-3: Modül zincir listelerinin bulunması 0:000> dt _PEB_LDR_DATA 0x77240200 ntdll!_PEB_LDR_DATA +0x000 Length : 0x30 +0x004 Initialized : 0x1 '' +0x008 SsHandle : (null) +0x00c InLoadOrderModuleList : _LIST_ENTRY [ 0x2f4cf8 - 0x2f5990 ] +0x014 InMemoryOrderModuleList : _LIST_ENTRY [ 0x2f4d00 - 0x2f5998 ] +0x01c InInitializationOrderModuleList : _LIST_ENTRY [ 0x2f4d98 - 0x2f59a0 ] +0x024 EntryInProgress : (null) +0x028 ShutdownInProgress : 0 '' +0x02c ShutdownThreadId : (null) 0x1c 3 Bu adresin 0x1C offset'inde ise yüklenme sırasına göre modül (yani DLL) bilgileri veri yapılarının başlangıç adresi tutulur.
  211. 211. ANALİZ kernel32.dll'in adresinin bulunması MODÜL ZİNCİR LİSTESİ Adım-4: Başlatılma sırasına göre modül zincir listesinin izlenmesi 0:000> dt _LIST_ENTRY 0x7724021c ntdll!_LIST_ENTRY [ 0x2f4d98 - 0x2f59a0 ] +0x000 Flink : 0x002f4d98 _LIST_ENTRY [ 0x2f5230 - 0x7724021c ] +0x004 Blink : 0x002f59a0 _LIST_ENTRY [ 0x7724021c - 0x2f5118 ] 0:000> dt _LIST_ENTRY 0x002f4d98 ntdll!_LIST_ENTRY [ 0x2f5230 - 0x7724021c ] +0x000 Flink : 0x002f5230 _LIST_ENTRY [ 0x2f5118 - 0x2f4d98 ] +0x004 Blink : 0x7724021c _LIST_ENTRY [ 0x2f4d98 - 0x2f59a0 ] 0:000> dt _LIST_ENTRY 0x002f5230 ntdll!_LIST_ENTRY [ 0x2f5118 - 0x2f4d98 ] +0x000 Flink : 0x002f5118 _LIST_ENTRY [ 0x2f59a0 - 0x2f5230 ] +0x004 Blink : 0x002f4d98 _LIST_ENTRY [ 0x2f5230 - 0x7724021c ] 1 2 3 Bu veri yapısı bir zincir listedir [linked list] ve zincirin her bir bileşeni bir sonra gelene işaret eden adresi ilk 4 byte'ında barındırır.
  212. 212. ANALİZ kernel32.dll'in adresinin bulunması MODÜL ADI Adım-5: Modül adının bulunması 0:000> dd 0x002f4d98 + 20 002f4db8 77185bc4 00004004 0000ffff 002f59cc 002f4dc8 772448e0 521ea8e7 00000000 00000000 0:000> db 77185bc4 77185bc4 6e 00 74 00 64 00 6c 00-6c 00 2e 00 64 00 6c 00 n.t.d.l.l...d.l. 77185bd4 6c 00 00 00 14 00 16 00-e0 5b 18 77 5c 00 53 00 l........[.w.S. 77185be4 59 00 53 00 54 00 45 00-4d 00 33 00 32 00 5c 00 Y.S.T.E.M.3.2.. 77185bf4 00 00 90 90 90 90 90 8b-ff 55 8b ec 51 51 83 65 .........U..QQ.e 77185c04 fc 00 53 56 8b 35 0c 02-24 77 57 81 fe 0c 02 24 ..SV.5..$wW....$ 77185c14 77 74 31 8d 45 f8 50 6a-09 8b fe 8b 36 6a 01 ff wt1.E.Pj....6j.. Ayrıca bu adresten [decimal] 20 byte sonraki 4 byte'lık alanda da bu veri yapısının ait olduğu DLL'in adının tutulduğu alanın pointer'ını barındıran veri yer alır. Bu alanlar sırasıyla incelenerek Kernel32.dll'in kaydına ulaşıp ulaşmadığımız tespit edilebilir. Zincir halkalarında her bir modül'ün adresi de bulunur. Sonraki adımlar bu modül başlangıç adresinden başlayarak modülün (yani DLL'in) Export tablosu içinde gezinmeye başlamak ve LoadLibrary fonksiyon adresini bulmaya çalışarak devam edecektir. Biz örneği daha da karmaşıklaştırmamak için bu adımı burada sonlandırıyoruz. Bu aşamada zararlı yazılım yazarının bazı DLL'leri yüklediğinin kolay görünür olmaması için çaba gösterdiğini söyleyebiliriz.
  213. 213. ANALİZ STATİK ANALİZ [Disassembly] Bu fonksiyonda daha aşağılara ilerlediğimizde bazı HEX değerlerin stack'e push edildiğini görüyoruz. Bunları "R" karakteri ile ASCII karakterlere dönüştürebiliriz. Zararlı yazılım yazarı strings incelemesinden [wininet.dll] DLL adının stack'e yazıldığı ortaya çıkmasın diye işlevsiz opcode'ları da assembly koduna eklemiş.
  214. 214. ANALİZ STATİK ANALİZ [Disassembly] [wininet.dll] kütüphanesinin barındırdığı fonksiyonlara MSDN'den göz atalım.
  215. 215. ANALİZ STATİK ANALİZ [Disassembly] HTTP erişimi ile ilgili olanların bir kısmı burada görüldüğü gibidir.
  216. 216. ANALİZ STATİK ANALİZ [Disassembly] InternetOpenUrl fonksiyonu HTTP protokolü ile bir web kaynağına erişmek için kullanılabilir.
  217. 217. ANALİZ STATİK ANALİZ [Disassembly] İncelediğimiz kodun içinde pek çok defa çağrıldığını gördüğümüz bir fonksiyon da dikkatimizi çekebilir. Yeterli zaman olması halinde bu fonksiyona verilen iki parametrenin belli bir DLL'in başlangıç adresi ve bir fonksiyon adının basit bir algoritma ile hash'lenmiş değeri olduğunu tespit edebilirdik. Bu sayede çağrılan fonksiyonların neler olduğunu statik analiz ile tespit etmemiz çok zorlaştırılmıştır. Ancak dinamik analizde hangi fonksiyonların çağrıldığı açıkça görülebilir.
  218. 218. ANALİZ STATİK ANALİZ [Disassembly] Fonksiyon kodları içinde biraz daha aşağıya indiğimizde stack'e yazılan bir dizi HEX veri daha görebiliriz. Ancak bu verileri "R" komutuyla ASCII karşılıklarına dönüştüremiyoruz, çünkü dikkat ederseniz arada NULL [00] karakterleri bulunması bu karakterlerin Unicode karakterler olabileceğine işaret etmektedir.
  219. 219. ANALİZ STATİK ANALİZ [Disassembly] Bu karakterleri kodun içinden daha rahat çekebilmek için IDA'nın 8 opcode byte'ına kadar görüntüleme ayarını Options penceresinden yapalım.
  220. 220. ANALİZ STATİK ANALİZ [Disassembly] Opcode'ları da içeren satırları tarayarak clipboard'a kopyalayalım (sağ klikle)
  221. 221. ANALİZ STATİK ANALİZ [Disassembly] Kopyaladığımız veriyi Notepad++ ekranına yapıştırdıktan sonra sadece push edilen 2. ve 5. byte'lar arasını ALT tuşuna basarken mouse ile tarayarak kopyalayalım.
  222. 222. ANALİZ STATİK ANALİZ [Disassembly] Kopyaladığımız veriyi bir başka Notepad++ ekranına yapıştırdıktan sonra boşlukları ve satır sonlarını kaldıralım.
  223. 223. ANALİZ STATİK ANALİZ [Disassembly] Kalan son veriyi HxD veya farklı bir Hexadecimal bir editöre kopyaladığımızda sağ tarafta Unicode karakter karşılıklarını görebiliriz [Microsoft Internet Explore]
  224. 224. ANALİZ STATİK ANALİZ [Disassembly] Aynı işlemi daha aşağıdaki bölüm için de tekrarlayalım.
  225. 225. ANALİZ STATİK ANALİZ [Disassembly] Notepad++'da sadece push edilen verilerin kalmasını sağlayalım.
  226. 226. ANALİZ STATİK ANALİZ [Disassembly] Bu alanda da aşağıdaki verinin stack'e yazıldığını ortaya çıkarmış olduk: [http://www.btr-mlwsunucu.com/paket.bin]
  227. 227. ANALİZ DİNAMİK ANALİZ [Debugging] Bu noktaya kadar analizin tamamını statik analiz olarak yapmanın kulağa geldiği kadar hoş olmadığını farketmiş olmalıyız. Zararlı yazılımın farklı bir proses'in address alanına yazdığı verinin ne olduğunu anlamanın en pratik yolu dinamik analizden faydalanmak olacaktır. Bunun için zararlı yazılımımızın çalışacağı Windows bilgisayarla aynı karantina subnet'inde bulunmakta olan Kali bilgisayarımız üzerindeki Honeypot servislerini [inetsim] başlatalım.
  228. 228. ANALİZ DİNAMİK ANALİZ [Debugging] Decompress edilmiş olan uygulamamızın ASLR desteğini daha önceden kaldırmıştık (çünkü başka türlü çalışmıyordu). Bu imkan sayesinde statik analizdeki VA adreslerimizin debug ederken de aynı kalacağından emin olabiliriz. Şimdi tam farklı process'in address alanına yazılacak olan verinin Stack'e yazıldığı instruction'ın adresi olan [0x401E79] adresine bir breakpoint koyalım.
  229. 229. ANALİZ DİNAMİK ANALİZ [Debugging] Play düğmesine gerektiği kadar basarak breakpoint satırına kadar ilerleyelim.
  230. 230. ANALİZ DİNAMİK ANALİZ [Debugging] F7 tuşu veya Step Into düğmesine basarak Stack'e farklı process'in address alanına yazılacak olan verinin adresini yazalım. Bu işlem gerçekleştikten hemen sonra da yazılan adresin işaret ettiği alanı daha iyi gözlemleyebilmek için Stack'te bu adrese sağ tıklayarak [Follow in Dump] seçeneğini seçelim.
  231. 231. ANALİZ DİNAMİK ANALİZ [Debugging] Sol altta bulunan Memory Dump alanındaki verileri daha iyi görebilmek için bu alana sağ klikleyerek [Hex/ASCII (16 bytes)] seçeneğini seçelim.
  232. 232. ANALİZ DİNAMİK ANALİZ [Debugging] Anlaşılan o ki söz konusu veri [www.btr- mlwsunucu.com/paket.bin] HTTP isteğine gelen yanıttan oluşuyor. Inetsim servisi sayesinde bu yanıt gerçek paket.bin dosyası değil de sahte bir HTML yanıtından oluşuyor.
  233. 233. ANALİZ PAYLOAD ANALİZİ Bu noktada [http://www.btr-mlwsunucu.com/paket.bin] isteğine dönen gerçek yanıtı inceleyelim.
  234. 234. ANALİZ PAYLOAD ANALİZİ paket.bin dosyasını VirusTotal'e gönderdiğimizde Shellcode olarak tanımlanıyor.
  235. 235. ANALİZ PAYLOAD ANALİZİ IDA Pro'da bu dosyayı incelediğimizde dosya normal bir PE dosyası olmadığından paket.bin dosyasının içeriğini veri olarak algılanacaktır.
  236. 236. ANALİZ PAYLOAD ANALİZİ IDA Pro'nun bu verileri kod olarak değerlendirmesi için sağ klikleyerek [Code] seçeneğini seçebiliriz.
  237. 237. ANALİZ PAYLOAD ANALİZİ Kod bölümü hemen normal bir uygulamadaki gibi grafik halinde görüntülenmeyebilir, uygulama grafiğini görebilmek için [Space] tuşuna basınız.
  238. 238. ANALİZ PAYLOAD ANALİZİ Grafik gösterimde sağdaki koyu mavi çizgi bir döngü olduğuna işaret ediyor. Bu shellcode'un encoded bir shellcode olması durumunda dinamik analiz daha doğru bir tercih olacaktır. Zararlı uygulamanın internete erişmesi yerine paket.bin dosyasını inetsim tarafından sağlayarak dinamik analiz gerçekleştirilebilir.
  239. 239. ANALİZ PAYLOAD ANALİZİ • Gerçekte bu payload'un tam olarak ne yaptığını anlamak için ciddi bir süreyi tersine mühendislik için harcamamaız gerekebilir. • Bu payload bir meterpreter reverse_tcp payload'u ve karşı tarafta bir handler tarafından karşılanması gerekir. • Gerçek payload'un ne yaptığının dinamik analizle görülmesi için kurum ağından bağımsız bir ADSL hattı ve yine bir sanal makine kullanılarak inceleme yapılabilir, elbette çok dikkatli olmak kaydıyla.
  240. 240. ANTI-DISASSEMBLY ANTI-DISASSEMBLY TEKNİKLERİ • Uygulamamızda bir anti-disassembly örneği barındırmadık, çünkü yeterli zaman ayrılmaması durumunda ve henüz konuya yeni kişiler için bu durumların tespiti ve çözülmesi zor olabilir. • Ancak deneyimli tersine mühendislik uzmanları için bu tekniklerin tespiti ve ortadan kaldırılmasının zannedilebileceğinden daha kolay olacağını söyleyebiliriz.
  241. 241. ANTI-DISASSEMBLY ANTI-DISASSEMBLY TEKNİKLERİ • Disassembler'ları yanlış yönlendirmek ve disassembly kodunun uygulamanın gerçek davranışından farklılaştırmak için pek çok teknik kullanılabilir, örneğin: • [EB FF C0 48] opcode'ları "EB FF - jmp 1", geçerli olmayan bir "C0" opcode'u ve "48 - dec eax" olarak disassemble edilecektir. • Gerçekte ise "jmp 1" instruction'ı Instruction Pointer'ı "EB FF" opcode'larının başından itibaren 1 byte ileriye atlatacak ve "FF C0 - inc eax" olarak, "48 - dec eax" olarak çalıştırılacaktır. • Çözüm bu işe yaramayan ve karmaşıklığa neden olan opcode'ları NOP ile yamalayarak ortadan kaldırmaktır.

×