┌───────────────────────┐
                                                                           ▄▄▄▄▄ ▄▄▄▄▄ ▄▄▄▄▄       │
                                                                           │ █   █ █ █ █   █       │
                                                                           │ █   █ █ █ █▀▀▀▀       │
                                                                           │ █   █   █ █     ▄     │
                                                                           │                 ▄▄▄▄▄ │
                                                                           │                 █   █ │
                                                                           │                 █   █ │
                                                                           │                 █▄▄▄█ │
                                                                           │                 ▄   ▄ │
                                                                           │                 █   █ │
                                                                           │                 █   █ │
                                                                           │                 █▄▄▄█ │
                                                                           │                 ▄▄▄▄▄ │
                                                                           │                   █   │
PT_NOTE Disinfector                                                        │                   █   │
~ manizzle                                                                 └───────────────────█ ──┘

[ Çeviri @batcain tarafından yapılmıştır ]

Selam herkese. Başlangıç olarak şunu belirtmek isterim, ben bir "AVer"
(AV ile uğraşan kişiler için kullanılıyor, "VXer" gibi düşünebilirsiniz.) değilim. 
Anti-virüsler saçmalık, hala çözülememiş bir sürü hataları var ve bu hatalardan
dolayı sömürülmeye açıklar. AVler tarafından sıkça kullanılan lief ve capstone
bileşenlerini fuzzlamaktan çekinmeyin. Eminim birçok çözülmemiş sıkıntıları
çıkacaktır. Şimdi, zararlının etkilerini nasıl tersine çevireceğimize gelecek olursak...

PT_NOTE injection tekniği epey temiz, derli toplu bir teknik; hazırlanmış
hafıza alanının zararsız bir içerikle doldurulmasını sağlıyor. Ancak bilindiği üzere,
neredeyse her infection tekniğinin bir de infection engelleyicisi karşılığı vardır 
ve bu durum yaşamın doğasının bir tezahürüdür. 

Bir infection tekniğinin ne kadar iyi olduğunu ölçmek için disinfection 
işleminin kolaylığını göz önünde bulunduruyorum. Çünkü, kullandığınız 
disinfection işleminde ne kadar sabit değer olursa o kadar kolay alt edilecektir. 
Kedi fare oyunu devam ettiği sürece yapılması gereken, her seferinde daha sinsi 
bir çözümle ortaya çıkmaktır. Şayet bu kedi fare oyununu kendinizle oynarsanız 
yazacağınız zararlı, dehşet verici ve harika bir şeye evrilebilir. 

Bu enfekte olan dosyayı geri çevirme tekniği için -birçok zararlının da yaptığı gibi-
büyük çalıştırılabilir dosyaları yüklerken programın hafıza alanında normalde 
çalışan kodlarla kesişmediğinden ve üzerine yazılmadığından emin olmak için 
PT_NOTE segmentini olabildiğince uzak bir hafıza alanına konumlandırmak 
gerekiyor, sonuçta infection esnasında ayak altında dolanmak istemeyiz.

PT_LOAD segmentlerini toparlayıp çalıştırılabilir olacak şekilde kullanabilmek için
gruplandırılmış çalıştırılabilir segmentlerin merkezini belirlemede Kmeans algoritmasından
ve Kmeans ortalamasından yararlanacağız. Genellikle infection operasyonlarında bir tane PT_NOTE
segmenti zararlı kod çalıştırma için kullanılır ancak belki de daha sonra sblip 
komutunun size bildireceği üzere enfekte segment sayısı iki olabilir :)

    if (math.log(cluster_1.inertia_)/math.log(cluster_2.inertia_)) < INERTIA_RATIO:

Hangi segentlerin normalden biraz daha uzak bir çalıştırılabilir dosya 
alanına konumlandırıldığını tespit ettikten sonra (her ne kadar PT_NOTE
segmentini geçerli bir PT_LOADS adresine konumlandırıp bütün imajın 
yeniden konumlandırılmış adreslerini güncellesek de, yani kim bunu yapar ki? :)) 
enfekte olmuş alanın kodunun detaylı incelemesini gerçekleştirebiliriz.

Normalde bu tarz zararlılar biraz solucan gibi takılır, birkaç dosyayı 
daha enfekte eder; ancak eninde sonunda asıl programın çalışma düzenine
devam etmesi -bilirsiniz şüphe çekmemek için- gerekir. Yani asıl programın
başlangıç noktasına atlamak için kullanılacak olan jmp komutu enfekte edilen
zararlı kodun sonlarında olmalıdır. Dolayısıyla biz bu atlama komutunu aramalıyız. 

Bazen bu atlama işlemi direkt gerçekleşir, bazen ise atlanacak adres 
enfekte edilmiş kodun içerisinde bir yerlerde göreli olarak türetilir. 
Bu süreçte atlanacak adres daha önce işleme hafızada ayrılan temel 
adresin üzerine OEP eklenmesiyle bulunur. (eğer biraz daha havalı olmak
isterseniz bu tarz bir operasyon için use-def chain kullanabilirsiniz, 
tabii sonunda zararlı da biraz daha havalı olmaya karar verirse sizi 
zincerleme şekilde birbirini çağıran fonksiyonları**  çözmeye zorlayabilir)

**(çeviri notu: orijinal terim chain cross function )

    add {target}, CONST

PHDR (Program başlık bilgileri) kısmına bu satırı "pop" komutuyla ekleyin 
vee orijinal programın çalışması temiz bir şekilde devam etsin

Zararlıya bir sonraki infection işleminde iyi şanslar diliyoruz ve üç hayırla uğurluyoruz!

##################################################################

#!/usr/bin/env python3

from capstone import *
from collections import Counter
import lief
import math
import numpy as np
from sklearn.cluster import KMeans
import sys

# o anti-re'ci şerefsiz arkadaşlardan olma
SUCKER_PUNCH = 3
# hem büyük hem küçük birkaç tane çalıştırılabilir dosyada test edildi
# çoğu normal çalıştırılabilir dosya "1.0bir şeyler" civarında çıkıyor
# inanmayacaksınız ama birkaç megabayt boyutundaki büyük dosyalar dahi
# ama eminim bozulan istisna durumlar bulunuyordur
INERTIA_RATIO = 1.1

def find_anomalous_load_segment(segment_ranges):
  segment_array = np.array(segment_ranges)
  cluster_2 = KMeans(n_clusters=2, random_state=0).fit(segment_array)
  cluster_1 = KMeans(n_clusters=1, random_state=0).fit(segment_array)
  if (math.log(cluster_1.inertia_)/math.log(cluster_2.inertia_)) < INERTIA_RATIO:
    print("No anomaly detected")
    return None
  cluster_counts = {v:k for k,v in Counter(cluster_2.labels_.tolist()).items()}
  if 1 not in cluster_counts:
    print("No singular cluster found")
    return None
  return segment_array[np.where(cluster_2.labels_ == cluster_counts[1])[0]][0]


def find_oep(segment_bytes, segment_start):
  # şimdilik sadece x64-64 destekliyoruz ama ihtiyaç durumunda
  # kolayca başka mimarilere de dönüştürülebilir. 
  # Burada başka mimarilerde de çalışsın diye
  # IR(Intermediate representation)  kullansak epey havalı olur
  md = Cs(CS_ARCH_X86, CS_MODE_64)
  md.skipdata = True
  oep = None
  last_jump = None
  early_bail = 0
  for r in [instr for instr in md.disasm(segment_bytes, segment_start)][::-1]:
    if last_jump:
      # eğer aşağıdaki formdaki bir komut görüyorsak
      # add {target}, CONST
      # muhtemelen OEP adresini temel adrese ekliyordur
      # bu durumu genelleştirip rax kaydedicisindeki değeri 
      # okumak için use-def chain kullanabiliriz
      # bu durumda fonksiyonları bulmak ve göreli adrese göre 
      # kod atlamaları için get_rip tarzı bir fonksiyon lazım olur

      if last_jump + ", " in r.op_str and "add" == r.mnemonic.strip():
        try:
          oep = int(r.op_str.split(",")[1].strip(), 16)
          break
        except Exception as e:
          # hobi olarak devam et ama buraya düştüysek muhtemelen bulamayız
          # az daha dene, ama çok da deneme yani, gerek yok
          # anti-re yüzünden keyifler kaçmasın şimdi
          early_bail += 1
          if early_bail == SUCKER_PUNCH:
            break
          continue
    if not last_jump and r.mnemonic.strip() == "jmp":
      target = r.op_str.strip()
      # bir bak jmp direkt gerçekleşiyor mu 
      # durum böyleyse oradaki değeri OEP olarak kaydet
      try:
        oep = int(target, 16)
        break
      except Exception as e:
        # değilse muhtemelen kaydedicilerden(register) 
        # aldığı değerle atlıyordur
        oep = None
        last_jump = target
  return oep

def main():
  l = lief.parse(sys.argv[1])
  load_segs = [ [ll.virtual_address, ll.virtual_address + ll.virtual_size]
        for ll in l.segments
        if ll.type == lief.ELF.SEGMENT_TYPES.LOAD
      ]
  anomalous_segment_start, anomalous_segment_end = find_anomalous_load_segment(load_segs)
  segment_bytes = l.get_content_from_virtual_address(anomalous_segment_start, anomalous_segment_end)
  real_oep = find_oep(bytes(segment_bytes), anomalous_segment_start)
  print("found OEP: ", hex(real_oep))
  l.header.entrypoint = real_oep
  l.write(sys.argv[1] + ".cleaned")

if __name__ == "__main__":
  main()