イ良い日ン マを作るしゅーと
View Slide
イ良い日ン マとは• 2018年、突如ネット上に現れたmicroSD• アググンと呼ばれるものもある• 基本的に容量偽装系ストレージ• 2022年、SSDに形を変えてパンピーを襲っている
容量偽装について• 実際のフラッシュ領域に対しての見せかけが異なる• 使えないわけではない• 返品期限までごまかすため?• 偽装方法には大きく2種類• 無視タイプ• 上書きタイプhttps://www.rescue-center.jp/elementary/vol54.html
目標• 任意の容量だと嘘をつく• 1ペタバイトを目標• 書き込めるけど一定のサイズを超えると異常動作を起こす• 無視または上書き動作
その前に
USBデバイスを作る方法
USBデバイスを作る方法• USBデバイスICを使う• 汎用マイコン内蔵のUSB PHYを使う• USBエミュレーションツールを使う
Facedancer• USBデバイスのエミュレーションライブラリ(Python製!)• 対応ハードウェアのUSB APIを利用して機能を実現• GreatFET Oneと呼ばれるボードが現在最も再現性が高い• 今年6月発売のLUNAに合わせて進化を遂げるらしいGreatFET One LUNA
facedancer-umass.py• イメージをマスストレージデバイスとして流し込むスクリプト• 以下で簡単にディスクイメージを作って接続できる• 接続するとターゲット上で認識される(未初期化)# 100MBサイズのディスクイメージ (何も初期化しない)dd if=/dev/zero of=disk_100MB.bin bs=100M count=1# スクリプト実行./legacy-applets/facedancer-umass.py ./disk_100MB.binコントロール用USBポート ターゲット用USBポート
メモ: オンメモリだけで実現も• コードからfdを排除し全てdictに• プログラム終了時にはデータが失われる
任意の容量と嘘をつく
ストレージサイズはどう認識される?• UMS(USB Mass Storage)クラスではSCSIコマンドを利用する• Read Capacity(10)でセクタ数とブロックサイズを提示• PCがそこからディスクのサイズを割り出す
Facedancerでの実装• ブロックサイズは512バイト固定• セクタ数は読み込まれるイメージから算出される→ここを変更すれば任意のサイズを宣言できる!• ただしコードが全て最大32bit LBA• 現状は2TiBまでのディスクしか対応しない(GPTであれば認識可能だが)• →64bit LBA対応に改造して問題を回避👏https://github.com/shutingrz/Facedancer/commit/0fcd48586a1e20b568d6d11d3408c8e854dba1f8
未初期化状態の罠• リムーバブルディスクだと未初期化を未初期化と認識しない• →全セクタを走査しパーティションを探してるっぽい?→遅い!!• Windowsでのフォーマット時にメタデータを全セクタに書き込む→遅い!!• 10MBのディスク+FAT32で2分ちょっとかかる• Facedancerで偽装する場合は事前にフォーマットしないと無理
手始めに100GBの仮想ディスクを初期化• 以下のコマンドで事前にexFATでフォーマット• 問題なく100GBとしてマウントできた#100GBのスパースファイルを作成しGPT作成、exFATでフォーマット$truncate –s 100GB test.img$parted –s test.img mklabel gpt mkpart primary ntfs 1MiB 100%print quit$sudo losetup –f –show test.img$sudo kpartx –a /dev/loop2$sudo mkfs.exfat /dev/mapper/loop2p1# スクリプト実行$./legacy-applets/facedancer-umass.py ./test.img
調子に乗って2ペタバイト!?$truncate -s 2PB test.imgtruncate: failed to truncate 'test.img' at2000000000000000 bytes: File too large
ext4の制限• ext4>このファイルシステムは、最初にLinuxカーネル2.6.19でストレージ制限を拡張し、パフォーマンスを向上させるために使用されていました。 Ext2およびExt3と比較すると、Extファイルシステムは標準の4Kブロックサイズを使用して、最大1EBのボリュームサイズと最大16TBの単一ファイルサイズをサポートできます。
btrfsの中にスパースファイル作成• btrfsは16EBの単一ファイルをサポート• 10GBのbtrfsイメージを作りその中で2PBのディスクを作成• うまくいった• あとはいつも通りGPTからのexFATのフォーマット$truncate -s 10GB btr.img$mkfs.btrfs btr.img$sudo mount btr.img /mnt/target1$ truncate -s 2PB /mnt/target1/test.img $ ls –la /mnt/target1/test.img-rw-r--r-- 1 user user 2000000000000000 Jan 25 01:46 /mnt/target1/test.img
2PBのUSBドライブを見よ!• 無事マウントに成功• Facedancerの微修正が必要• ただしマウント完了まで30分必要• 全セクタを読み込むため• こういうものなの?• 容量偽装はできたので、時間かかる2PBは一旦封印
目標• 任意の容量だと嘘をつく• 1ペタバイトを目標• 書き込めるけど一定のサイズを超えると異常動作を起こす• 無視または上書き動作💮
一定のサイズを超えると異常動作を起こす• 今はbtrfsの実サイズを超えたら書き込みエラーが発生するはず• アググン/イ良い日ン マは書き込み自体はできる• イ良い日ン マ実現までの道のり:• 4GBのディスクイメージを用意• 32GBとみせかける• 書き込み要求セクタが4GBより上位の場合は書き込まない• 偽装と書き込み無視は全てFacedancer側で対応可能• 特定セクタより上の場合はprint()するだけのコードを書いた↓
試した が・・・• 転送速度が遅すぎて検証にならない• コントロールがwsl2のためUSB-IPで転送しているのも原因か• もっとディスクサイズを減らすことに350 KB/s
というわけで見かけ32MBのディスク• ディスクイメージは16MB確保• 15MB分のセクタを超える場合書き込みを行わないように
テストデータ• 1つあたり1.08MBのjpgファイル• 14枚目の途中で特定セクタに到達する計算
デモ(1)• 途中で書き込みされなかった画像ファイル
デモ(2)• 事象発生時のログと空き容量
目標• 任意の容量だと嘘をつく• 1ペタバイトを目標• 書き込めるけど一定のサイズを超えると異常動作を起こす• 書き込み無視💮💮
まとめ• あくまでUSBエミュレーションを使ったものだができた• イ良い日ン マの作り方を完全に理解した• 実際にやるにはちゃんとしたICでのネイティブ実行が必要• Pico にUSBコントローラがあるのでTinyUSBライブラリで優勝?
おわり