1台100円で拾ったNFCリーダーACR1251Uを動かせるか試してみた
目次
もともとNFCリーダーが欲しかったところに、Xで秋葉原のパレットタウンがジャンクを出すという告知を見かけて買いに行った。1台100円で2台200円。買った時点では何に使うか決めておらず、後から使い道を探していた。
そこで見つけたのが、NFCで表示を書き換えるSantekの電子ペーパーサイン「EZ Sign」だった。電池を積んでおらず、NFCから電力とデータの両方を受け取って画面を書き換える。スマートフォン向けアプリだけでなくWindows対応も明記されていて、PCからNFCリーダー経由で書き込める。
ただ、公式がWindows用の推奨リーダーとして挙げているのはSony RC-S300で、手元のACS製リーダーの名前は出てこない。アプリがICカードリーダーの標準規格(PC/SC)経由で汎用的にリーダーを扱っていれば動くはずで、RC-S300専用の機能に依存していれば動かない。
2台200円のジャンクリーダーでNFC電子ペーパーの表示を書き換えられるなら、その組み合わせのほうが面白そうだ。
拾ってきたもの

2台とも新品同様で、うち1台は会計時に店がNFCロゴの上に貼った「毎度ありがとうございます」の黄色いシールを剥がさずそのままにしている。ケーブルは本体直付け。

筐体裏のラベルに記載されていた情報はこんな感じ。
| 項目 | 表記 |
|---|---|
| 型番 | SO-SOL122-D / P/N: ACR1251U-M3 |
| 電源 | 5VDC, 200mA |
| S/N | RR534-019046(撮影した1台) |
| 認証 | FCC ID: V5MACR1251、CE、VCCI、総務省指定 第AC-13011号 |
読み書きの相手として、NFCタグ用IC(NTAG)搭載の白いカードを10枚セットで用意した。袋のラベルは「NFCカード NTAG…書換可能 ホワイトカード 10枚セット」まで読める。NTAG213 / 215 / 216のどれかは袋からは分からないので、カードから直接読み出して確認する。

そしてEZ Sign。箱の表記は「EZ Sign 4.2 Inch E-Paper Display」、パネル裏の刻印は「Santek EZ Sign 4 Color」。

製品仕様はこんな感じ。
| 項目 | 内容 |
|---|---|
| 解像度 | 400×300ピクセル |
| 表示色 | 黒・白・赤・黄の4色 |
| 書き換え時間 | 約30秒 |
| 電源 | 電池不要、NFCから給電。書き換え後は無給電で表示を保持 |
| 対応 | iOS / Android / Windows |
| 保護等級 | IP65 |
| 厚さ | 3.4mm |
給電の問題も別にある。書き換えに約30秒かかるということは、通信規格が合うだけでなく、リーダーの高周波(RF)出力で書き換えに必要な電力を供給し続けられるかも確かめる必要がある。
検証環境
| 項目 | 内容 |
|---|---|
| PC | Windows 11 Home 10.0.26200 |
| PC/SCサービス | SCardSvr は開始前の時点で停止・手動起動 |
| NFCリーダー | ACS ACR1251U-M3 ×2 |
| NFCカード | NTAG搭載の書き換え可能な白カード 10枚セット |
| 表示デバイス | Santek EZ Sign 4.2インチ 電子ペーパー(4色) |
PC/SCは、ICカードリーダーとアプリケーションの間を取り持つWindows標準の仕組みで、対応リーダーを挿すとSCardSvr(スマートカードサービス)が自動で動いてリーダー一覧に出てくる。今回はこのPC/SC経由でリーダーを操作する。
確認する項目は次の4点。
| # | 確認すること | 満たせた判定 |
|---|---|---|
| 1 | NFCリーダーとして認識するか | リーダー名がPC/SCの一覧に出る |
| 2 | カードを読めるか | UIDとNTAGの型番が取れる |
| 3 | カードへ書けて読み戻せるか | 書いた内容がそのまま読める |
| 4 | EZ Signへ表示を書けるか | パネルの表示が変わる |
まずはリーダーの認識から順に確認していく。リーダーが見えない状態でカードの読み書きを試しても、どこで失敗したか切り分けられないからだ。
リーダーとして認識させる
ドライバを追加することなく、そのまま認識された。
接続前はPowerShellのGet-PnpDevice -Class SmartCardReaderが0件、SCardSvrサービスは停止中(手動起動)。USBポートに1台挿すとSCardSvrが実行中へ変わり、スマートカードリーダーのクラスにデバイスが1つ増えた。
| 項目 | 値 |
|---|---|
| デバイス名 | Microsoft Usbccid Smartcard Reader (WUDF) |
| ハードウェアID | USB\VID_072F&PID_222D&REV_0541 |
| USB記述子の製品名 | ACR122U for NFC |
| PC/SCのリーダー名 | ACS ACR122U for NFC 0 |
| 状態 | OK |
Windows標準のUsbccidドライバがそのまま適用されている。USB CCIDは、ICカードリーダーをUSBの標準クラスとして扱う規格で、これに沿ったリーダーはメーカー製ドライバを入れなくてもOSの汎用ドライバで動く。
ベンダーID(VID)の072FはACSで、そこはラベルの表記と一致している。一方で、USB記述子の製品名もPC/SCのリーダー名もACR122Uだった。挿した個体の裏ラベルはACR1251U-M3なので、外側の表記と中身が食い違っている。
リーダーのファームウェア版数を確認するため、カードを載せずに直接接続してACS独自のエスケープコマンド(FF 00 48 00 00)を送信した。結果は試した3つの制御コード(IOCTL)すべてでrc=0x00000001が返り、Win32のERROR_INVALID_FUNCTIONで拒絶された。エスケープコマンドはPC/SCの標準API越しにベンダー独自の低レベルコマンドをリーダーへ直接投げる仕組みだが、Windows標準のUsbccidドライバはセキュリティや互換性のため既定でこれを通さない。
型番の確定は後回しにして、先にカードの読み書きを試してみた。ACR122UとACR1251UはどちらもISO 14443 Type Aを扱うので、NTAGの読み書き自体はどちらでもできるはずだった。
カードの読み出しを試す
NTAGカードを1枚リーダーに置いて、PC/SCでカードの状態を取得した。
| 項目 | 値 | 意味 |
|---|---|---|
| eventState | 0x00020422 | カード検出(PRESENT)かつ未給電(UNPOWERED) |
| ATR | 3B 00 | 2バイト(最小形) |
ATR(Answer to Reset)は、カードに電波で給電したときにカード側から返ってくる識別用のバイト列で、カードの種別や通信条件がここに入る。正常に起動したISO 14443 Type AのNTAGカードであれば、20バイト前後の実体のある情報列が返ってくるはずだ。今回の3B 00はデータを含まない最小フォーマットで、カードから意味のある情報が取れていないことを示す。
PC/SCでSCardConnectを実行すると関数自体は成功するが、これは「PCとリーダー間の通信口が開いた」だけで、カードの起動成功を意味しない。実際にカードへ送信したAPDU(コマンド)は、すべて失敗を示すSW=63 00で返った。
| APDU | 内容 | 役割 |
|---|---|---|
FF CA 00 00 00 | UIDの取得 | リーダーへカード固有IDの問い合わせ |
FF CA 01 00 00 | ATSの取得 | リーダーへカード通信仕様の問い合わせ |
FF B0 00 00 10 | ページ0〜3の読み出し | メモリデータの読み出し要求 |
FF B0 00 04 10 | ページ4〜7の読み出し | メモリデータの読み出し要求 |
ここで使っているFFから始まるコマンドは、リーダー自身にカードの読み出しを要求するPC/SC疑似コマンドになる。応答末尾の2バイトであるSW(Status Word)は、90 00が成功、それ以外は失敗や警告を表す。すべて63 00で返るということは、リーダーがカードを捉えられていない状態を意味する。
カード検出(PRESENT)が立っているので、カード自体の存在は検出できていて、そこから起動する段階で失敗していると考えた。
未載置でもカード検出が返る原因を探る
条件を変えながら試し直した。会計時に貼られたシールを剥がしていないが、買い物で貼られるシール1枚程度で通信が変わるはずもない。実際、シールを貼られていないもう1台のリーダーに差し替えても挙動は全く同じだった。
| 変更点 | 結果 |
|---|---|
| カードをNFCロゴの中央へ置き直し、押し当てる | 変化なし |
| シールが貼られていない2台目のリーダーに差し替える | 変化なし |
| NTAGカードをマイナンバーカードに替える | 変化なし |
| カードを全部どけて、何も載せない | 変化なし |
何も載せていないのにPRESENTが返るため、そもそも「カードが検出されている」という前提自体が成り立っていなかった。
正常なリーダーであれば、カードがない時はEMPTY、カードを載せた時に初めてPRESENT + POWEREDとなり実体のあるATRが返る。しかし手元の個体は、カードの有無に関係なく常に架空のカードを載せたまま未給電(PRESENT + UNPOWEREDかつ3B 00)だと報告し続けているだけで、実際のカード検出情報は取れていなかった。
空の状態で確認していなかったら、カードの置き方や個体差を疑い続けるところだった。
2台目もハードウェアIDはUSB\VID_072F&PID_222D&REV_0541、USB記述子の製品名もACR122U for NFCで1台目と同じ。2台とも同じ型番で、挙動も同じだった。なおこの2台はUSB記述子にシリアル番号を持たないため、同じポートに挿すとWindowsのインスタンスIDまで同一になる。Windowsでは同じポートに同じ性質のデバイスを挿すと同一デバイスの続きのように扱われる場合があり、デバイスマネージャーの表示だけではどちらを挿したのか区別できない。
「リーダーとして認識される(USBデバイスやPC/SC一覧に見える)」ことと、「カードを検出できる(電波でカードに給電・起動して通信できる)」ことは全く別のレイヤーになる。リーダーとカードの通信は、次のような階層で動いている。
flowchart TD
subgraph Host["ホストPC(Windows)"]
App["アプリ / スクリプト"]
SCardSvr["Smart Card サービス<br/>(SCardSvr)"]
Driver["USB CCID ドライバ<br/>(Usbccid / ACS専用)"]
App -->|"PC/SC API(WinSCard)"| SCardSvr
SCardSvr --> Driver
end
subgraph Device["NFCリーダー(ACR1251U)"]
MCU["リーダーMCU / ファームウェア"]
end
subgraph Target["対象デバイス"]
Card["NFCカード / EZ Sign"]
end
Driver -->|"USB通信"| MCU
MCU -->|"13.56MHz RF電波(給電・通信)"| Card
手元の個体は、リーダー自体は正常に見えてWindows側からもアクセスできているのに、カードを置いても一切通信できない。現象はリーダー2台とも同じで、カードの種類にもよらず、カードの有無でも変わらない。どこまでが正常でどこからが異常なのか、ドライバ、設定、給電、ファームウェアと順に切り分けていくことにした。
ACS純正ドライバを入れてみる
ACS公式のACR1251UのページとACR122Uのページは、どちらも同じ「ACS Unified PC/SC Driver 4.2.8.0」を配布している。リリースは2018年3月で、配布形式はRAR形式。
インストール前に、MSIの中身を展開してacsdrv.infを確認した。INFはWindowsに対して「このハードウェアIDのデバイスには、このドライバを割り当てる」と指示する定義ファイルだ。このINFにはVID 072FのPIDが70個以上並んでいるが、手元の個体のPIDである222Dは記載されていない。
| PID | INFでの記載 |
|---|---|
| 2200 | ACR122U |
| 2218 | ACR1251U-C(PICC / SAM) |
| 2229 | ACR1251U-A2 |
| 222C | ACR1283L PICC |
| 222D | 記載なし |
| 222E | ACR123-PICC+3SAM Bus |
222Cと222Eはあるのに222Dだけ抜けている。一方、ACSがLinux / macOS向けに出しているacsccidの対応リーダー一覧には072F 222Dがあり、[OEM Reader]という名前のない枠で登録されていた。
インストール自体は成功してoem263.infとして登録されたが、デバイス側のドライバはwudfusbcciddriver.infのままで、値も変わらない。ハードウェアIDが一致しない以上、自動で適用されないのは当然だった。
同じ現象の先行例もある。ブックオフで100円のジャンクICカードリーダー(Maxell版のACR122U)を買った記録で、「カードを乗せていないのに情報を返してくる」「カードの有無に関係なく不変の値を返す」と、同じ現象が書かれている。そちらは未解決で終わっている。
ドライバを手動適用して型番を確認する
デバイスマネージャーから、互換性のあるハードウェアの表示を外して、製造元「Advanced Card Systems Ltd.」のモデル「ACR122 Smart Card Reader」を選んで割り当てた。本来はハードウェアIDが一致しなければ適用されないはずのドライバを、あえて手動で割り当てる操作になる。異なる機種用のドライバを手動で割り当てる行為は本来自己責任の操作だが、今回は比較用にもう1台の正常個体がある前提なので検証として試した。互換性の警告は出るが、インストールはできた。
ここで、さっき弾かれたエスケープコマンドが通るようになった。エスケープ送信用制御コード3500にFF 00 48 00 00を送信すると、文字列が返ってきた。
ASCII: ACR1251U_V541.00
中身は ACR1251U で、筐体のラベルと一致した。USBのハードウェアIDにあったREV_0541も、このファームウェア版数V541.00と対応している。USB記述子の製品名がACR122U for NFC、PIDが222DというOEM仕様の個体で、外側の型番表記のほうが正しかった。
エスケープが通るので、内部設定も取得できた。
| 項目 | コマンド | 応答 | 意味 |
|---|---|---|---|
| ファームウェア | E0 00 00 18 00 | ACR1251U_V541.00 | ACR1251U系 |
| PICC動作パラメータ | E0 00 00 20 00 | 07 | Type A / Type B / Topaz が有効 |
| 自動PICCポーリング | E0 00 00 23 00 | 8F | ポーリング有効 |
| アンテナ状態 | E0 00 00 25 00 | 00 | オフ |
アンテナがオフなら、カードの検出も給電もできない。E0 00 00 25 01 01でオンにすると応答は01に変わり、読み直しても01のままになる。
それでもカードは認識しなかった。ATRは3B 00、UIDもページ読み出しもSW=6300で、ドライバを替える前と同じ。アンテナをオンにしても状況は変わらず、オンオフは直接の原因ではなさそうだった。
ACR1251U用ドライバの再適用
割り当てたのがACR122U用のセクションで、実体はACR1251Uなので、非接触スロットの制御が合っていない可能性もある。同じ手順でモデルだけ「ACR1251 CL Reader PICC」に替えてみた。
リーダー名はACS ACR1251 CL Reader PICC 0に変わったが、ATRもAPDUの応答も変わらない。
設定領域をE0 00 00 xx 00の形式で0x10から0x40まで読み出すと、応答があったのは次の項目だった。
| 項目 | コマンド | 応答 | 意味 |
|---|---|---|---|
| ファームウェア | E0 00 00 18 00 | ACR1251U_V541.00 | ACR1251U系ファームウェア |
| PICC動作パラメータ | E0 00 00 20 00 | 07 | 有効プロトコル |
| ポーリング設定 | E0 00 00 21 00 | 8F | ポーリング間隔 |
| 自動PICCポーリング | E0 00 00 23 00 | 8F | 自動検出有効 |
| アンテナ状態 | E0 00 00 25 00 | 01 | アンテナオン |
| RF系レジスタ | E0 00 00 2F 00 | 11 85 85 85 85 A5 A5 A5 A5 69 … | RF制御レジスタ値 |
| しきい値設定 | E0 00 00 3F 00 | 2F 55 69 3F 2F 55 69 3F | 受信しきい値 |
マイコン(MCU)とUSB側は正常に応答していて、設定の読み出しや書き換えも反映される。にもかかわらず非接触カード側だけを検出しない。無効化を示す設定値も見当たらなかった。
LEDとブザーを直接制御してみる
本体の挙動も確認した。ACS製リーダーは既定でカード検出時にブザーが鳴るが、カードを載せても鳴らない。LEDはカードの有無に関係なく点滅し続けている。
ACS公式の技術仕様書(ACR1251U Technical Specifications V1.11)を読むと、LEDもブザーもホストから直接制御する部品だと記載されている。そのため点滅自体は異常表示とは限らない。こちらから鳴らす指示を出せば、ブザーが無音なのは壊れているからなのか、カードを検出していないから鳴らないだけなのかを切り分けられる。
| 指示 | コマンド | 応答 | 実機の様子 |
|---|---|---|---|
| LED赤 | FF 00 40 50 04 00 00 00 00 | 90 00 | 赤く点灯した |
| LED緑 | FF 00 40 A0 04 00 00 00 00 | 90 00 | 緑に点灯した |
| LED点滅+ブザー | FF 00 40 D0 04 05 05 04 03 | 90 02 | 色が一瞬変わった(音は鳴らない) |
| LED消灯 | E0 00 00 29 01 00 | 01 00 | 消灯した |
LEDは指示どおりに色が変わり、消灯もした。一方、ブザーは直接鳴らす指示を出しても無音のままで、直接制御のコマンドに対しても音が出なかった。物理的な故障か、そもそもOEM基板でブザー部品が未実装である可能性が高い。
LEDは動作し、ブザーとRF側は応答しない。ラベルにあるSO-SOL122-DというOEM向けらしい型番と合わせると、ブザーとアンテナが実装されていないOEM基板の可能性も考えられる。ケースを開けて基板を確認すれば早いが、この個体にはネジ穴も、工具を差し込める隙間もないため、基板破損を避けて分解は見送った。
2台目の個体確認と本体直挿しでの検証
ドライバを当てたのは挿していた1台だけだったので、同じポートへ挿し替えて確認した。シリアル番号を持たないため、インスタンスIDが同じままACSのドライバを引き継ぐ。
| 項目 | 2台目 |
|---|---|
| ファームウェア | ACR1251U_V541.00(1台目と同一) |
| アンテナ状態(挿した直後) | 00 |
| アンテナをオンにした後 | 01 |
| カード読み取り | ATR3B 00、SW=6300 |
挿した直後のアンテナが00だったので、1台目で01にした設定はその個体に残っていたことになる。入れ替えたこと自体はこれで確認できたが、結果は変わらなかった。
LEDの点灯挙動も途中で変化したが、個体差による違いではなかった。アンテナをオンにした直後は点灯に変わり、しばらくすると元の点滅に戻る。2台とも同じ挙動を示している。LEDや設定書き込みが通っていることから、MCUの制御までは正常に動いている。
給電も疑った。ここまでドッキングステーション経由で挿していて、このリーダーは5VDC 200mA、高周波のRF磁界(搬送波)を出力する部分で消費が大きい。ハブ側の給電が足りなければ、MCUとUSBは動くのにRF回路だけ立ち上がらない、という現象とも辻褄が合うと考えた。
PC本体のUSBポートへ直挿しして確認し直した。ポートが変わるとインスタンスIDも変わるため、ドライバを再適用して検証したが、結果は変わらず給電不足の可能性もなくなった。
スマートフォンで電波の有無を確認する
ここまで「カードを検出しない」ことは分かっていたが、電波が出ていないのか、出ているが受信できないのかを区別できていない。リーダー自身の報告だけを見ていたからで、外から測る手段がいる。
スマートフォンが使える。NFC対応の端末は外部の磁界に入ると反応するので、リーダーの面に載せて反応を確認すれば、リーダー側の応答とは独立した判定になる。
先に未試行だったコマンドも確認した。
| 試したもの | 結果 |
|---|---|
E0 00 00 40 の読み書き | 応答は空。設定として存在しない |
PN532用ダイレクトコマンド FF 00 00 00 02 D4 32 | 63 00。ACR1251UはPN532系ではないため想定どおり |
そのうえで、アンテナを10秒間オンに保持した状態でスマートフォンを載せてみた。ウォレットアプリも先に起動しておいた。
載せてみたが反応はなく、決済画面も出ず、振動や検出音も鳴らなかった。
アンテナ設定が01を返すのに、13.56MHzの電波が実際には出ていない可能性が高い。送信段が故障しているか、ファームウェアが実際には発振させていない可能性が考えられる。
裏面スイッチによる書き換えモードの起動
筐体の裏に、リセットのように見える小さなスイッチがある。通常どおり挿した状態で押しても、PC/SCの値は何も変わらなかった。
ACSのドライバINFにはACR1281 USB FW_Upgrade v100というファームウェア書き換えモード用のデバイス登録がある。ACS製リーダーには、ボタンを押しながら挿すと書き換えモードで起動するものがある。そこで、スイッチを押したままUSBへ挿して、3秒ほど押し続けてから離してみた。
| 項目 | 通常モード | スイッチを押しながら挿したとき |
|---|---|---|
| ハードウェアID | USB\VID_072F&PID_222D | USB\VID_072F&PID_220B |
| デバイス名 | ACR1251 CL Reader PICC | ACR1281 USB FW_Upgrade v100 |
| カード状態 | PRESENT + UNPOWERED | EMPTY |
| ATR | 3B 00 | なし(cbAtr=0) |
スイッチの正体はファームウェア書き換えモードのボタンで、このモードではカード状態がEMPTYと正しく返った。
常時検出されていた架空のカード反応は、通常モードで動いているファームウェア側の挙動だったことになる。ハードウェアが完全に故障しているというより、書き込まれているファームウェアが非接触側を正常に動作させていない可能性が考えられる。
ファームウェアを書き換える手段はある。2台あるため、片方を書き換え検証に使い、もう片方をV541.00のまま比較用として残す方針にした。
ファームウェアの入手先を探してみる
ACS公式には、ファームウェア本体も書き換えツールも置かれていない。公開ツールの一覧13件にも無く、archive.orgにも過去の配布物は残っていなかった。入手は問い合わせ経由になる。
NTTコミュニケーションズが配布しているものが見つかった。公的個人認証サービス向けにOEM版のACR1251を配っていて、そのファームウェア一式が登録なしでダウンロードできる。中身はACS純正の「ACR1251 FW Update Tool」と、ファームウェア本体のPatch/Patch.hexだった。
| ファイル | 対象FW版数 |
|---|---|
| ACR1251CL_FW431.2.zip | 431.2 |
| ACR1251DI_FW713.0.zip | 713.0 |
| ACR1251DI_FW721.1.zip | 721.1 |
3種ともツールのexeはバイト単位で同一で、機種差はInitFile.iniとPatch/だけ。exe内の文字列にはTool for update ACR1251U-M2 and ACR1251U-C4 Firmware、ACS ACR1281 USB FW_UPGRADE V100、READER_AES_KEY、ReaderAuthがある。スイッチを押しながら挿したときに出たデバイス名と一致する。
ここで手元の個体の正体も確定した。acsccidの対応リーダー定義に次の1行がある。
# ACR1251U-A2
0x072f:0x222d:ACS ACR122U
222Dは「ACR122Uを名乗るACR1251U-A2のOEM品」としてACS自身が定義していた。ラベルのACR1251U-M3、ファームのACR1251U_V541.00、USBの名乗りACR122U for NFCが食い違って見えた理由が判明した。手で当てたモデル「ACR1251 CL Reader PICC」はPID 2229のACR1251U-A2用なので、選択自体も合っていた。
2025年12月版のACS純正ドライバ4.4.2.1も取得してINFを確認したが、こちらにも222Dは無い。インストールはしておらず、中身を読んだだけになる。同梱のReadMeには072F 2229 ACR1251U-A2/M2 ACS ACR1251 CL Reader PICCとあり、当てたモデルが正しいことだけが確認できた。
NTT版の初期化設定を流してみる
NTT版のPatch/Init.txtは、書き換え後にリーダーへ流す設定APDUの列だった。形式はE0 00 00 xxと同じで、ファームウェアを書き換えずに流せる。
手元の値と照らすと、一致と不一致がはっきり分かれた。
| 設定 | CL 431.2が流す値 | 手元の個体 |
|---|---|---|
2F(RF系レジスタ) | 11 85 85 85 85 A5 A5 A5 A5 69 … | 完全一致 |
3F(しきい値) | 2F 55 69 3F 2F 55 69 3F | 完全一致 |
20(PICC動作パラメータ) | 1F | 07 |
21 | 57 | 8F |
23(自動PICCポーリング) | 8B | 8F |
RF系のレジスタ値が完全一致しているので、ハードがCL系(ACR1251U-A2)だとここでも確認できた。そのうえで動作パラメータとポーリング設定が正規の初期化列と違う。20の07はType A / Type B / Topazだけで、正規の1FはFeliCa 212 / 424まで有効にする値になる。
設定の書き込みだけなら戻せるので、そのまま流した。書き込みはすべて受け付けられ、読み戻しでも変化した。
| 設定 | 適用前 | 適用後 |
|---|---|---|
08 | FF FF | 11 FF |
20 | 07 | 1F |
21 | 8F | 57 |
23 | 8F | 8B |
24 | 00 00 00 00 | 02 00 02 00 |
それでもカードは読めない。しかも抜き差しして測り直すと、20は07、23は8Fへ戻っていた。NVRAMに残るタイプではなく、電源を入れ直すたびに既定値へ戻る。設定変更で対処する道も行き止まりになった。
書き換えツールでのリーダー検出エラー
残るのはファームウェアの書き換えだけになった。ただし手元は541.00で、入手できたCL版は431.2。Patch.hexは暗号化済みで、ツール側にはREADER_AES_KEYとReaderAuthがある。適当なHEXをフラッシュメモリへ流すだけの仕組みではなく、機種判定と認証を伴う正規の更新経路になっている。
焼く前に、ツールが個体をどう認識するかだけ確認した。画面に出たのはこれだけだった。
| 項目 | 表示 |
|---|---|
| Reader モデル | ACR1251CL-NTTCom |
| Reader Name 選択 | ドロップダウン1件 |
| ボタン | 再表示 / 更新 |
現在の版数も対象の版数も表示しない。リーダーを選んで更新を押すだけのツールだった。ドロップダウンの中身はACS ACR1251 USB FW_UPGRADE V100 0の1件のみ。手元の個体がPC/SCへ出している名前はACS ACR1281 USB FW_Upgrade v100 0で、1251と1281で数字が違う。
ここで「ツールは実機を検出しておらず、exeに埋め込まれた候補名を並べているだけだ」と推測した。
名前を合わせにいった。exeの文字列をUTF-16で抜き出すと、探している名前が両方入っている。
0x00AF92 ACS ACR1281 USB FW_UPGRADE V100
0x00AFD2 ACS ACR1251 USB FW_UPGRADE V100
どちらも31文字なので、複製したexeの該当2箇所を実機の名前へ置き換えた。バイト数は変わらない。ドロップダウンにはACS ACR1281 USB FW_Upgrade v100 0が出るようになり、リーダーを抜いて再表示すると選択肢が消えるので、実際に列挙していることも確かめた。
通常モードで渡す線も試した。exeにはRun Change to Upgrade Modeという文字列があり、ツール自身が通常モードのリーダーを書き換えモードへ切り替える作りになっている。通常モードでのリーダー名ACS ACR1251 CL Reader PICC 0は、PID 2229のACR1251U-A2が名乗る名前そのもので、オリジナルのツールでもドロップダウンに出た。
結果はオリジナル・パッチ版、ブートローダー・通常モードの4通りとも同じで、更新を押すと「Reader検索エラー」となった。
| exe | 渡したモード |
|---|---|
| オリジナル | ブートローダー |
| オリジナル | 通常 |
| パッチ版 | ブートローダー |
| パッチ版 | 通常 |
リーダーの選択までは通るのに、更新処理の中の検索で落ちる。置き換えた2箇所は、更新処理が使っている名前ではなかった。書き込みは一度も始まっていない。
ツールを逆コンパイルして判定条件を調べる
文字列を当てずっぽうに置き換えるより、中を調べたほうが確実だった。exeは.NETアセンブリなので逆コンパイルが可能だった。SDKは入っていない環境のため、NuGetからICSharpCode.Decompilerのライブラリを取得し、PowerShellから呼び出して解析した。
解析の結果、まずツールはACR1281の名前を最初から受け入れていたことが判明した。
else if (Mid(array2[i].ToUpper(), 0, "ACS ACR1281 USB FW_UPGRADE V100".Length)
== "ACS ACR1281 USB FW_UPGRADE V100".ToUpper())
{
cmbICC.Items.Add("ACS ACR1251 USB FW_UPGRADE V100" + array2[i].Substring(...));
}
ACS ACR1281 …のリーダーを見つけると、表示だけACS ACR1251 …に差し替えてリストへ入れ、選択時に元へ戻している。最初にブートローダーモードで見えたACS ACR1251 USB FW_UPGRADE V100 0は、固定文字列ではなく手元の個体だった。名前が合わないという読みは外れていた。exeの文字列を書き換えたパッチは、比較にも同じリテラルが使われているので、むしろ判定を壊していた。
次に、実際に弾いていたのはファームウェアの版数だった。更新処理は最初にリーダーへE0 00 00 18 00を投げ、返ってきた文字列から機種名と版数を切り出して判定する。
text = ASCII.GetString(array, 5, 7); // "ACR1251"
text2 = ASCII.GetString(array, 15, len - 15); // "541.00"
num = Convert.ToInt32(text2.Substring(0, 3), 16); // 0x541
// C4版: (num & 0x700) == 0x700 を要求(7xx系)
// M2版: (num & 0x700) == 0x400 を要求(4xx系)
手元は0x541 & 0x700 = 0x500で、どちらにも該当しない。判定処理は16進数の上位桁をマスク(& 0x700)して版数の系統を調べており、InitFile.iniのReader#ACR1251CL-NTTCom#は内部でM2扱いになるため、要求されるのは4xx系(0x400)だった。名前ではなく版数の系統で弾かれていた。
また、ブートローダーモードで始めても失敗する理由も判明した。版数判定の直後に、通常モードのリーダーを書き換えモードへ切り替えるコマンドを必ず送る。すでにブートローダーで起動している個体にこれを投げても通らない。そのため通常モードでは版数、ブートローダーでは切り替えコマンドで、どちらも同じエラーに落ちていた。
なお、AES鍵はexeの中の定数だった。READER_AES_KEYもPC_AES_KEYも直書きで、個体ごとの秘密ではないため、認証処理も通りそうだという見込みが立った。
版数判定を1バイト書き換える
通すには版数判定を外すしかない。該当のILはldc.i4 0x700、and、ldc.i4 0x400の並びなので、複製したexeの最後の定数を0x500へ書き換えた。バイト列20 00 07 00 00 5F 20 00 04 00 00の中の1バイトだけで、該当は0x003927の1箇所。なお、バイナリの直接改変や異種ファームウェアの書き込みはデバイスを文鎮化(brick)させるリスクがあり、今回は壊れてもよい検証用個体での自己責任の実験になる。
通常モードで起動し、リーダーを選んで更新を押すと、今度は確認ダイアログが出た。
現在のバージョン: 541.00
更新後: 431.2(実際はダウングレード)
更新しますか?
実機から読んだ版数が出ている。はいを押すと、ツールが書き換えモードへ切り替え、認証を通し、書き込みまで進んで正常終了した。
| 項目 | 書き換え前 | 書き換え後 |
|---|---|---|
| USB PID | 222D(名前のないOEM枠) | 2229(正規のACR1251U-A2) |
| ファームウェア | ACR1251U_V541.00 | ACR1251U_V431.2 |
| PICC動作パラメータ | 07 | 1F |
| 自動PICCポーリング | 8F | 8B |
| シリアル番号 | 空 | 値が返る |
USB PIDが222Dから2229に変わったのは、書き込まれたファームウェアが「正規のACR1251U-A2」としてWindowsに名乗り出るようになったためだ。単に設定が変わっただけでなく、OSから見たデバイス種別そのものが正規版へ入れ替わったことになる。
設定を流したときは電源を切ると既定値へ戻っていたが、今度は保持されている。
書き換えの手順と、今回使ったPowerShellのスクリプト一式は LiltingChannelLabo に置いた。ファームウェア本体とツールは再配布していないので、NTTの配布ページから取得する形になる。
NTAGカードの読み出し
NTAGカードを載せて読み直した。
ATR : 3B 8F 80 01 80 4F 0C A0 00 00 03 06 03 00 03 00 00 00 00 68
UID (FF CA 00 00 00) SW=90 00 DATA=04 74 9C 82 20 24 90
page 00-03 SW=90 00 DATA=04 74 9C 64 82 20 24 90 16 48 00 00 E1 10 3E 00
page 04-07 SW=90 00 DATA=03 00 FE 00 00 00 00 00 00 00 00 00 00 00 00 00
ATRはPC/SC標準のストレージカード用の形で、中身はISO 14443A part 3。UIDの先頭04はNXP製を示す。
NTAGのようなメモリカードは、メモリを4バイト単位の「ページ」として管理する。ページ0〜3にはUIDやメーカー情報、容量情報が置かれ、ユーザーデータの読み書きはページ4以降で行う。
ページ3のE1 10 3E 00は容量情報(Capability Container)で、最後の0x3E(10進数で62)に8を掛けた62 × 8 = 496バイトがNDEFの利用可能領域になる。袋の表記では読めなかったチップの型番が NTAG215 と確定した。ページ4の03 00 FEは中身が空のNDEFで、未書き込みのカードだった。
本体のLEDも変わった。書き換え前はカードの有無に関係なく点滅し続けていたが、書き換え後はカードを載せると点灯し、載せていないときはゆっくり点滅する。点滅が正常なポーリング表示ではなく異常側の表示だったことが、ここではっきりした。
NTAGカードへの書き込みと読み戻し
NDEFでURIレコードを組んで、ページ4から書いた。書いたのはhttps://lilting.ch/。NTAGへの書き込みは1ページ4バイト単位で、FF D6 00 <ページ> 04 <4バイト>を並べる。
| ページ | 書いた値 |
|---|---|
| 04 | 03 10 D1 01 |
| 05 | 0C 55 04 6C |
| 06 | 69 6C 74 69 |
| 07 | 6E 67 2E 63 |
| 08 | 68 2F FE 00 |
各ページの書き込み応答はいずれも 90 00 だった。
読み戻しも一致した。
page 04-07 : 03 10 D1 01 0C 55 04 6C 69 6C 74 69 6E 67 2E 63
page 08-0B : 68 2F FE 00 00 00 00 00 00 00 00 00 00 00 00 00
並びの意味は、03がNDEFのTLV、10が長さ16バイト、D1 01 0C 55がURIレコードの見出し、04がhttps://を表す短縮コード、続く11バイトがlilting.ch/のASCII、FEが終端になる。
スマートフォンでも読めるか試したが、こちらは画面に何も出なかった。カードをリーダーから離し、画面をオンにして背面を当てても変化しなかった。カード側の中身はリーダーから規格どおりに読み戻せているため、スマートフォンのアンテナ位置や読み取り側の要因が考えられる。
マイナンバーカードでの読み取り確認
NTAGはISO 14443 Type Aのメモリカードで、系統が1つしか確かめられていない。書き換え前に反応しなかったマイナンバーカードを使い、ISO 14443-4のICカードも認識できるか確認した。
15秒間の状態変化を監視しながらカードを載せた。
[PRESENT] ATR = 3B 88 80 01 00 4B 51 FF B3 81 D1 00 0F
3B 00ではない実体のあるATRが返ってくる。続けてUIDもSW=90 00で取れた。
ページ読み出しはSW=63 00で失敗するが、これは正しい動作になる。FF B0はNTAGのようなメモリカード用の命令で、ISO 14443-4のICカードには通らない。ATRとUIDが取れている時点で、別系統のカードも認識できていることになる。
カードを載せていないときはEMPTY、cbAtr=0。幽霊カードも消えた。
EZ Signとの通信確認
リーダーが動くようになったので、EZ Signをそのまま載せてみた。電池を持たずNFCから給電する仕組みなら、リーダーから見れば1枚のカードとして出てくるはずで、出てくれば通信の入口は開いていることになる。
載せると検出された。
| 項目 | 値 |
|---|---|
| ATR | 3B 86 80 01 90 DE 33 01 1E 03 66 |
| UID | DE 33 01 1E |
| ATS | 0B 78 00 A0 02 90 DE 33 01 1E 03 |
| 種別 | ISO 14443-4 Type A、最大フレーム256バイト |
ISO 14443-4ということは、APDUで通信できる相手になる。標準的な問い合わせを投げると、NFC Forum Type 4タグとして応答した。Type 4は、NDEFをファイルとして読み書きする形式で、アプリケーションを選択してから容量情報ファイルを読み、そこに書かれたファイルIDでNDEF本体を読む。
SELECT NDEF App (D2760000850101) SW=90 00
SELECT CC (E103) SW=90 00
READ CC 00 0F 20 01 00 00 FA 04 06 E1 04 01 F4 00 00
容量情報を展開すると次のようになる。
| 項目 | 値 |
|---|---|
| マッピング版 | 2.0 |
| NDEFファイルID | E104 |
| 最大NDEFサイズ | 500バイト |
| 読み出し権限 | 00(制限なし) |
| 書き込み権限 | 00(制限なし) |
| 現在のNDEF長 | 0バイト |
書き込み権限は開いている。テキストのNDEFを書いて、表示が変わるか確認した。
| コマンド | 応答 |
|---|---|
| NDEF長を0にする | SW=6A E1 |
| NDEF本体を書く | SW=90 00 |
| NDEF長を17にする | SW=6A E2 |
| 読み戻し | NDEF長は0のまま |
本体への書き込みは受理されるのに、長さフィールドの更新だけ拒否される。NDEFファイルへデータを書き込めても、その長さを正式に更新できなければタグとして中身を読み出すことができない。しかも6A E1と6A E2はISO 7816の標準にないコードで、EZ Signが標準的なType 4層の上に独自の手順を乗せて制御していることを示している。表示も変わらなかった。
そもそも容量の桁が合わない。400×300を4色で持つと、1画素2ビットの生データでも400 × 300 × 2 ÷ 8 = 30,000バイトになる。500バイトのNDEF領域とは2桁違うので、画像がここを通るはずがない。標準のType 4層と、表示を書き換える経路は別系統だと考えるのが自然になる。
そこでEZ Signが対応する命令の一覧を調査した。CLAとINSを総当たりして、「命令未対応」以外を返すものを拾う。消去やレコード更新、ファイル削除といった破壊的な標準命令は除外した。
| CLA | INS | 応答 |
|---|---|---|
| 00 | 20 | 6A86(VERIFY。P1/P2が違う) |
| 00 | 84 | 6700(GET CHALLENGE。長さが違う) |
| 00 | B0 | 6986(READ BINARY。選択中のファイルがない) |
| 00 | D1 | 9000 + データ |
| 00 | D5 | 9000 + 00 |
INS=D1が返してきたのはTLV形式のデバイス情報だった。
A0 07 F0 07 20 02 58 01 90
A1 07 01 12 00 30 FF FF FF
B1 01 08
B2 01 14
B3 01 00
C0 0A 53 45 41 42 ... ← ASCIIのシリアル番号
C1 04 DE 33 01 1E ← UIDと一致
D1 07 01 20 00 00 00 00 00
C1がUIDと一致しているので、TLVの読み方は合っている。C0はASCIIのシリアル番号。A0の中には02 58(600)と01 90(400)が見える。INS=D5は00を返すだけで、状態の問い合わせらしい。
データを伴う形でも総当たりしたが、新しく応答する命令は出てこない。画像転送の命令は、最初から見えているわけではなく手前に認証が存在していた。
| コマンド | 応答 |
|---|---|
00 84 00 00 08 | 9000 + 乱数8バイト |
00 84 00 00 20 | 9000 + 乱数32バイト |
00 20 00 01 00 | 6700(データが必要) |
00 20 00 80 / 00 81 / 01 00 | 6A86 |
GET CHALLENGEが要求した長さぶんの乱数を返し、VERIFYはP2=01のときだけ「データが足りない」と答える。チャレンジレスポンスの認証を通さないと、その先の命令は受け付けない作りになっている。
| 層 | 状態 |
|---|---|
| ISO 14443-4 | 通る。APDUで通信できる |
| NFC Forum Type 4 / NDEF | 通る。E104に500バイト、権限も開いている |
| 独自のデバイス情報・状態 | 通る。INS=D1とINS=D5 |
| 認証 | GET CHALLENGEは通るが、照合する鍵が不明 |
| 画像転送・表示更新 | 認証の向こう側。未到達 |
表示までは届かないが、原因がチャレンジレスポンス認証にあることは特定できた。
公式アプリで表示を書き換えてみる
Santekの公式サイトにWindows版アプリがあった。日本語サイトが最新のv1.4.0を配っている。ダウンロードしたものの署名を確認すると、San Technology (Zhuhai) Co., Ltd.のEV証明書で有効だった。公式が「インストール時の発行元表示はこの名前になる」と告知している内容とも一致する。
インストール先は%APPDATA%\San Technology, Inc\EZ Sign(TM) NFC\。中身はFlutter製のデスクトップアプリで、同梱DLLを見るとNFCベンダーのライブラリが1つも入っていない。ソニーのSDKもACSのDLLもlibusbも無い。
DartのAOTコードが入るdata\app.soを文字列で走査すると、使っているAPIが出てきた。
SCardEstablishContext / SCardListReaders / SCardConnect
SCardTransmit / SCardGetStatusChange / SCardReleaseContext
PC/SCそのものだった。さらにRC-S300、Sony、FeliCa、PaSoRi、ACR122、ACR1251といった機種名の文字列は1つも入っていない。特定のリーダーに縛る作りではなく、PC/SCに出ているリーダーを一般的に列挙している。公式が「推奨はRC-S300」と書いているのは推奨であって、限定ではなかった。
アプリを起動し、パネルをリーダーに載せた状態で「Scan EZ Sign to create」を押すと、Your EZ Sign is ready!と出た。100円のリーダー経由でパネルと通信できている。
画像の条件は400×300ピクセル、PNG / BMP / JPG、色は白・黒・赤・黄の4色。ただしアプリ自身が減色機能を持っており、元画像に一番近い色でベタ塗りするPure Colorや、誤差を周囲に散らして網点で階調を表現するFloyd-Steinberg(誤差拡散)など3方式を選べるため、あらかじめ4色へ減色して渡す必要はない。
手持ちのかなちゃん画像を400×300にリサイズしたものを、フルカラーのまま渡した。リサイズしたのは色のためではなく、顔が中央に来るよう切り取る位置をあらかじめ決めておきたかったためだ。マニュアルでは400×300が推奨サイズと指定されていた。
先に自前で4色へ減色した版も2つ作った。誤差拡散をかけた網点の版と、最近色で置き換えただけのベタ塗りの版になる。結局どちらも使っていない。アプリが減色を持っているので不要だったのに加えて、ベタ塗りの版は面で潰れて、キャラクターとして原形をとどめていなかった。階調を網点で作る側のほうが、4色でも絵として見られる。
プレビューはPure Colorのまま、Uploadを押す。約30秒で書き換えは完了した。

髪がベタの赤ではなく、赤と黒の点の混ざりで茶色く見えている。パレットに茶色が無い以上、これが4色の限界になる。
検証で使用したPowerShellスクリプトや書き換え手順一式は、LiltingChannelLabo に置いた。