技術約29分で読めます

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電子ペーパーの表示を書き換えられるなら、その組み合わせのほうが面白そうだ。

拾ってきたもの

秋葉原のパレットタウンで1台100円だったACR1251U 2台

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

筐体裏のラベル。P/NはACR1251U-M3

筐体裏のラベルに記載されていた情報はこんな感じ。

項目表記
型番SO-SOL122-D / P/N: ACR1251U-M3
電源5VDC, 200mA
S/NRR534-019046(撮影した1台)
認証FCC ID: V5MACR1251、CE、VCCI、総務省指定 第AC-13011号

読み書きの相手として、NFCタグ用IC(NTAG)搭載の白いカードを10枚セットで用意した。袋のラベルは「NFCカード NTAG…書換可能 ホワイトカード 10枚セット」まで読める。NTAG213 / 215 / 216のどれかは袋からは分からないので、カードから直接読み出して確認する。

NTAGカード10枚セット

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

書き換え前のEZ Sign 4.2インチパネル

製品仕様はこんな感じ。

項目内容
解像度400×300ピクセル
表示色黒・白・赤・黄の4色
書き換え時間約30秒
電源電池不要、NFCから給電。書き換え後は無給電で表示を保持
対応iOS / Android / Windows
保護等級IP65
厚さ3.4mm

給電の問題も別にある。書き換えに約30秒かかるということは、通信規格が合うだけでなく、リーダーの高周波(RF)出力で書き換えに必要な電力を供給し続けられるかも確かめる必要がある。

検証環境

項目内容
PCWindows 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点。

#確認すること満たせた判定
1NFCリーダーとして認識するかリーダー名がPC/SCの一覧に出る
2カードを読めるかUIDとNTAGの型番が取れる
3カードへ書けて読み戻せるか書いた内容がそのまま読める
4EZ Signへ表示を書けるかパネルの表示が変わる

まずはリーダーの認識から順に確認していく。リーダーが見えない状態でカードの読み書きを試しても、どこで失敗したか切り分けられないからだ。

リーダーとして認識させる

ドライバを追加することなく、そのまま認識された。

接続前はPowerShellのGet-PnpDevice -Class SmartCardReaderが0件、SCardSvrサービスは停止中(手動起動)。USBポートに1台挿すとSCardSvrが実行中へ変わり、スマートカードリーダーのクラスにデバイスが1つ増えた。

項目
デバイス名Microsoft Usbccid Smartcard Reader (WUDF)
ハードウェアIDUSB\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でカードの状態を取得した。

項目意味
eventState0x00020422カード検出(PRESENT)かつ未給電(UNPOWERED)
ATR3B 002バイト(最小形)

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 00UIDの取得リーダーへカード固有IDの問い合わせ
FF CA 01 00 00ATSの取得リーダーへカード通信仕様の問い合わせ
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は記載されていない。

PIDINFでの記載
2200ACR122U
2218ACR1251U-C(PICC / SAM)
2229ACR1251U-A2
222CACR1283L PICC
222D記載なし
222EACR123-PICC+3SAM Bus

222C222Eはあるのに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 00ACR1251U_V541.00ACR1251U系
PICC動作パラメータE0 00 00 20 0007Type A / Type B / Topaz が有効
自動PICCポーリングE0 00 00 23 008Fポーリング有効
アンテナ状態E0 00 00 25 0000オフ

アンテナがオフなら、カードの検出も給電もできない。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 00ACR1251U_V541.00ACR1251U系ファームウェア
PICC動作パラメータE0 00 00 20 0007有効プロトコル
ポーリング設定E0 00 00 21 008Fポーリング間隔
自動PICCポーリングE0 00 00 23 008F自動検出有効
アンテナ状態E0 00 00 25 0001アンテナオン
RF系レジスタE0 00 00 2F 0011 85 85 85 85 A5 A5 A5 A5 69 …RF制御レジスタ値
しきい値設定E0 00 00 3F 002F 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 0090 00赤く点灯した
LED緑FF 00 40 A0 04 00 00 00 0090 00緑に点灯した
LED点滅+ブザーFF 00 40 D0 04 05 05 04 0390 02色が一瞬変わった(音は鳴らない)
LED消灯E0 00 00 29 01 0001 00消灯した

LEDは指示どおりに色が変わり、消灯もした。一方、ブザーは直接鳴らす指示を出しても無音のままで、直接制御のコマンドに対しても音が出なかった。物理的な故障か、そもそもOEM基板でブザー部品が未実装である可能性が高い。

LEDは動作し、ブザーとRF側は応答しない。ラベルにあるSO-SOL122-DというOEM向けらしい型番と合わせると、ブザーとアンテナが実装されていないOEM基板の可能性も考えられる。ケースを開けて基板を確認すれば早いが、この個体にはネジ穴も、工具を差し込める隙間もないため、基板破損を避けて分解は見送った。

2台目の個体確認と本体直挿しでの検証

ドライバを当てたのは挿していた1台だけだったので、同じポートへ挿し替えて確認した。シリアル番号を持たないため、インスタンスIDが同じままACSのドライバを引き継ぐ。

項目2台目
ファームウェアACR1251U_V541.00(1台目と同一)
アンテナ状態(挿した直後)00
アンテナをオンにした後01
カード読み取りATR3B 00SW=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 3263 00。ACR1251UはPN532系ではないため想定どおり

そのうえで、アンテナを10秒間オンに保持した状態でスマートフォンを載せてみた。ウォレットアプリも先に起動しておいた。

載せてみたが反応はなく、決済画面も出ず、振動や検出音も鳴らなかった。

アンテナ設定が01を返すのに、13.56MHzの電波が実際には出ていない可能性が高い。送信段が故障しているか、ファームウェアが実際には発振させていない可能性が考えられる。

裏面スイッチによる書き換えモードの起動

筐体の裏に、リセットのように見える小さなスイッチがある。通常どおり挿した状態で押しても、PC/SCの値は何も変わらなかった。

ACSのドライバINFにはACR1281 USB FW_Upgrade v100というファームウェア書き換えモード用のデバイス登録がある。ACS製リーダーには、ボタンを押しながら挿すと書き換えモードで起動するものがある。そこで、スイッチを押したままUSBへ挿して、3秒ほど押し続けてから離してみた。

項目通常モードスイッチを押しながら挿したとき
ハードウェアIDUSB\VID_072F&PID_222DUSB\VID_072F&PID_220B
デバイス名ACR1251 CL Reader PICCACR1281 USB FW_Upgrade v100
カード状態PRESENT + UNPOWEREDEMPTY
ATR3B 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.zip431.2
ACR1251DI_FW713.0.zip713.0
ACR1251DI_FW721.1.zip721.1

3種ともツールのexeはバイト単位で同一で、機種差はInitFile.iniPatch/だけ。exe内の文字列にはTool for update ACR1251U-M2 and ACR1251U-C4 FirmwareACS ACR1281 USB FW_UPGRADE V100READER_AES_KEYReaderAuthがある。スイッチを押しながら挿したときに出たデバイス名と一致する。

ここで手元の個体の正体も確定した。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動作パラメータ)1F07
21578F
23(自動PICCポーリング)8B8F

RF系のレジスタ値が完全一致しているので、ハードがCL系(ACR1251U-A2)だとここでも確認できた。そのうえで動作パラメータとポーリング設定が正規の初期化列と違う。2007はType A / Type B / Topazだけで、正規の1FはFeliCa 212 / 424まで有効にする値になる。

設定の書き込みだけなら戻せるので、そのまま流した。書き込みはすべて受け付けられ、読み戻しでも変化した。

設定適用前適用後
08FF FF11 FF
20071F
218F57
238F8B
2400 00 00 0002 00 02 00

それでもカードは読めない。しかも抜き差しして測り直すと、2007238Fへ戻っていた。NVRAMに残るタイプではなく、電源を入れ直すたびに既定値へ戻る。設定変更で対処する道も行き止まりになった。

書き換えツールでのリーダー検出エラー

残るのはファームウェアの書き換えだけになった。ただし手元は541.00で、入手できたCL版は431.2。Patch.hexは暗号化済みで、ツール側にはREADER_AES_KEYReaderAuthがある。適当な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.iniReader#ACR1251CL-NTTCom#は内部でM2扱いになるため、要求されるのは4xx系(0x400)だった。名前ではなく版数の系統で弾かれていた。

また、ブートローダーモードで始めても失敗する理由も判明した。版数判定の直後に、通常モードのリーダーを書き換えモードへ切り替えるコマンドを必ず送る。すでにブートローダーで起動している個体にこれを投げても通らない。そのため通常モードでは版数、ブートローダーでは切り替えコマンドで、どちらも同じエラーに落ちていた。

なお、AES鍵はexeの中の定数だった。READER_AES_KEYPC_AES_KEYも直書きで、個体ごとの秘密ではないため、認証処理も通りそうだという見込みが立った。

版数判定を1バイト書き換える

通すには版数判定を外すしかない。該当のILはldc.i4 0x700andldc.i4 0x400の並びなので、複製したexeの最後の定数を0x500へ書き換えた。バイト列20 00 07 00 00 5F 20 00 04 00 00の中の1バイトだけで、該当は0x003927の1箇所。なお、バイナリの直接改変や異種ファームウェアの書き込みはデバイスを文鎮化(brick)させるリスクがあり、今回は壊れてもよい検証用個体での自己責任の実験になる。

通常モードで起動し、リーダーを選んで更新を押すと、今度は確認ダイアログが出た。

現在のバージョン: 541.00
更新後: 431.2(実際はダウングレード)
更新しますか?

実機から読んだ版数が出ている。はいを押すと、ツールが書き換えモードへ切り替え、認証を通し、書き込みまで進んで正常終了した。

項目書き換え前書き換え後
USB PID222D(名前のないOEM枠)2229(正規のACR1251U-A2)
ファームウェアACR1251U_V541.00ACR1251U_V431.2
PICC動作パラメータ071F
自動PICCポーリング8F8B
シリアル番号値が返る

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バイト>を並べる。

ページ書いた値
0403 10 D1 01
050C 55 04 6C
0669 6C 74 69
076E 67 2E 63
0868 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レコードの見出し、04https://を表す短縮コード、続く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が取れている時点で、別系統のカードも認識できていることになる。

カードを載せていないときはEMPTYcbAtr=0。幽霊カードも消えた。

EZ Signとの通信確認

リーダーが動くようになったので、EZ Signをそのまま載せてみた。電池を持たずNFCから給電する仕組みなら、リーダーから見れば1枚のカードとして出てくるはずで、出てくれば通信の入口は開いていることになる。

載せると検出された。

項目
ATR3B 86 80 01 90 DE 33 01 1E 03 66
UIDDE 33 01 1E
ATS0B 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ファイルIDE104
最大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 E16A 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を総当たりして、「命令未対応」以外を返すものを拾う。消去やレコード更新、ファイル削除といった破壊的な標準命令は除外した。

CLAINS応答
00206A86(VERIFY。P1/P2が違う)
00846700(GET CHALLENGE。長さが違う)
00B06986(READ BINARY。選択中のファイルがない)
00D19000 + データ
00D59000 + 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=D500を返すだけで、状態の問い合わせらしい。

データを伴う形でも総当たりしたが、新しく応答する命令は出てこない。画像転送の命令は、最初から見えているわけではなく手前に認証が存在していた。

コマンド応答
00 84 00 00 089000 + 乱数8バイト
00 84 00 00 209000 + 乱数32バイト
00 20 00 01 006700(データが必要)
00 20 00 80 / 00 81 / 01 006A86

GET CHALLENGEが要求した長さぶんの乱数を返し、VERIFYP2=01のときだけ「データが足りない」と答える。チャレンジレスポンスの認証を通さないと、その先の命令は受け付けない作りになっている。

状態
ISO 14443-4通る。APDUで通信できる
NFC Forum Type 4 / NDEF通る。E104に500バイト、権限も開いている
独自のデバイス情報・状態通る。INS=D1INS=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-S300SonyFeliCaPaSoRiACR122ACR1251といった機種名の文字列は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秒で書き換えは完了した。

100円のリーダーの上で表示が書き換わったEZ Sign

髪がベタの赤ではなく、赤と黒の点の混ざりで茶色く見えている。パレットに茶色が無い以上、これが4色の限界になる。


検証で使用したPowerShellスクリプトや書き換え手順一式は、LiltingChannelLabo に置いた。