Baru-baru ini di eBay saya menemukan banyak perangkat USB yang menarik (Epiphan VGA2USB LR), yang menerima input VGA dan mengirim video ke USB sebagai webcam. Saya sangat senang dengan gagasan bahwa saya tidak perlu repot dengan monitor VGA lagi, dan diberi dukungan yang dinyatakan untuk Linux, saya mengambil kesempatan dan membeli seluruh batch seharga sekitar 20 pound (25 dolar AS).
Setelah menerima paket, saya menghubungkan perangkat, tetapi bahkan tidak berpikir untuk muncul dalam sistem sebagai
UVC . Apa yang salah
Saya mempelajari situs web pabrikan dan menemukan bahwa driver khusus diperlukan untuk bekerja. Bagi saya, ini adalah konsep baru, karena kernel distribusi Linux saya biasanya memiliki driver untuk semua perangkat.
Sayangnya, dukungan driver untuk perangkat ini hanya berakhir di Linux 4.9. Jadi, tidak ada sistem saya yang akan melihatnya (Debian 10 di Linux 4.19 atau versi terbaru dari LTS Ubuntu di Linux 5.0).
Tapi itu bisa diperbaiki, bukan? Tentu saja, file datang dalam
paket DKMS , yang, sesuai permintaan, mengumpulkan driver dari kode sumber, seperti banyak driver biasa ...
Menyedihkan. Tapi di sini tidak demikian.
Di dalam paket itu hanya binari
vga2usb.o
dikompilasi. Saya mulai mempelajarinya, bertanya-tanya kerumitan rekayasa balik, dan menemukan beberapa baris yang menarik:
$ strings vga2usb.ko | grep 'v2uco' | sort | uniq v2ucom_autofirmware v2ucom_autofirmware_ezusb v2ucom_autofirmware_fpga
Jadi apakah ini benar-benar
FPGA -on-a-stick? Bagaimana membuat sesuatu seperti ini berfungsi?
Temuan lucu dan sedikit mengganggu lainnya adalah garis dengan parameter kunci pribadi DSA. Ini membuat saya bertanya-tanya: apa yang bisa ia lindungi di dalam pengemudi?
$ strings vga2usb.ko | grep 'epiphan' | sort | uniq epiphan_dsa_G epiphan_dsa_P epiphan_dsa_Q
Untuk mempelajari driver di lingkungan normalnya, saya mengambil mesin virtual Debian 9 (rilis yang didukung terakhir) dan membuat
KVM USB Passthrough untuk memberikan akses langsung ke perangkat. Kemudian saya menginstal driver dan memastikan itu berfungsi.
Setelah itu, saya ingin melihat seperti apa protokol komunikasi itu. Saya berharap perangkat akan mengirim bingkai mentah atau hampir mentah, karena itu akan membuatnya lebih mudah untuk menulis driver untuk ruang pengguna.
Untuk melakukan ini, saya memuat modul
usbmon
pada
usbmon
mesin virtual dan meluncurkan Wireshark untuk menangkap lalu lintas USB ke dan dari perangkat selama startup dan pengambilan video.

Saya menemukan bahwa ketika diluncurkan, sejumlah besar paket kecil ditransmisikan ke perangkat sebelum mulai menangkap gambar. Ini kemungkinan didasarkan pada platform FPGA tanpa penyimpanan data. Setiap kali setelah terhubung, driver mentransfer firmware dalam bentuk
bitstream FPGA ke perangkat.
Saya yakin dengan membuka salah satu kotak:

Karena untuk "mengunduh" perangkat, Anda perlu mengirimkannya bitstream / firmware, Anda harus mencarinya di binari yang sudah dikompilasi. Saya berlari
binwalk -x
dan mulai mencari beberapa objek yang dikompresi (zlib). Untuk melakukan ini, saya menulis skrip pencarian urutan hex - dan menetapkan tiga byte dari paket yang dicegat.
$ bash scan.sh "03 3f 55" trying 0.elf trying 30020 trying 30020.zlib trying 30020.zlib.decompressed ... trying 84BB0 trying 84BB0.zlib trying 84BB0.zlib.decompressed trying AA240 trying AA240.zlib trying AA240.zlib.decompressed 000288d0 07 2f 03 3f 55 50 7d 7c 00 00 00 00 00 00 00 00 |./.?UP}|........| trying C6860 trying C6860.zlib
Setelah membongkar file AA240.zlib, ternyata tidak ada cukup data untuk bitstream lengkap. Jadi saya memutuskan untuk mengambil firmware dari paket USB.
Baik tshark dan
tcpdump dapat
membaca paket USB dari file pcap, tetapi keduanya menyimpannya hanya sebagian. Karena setiap utilitas memiliki bagian puzzle yang berbeda, saya menulis sebuah
program kecil yang menggabungkan output dari kedua program ke dalam struktur go untuk memutar paket kembali ke perangkat.
Pada titik ini, saya perhatikan bahwa pengunduhan berlangsung dalam dua tahap: pertama pengontrol USB, dan kemudian FPGA.
Saya macet selama beberapa hari: sepertinya seluruh bitstream sedang dimuat, tetapi perangkat tidak mulai, meskipun paket dari driver nyata dan simulasi saya terlihat serupa.
Pada akhirnya, saya memecahkan masalah dengan hati-hati memeriksa pcap dengan mempertimbangkan waktu respons untuk setiap paket - dan melihat perbedaan waktu yang besar dalam satu paket tertentu:

Ternyata karena
kesalahan ketik kecil
, rekaman terjadi di area perangkat yang salah. Ini akan menjadi pelajaran bagi saya cara memasukkan nilai secara manual ...
Namun, LED akhirnya berkedip pada perangkat! Sebuah pencapaian besar!
Itu relatif mudah untuk mereplikasi paket yang sama yang memicu transfer data, jadi saya bisa menulis titik akhir USB Bulk dan menyiram data ke disk secara instan!
Di sinilah kesulitan sebenarnya dimulai. Karena setelah analisis ternyata data itu tidak secara eksplisit dikodekan dengan cara apa pun.
Untuk memulai, saya menjalankan
perf untuk mendapatkan ide
dasar dari jejak stack driver saat runtime:

Meskipun saya bisa menangkap fungsi dengan data bingkai, saya tidak bisa memahami pengkodean data itu sendiri.

Untuk lebih memahami apa yang terjadi di dalam driver sebenarnya, saya bahkan mencoba alat
Ghidra dari NSA:

Meskipun Ghidra luar biasa (ketika saya pertama kali menggunakannya bukan IDA Pro), itu masih tidak cukup baik untuk membantu saya memahami driver. Rekayasa balik membutuhkan jalur yang berbeda.
Saya memutuskan untuk mengambil mesin virtual Windows 7 dan melihat driver Windows, tiba-tiba itu akan memunculkan ide. Dan kemudian saya perhatikan bahwa ada SDK untuk perangkat. Salah satu alat ternyata sangat menarik:
PS> ls Directory: epiphan_sdk-3.30.3.0007\epiphan\bin Mode LastWriteTime Length Name ---- ------------- ------ ---- -a--- 10/26/2019 10:57 AM 528384 frmgrab.dll -a--- 10/27/2019 5:41 PM 1449548 out.aw -a--- 10/26/2019 10:57 AM 245760 v2u.exe -a--- 10/26/2019 10:57 AM 94208 v2u_avi.exe -a--- 10/26/2019 10:57 AM 102400 v2u_dec.exe -a--- 10/26/2019 10:57 AM 106496 v2u_dshow.exe -a--- 10/26/2019 10:57 AM 176128 v2u_ds_decoder.ax -a--- 10/26/2019 10:57 AM 90112 v2u_edid.exe -a--- 10/26/2019 10:57 AM 73728 v2u_kvm.exe -a--- 10/26/2019 10:57 AM 77824 v2u_libdec.dll PS> .\v2u_dec.exe Usage: v2u_dec <number of frames> [format] [compression level] <filename> - sets compression level [1..5], - captures and saves compressed frames to a file v2u_dec x [format] <filename> - decompresses frames from the file to separate BMP files
Alat ini memungkinkan Anda untuk "mengambil" satu frame, dan pada awalnya tidak dikompresi, sehingga memungkinkan untuk memproses frame nanti pada mesin yang lebih cepat. Ini hampir sempurna, dan saya meniru urutan paket USB untuk mendapatkan gumpalan yang tidak terkompresi ini. Jumlah byte terkait dengan kira-kira tiga (RGB) per piksel!
Pemrosesan awal gambar-gambar ini (hanya menerima output dan menuliskannya sebagai piksel RGB) memberikan sesuatu yang samar-samar mengingatkan pada gambar nyata yang diterima perangkat melalui VGA:

Setelah debugging di hex editor, ternyata setiap marker diulang setiap 1028 byte. Agak memalukan berapa banyak waktu yang saya habiskan untuk menulis filter. Di sisi lain, dalam prosesnya orang dapat menikmati beberapa contoh seni kontemporer.

Kemudian saya menyadari bahwa kemiringan dan distorsi gambar disebabkan oleh lompatan dan bungkus piksel pada setiap baris (x = 799 tidak sama dengan x = 800). Dan akhirnya, saya mendapatkan gambar yang hampir benar, kecuali warnanya:

Pada awalnya, saya pikir masalah kalibrasi adalah karena pengambilan sampel data ketika input VGA macet dalam warna solid. Untuk koreksi, saya membuat gambar uji baru untuk mengidentifikasi masalah seperti itu. Kalau dipikir-pikir, saya mengerti bahwa Anda harus menggunakan sesuatu seperti
kartu tes Philips PM5544 .

Saya mengunggah gambar ke laptop, dan menghasilkan gambar VGA seperti itu:

Kemudian saya mendapatkan memori beberapa karya lama dalam rendering / shader 3D. Itu sangat mirip dengan
skema warna YUV .
Akibatnya, saya terjun membaca literatur YUV dan ingat bahwa selama rekayasa balik driver kernel resmi, jika saya meletakkan breakpoint pada fungsi yang disebut
v2ucom_convertI420toBGR24
, maka sistem akan menggantung tanpa kemungkinan pembaruan. Jadi mungkin inputnya adalah encoding I420 (dari
-pix_fmt yuv420p
), dan outputnya adalah RGB?
Setelah menggunakan fungsi Go
bawaan YCbCrToRGB, gambar tiba-tiba menjadi lebih dekat dengan aslinya.

Kami berhasil! Bahkan pengemudi mentah menghasilkan 7 frame per detik. Jujur, ini sudah cukup bagi saya, karena saya menggunakan VGA hanya jika terjadi kecelakaan sebagai tampilan cadangan.
Jadi, sekarang kita tahu perangkat ini cukup baik untuk menjelaskan algoritma untuk memulai dari awal:
- Anda perlu menginisialisasi pengontrol USB . Dilihat dari jumlah informasi, pada kenyataannya, pengemudi melewati kode untuk mengunduh.
- Ketika Anda selesai memuat USB, perangkat akan memutuskan koneksi dari bus USB dan setelah beberapa saat akan kembali dengan satu titik akhir USB.
- Sekarang Anda dapat mengirim bitstream FPGA , satu paket USB 64-byte untuk setiap transfer kontrol.
- Di akhir transfer, indikator pada perangkat akan berkedip hijau. Pada titik ini, Anda dapat mengirim apa yang tampak seperti urutan parameter (overscan dan properti lainnya).
- Kemudian jalankan paket kontrol untuk mendapatkan frame , paket yang ditentukan izinnya. Jika Anda mengirim permintaan untuk frame 4: 3 ke input layar lebar, ini biasanya akan menyebabkan kerusakan pada frame.
Untuk kemudahan penggunaan maksimal, saya menerapkan server web kecil di driver. Melalui
MediaRecorder API berbasis
browser, ia dengan mudah merekam aliran dari layar ke file video.

Mencegah klaim yang tak terhindarkan terhadap kualitas kode eksperimen, saya akan segera katakan: Saya tidak bangga karenanya. Mungkin, dia dalam kondisi seperti itu, yang cukup bagi saya untuk penggunaan yang dapat diterima.
Kode dan build yang sudah jadi untuk Linux dan OSX
ada di GitHub .
Bahkan jika tidak ada yang memulai program, bagi saya itu adalah perjalanan yang menakjubkan melalui belantara protokol USB, debugging kernel, modul reverse engineering dan format decoding video! Jika Anda suka hal-hal ini, Anda dapat melihat
posting blog lainnya .