İçeriğe atla
0 XP 0
12 dkderinleşmeyle 13 dk50 XP7 etkinlik

Kod karartma ve şifreli dizeler

Bu derste
  • Karartmanın neden analizi yavaşlattığını, XOR, Base64, onaltılık ve ROT13 ile gizlenmiş dizeleri nasıl çözeceğini öğrenirsin.
  • Dize şifreleme, API karması ve ölü kod ekleme en sık görülen üç yöntemdir.
  • Bu derste basit kodlamaları statik olarak çözer, floss aracını ve dinamik yakalamayı kullanırsın.

Puan bütün etkinlikleri cevaplayınca hesaba yazılır. Bu dersi tamamlayınca +50 XP alacaksın. Giriş yapmadan ilerlersen puan yalnız bu tarayıcıda durur.

Karartmanın amacı analizi yavaşlatmaktır, imkânsız kılmak değil. Kod sonunda çalışmak zorundadır. Çalıştığı yerde de çözülmüş haliyle bellekte durur. Bu gerçek, her karartmanın açık kapısıdır.

Altay Kargo'nun örneğinde dize taraması hiçbir adres ya da komut bulmuyorsa, bu dosyanın temiz olduğunu değil, dizelerin gizlendiğini gösterir. Karartma ile şifrelemeyi de karıştırma: şifrelemede anahtar gizlidir ve güvenlik ona dayanır, karartmada ise her şey dosyanın içindedir ve yalnız zor okunur. Yeterli zaman verilen her karartma çözülür.

Dize şifreleme ve kodlama

En yaygın yöntem dize şifrelemedir. Adresler, anahtar yolları ve komutlar düz metin olarak durmaz. Kullanılacağı anda çözülür. Böylece basit bir dize taraması hiçbir şey bulmaz.

Çözme çoğu zaman basittir: tek baytlık XOR, Base64 kodlaması, onaltılık gömme ya da sabit kaydırmalı harf değişimi. Hiçbiri gerçek şifreleme değildir; hepsi imza aramalarını atlatmayı hedefler. Bu yöntem MITRE çerçevesinde karartma başlığı altında geçer ve çözme işine ayrı bir ad verilir.

Onaltılık gömme en kolay çözülenidir. İki onaltılık karakter bir baytı, yani bir harfi karşılar. Örneğin 70 değeri p harfinin ASCII kodudur.

Karakterleri ikişer ikişer ayırıp bir tabloya bakarsan düz metni elde edersin. Bir dosyada düz metin olarak powershell araması yapan basit bir tarama bu diziyi asla bulamaz; onaltılık karşılığı bambaşka görünür. Kodlamayı tanımak da bir beceridir: yalnız rakam ve a ile f arası harf taşıyan çift uzunluklu diziler onaltılıktır.

Base64'ü tanımak bir örnekle oturur. Dört Base64 karakteri üç bayta çözülür. Diziyi açmak için her karakteri altı bitlik değerine çevirir, bitleri birleştirir ve sekizerli baytlara bölersin.

Çoğu araç bunu tek komutla yapar. Sonu tek eşittir ile biten dizi bir dolgu baytı, çift eşittir ile biten iki dolgu baytı taşır. Bu kuyruk, uzunluğu dörde tamamlamak içindir ve Base64'ü ilk bakışta ele verir.

Hangi kodlamayla karşılaştığını anlamak, çözüme giden ilk adımdır. Dizeye bakarsın: uzunluğu çift ve yalnız onaltılık simgeler mi var, onaltılıktır. Sonunda eşittir ve karışık harf kümesi mi var, Base64'tür.

Harfler kaymış ama sözcük yapısı duruyor mu, bir kaydırma şifresidir. Baytlar rastgele ama tekrar eden bir desen mi taşıyor, tek baytlık XOR olabilir. Bu hızlı tanıma, hangi aracı çalıştıracağını saniyeler içinde söyler ve deneme yanılmayı azaltır.

Etkinlik 1 / 7

Kodda bu dize onaltılık gömülü duruyor. Çöz.

Araçları sırayla dene. Yanlış araç bozuk çıktı verir.

706f7765727368656c6c

Sabit kaydırmalı harf değişimi de sık görülür. ROT13 her harfi alfabede on üç ileri kaydırır.

Latin yirmi altı harfini kullanır ve kendi tersidir: aynı işlem hem karartır hem çözer. Base64 ise farklıdır. Sonu eşittir işaretiyle biten ve belirli bir karakter kümesini kullanan diziler Base64'tür. Base64 bir şifreleme değil, veriyi yazdırılabilir karakterlere taşıyan bir kodlamadır; görür görmez çözersin.

Etkinlik 2 / 7

Yapılandırmadan çıkan bu satır 13 kaydırmalı. Çöz.

Araçları sırayla dene. Yanlış araç bozuk çıktı verir.

pzq.rkr /p jubnzv

XOR ve çok baytlı anahtarlar

Tek baytlık XOR en sık görülen karartmadır. Veri sabit bir baytla XOR'lanır. Aynı bayt ikinci kez uygulanınca özgün veri geri gelir, çünkü XOR tersine çevrilebilir.

Anahtar çoğu zaman kodun içinde, döngünün hemen yanındadır. Aşağıdaki döngü bir veriyi 0x5a baytıyla XOR'lar ve sonucu bir arabelleğe yazar. Anahtarı görmek için döngüye bakman yeter; sabiti alıp aynı işlemi uygularsan dizeyi okursun.

for (i = 0; i < len; i++)
    buf[i] = veri[i] ^ 0x5a;

; anahtar kodun icinde durur, ayni islem cozer de
Tek baytlık XOR: hem şifreler hem çözer, anahtar hemen yanındadır.

Çok baytlık anahtarlar da kullanılır. Anahtar kısa bir dizedir ve veriye döngüsel olarak uygulanır.

İlk bayt anahtarın ilk baytıyla, ikinci bayt ikinci baytıyla XOR'lanır ve anahtar bitince başa döner. Bu yöntemi de kırmak zor değildir. Bilinen bir düz metin parçası varsa anahtar doğrudan hesaplanır: bir adresin başındaki http dizesi ya da bir komutun bilinen başlangıcı, karşılık gelen şifreli baytlarla XOR'lanınca anahtarı verir.

Bilinen düz metin yöntemi bir örnekle netleşir. Diyelim şifreli veri bir adresle başlıyor ve her adresin başında http dizesi durur. Şifreli ilk dört baytı, bilinen h, t, t, p harfleriyle XOR'larsın.

Çıkan dört bayt anahtarın ilk dört baytıdır. Anahtar bu kadarsa işin biter; daha uzunsa aynı yöntemi bilinen başka bir parçayla sürdürürsün. Anahtarı bulduğunda bütün veriyi tek geçişte çözersin.

Dizeleri yığında kurmak da bir yöntemdir. Metin tek tek karakterler halinde belleğe yazılır ve dosyada hiçbir yerde bütün dize durmaz.

Statik tarama tek tek karakterleri bağlayamaz. Bu durumda çözüm dinamik analizdir: dize bellekte bir anda tamamlanır ve orada okunur. Statik ile dinamik arasındaki seçim, karartmanın türüne göre değişir.

Etkinlik 3 / 7

Bu döngü ne yapar?

Önce kodu oku, sonra çıktıyı seç.

for (i = 0; i < len; i++)
    buf[i] = veri[i] ^ 0x5a;

floss ve dinamik çözüm

Dize çözmeyi elle yapmak yavaştır. floss aracı bu işi otomatikleştirir. Dört tür dize çıkarır: sıradan statik dizeler, yığında kurulan dizeler, yığında çözülen sıkı dizeler ve bir yordamın içinde çözülen dizeler.

Araç çözme yordamlarını taklit ederek karartılmış dizeleri açar. Çıktı doğrulanmadan kullanılmaz; araç bazen anlamsız diziler de üretir. En az uzunluğu ayarlayabilirsin ve yalnız belirli türleri isteyebilirsin.

Yığın dizeleri ayrı bir başlıktır ve floss'un güçlü olduğu yer burasıdır. Bu dizeler dosyada bütün olarak durmaz; kod çalışırken karakter karakter yığına yazılır. Sıradan bir dize taraması onları hiç göremez.

floss kısa kod parçalarını taklit ederek bu karakterleri bir araya getirir ve dizeyi yeniden kurar. Bir yordamın içinde çözülen dizeler için de aynı taklit yöntemini kullanır. Çıktıyı türe göre süzmek, aradığın izi hızlı bulmanı getirir.

Etkinlik 4 / 7

floss ile ornek.exe içindeki karartılmış dizeleri çıkar.

ogrenci@lab

API karması ve akış karartması

İkinci yöntem API karmasıdır. Çağrı adları dizge olarak tutulmaz. Her adın sayısal bir özeti saklanır.

Çalışma anında kütüphane tablosu gezilir ve özeti tutan yordam bulunur. Sonuç şudur: ne içe aktarma tablosunda ne dizelerde ad görünür. Örnek yordam adreslerini çalışma anında kendi eliyle çözer; bu, bağlama işini elle yeniden yapmak demektir.

Karşı hamle, karma algoritmasını tersine çevirip bilinen ad listesiyle bir eşleme tablosu kurmaktır. Bu tablo bir kez yazılır ve tüm ailede işler.

Çalışma anında ad çözmenin bir de hazır yolu vardır. Örnek, kütüphaneyi yükleyen ve yordam adresini ada göre bulan iki sistem çağrısını kullanır.

Ama ad yerine özet tutulduğunda bu çağrılara verilecek düz ad da yoktur. Bu yüzden örnek kendi arama döngüsünü yazar: yüklü kütüphanenin dışa aktarım tablosunu gezer, her adı aynı karmadan geçirir ve aradığı özete ulaşınca adresi alır. Böylece çağrı adları hiçbir yerde açık görünmez.

Üçüncü yöntem akış karartmasıdır. Ölü kod eklenir, atlamalar çoğaltılır ve bir yordam yüzlerce küçük bloğa bölünür. Akış grafiği okunmaz hale gelir ama davranış aynı kalır. Bu durumda statik okuma zorlaşır ve dinamik analiz öne çıkar.

Ölü kod çalışma anında zaten atlanır. Hata ayıklayıcıda izlenen gerçek yol, yüzlerce bloğun yalnız birkaçından geçer. Karartma araçları da tanınabilir; ticari koruyucuların ürettiği kod kendine özgü desenler taşır ve hangi çözücünün işe yarayacağını baştan söyler.

Etkinlik 5 / 7

API karma (API hashing) tekniği analizi nasıl zorlaştırır?

Çözülmüş veriyi bellekte yakala

Karartmayı aşmanın genel kuralı şudur: veriyi çözüldüğü yerde yakala. Anahtarı aramak yerine sonucu okumak, çoğu analizde en kısa yoldur.

Bu kural her karartma yöntemi için geçerlidir; şifreleme algoritması ne kadar karmaşık olursa olsun, sonuç bellekte açık biçimde durmak zorundadır. Bu yüzden dinamik analiz, karartmaya karşı en güvenilir yöntem sayılır. Statik okuma her yeni yöntemde yeniden zorlaşır, ama çalışma anındaki bellek her zaman çözülmüş veriyi taşır.

Karartmanın kendisi de bir göstergedir. Yoğun karartma taşıyan bir dosya, sıradan iş yazılımından ayrılır. Tek başına hüküm vermez ama öncelik sırasını değiştirir.

Triyajda bunu entropi ile ölçersin: sıkıştırılmış ya da şifreli bölümler yüksek entropi verir ve okunur dize sayısı düşer. Yüksek entropi ile az dizenin birlikte görünmesi, dosyayı analiz kuyruğunun başına taşır.

Karartmaya karşı savunma iki yöne ayrılır. Statik tarafta entropi ve dize sayısı triyajı hızlandırır. Dinamik tarafta ise örnek yalıtılmış ortamda çalıştırılır ve çözülen veri bellekten alınır.

İki yöntem birbirini tamamlar: biri hangi dosyaya bakacağını, öbürü o dosyanın gerçekte ne yaptığını söyler. İyi bir triyaj, derin analizin zamanını doğru dosyaya ayırır.

Etkinlik 6 / 7

Doğru mu, yanlış mı?

Tek baytlık XOR ile karartılmış bir dizeyi, anahtar kodun içinde durduğu için örneği çalıştırmadan çözebilirsin.

Triyaj ölçütlerini bir arada okumak kararı hızlandırır. Tek bir yüksek entropi değeri her zaman karartma demek değildir; sıkıştırılmış ortam dosyaları da yüksek çıkar. Ölçütleri birleştirirsin: yüksek entropi, az okunur dize ve tuhaf bölüm adları aynı anda görünürse dosya kuyruğun başına geçer.

Etkinlik 7 / 7

Yoğun karartılmış bir dosyayı triyajda ne ele verir?

Derinleş:Base64 ile onaltılığı ayırmak

İki kodlama ilk bakışta benzer görünür ama ayrımı kolaydır. Onaltılık yalnız on altı simge kullanır: sıfırdan dokuza rakamlar ve a'dan f'ye harfler. Uzunluğu her zaman çifttir, çünkü iki simge bir bayttır. Base64 ise altmış dört simge kullanır: büyük ve küçük harfler, rakamlar, artı ve bölü işaretleri.

Üç baytı dört karaktere taşır, bu yüzden uzunluğu dörde bölünür ve sonu çoğu zaman bir ya da iki eşittir işaretiyle doldurulur. Bir dizede büyük harf, küçük harf ve artı işaretini birlikte görürsen Base64'tür.

Yalnız rakam ve a-f harfi görürsen onaltılıktır. Bir uyarı da şu: bir Base64 dizesini çözdüğünde yine okunmaz baytlar çıkabilir, çünkü örnek veriyi önce XOR'layıp sonra Base64 ile sarmış olabilir. Bu ayrım, hangi çözücüyü hangi sırayla çalıştıracağını bir bakışta söyler.

Derinleş:API karmasını tersine çevirmek

API karması adları gizler ama algoritma kodun içindedir. Döngüyü okuyup hangi karma işleminin kullanıldığını çıkarırsın; sık görülen biçimlerden biri her karakterde değeri on üç bit döndürüp toplamaktır. Örnek, karmayı tutar ama adresi bulmak için yine kütüphaneyi yükleyen ve dışa aktarım tablosunu gezen hazır çağrılara döner; yani karma yalnız adı gizler, mekanizmayı değil. Algoritmayı anladıktan sonra bilinen kütüphanelerin bütün dışa aktarım adlarını alıp aynı karmadan geçirirsin.

Ortaya özet ile ad arasında bir eşleme tablosu çıkar. Örnekteki her özeti bu tablodan ararsın ve gerçek çağrı adını bulursun. Tabloyu bir kez kurarsın; aynı aileyi kullanan sonraki bütün örneklerde yeniden işe yarar. Bu yüzden karma çözmek, tek örneğin değil ailenin maskesini kaldırır.

Bu derste bir hata mı gördün? Bildir