「Drawbot:かわいいものをハックしてみよう(2025)」

2026/01/17 7:13

「Drawbot:かわいいものをハックしてみよう(2025)」

RSS: https://news.ycombinator.com/rss

要約

Japanese Translation:

Summary:

この記事では、著者が8ビットバーコードを使用した物理カードで256種類の事前定義された図形から1つを選択する単純な描画ロボットを逆エンジニアリングした方法を説明しています。2つのSPI NORフラッシュチップ(1つは音声、もう1つはグラフィック)をダンプすると、ファイル名とCRCチェックサムを含むディレクトリ構造が判明しました。生データは座標ペアであり、SVGパスに解析できます。Pythonスクリプトで16 MBのダンプから254個の利用可能な画像を抽出しました。新しい図形を追加するために、著者はSVGをカードのバウンディングボックスに合わせてリサイズし、必要なバイナリ形式にパックして

flashrom
で書き戻すスクリプトを書きました。ロボットは複数段階でマルチプレクスされたセンサーを通じてバーコードを読み取り、5つのカテゴリ(食べ物・動物・植物・車両・円)にわたる8ビットインデックスを取得します。今後の計画としては、抽出からアップロードまでのパイプライン全体を自動化し、音声フォーマットを解読し、ロボットの機械構造を再設計することが挙げられます。この作業により、ホビイストは玩具のアートライブラリをカスタマイズできるようになり、低電力組込みグラフィック保存技術への洞察が得られ、同様のデバイスを改良または再利用するメーカーにもインスピレーションを与える可能性があります。

Summary Skeleton

What the text is mainly trying to say (main message)
著者は8ビットバーコード付き物理カードを使用して256種類の事前定義された図形から1つを選択する玩具描画ロボットを逆エンジニアリングし、フラッシュメモリに新しい図形を抽出・変更・アップロードする方法を示しました。

Evidence / reasoning (why this is said)

  • ロボットのハードウェアはARM Cortex‑M0 MCUと2つのSPI NORフラッシュチップで構成されており、より小さいチップが音声ファイルを保持し、大きいチップに描画データが保存されています。
  • フラッシュダンプからディレクトリ構造(CRC、オフセット、サイズ、フラグ、ファイル名例「001.f1a」)が判明し、生データはSVGパスに解析できる座標ペアを含んでいます。
  • Pythonスクリプト(
    img_carver.py
    )で16 MBダンプから254個のSVG図形を抽出し、期待される画像数を確認しました。

Related cases / background (context, past events, surrounding info)

  • ロボットはマルチプレクスされたセンサーを2フェーズで駆動してバーコードを読み取り、5つのカテゴリ(食べ物・動物・植物・車両・円)にわたる8ビット値を取得します。
  • カスタムスクリプト(
    svg_fit_to_slot.py
    )はSVGをスロットのバウンディングボックスにマッピングし、必要なバイナリ形式にパックして
    flashrom
    で書き戻します。

What may happen next (future developments / projections written in the text)
著者は抽出からアップロードまでの全プロセスを自動化し、音声ファイルフォーマットを解読し、ロボットの機械的構造を再設計することを計画しています。

What impacts this could have (users / companies / industry)
ユーザーはロボット用にカスタム図形を作成できるようになり、その創造性を拡張します;ホビイストや研究者は低電力組込みグラフィック保存技術への洞察を得られ、メーカーは同様の玩具デバイスを改善または再利用するインスピレーションを受ける可能性があります。

本文

ターゲット

数か月前、私は楽しくてユニークなハードウェアプロジェクトに取り掛かるべきだと感じました。時々、新しい面白い電子子ども向け玩具が市場に出ているのを確認するのが好きです。調査するときは、潜在的な攻撃対象(通常は同伴モバイルアプリやワイヤレス通信、その他の複雑さを持つもの)を意識しています。

私はあるロボットを見つけました。このロボットは事前に定義された画像セットから描画します。すべてのブランドでカードが100〜150枚ずつ付属し、描画は非常に似通っています。物理的なカードを使っているので攻撃対象は小さく見えました(FCC ID を覗き込んで内部を見ることもできないでしょうし、私はそれ自体がスプライヤーだと考えていました)。それでも興味深いターゲットのように思え、抵抗できませんでした。


選んだ理由

  • 箱のデザインが一番良かった。
  • ラベルやタイプミスはクワイアリティの兆候だった。
  • 100枚のカード付きで、それぞれに8ビット(256通り)の「バーコード」が最小限に記載されている。
  • カードは食べ物、動物、植物、車両、円形という5つのカテゴリに分かれていた。

私は「ボブスカクタス」のカードを読み込ませ、実際に描画させました。ロボットが話し、歌い、完璧でした。


解析開始

分解

正直言って、これは私のお気に入りの部分です。
底部には極端に浅く掘られたネジ穴があります。この段階で適切な工具を持っているはずなのですが、実際にはありませんでした。ハードウェア評価では、まだ何が足りないか(忍耐力以外)を常に認識します。自宅ラボで集めた専門ツールや部品でも、必ず購入しなければならないものがあります。この時点で同じ日または翌日に必要なものを簡単に手に入れられましたが、それには忍耐が必要です。3Dプリントで解決できるかもしれませんが、私はそれほど忍耐力がありません。

忍耐不足をパワーツールで補います。穴を少し大きく掘り、ドライバーのビットとチェーンビットを組み合わせました。4つのネジを外すと上半分はほぼ問題なく外れました。

バーコードリーダーが露出

バーコードリーダーが見えるようになったので、正当なカードを取り込み、予期しない入力としてシフトして基本的なファズィングを試みました。カードをセンサーに置くとデバイスは音を鳴らし、その後関連画像を発表します。

ファズィング中、さまざまな画像が報告され、すべてはデッキ内の他のカードと一致していましたが、ロボットが「お風呂に入って!」と言い出しました。これは奇妙で(少し)不快でしたので、デッキを調べましたが、お風呂のイメージを持つカードは見当たりませんでした。カードを固定したままボタンを押すと、ロボットは歌い始め、この画像を描きました。


目標

作業対象を把握した今、次の2つのゴールを設定しました:

  1. 利用可能なすべての描画を列挙し、特定する。
    カードだけでは全貌が分かりません。

  2. Bird on It™ を実装する(つまり、これらの描画がどのように表現・保存されるかを解明し、その情報を使って自分で追加できるようにする)。

コンポーネント

次にボード上の部品を特定し、取得/ダンプできるものを確認します。主な3つは以下です:

  • LKS32MC07x
    – ARM Cortex‑M0 MCU
  • uc25IQ64
    – 64 MB SPI NORフラッシュ
  • uc25IQ128A
    – 128 MB SPI NORフラッシュ

私は64 MBフラッシュをSPI経由でダンプできましたが、128 MBフラッシュは取得できず、MCUにSWDで接続することもできませんでした。良いスタートではありませんが、諦めません。

バーコード解析

マルチメータと印刷されたトレース線を使って、バーコードを読み取る光学センサーの配線をマッピングし、どのカードが挿入されているか判定します。最初はセンサーとピンに重複があることに困惑しましたが、入力マルチプレクシングという概念に出会いました。基本的にはボードはVCC 1でセンサー1〜5を電源供給し、その後入力ピンの値を読み取ります。その後VCC 2でセンサー6〜8を電源供給し、同じ入力ピンを再利用して値を読み取ります。

理論を検証するためにロジックアナライザを各入力に接続しました。元の赤いワイヤーコネクタはカラ―コード付きの独自製作に置き換え、ブレッドボードとヘッダーで2行に分けました。このセットアップにより受動解析と積極的信号操作を同時に行うことができました。

VCCラインが定期的に交互に変化する様子を確認し、マルチプレクシング理論の説得力を高めました。Saleae に接続した状態でカードをスキャンすると、期待通りの振る舞いを観察できます。

00000001
のバーコード値に対応するカード(クラブカード)を選びました。右側センサーが HIGH になるはずですが、裏面では逆になっているため左側センサーが HIGH になります。

VCC 1フェーズでセンサー1〜5が電源供給され、ピンが読み取られます。左側(センサー1)が唯一の HIGH (1) です。他は LOW (0)。次に VCC 2 フェーズでセンサー6〜8が電源供給され、再びピンを読み取り、バーコードの最後の3ビットを構成します。最終的な値は

00000001
となります。

VCCトリガーを逆順(VCC 2→VCC 1)で示したものもありますが、処理は何度か繰り返されるため順序は重要ではありません。


バーコードエミュレーション

バーコードが信号に変換される仕組みを理解したので、プログラム可能な入力形式でエミュレートできます。Raspberry Pi を使用しました(3.3 V で動作し、この用途に最適)。

まずセンサー基板の各関連ピンを Pi の GPIO ピンにマッピングします。実際にはボードを電源供給する必要はないので、入力として扱い、パワーサイクルを追跡して「どのセンサーセット」が読み取られているか、そしてそれがバーコードの何ビットに対応するかを知ります。

すべてを配線した後、次のスクリプトでロジックを書きました。10進数値 1〜256 をループし、2進数へ変換し、それを2つのグループに分割して VCC マルチプレクシングフェーズに応じた GPIO ピンに書き込みます。

import gpiod
import time

chip = gpiod.Chip("gpiochip0")

# inputs:
vcc1 = chip.get_line(23)
vcc2 = chip.get_line(5)
vcc1.request(consumer="vcc1", type=gpiod.LINE_REQ_DIR_IN)
vcc2.request(consumer="vcc2", type=gpiod.LINE_REQ_DIR_IN)

# outputs:
outputs = chip.get_lines([2, 3, 4, 17, 27])
outputs.request(consumer="barcode", type=gpiod.LINE_REQ_DIR_OUT)

try:
    for bcode in range(1, 256):
        bits = [int(b) for b in format(bcode, '08b')]
        group1 = bits[-5:][::-1]   # sensors 1‑5
        group2 = bits[:-5][::-1]   # sensors 6‑8

        last_vcc1 = 0
        last_vcc2 = 0
        start = time.time()

        while time.time() - start < 4:      # 各バーコードを 4 秒間保持
            v1 = vcc1.get_value()
            v2 = vcc2.get_value()

            if v1 == 1 and last_vcc1 == 0:   # VCC 1 上昇エッジ
                outputs.set_values(group1)
                time.sleep(0.02)
                outputs.set_values([1, 1, 1, 1, 1])

            if v2 == 1 and last_vcc2 == 0:   # VCC 2 上昇エッジ
                outputs.set_values(group2 + [1, 1])
                time.sleep(0.02)
                outputs.set_values([1, 1, 1, 1, 1])

            last_vcc1 = v1
            last_vcc2 = v2

        outputs.set_values([1, 1, 1, 1, 1])
        time.sleep(2)

except KeyboardInterrupt:
    outputs.set_values([1, 1, 1, 1, 1])
    outputs.release()
    vcc1.release()
    vcc2.release()

多くの試行錯誤、ロジック解析、配線確認と呪文を繰り返してこのポイントに到達しました。


画像列挙

「lookup」ファイルでスクリプトを修正し、数値とともにテキストも出力できるようにしました。これで奇妙なものや「チェーンブロック」と呼ばれるものを描画できます。

$ python3 all-barcodes.py
218 ([1, 1, 0, 1, 1, 0, 1, 0])
218: chain block?

これで、カードにない「隠し」画像も見つけることができました。以下は利用可能なすべての画像です。ロボットと一緒に提供されるカードは 1〜100 の画像のみを含み、それ以降は謎めいた隠しボーナスです。


描画解析

自分で画像を描くには、画像がどのように表現・保存されているか、そして上書きできるかを理解する必要があります。最初に開封したとき、小さい方のフラッシュチップだけダンプできたので、そこに画像ファイルがあると仮定して解析しました。HEX 出力はディレクトリエントリーのレイアウトと数値ファイル名を含んでいるようでした。

典型的なディレクトリエントリー(32 バイト)は次の通りです:

┌───────────────┬──────────────┬─────────────┬─────────────┬──────────────────────────┐
│ CRC / checksum│ START offset │   SIZE      │   FLAGS     │   NAME (ASCII, 16 bytes) │
│   (uint32 LE) │  (uint32 LE) │ (uint32 LE) │ (uint32 LE) │   null‑terminated        │
└───────────────┴──────────────┴─────────────┴─────────────┴──────────────────────────┘

例:

001.f1a
のディレクトリエントリーは

  • CRC:
    0xD243AE42
  • START offset:
    0x004520
  • SIZE bytes:
    0xFAC
  • FLAGS / unk:
    0x0000FF02
  • NAME:
    '001.f1a'

これを基に Logic の HLA を使い、SPI フラッシュの読み取り操作を検出し、fast_read から取得したアドレスでディレクトリエントリーと照合し、読み取られているファイル名を表示します。

ロボットが画像 105 を描いた際は

Y105.f1a
が読み込まれました。音声ファイルもいくつか読み込んだため、大きなフラッシュチップに描画データが格納されていると判明しました。


フラッシュ抽出

128 MB のフラッシュを BusPirate で取り外し、抽出しました:

$ sudo flashrom -p buspirate_spi:dev=/dev/ttyUSB0,spispeed=1M -r UC25IQ128_3.bin

内容は構造化されており、おそらく座標ベースの描画データです。LLM で解析した結果、16 MB 読み取りを強制すると254 個の画像が確認できました。


生データ → SVG

Python スクリプト

img_carver.py
は各画像スロットを解析し SVG を書き出します:

def write_svg(strokes, out: Path, flip_y=True, stroke_w=2):
    bb = bbox(strokes)
    if not bb:
        return False
    xmin, ymin, xmax, ymax = bb
    w, h = xmax - xmin + 1, ymax - ymin + 1
    with out.open("w", encoding="utf-8") as f:
        if flip_y:
            f.write(f'<svg xmlns="http://www.w3.org/2000/svg" viewBox="{xmin} {ymin} {w} {h}" '
                    f'width="{w}" height="{h}" stroke="black" fill="none" stroke-width="{stroke_w}">\n')
            f.write(f'  <g transform="translate(0,{ymin + ymax}) scale(1,-1)">\n')
            for s in strokes:
                f.write('    <path d="M{},{} {}"/>\n'.format(
                    s[0][0], s[0][1], " ".join(f"L{x},{y}" for x, y in s[1:])))
            f.write('  </g>\n</svg>\n')
        else:
            # … (non‑flipped version omitted)
    return True

実行例:

$ python3 img_carver.py UC25IQ128_forced.bin --no-flip-y --out svgs
Exported 254 SVGs to svgs from 279 slots …

SVG → スロット

単一画像を上書きするために

svg_fit_to_slot.py
を作成しました。手順は:

  1. 既存スロットを読み込み、バウンディングボックスを取得。
  2. SVG を連続ストロークにサンプリング。
  3. ストロークをターゲットバウンディングボックス内に量子化。
  4. 0xEA5C バイトペイロード形式に再パック。
$ python3 svg_fit_to_slot.py slot_006_content.bin whisky-outline.svg \
    --out slot_006_new_content.bin --step 6.0 --margin 4
[info] target bbox (from slot): x[56..1124], y[176..1005]
[done] wrote slot_006_new_content.bin (59996 bytes).

新しいバイナリをフラッシュへ書き戻します:

$ dd if=slot_006_new_content.bin of=UC25IQ128_trunc_mod.bin bs=1 seek=$((0x000493E4)) conv=notrunc

$ sudo flashrom -p buspirate_spi:dev=/dev/ttyUSB0,spispeed=250k -f -w UC25IQ128_trunc_mod.bin -VV

フラッシュをロボットに再装着すると、新しい描画が正しく表示されます。


今後の作業

  • SVG → フラッシュ書き込み → GPIO で描画トリガーするパイプラインを自動化。
  • 音声ファイル(カスタム WAV/ADPCM のように見える)を解析・置換。
  • より簡単にフラッシュへアクセスできるロボット本体の再設計や新規構築を検討。

このプロジェクトを再度取り掛かる、または別のターゲットを選んで尊敬しつつ「解剖」する場合は、随時更新します。ハッキングを楽しんでください!

Jessie Chab
リサーチコンサルティングディレクター

同じ日のほかのニュース

一覧に戻る →

2026/01/17 2:16

東ドイツのバルーン脱走(「East Germany Balloon Escape」)

## Japanese Translation: (すべての重要ポイントを含む)** この物語は、1979年9月16日に東ドイツから西ドイツへと2家族が自作熱気球で大胆に脱出したことを記述しています。目的地は西ドイツ近郊のナイラで、計画には18か月以上の準備が必要でした:3つの熱気球、800 m² のタフタ素材、2本のプロパンタンク、ブロワー、および家庭用ガスボトルから作ったバーナー。7月3日の以前の試行では、熱気球は国境から180 m 先に着陸し失敗しましたが、その朝、当局は放置された装備を発見しました。 9 月の飛行は28分間続き、高度2,500 m に達し、西ドイツへと横断。最終的に1 人だけ怪我(ウェッツェルの足首骨折)で着陸しました。この脱出直後、東ドイツは国境警備を強化しました:小型空港が閉鎖され、プロパンや布地の購入も厳しく管理されました。 飛行後、ストレリク兄弟はポツダムで逮捕され、ストレリクと彼女の妹マリア、そしてその夫は2年半の刑を受けましたが、アモニティ・インターナショナルの圧力により後に釈放されました。家族はナイラに定住し(ウェッツェルは自動車整備士、ストレリクはテレビ修理店を経営)、1985 年にスタジが脅迫したためスイスへ移住しました。1990 年のドイツ統一後、再びポエスネックに戻りました。 この物語はディズニー映画「ナイト・クロッシング」(1982)やマイケル・ヘルビグの「バルーン」(2018)、BBC Outlook および PBS Nova のドキュメンタリーにもインスピレーションを与えました。2017 年には、レゲンブルクにあるハウズ・デア・バイエリッヒェン・ギセヒト博物館で熱気球が常設展示され、同年ピーター・ストレリクは長い病気の後に74 歳で亡くなりました。 この改訂された概要は、リストからすべての主要ポイントを取り入れつつ、明確かつ曖昧さのない表現を保っています。

2026/01/16 23:25

**Cloudflare が Astro を買収** Cloudflare は、Astro の買収を発表し、エッジコンピューティング機能を拡充するとともに、ウェブパフォーマンス市場での地位を強化しました。今回の取引は、Astro の技術を Cloudflare のサービス群へ統合することが見込まれ、顧客にはモダンな Web アプリケーション向けに高速・セキュリティ・信頼性が向上したソリューションが提供されます。

## Japanese Translation: Cloudflare は公式に Astro のフルタイムチームを吸収し、同社は全リソースをオープンソースの Astro フレームワークの開発と保守に注力できるようになりました。これにより Cloudflare のグローバルインフラストラクチャを活用しつつ、Astro はウェブ体験の中心にコンテンツを置くというビジョンを共有する長年のスポンサーシップに続くパートナーシップが実現します。 Astro は MIT ライセンスであり、オープンガバナンスモデルに従い、任意のプラットフォーム上で無料で利用できます。採用率は毎年倍増しており、ほぼ 100 万件の週次ダウンロードが Webflow、Wix、Microsoft、Google などのサイトを支えています。ホストされたプリミティブ、Astro DB、または e‑commerce レイヤーによる収益化試みは成功せず、コアフレームワークから注意が逸れました。 Astro 6 beta は既に公開されており、チームは正式リリースを計画し、その後 2026 年のロードマップでコンテンツ主導型ウェブ構築、パフォーマンス、スケーラビリティ、信頼性、および開発者体験(特に AI コーディングツールが登場する中)を強調します。この協力関係により Astro は有料エコシステムモデル(ホスティングや CMS)を追求することを止め、コンテンツ中心のウェブサイト向けフレームワークの改善に専念できます。 結果として、さらに高速で信頼性の高いオープンソース ソリューションが実現し、ベンダー非依存のままで開発者と企業はベンダーロックインなしで高性能サイトを構築できるようになり、ウェブエコシステム全体にわたってパフォーマンス、スケール、信頼性、および開発者体験が向上します。

2026/01/17 7:15

## Install.md LLM実行可能ファイルのインストール規格。

## Japanese Translation: **install.md** は、AI アシスタントがソフトウェアインストール手順を自動的に読み取り実行できる軽量 Markdown フォーマットであり、手動設定を排除します。 ファイルはプロジェクトルートまたは `/docs` ディレクトリに配置されるべきです。Mintlify は `https://<your-docs-url>/install.md` で自動生成しますが、開発者は必要に応じて上書きや無効化を行うことができます。 典型的な install.md はヘッダー(製品名)、説明ブロッククオート、アクションプロンプト(「[Product] をインストールしてほしい」)、**OBJECTIVE**、**DONE WHEN** の基準、TODO チェックリスト、詳細ステップセクション(コードブロック付き)および **EXECUTE NOW** コール・トゥ・アクションを含みます。 このフォーマットは言語非依存であり、バイナリ、パッケージ、スクリプトのいずれもサポートします。ステップ内の条件付きロジックにより、npm/pnpm、macOS/Linux、Arch Linux などの環境に適応できます。 Mintlify のツールは既存ドキュメントからインストール知識を自動検出し、エージェント向けの install.md を合成・ホストします。開発者はメインドキュメントを煩雑にせずにエッジケース処理を組み込むことが可能です。 ユーザーは `curl -fsSL https://www.example.com/docs/install.md | claude` のような簡単なコマンドでファイルを取得し、任意の LLM に貼り付けるか、オートノーマルエージェントへ直接パイプして実行し、ステップごとの承認を選択できます。 仕様はオープンソース(spec: installmd.org, GitHub: github.com/mintlify/install-md)であり、カスタマイズ可能です。開発者はバージョン固有ファイルのホスティングや検出ロジックの追加を行えます。 セキュリティ上の配慮として、ファイルは人間が読める形式で、ステップごとの承認を許可し、自然言語で結果を明示するため、`curl | bash` スクリプトに比べて隠れた悪意ある動作を減らします。 多くの設定オプションを必要とする高度な統合の場合は専用ウィザードがまだ優先されることがありますが、それ以外では install.md がほぼすべてのメリットを提供し、エンジニアリング労力を削減します。 任意で、`llms.txt` ファイルを install.md と併用してインストール中に追加情報やトラブルシューティング情報を提供できます。

「Drawbot:かわいいものをハックしてみよう(2025)」 | そっか~ニュース