- Eski bir Yamaha PSR-E433 synthesizer’daki SWL01U çipi tersine mühendislik ile incelenerek, yalnızca USB-MIDI SysEx mesajlarıyla RAM’e kod yazıldı ve LCD’de Bad Apple videosu gösterildi
- JTAG IDCODE
0x3f0f0f0file OpenOCD/GDB deneyleri, çipin ARM7TDMI çekirdeği gibi davrandığını doğruladı; dahili 64KiB ROM ve harici 16MiB flash firmware dump edildi - Firmware içinde MIDI SysEx üzerinde çalışan gizli bir shell vardı;
loginve#0000parolasından sonra bellek okuma/yazma komutları kullanılabiliyordu - Keyfi bellek yazma komutuyla RAM’e ARM kodu enjekte edilip stack’teki dönüş adresi ezilerek, JTAG veya UART olmadan yalnızca MIDI dosyası çalarak kod çalıştırmak mümkün oldu
- LCD çıktısı; CGRAM kontrolü, görev tablosu kopyalama, görüntüleme görevinin devre dışı bırakılması ve shell callback’inin değiştirilmesiyle iyileştirildi; kare başına aktarım miktarı 6732 bayttan 92 bayta düşürüldü
Yamaha PSR-E433’ün İçinin İncelenmesi
- Hedef cihaz, uzun süredir kullanılan bir Yamaha PSR-E433 synthesizer’dı; ana kartta
DMLCDibaresiyle birlikte iki flash çipi, bir RAM çipi veYAMAHA SWL01Uçipi bulunuyordu - SWL01U hakkında herkese açık bilgi neredeyse yoktu; çevrimiçi bulunan tek bir yazı, bunun SuperH CPU çekirdeği tabanlı olabileceğinden bahsediyordu
- Benzer model E443’ün servis kılavuzunda SWL01U pin dizilimi vardı;
TESTN,PROTN, iki çift yönlü UART ve JTAG test noktaları gösterilmişti - İlk yaklaşım dört koldan ilerledi
TESTN,PROTNpinlerini değiştirerek boot modu değişikliklerini kontrol etmek- UART Tx pinine lehim yaparak çıktıyı kontrol etmek
- JTAG ile çip tanımlama kodunu okumak
- Flash çipini sökerek firmware dump almak
TESTNetkinleştirildiğinde synthesizer boot etmiyordu;PROTNise davranışta bir değişiklik yaratmadı- Kullanılmıyor gibi görünen UART Tx pinine doğrudan lehim yapıldı, ancak
TESTN/PROTNiçin dört kombinasyonun hiçbirinde çıktı alınmadı
JTAG ile Ortaya Çıkan ARM7TDMI Davranışı
- JTAG, üreticiye özgü uygulamalara göre ayrıntılı devre açıklaması gerektirse de, neredeyse tüm cihazların desteklediği IDCODE okuması önce OpenOCD ile denendi
- OpenOCD, IDCODE’u
0x3f0f0f0folarak raporladı; bu değer STMicroelectronics STR7xxx veya Atmel SAM7xxx serisi gibi ARM7 tabanlı mikrodenetleyicilerle ilişkilendirilebilir görünüyordu - SWL01U, OpenOCD’de
arm7tdmihedefi olarak belirtildiğinde düzgün biçimde bağlandı ve donanımda 2 breakpoint/watchpoint birimi olduğu gösterildi - GDB ile yürütme durdurulup yeniden başlatıldığında kart akımı öngörülebilir şekilde değişti
- Çalışırken yaklaşık 115mA
- Duraklatılmışken yaklaşık 98mA
- Bu akım değişimi, gerçekten ARM7TDMI çekirdeğinin durdurulup yeniden başlatıldığına dair güçlü bir işaret oldu
ROM ve Flash Firmware Dump’ı
- ARM7TDMI belgelerine göre reset vector adres
0’dadır; GDB ile adres0okunduğundaldr pc, [pc, #24]biçiminde bir atlama komutu görüldü - Adres
0’dan 16MiB dump alınıp Cutter ile açıldı, ancak dizgeler her 64KiB’de bir tekrarlanıyordu- Örn:
SWL01U Internal,0x0000bfd0,0x0001bfd0,0x0002bfd0vb. adreslerde tekrarlanıyordu
- Örn:
- Tekrarlayan desen ve dizgeler nedeniyle bu dump’ın harici flash değil, çipin dahili belleği olduğu değerlendirildi; SWL01U’da 64KiB ROM bulunduğu sonucuna varıldı
- Reset vector’ün atlama hedefi
0x02000000idi; bu adresten tekrar 16MiB dump alındığında tekrar yoktu - Harici flash dump’ında synthesizer kullanımı sırasında görülebilen dizgeler vardı
GrandPnoTr1 will be OverWritten!BogiWogi
- Doğrulanan bellek düzeni şöyleydi
- Dahili ROM:
0x00000000, 64KiB - Harici flash:
0x02000000, 16MiB - Boot sırasında ROM, kontrolü hemen harici flash’a devrediyor
- Dahili ROM:
Ghidra ile Bulunan Gizli Shell
- Cutter tek başına analiz için yetersiz kaldığından Ghidra’ya geçildi; dizgeler ve xref’ler takip edilerek firmware yapısı anlaşıldı
help,?,info,vergibi dizgeler yakın adreslerde kümelenmişti; her dizge, komut adı ve fonksiyon işaretçisi çiftlerinden oluşuyor gibi görünen bir diziye bağlıydı- Komut işleme fonksiyonu bir durum makinesi biçimindeydi;
logindizgesi vePasswd Errordizgesi üzerinden bunun giriş prosedürü olan bir shell olduğu doğrulandı - Shell giriş işleme, 256 baytlık halka buffer üzerinde dolaşıp karakter karakter çalışıyor;
\rkarakteriyle karşılaşınca komutu çalıştıracak şekilde tasarlanmıştı - Giriş akışı şöyleydi
logingirilincepasswd?çıktısı- Parola olarak
#0000girilincelogin OK - Sonrasında komut çalıştırma mümkün
- Doğrulanan shell komutları arasında şunlar vardı
logout,help,?,info,verstack,perf-on,perf-off,perf-dispd,dp,d xxxxx,d/s xxxxxm ADDRESS DATA,m/b ADDRESS DATA,m/w ADDRESS DATA,m/l ADDRESS DATA
infokomutu şu bilgileri döndürdüDevelopName PSR-E433DevelopNumber #3341Main DevelopNumber #3341Make data & time MAY 16 2012 19:00:57J/E Select English
USB-MIDI SysEx Üzerinde Çalışan Shell
- Shell çıktı fonksiyonu, her baytı üst/alt 4 bitlik nibble’lara ayırıp ayrı baytlara koyuyor ve başına/sonuna sabit header ve footer ekliyordu
>prompt’una karşılık gelen paket yapısı şöyleydi- Header:
F0 43 73 01 52 19 00 00 - Payload:
03 0E 02 00 - Footer:
F7
- Header:
- MIDI SysEx mesajı
0xF0ile başlar, üretici ID’si ve payload’dan geçerek0xF7ile biter; payload’da yalnızca MSB’si 0 olan baytlar bulunabilir - Header’daki
0x43, Yamaha üretici ID’siydi ve shell paket yapısı Yamaha SysEx mesaj biçimiyle uyuşuyordu - Synthesizer’ın USB descriptor’ında yalnızca MIDI arayüzü vardı; ayrı bir seri port yoktu
- Bir Python betiğiyle terminal ile shell protokolü arasında dönüşüm yapılınca USB-MIDI üzerinden shell ile iletişim kurulabildi
MIDI Shellcode ile Kod Çalıştırma
- Shell’in
m/l AAAAAAAA DDDDDDDD\rkomutu 32 bit bellek yazma işlemi yapıyor; adres ve veri 16’lık tabanda ASCII olarak aktarılıyordu - 4 baytlık payload yazma sürecinde bile gerçek aktarım miktarı ciddi biçimde şişiyordu
- Komut baytlarının her biri iki 4 bitlik nibble baytına dönüştürülüyor
- SysEx mesajına 9 bayt ekleniyor
- Her 3 bayt, 4 baytlık USB-MIDI paketiyle sarılıyor
- 4 bayt yazmak için synthesizer’a 72 bayt göndermek gerekiyor
- Echo ve prompt dahil edildiğinde toplam 396 bayt gidip geliyor
- Kullanılmıyor gibi görünen bir RAM bölgesi bulunarak ARM assembly kodu yerleştirildi ve stack dönüş adresi ezilerek bu kod çalıştırıldı
- İlk payload, firmware içindeki dizge çıktı fonksiyonunu çağırıp LCD’nin 8 karakterlik metin alanında
HeloWrldgösterdi - Bu yöntem JTAG veya UART olmadan da çalışıyor; mesajı bir MIDI dosyasına koyup çalmak yeterli oluyordu
- PSR-E433 firmware 1.02 için bir MIDI dosyası da sağlandı; ancak başka Yamaha cihazlarda veya farklı firmware sürümüne sahip PSR-E433’te çalınırsa öngörülemez davranabileceği konusunda uyarıldı
Bad Apple’ı LCD’de Göstermek
- Yamaha PSR-E433’ün LCD denetleyicisi ML9040A; temel olarak nokta matrisli metin karakterlerini işleyen bir yapıya sahipti
- LCD’de nokta matris alanının yanı sıra nota gösterimi, 7 segment alanı, akor gösterimi ve altta klavye gösterim alanı da vardı
- ML9040A’da üç tür bellek vardı
- DDRAM: Gösterilecek karakter verisini host yazar
- CGROM: Karakter kodlarını grafik desenlere dönüştürür
- CGRAM: Host en fazla 8 kullanıcı tanımlı karakter tanımlar
- Firmware, CGRAM’i değiştirerek nokta matrisin altındaki metin dışı görüntü öğelerini kontrol ediyordu; bu yol kullanılarak kullanıcı tanımlı grafik gösterilebiliyordu
- LCD denetleyicisine keyfi veri gönderen firmware fonksiyonu bulunup CGRAM’e dama tahtası deseni yüklendi, ancak firmware CGRAM’i sürekli güncellediği için kısa süre sonra üzerine yazdı
RAM Manipülasyonuyla Ekran Yenilemeyi Kontrol Etme
- Flash’ı doğrudan ezmek cihazı kullanılamaz hâle getirme riski taşıdığından, tüm deneyler güç yeniden başlatmasıyla geri döndürülebilecek şekilde RAM manipülasyonu ile sınırlandırıldı
- Firmware’de ilkel bir RTOS gibi görünen bir yapı vardı; flash’ta 64 görevin callback fonksiyonlarını, stack’lerini ve özniteliklerini tanımlayan global bir tablo bulunuyordu
- Boot sırasında flash firmware, ROM’a görev tablosu konumunu bildiriyor; ROM da bu konumu dahili SRAM’deki global değişkende saklıyordu
- Görev tablosu RAM’e kopyalanıp ROM’un yeni tabloyu kullanması sağlanınca, flash değiştirilmeden görev callback’leri değiştirilebiliyordu
- Görüntü yenileme görevinin callback’i varsayılan idle callback ile değiştirilerek firmware’in CGRAM’in üzerine sürekli yazması engellendi
Aktarım Verimliliği ve Ekran Bozulmalarının İyileştirilmesi
- Bad Apple’ın ilk uygulaması çalıştı, ancak aktarım verimliliği düşük olduğundan kare hızı çok düşüktü ve ekranda artefaktlar vardı
- Her karede yalnızca 64 bayt CGRAM ve 32 bit dönüş adresi ezme gönderilse bile gerçek aktarım miktarı 70 bayt payload başına 6732 bayt idi
- Düşük verimliliğin iki ana nedeni vardı
- Verinin shell komutu biçiminde sarılması gerekiyordu
- Synthesizer her komutu karakter karakter büyük SysEx paketleriyle echo ediyordu
- Shell görev callback’i, doğrudan yazılmış bir callback ile değiştirilip raw veri alacak ve yanıt vermeyecek hâle getirilince, komut sarmalama ve echo ek yükü kaldırılabildi
- Ek paketleme optimizasyonlarından sonra kare başına aktarım miktarı 6732 bayttan 92 bayta düştü; bu 73 kat azalma demekti
- Kalan artefaktlar, LCD iletişimi ile panel düğmesi/LED taramasının aynı 8 GPIO hattını paylaşmasından kaynaklanıyordu
- Son uygulama LCD’ye doğrudan yazmak yerine, LCD/panel çoklama görevinin panel taramasını bitirdikten sonra istenen veriyi göndermesini talep ederek bozulmayı önledi
Nihai Çalışma Prosedürü ve Kalan Analiz Konuları
- MIDI ile LCD görüntüsü göstermenin nihai prosedürü şöyle
- Shell’e giriş yap
- Shell’in bellek yazma komutuyla yürütülecek kodu RAM’e yaz
- Stack dönüş adresini ezerek RAM kodunu çalıştır
- Görev tablosunu RAM’e kopyala
- Yeni görev tablolarını birbirlerini gösterecek şekilde değiştir
- ROM’un yeni görev tablosunu kullanmasını sağla
- Görüntüleme görevi callback’ini varsayılan idle callback ile değiştir
- Shell görev callback’ini kendi callback’inle değiştir
- Kendi callback’inde MIDI verisini unpack edip LCD/panel çoklama görevine ilet
- MIDI ile video karelerini besle
- SWL01U’nun MMIO bölgesi hakkındaki anlayış hâlâ sınırlı; ana ARM çekirdeğinden ayrı olan DSP de analiz edilmeyi bekleyen konular arasında
- İlgili materyaller
1 yorum
Hacker News yorumları
SuperH, Sega 32X, Sega Saturn ve Sega Dreamcast’te de yer aldı; HP Jornada gibi bazı erken dönem Pocket PC’lerde de kullanıldı
Ancak Pocket PC’lerin çoğu ARM tabanlıydı
Ön kabul neredeyse saçma denecek kadar uçuk, ama bunu gerçekten başarmış olmaları şaşırtıcı
“Başka bir paketleme optimizasyonu”ndan söz etmişler; kareleri nasıl ilettiklerini merak ediyorum
Nokta matrisi 7x5 karakterden 8 adet ise toplam 280 bit, yani kare başına 7 bitlik 40 grup eder; ama iletimde bunun iki katı kadar alan kullanıyor gibi görünüyor
Bunun kontrol verisi yüzünden mi boşa gittiğini, yoksa iletim yönteminin biraz optimal olmadığını mı merak ediyorum
Buna 9 baytlık paket başlığı ve son eki ekleniyor
Yazıda 92 yazmış gibi görünüyor, ama sanırım hesap hatası var
7 bitin tamamını kullanmanın bir yolunu bulmak çok zor olduğu için, özgün yöntemle karşılaştırıldığında optimuma göre yalnızca çok az daha kötü bir çözüm seçilmiş
Tam algoritmayı merak ediyorsanız, henüz düzenlenmemiş kod olsa da şu dosyalara bakabilirsiniz: https://github.com/portasynthinca3/swl01u/blob/master/fun/bi..., https://github.com/portasynthinca3/swl01u/blob/master/fun/ba...
“Tersine mühendislikte pek deneyimli değilim” sözünün karşılığı buysa, geri kalanımızın nerede durduğunu bilemiyorum
“Dünyanın ilk MIDI shellcode’u” denmiş, ama büyük platformların çoğunda MIDI shellcode 20 yılı aşkın süredir vardı: https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=midi
Tabii ki SysEx’miş
Standart MIDI’de SysEx, Python’daki inline assembler gibidir
Neredeyse her MIDI cihazının içinde belgelenmemiş, tescilli şeyler saklıdır
MIDI klavye takıp Am6,9/G# çalınca root yetkili bir terminal penceresi açılsa gerçekten harika olurdu
Yakın zamanda MIDI fuzzing yapmak için neler gerektiğini araştırdım; bunun için .mid dosyası üreten kaynaklar buldum ama istediğim şeyden biraz farklıydı
Bunun yerine bu tarafı keşfetmeye değer görünüyor
Günümüz synthesizer’larının giderek daha az kullanıyor gibi olması epey üzücü, özellikle Roland
Yine de Behringer hâlâ oldukça iyi destekliyor
Örneğin Deepmind’in MIDI CC aralığı zaten iyi, ama SysEx ile neredeyse %100 programlanabiliyor
Şaşırtıcı bir araştırma
Gerçek DNA/RNA moleküllerine shellcode sentezleyip DNA dizileme cihazında uzaktan kod yürütme gösteren 2017 tarihli çalışmayı biraz hatırlattı: https://www.usenix.org/conference/usenixsecurity17/technical...
“Sırada OSC mi var?” diyecektim, ama şimdilik MIDI hâkim gibi görünüyor
Yazının tamamını okumayı öneririm, ama bence kilit cümleler şunlar
“Bu [klavye üreticisi] delileri, USB üzerindeki MIDI SysEx mesajları üstünde çalışan bir kabuk yapmış”
“En ilginç komut, rastgele bellek okuma/yazma komutudur. İsterseniz MIDI ile synthesizer belleğine bakıp onu kurcalayabilirsiniz”
“İsterseniz bu mesajları bir MIDI dosyasına yazıp diğer MIDI dosyaları gibi synthesizer’da çalabilirsiniz. Hah, aklıma iyi bir fikir geldi…”
“Firmware’in içine dalarak geçen sayısız uykusuz gecenin sonunda, LCD denetleyicisine rastgele veri gönderen bir fonksiyon buldum”
Bir bakıma Nesnelerin İnterneti kâbusuna küçük bir bakış atmak gibi
Neredeyse her cihazda bir arka kapı olabilir; hatta #0000 gibi aptalca bir arka kapı bile olabilir
Paket kaybı yaşanması tamamen normal
Bad Apple komutlarının arasına MIDI müziği sıkıştırıp sesin de kendi kendine çalmasını sağlayıp sağlayamayacaklarını merak ediyorum
Depo README’sinde imaj dökümü içerdiği yazıyor, ama gerçekte yok
Bunun beklenen durum olup olmadığını merak ediyorum
Son anda assemble edilmiş kod parçalarını hariç tutmak için
*.bin’i.gitignore’a ekledim, sanırım döküm de onunla birlikte hariç kaldıBirkaç saat içinde yükleyeceğim
Söz konusu dökümler Yamaha telif hakkı ile korunuyor olabilir; bu yüzden belki de daha iyi bir karar olmuştur
HN okurları arasında Ermenistan’da olan varsa, Porta 10 Ocak’ta Hacker Embassy’de bu konuda sunum yapacak
Mutlaka uğramanızı öneririm: https://t.me/hackerembassy/17