2 puan yazan GN⁺ 2023-09-29 | 1 yorum | WhatsApp'ta paylaş
  • Windows NT 3.1’de i386kd ile Ctrl-C break-in yapıldığında kd> istemi yerine hedef 486DX4 sistemi yeniden başlıyordu; nedenin enhanced 486 uyumluluğu sorunu olduğu ortaya çıktı
  • NTOSKRNL.EXE içindeki KiSaveProcessorControlState ve KiRestoreProcessorControlState, CPU tipini kontrol ederken word karşılaştırması kullandığı için CPUID destekli 486’yı Pentium veya daha üstü gibi yanlış değerlendiriyor
  • KPRCB’deki CpuType ve CpuID birlikte okununca CPUID destekli 486’nın model numarası 256 fazla yorumlanıyor; bunun sonucunda 486’da bulunmayan CR4 register’ına erişim gerçekleşiyor
  • Başta takılı olan 486DX-33 ve SMM’siz write-through Am486DX4-NV8T ile kernel debugging normal çalıştığından, sorun CPUID komutunu sağlayan enhanced 486’lara daraltıldı
  • NTOSKRNL.EXE içindeki iki cmp ds:word_FFDFF138, 5 konumu byte compare olarak yamalanırsa hem özgün NT 3.1 Advanced Server’da hem de NT 3.1 SP3’te düzeltilebiliyor

Yeniden üretme ortamı ve belirtiler

  • Compaq ProSignia 3080’e Windows NT 3.1 kurulduktan sonra kernel debugging deneniyor
    • Bu sistem gerçek kullanımda Windows NT 3.1 çalıştırmıştı ve Windows NT’nin açıkça hedeflediği makinelerden biri gibi görünüyor
    • RAM 128 MB’a çıkarılmış, soketli Intel 486DX-33 ise AMD enhanced 486DX4-SV8B ile değiştirilmişti
    • Bu CPU write-back cache ve SMM destekliyor ve voltaj adaptörü soketine takılıyor
  • BIOS’un 486DX4 desteğini ele alması ertelenip CPU 2x çarpan ile jumper’dan ayarlanıyor
    • Yonga setinin L1 write-back desteği olmadan 2x çarpanla ayarlandığında Intel 80486DX2-66 ile yazılım uyumlu olması bekleniyor
    • Intel 80486DX2-66 bu sistemin desteklediği seçeneklerden biri
  • Windows NT 3.1 kurulumu kendi başına sorunsuz tamamlanıyor
  • Windows NT 3.1 CD’sinde tüm debugging sembolleri bulunduğundan kernel debugging deneniyor
    • Amaç, NetDDE’nin event log’a neden hata bıraktığını araştırmaktı
    • Belirli bir EISA Ethernet kartında sistemin çökmesi sorunu da vardı ve donanım arızası olasılığı hâlâ duruyordu
  • En yeni Windows 10 geliştirme kitindeki kd veya ntkd yerine, kernel debugging ayarlarının uyması için Windows NT 3.1 ile gelen i386kd kullanılmalı
  • i386kd içinde Ctrl-C break-in denendiğinde hedef makine kd> istemini sunmadan yeniden başlıyor

Neden olarak elenenler

  • Belleğin sağlam olduğu doğrulandı
  • Sistem dosyası bozulması değildi
  • Çekirdek debugging için durduğunda sistemi yeniden başlatan bir donanım watchdog’u etkin değildi
  • Host tarafındaki USB-serial adaptör normal iletişim kuruyordu
    • Sahte PL2301 gibi görünen bir cihaz olsa da debugger komutlarını yanlış gönderip “reboot system” komutu iletmiş değildi
    • KD protokolünde gerçekten reboot system komutu var
  • Anakartın uzaktan yönetim veya uyarı seçenekleriyle de ilişkili değildi

Asıl neden: enhanced 486 ile NT 3.1 çekirdeğinin uyumsuzluğu

  • Windows NT 3.1 çekirdeği enhanced 486 işlemcilerle uyumlu değil
  • Daha spesifik olarak sorun, CPUID komutunu sağlayan 486 işlemcilerde ortaya çıkıyor
  • Kernel debugging şu CPU’larda normal çalışıyor
    • Başta takılı olan 486DX-33
    • SMM’siz, daha eski non-enhanced core’a sahip write-through Am486DX4-NV8T
  • Amaç yalnızca NT 3.1 kernel debugging’i denemekse Windows NT 3.1 ile temel olarak uyumlu bir CPU kullanmak daha uygun
  • NT’nin kendisini düzeltmek için NTOSKRNL.EXE’deki CPU tipi belirleme hatasını yamalamak gerekiyor

Sorunun patladığı çekirdek kod yolu

  • Uyumsuzluğun doğrudan nedeni KiSaveProcessorControlState içindeki bug
    • Karşılık gelen fonksiyon KiRestoreProcessorControlState içinde de benzer bir bug var
  • KiSaveProcessorControlState, NTOSKRNL.EXE içinde üç yerde çağrılıyor
    • Bir exception KdpTrap üzerinden kernel debugger’a yansıtıldığında
      • Ctrl-C break-in sırasında, timer tick interrupt içindeki break-in polling özelliğinden breakpoint exception oluşuyor
    • KeBugCheckEx çağrıldığında, yani “mavi ekran” durumunda
    • KiSaveProcessorState çağrıldığında
      • IDA’nın NTOSKRNL.EXE control flow analizi eksiksizse bu fonksiyon export edilmiyor ve NTOSKRNL içinde de çağrılmıyor; dolayısıyla pratikte gerçekleşmiyor gibi görünüyor
  • KiSaveProcessorControlState, genişletilmiş CONTEXT yapısına işlemci kontrol durumunu kaydediyor
    • CR0, CR2, CR3’ü kaydediyor
    • Pentium ve üzeri için CR4’ü de kaydediyor
    • DR0~DR3, DR6, DR7 debug register’larını kaydediyor
    • GDT adresi, IDT adresi, etkin TSS selector, LDT selector gibi global protected mode ayarlarını da kaydediyor

KPRCB alanlarını yorumlama hatası

  • İşlemci tipini belirlemek için KPRCB’deki değer kullanılıyor
    • KPRCB, KPCR’nin bir parçası
    • Boot işlemcisinin veya tek işlemcili sistemin KPRCB’si sanal adres FFDFF120 üzerinde ve ilgili metoda hardcode edilmiş
  • Geoff Chappell tarafından derlenen NT 3.1 KPRCB alanları şöyle
    • +018 CHAR CpuType
    • +019 CHAR CpuID
    • +01A UShort CpuStep
  • Bu alanlar KiSetProcessorType içinde başlatılıyor
    • 486 işlemcinin offset 18 byte’ı 4 olarak ayarlanıyor
    • Pentium işlemciler için 5 olarak ayarlanıyor
    • Pentium Pro ve Pentium II/III işlemciler için 6 olarak ayarlanıyor
    • offset 19 byte’ı, işlemcinin CPUID destekleyip desteklemediğini ve “reasonable” şekilde çalışıp çalışmadığını gösteren boolean flag
  • Sorunlu karşılaştırma komutu FFDFF138 adresindeki byte’ı değil word’ü okuyor
    • FFDFF138, KPRCB başlangıcından 18h byte uzaklıktaki konum
    • Bu yüzden yalnızca CpuType değil, hemen sonraki byte olan CpuID de model numarasının bir parçası olarak birlikte yorumlanıyor
  • CPUID destekleyen işlemcilerde model numarası gerçekte olduğundan 256 fazla ele alınıyor
    • CPUID destekli 80-4-86, Windows NT 3.1’de 80-260-86 gibi ele alınıyor
    • 260, Pentium eşiği olan 5’ten çok daha büyük olduğundan çekirdek bu işlemcide CR4 olması gerektiğine karar veriyor
    • Enhanced 486’da CR4 bulunmadığı için break-in yolunda sorun oluşuyor

Yama yöntemi

  • Bug doğrulandıktan sonra düzeltme basit
  • NTOSKRNL.EXE içinde cmp ds:word_FFDFF138, 5 komutu yalnızca iki kez geçiyor
    • KiSaveProcessorControlState
    • KiRestoreProcessorControlState
  • Her iki konumda da word compare, byte compare olarak değiştirilmeli
  • Hex editörle şu byte dizisi iki kez yamalanır
    • Eski: 66 83 3D 38 F1 DF FF 05
    • Yeni: 90 80 3D 38 F1 DF FF 05
  • Bu düzeltme, özgün NT 3.1 Advanced Server dağıtımındaki NTOSKRNL.EXE’ye ve NT 3.1 SP3’e uygulanabiliyor

1 yorum

 
GN⁺ 2023-09-29
Hacker News yorumları
  • Bir zamanlar bir servisin ayakta olup olmadığını kontrol etmek için port kontrolü yazmıştım; makinelerde birkaç TCP portu açmakla şirketin yarısını devirmiştim
    Saçma sapan zamanlardı

    • Win95’in yalnızca belirli bir şekilde ping atılarak çökertilebildiği, hatta ele geçirilebildiği bir dönem vardı
      Gerçekten çok yol katettik
      https://en.wikipedia.org/wiki/Ping_of_death
      Bazı makinelerde yıllarca yamalanmamış SMB açıkları da vardı. Metasploit’in zaten var olduğu dönemdi; birkaç komutla yerel ağdaki Windows hostlarının çoğuna VNC enjekte edebiliyordunuz. Günümüzde en azından yama hızı muazzam derecede yüksek
    • “Birkaç”tan çok daha fazlaydı sanki
  • Ah, retro computing tavşan deliği. Gerçek dünyadaki sonuçlardan zararsızca ayrılmış durumda ama yine de çok tatmin edici
    Geek’ler için gerçek bir bal kapanı. Sonunda “6 yorum daha göster” genişletme düğmesine bastım

    • İmlecin o genişletme düğmesine doğru gittiğini görüp son anda geri çektim
      Bugün biraz iş yapabilirim belki
    • Benim dönemimden önceki bilgisayarlara, PET gibi şeylere bakınca, kurcalaması eğlenceli olur diye düşünüyorum. Eski bir IRIX kutusu da fena olmaz
      Ama 486 mı? Mavi ekranlar ve belleği yetmediği için diske swap yapmasını bekleyerek bitmek bilmeyen süreler geçirdiğim anılar çok fazla canlanıyor. Benim için hâlâ fazla erken gibi
    • Yazının içeriği bugün bile bir ölçüde ilgili görünüyor
  • Çözüm bariz” gerçekten doğru söz

    • Matematik hocam problemlerin iki türü olduğunu söylerdi: kolay problemler ve henüz anlamadığın problemler
    • Hata bir kez tespit edilince öyle. Ama böyle bir hatanın nasıl bulunduğunu merak ediyorum
      Muhtemelen trap kodunun disassembly’sini tekrar tekrar okuyup sorunu bulmuşlardır. QEMU ya da başka bir debugging aracını kullanabilmiş olduklarını sanmıyorum
  • Sonlardaki gizli yorumun içine gömülmüş yöntemi de mutlaka okumak gerekiyor

    • Stack Overflow’un yorumları otomatik katlamasını her gördüğümde anlam veremiyorum
      En az oy alan yorumları gizlemiyor, en yeni ya da en eski olanları da gizlemiyor. Rastgele gibi geliyor ve gereksiz
      Sorun alansa gizlemek yerine sayfalama koymak bence daha iyi olur
  • Eski Abit, Asus, belki MSI anakartlarda uyumluluk için kullanılan slotket adaptörleri gibi şeylerin gerçekten overclock yeteneği vardı
    RAM hızının ne olduğu ve anakartın çarpan ayarlarında ne kadar saat hızına dayanabildiği belirleyiciydi. Celeron ve Pentium II döneminin, overclock’un görece erken zamanlarıydı
    Bir ara uyumluluk yüzünden Celeron 600’ü bir adaptöre takıp, onu da tekrar Slot II - Socket 370 adaptörüne takarak [1] gibi bir kurulumla 1,2 GHz’de sorunsuz çalıştırmıştım. Hatta Windows ME’de 1,4 GHz’e kadar çıkardığımı sanıyorum; sonunda o CPU’yu yaktım
    [1]http://krick.3feetunder.com/370mod/

    • Overclock eğlenceliydi ama modern CPU’ların eskiden var olan güvenlik payını kullanacak şekilde saat hızını ve voltajı hassas biçimde kontrol edebilmesi de güzel
  • Soruya verilen yanıt gerçekten harikaydı
    Konu da güzel, yanıt da çok iyiydi

    • Aslında kendi sorusunu kendisi yanıtlamış. Yine de harika
  • Soruyu soran kişinin yanıtı da kendisinin yazmış olması güzel
    Böyle şeyleri seviyorum. İnsanların retro computing ile ilgilenmesine gerçekten seviniyorum
    Bu tür sorunları ve çözümlerini herkes için belgelendirmek iyi bir şey

  • Bu CPUID denen şeyin kötü bir fikir olduğunu biliyordum

    • Windows geliştiricilerinin yapıya “trustworthiness” bölümü koyma ihtiyacı hissetmiş olması komik
  • Neden soru ile yanıtın zaman damgaları aynıydı?

    • Bilgiyi paylaşmak için. Soru yazarı ile yanıt yazarının aynı kişi olduğunu görebilirsin
      Muhtemelen bu bilgiyi SO’nun soru-cevap biçiminde yayımlamanın, kimsenin bulamayacağı bir blog yazısından daha uzun ömürlü olacağını düşünmüştür
  • Açmadan ne olduğunu bilmiş olmam kötü mü?
    Neyse, gidip şu çocuklara çimlerimden uzak durmaları için bağırmam lazım

    • Biz büyürken problem çözmek farklıydı
      Güvenebileceğimiz şeyler zekâmız ve gerekirse sabit hattan arayabileceğimiz ustalardı. Faydalılığı değişken yanıtlarla dolu harika bir internet falan yoktu