コンパイラ出力から学ぶアセンブリ言語

Twitterアセンブリ言語の勉強の仕方が分からないという投稿を見かけたので...
11年ぐらい前の学習方法を振り返ります。

デバッガによるx86プログラム解析入門

デバッガによるx86プログラム解析入門

最初の最初の基礎固めはこちらの書籍からでした。
ただ書籍をさらっと読んだだけでは正直なところちんぷんかんぷんでしたね。

そこで試してみたのが自分で簡単なプログラムを書いてコンパイルした出力からアセンブリ言語を読み取り比較するというものでした。

当時通っていた高専ではプログラミングの講義でBorland C++ Compiler 5.5とBCpadというエディタを活用していました。

そのため、BC++の出力された実行ファイルをOllyDbgというデバッガ上で動作させて、C言語で記述されたコードとアセンブリ言語の出力を比較したりデバッガでステップ実行させて動作を確認するなどしていました。今思えば、BC++コンパイラの出力は比較的シンプル(だと思っているの)で学習に適していたのでは…!

まずはデバッガでメイン関数まで到達するチュートリアルです。

#include <stdio.h>

int main()
{
    printf("hello, world\n");
    return 0;
}

以下はBC++コンパイラで進めていきますが、お好みのコンパイラでかまいません。おなじみのC言語ハローワールドサンプルをコンパイルして、生成された実行ファイルをOllyDbgに放り込み、ステップオーバー実行(F8)で進んでいきます。

f:id:i53:20180623155404p:plain

00407C8B : CALL DWORD PTR DS:[ESI+18] の命令を実行した直後に、Hello,world! が出力されましたね。ここがメイン関数呼び出しになっています。

f:id:i53:20180623160937p:plain

Restart(Ctrl + F2)して00407C8B: CALL DWORD PTR DS:[ESI+18] までステップオーバー実行したら今度は、ステップイン実行(F7)してメイン関数の中に潜っていきます。

00401150  /. 55             PUSH EBP
00401151  |. 8BEC           MOV EBP,ESP
00401153  |. 68 28A14000    PUSH sample.0040A128      ; /Arg1 = 0040A128 ASCII "Hello, world!"
00401158  |. E8 0B270000    CALL sample.00403868      ; \sample.00403868
0040115D  |. 59             POP ECX
0040115E  |. 33C0           XOR EAX,EAX
00401160  |. 5D             POP EBP
00401161  \. C3             RETN

Hello Worldサンプルのメイン関数の実態はたったのこれだけです。
ここで何が行われているのかは今回は無視しておきます。
大事なのは、メイン関数の中身がここで確認できているということだけ。

#include <stdio.h>

int main()
{
    int i;
    for (i = 1; i <= 100; i++) {
        if (i % 3 == 0 && i % 5 == 0) {
            printf("FizzBuzz\n");
        } else if (i % 3 == 0) {
            printf("Fizz\n");
        } else if (i % 5 == 0) {
            printf("Buzz\n");
        } else {
            printf("%d\n", i);
        }
    }
    return 0;
}

お次はFizzBuzzサンプルをBC++でコンパイルし、生成された実行ファイルをOllyDbgに放り込み、ステップオーバー実行(F8)で進んでいきます。

00401150  /. 55             PUSH EBP
00401151  |. 8BEC           MOV EBP,ESP
00401153  |. 53             PUSH EBX
00401154  |. 56             PUSH ESI
00401155  |. BE 28A14000    MOV ESI,sample.0040A128                           ;  ASCII "FizzBuzz"
0040115A  |. BB 01000000    MOV EBX,1
0040115F  |> 8BC3           /MOV EAX,EBX
00401161  |. B9 03000000    |MOV ECX,3
00401166  |. 99             |CDQ
00401167  |. F7F9           |IDIV ECX
00401169  |. 85D2           |TEST EDX,EDX
0040116B  |. 75 17          |JNZ SHORT sample.00401184
0040116D  |. 8BC3           |MOV EAX,EBX
0040116F  |. B9 05000000    |MOV ECX,5
00401174  |. 99             |CDQ
00401175  |. F7F9           |IDIV ECX
00401177  |. 85D2           |TEST EDX,EDX
00401179  |. 75 09          |JNZ SHORT sample.00401184
0040117B  |. 56             |PUSH ESI                                         ; /Arg1
0040117C  |. E8 57270000    |CALL sample.004038D8                             ; \sample.004038D8
00401181  |. 59             |POP ECX
00401182  |. EB 41          |JMP SHORT sample.004011C5
00401184  |> 8BC3           |MOV EAX,EBX
00401186  |. B9 03000000    |MOV ECX,3
0040118B  |. 99             |CDQ
0040118C  |. F7F9           |IDIV ECX
0040118E  |. 85D2           |TEST EDX,EDX
00401190  |. 75 0C          |JNZ SHORT sample.0040119E
00401192  |. 8D46 0A        |LEA EAX,DWORD PTR DS:[ESI+A]                     ;  ASCII "Fizz"
00401195  |. 50             |PUSH EAX                                         ; /Arg1
00401196  |. E8 3D270000    |CALL sample.004038D8                             ; \sample.004038D8
0040119B  |. 59             |POP ECX
0040119C  |. EB 27          |JMP SHORT sample.004011C5
0040119E  |> 8BC3           |MOV EAX,EBX
004011A0  |. B9 05000000    |MOV ECX,5
004011A5  |. 99             |CDQ
004011A6  |. F7F9           |IDIV ECX
004011A8  |. 85D2           |TEST EDX,EDX
004011AA  |. 75 0C          |JNZ SHORT sample.004011B8
004011AC  |. 8D46 10        |LEA EAX,DWORD PTR DS:[ESI+10]                    ;  ASCII "Buzz"
004011AF  |. 50             |PUSH EAX                                         ; /Arg1
004011B0  |. E8 23270000    |CALL sample.004038D8                             ; \sample.004038D8
004011B5  |. 59             |POP ECX
004011B6  |. EB 0D          |JMP SHORT sample.004011C5
004011B8  |> 53             |PUSH EBX                                         ; /Arg2
004011B9  |. 8D56 16        |LEA EDX,DWORD PTR DS:[ESI+16]                    ;  ASCII "%d"
004011BC  |. 52             |PUSH EDX                                         ; |Arg1
004011BD  |. E8 16270000    |CALL sample.004038D8                             ; \sample.004038D8
004011C2  |. 83C4 08        |ADD ESP,8
004011C5  |> 43             |INC EBX
004011C6  |. 83FB 64        |CMP EBX,64
004011C9  |.^7E 94          \JLE SHORT sample.0040115F
004011CB  |. 33C0           XOR EAX,EAX
004011CD  |. 5E             POP ESI
004011CE  |. 5B             POP EBX
004011CF  |. 5D             POP EBP
004011D0  \. C3             RETN

メイン関数の中身を抜き出してきました。
細かな解説はしませんが、この中からでも学び取れることは非常に多いです。

  • forループに該当する箇所はどこでしょうか?
    • 変数i を担っているのはEBXレジスタです。
    • EBXレジスタをインクリメントした後、CMP命令で0x64と比較して、その後JLE(Jump if less or equal)命令で分岐しています。
  • 除算の結果が割り切れているかどうかどのように判定していますか?
    • IDIV(符号付き除算)命令で、除数・被除数・商や剰余はどこに格納されていますか?
    • TEXT EDX, EDX という命令はなにを判定しているのでしょうか?

f:id:i53:20180623223009p:plain
デバッガ上で動作させているので、この後なにが起こるのかをステップ実行で進めて確認することもできるのでオススメです。
慣れたらフラグやスタックの動きも確認しましょう。

gcc.godbolt.org
ちなみに、こんな便利なものもあります。

最近ではゲームハッキングなどの邪な動機付けに限らず、マルウェア静的解析(リバースエンジニアリング)、セキュリティ教育や競技(CTF)のためにアセンブリ言語を学習したいと考える学生も増えてきているのかなと思います。

お好みのコンパイラコンパイルして逆アセンブルして、ステップ実行で処理を追ってみて、分析してみて...少しでも楽しいなあ、面白いなと思えるのであれば、あなたには(変態の)素質があります...w

命令セットや頻出パターンに慣れたら次のステップへ移行するのは容易かと思います。
ぜひぜひお試しください。

Android Studio 2.0にアップデートしたら「Error:Cannot configure the 'publishing' extension after it has been accessed.」というエラーが出て数時間無駄にした話

忌々しきエラー:
Error:Cannot configure the 'publishing' extension after it has been accessed.

いくら調べても調べても解決できないので新しくプロジェクトを作り直してライブラリの追加〜からやり直していったらVolleyライブラリを追加したところで当該エラーが発生していることが判明した。

とりあえずの解決策としてはvolleyのbuild.gradle内の「apply from: 'bintray.gradle'」をコメントアウトすると良いらしく、自分もコメントアウト後は問題なく動作した。しかし原理は不明である(おそらく根本の原因はbintray.gradle内のpublishing〜の記述周りだと思うので時間があったら調べてみたい...)

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.0.0'
    }
}

apply plugin: 'com.android.library'

repositories {
    jcenter()
}

android {
    compileSdkVersion 22
    buildToolsVersion = '22.0.1'
}

apply from: 'rules.gradle'
// apply from: 'bintray.gradle' ← コメントアウト!!!

スタックオーバーフローに圧倒的感謝:)
stackoverflow.com

2016/04/14 追記

git submodule addでライブラリを追加していたためにトラブルが発生したらしい…mavenリポジトリにアップロードされているライブラリはdependenciesに記述する方法でライブラリ追加する方が簡単だしトラブルにもなりにくいだろう…

解決までの手順

  1. git submodule deinit -f volleyのパス
  2. git rm -f volleyのパス
  3. build.gradleに「compile 'com.mcxiaoke.volley:library:1.0.19'」を追加
  4. 設定のVersion ControlからVolleyを削除(右上のポップアップからConfigureで移動できる)
  5. ビルドからClean Projectを行った後でRun!
dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.2.1'
    compile 'com.android.support:design:23.2.1'
    // compile project(':modules:volley')              // ← 削除
    compile 'com.mcxiaoke.volley:library:1.0.19' // ← 追加
}

コード難読化・アンパック系論文サーベイ

最終更新:2016/03/02
関係しそうな論文を古いものから新しいものまで発掘してアブスト訳(※ガバガバ訳)とともにここに記します.暇な時にどんどん増えます.ある程度まとめ終わったらなんとなく読みたいと思ったものを読みます.この分野の研究者ではないのでほとんど趣味です.

アンパッキングは芸術である.
それは知的な挑戦であり,リバース・エンジニアリングの分野における
最もエキサイティングなマインドゲームの一つである.
The Art of Unpacking : Mark Vincent Yason (IBM X-Force)

続きを読む

AndroidにおけるUID(Uniqe IDentifier)とその取得方法の一覧

Androidにおける端末を個体識別する目的で利用可能なIDとその取得方法をまとめる.※ importやpermissionの記載は割愛

端末ID(IMEI)

// TelephonyManagerを利用するアクセス
TelephonyManager tm = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
String imei = tm.getDeviceId();
// SystemPropertiesを利用するアクセス
String imei = android.os.SystemProperties.get(android.telephony.TelephonyProperties.PROPERTY_IMSI);

端末のソフトウェアバージョン

// TelephonyManagerを利用するアクセス
TelephonyManager tm = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
String deviceSvn = tm.getDeviceSvn();

端末ソフトウェアバージョン番号(IMEI/SV)

TelephonyManager tm = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
String imei_sv = tm.getDeviceSoftwareVersion();

加入者ID(IMSI)

TelephonyManager tm = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
String imsi = tm.getSubscriberId();

SIMシリアルID(ICCID)

TelephonyManager tm = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
String iccid = tm.getSimSerialNumber();
// String iccid = tm.getIccSerialNumber();

電話番号(GSMのMSISDN)

TelephonyManager tm = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
String line1Number = tm.getLine1Number();
// String msisdn = tm.getMsisdn();

GSMのアルファベットタグ

TelephonyManager tm = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
String line1AlphaTag = tm. getLine1AlphaTag();

ボイスメール名

TelephonyManager tm = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
String voiceMailAlphaTag = tm. getVoiceMailAlphaTag();

ボイスメール番号

TelephonyManager tm = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
String voiceMai = tm.getVoiceMailNumber();

Android ID(OS初回起動時に生成される16桁の乱数=端末ID)

String udid = Settings.Secure.getString(getContentResolver(), Settings.System.ANDROID_ID);

MACアドレス

WifiManager wifi = (WifiManager)getSystemService(Context.WIFI_SERVICE);
String mac = wifi.getConnectionInfo().getMacAddress();

UUIDの生成例

public class Installation {
    private static String sID = null;
    private static final String INSTALLATION = "INSTALLATION";

    public synchronized static String id(Context context) {
        if (sID == null) {  
            File installation = new File(context.getFilesDir(), INSTALLATION);
            try {
                if (!installation.exists())
                    writeInstallationFile(installation);
                sID = readInstallationFile(installation);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        return sID;
    }

    private static String readInstallationFile(File installation) throws IOException {
        RandomAccessFile f = new RandomAccessFile(installation, "r");
        byte[] bytes = new byte[(int) f.length()];
        f.readFully(bytes);
        f.close();
        return new String(bytes);
    }

    private static void writeInstallationFile(File installation) throws IOException {
        FileOutputStream out = new FileOutputStream(installation);
        String id = UUID.randomUUID().toString();
        out.write(id.getBytes());
        out.close();
    }
}

参照:Identifying App Installations | Android Developers Blog

複数のUIDを組み合わせたUUIDの生成例

TelephonyManager tm = (TelephonyManager) getBaseContext().getSystemService(Context.TELEPHONY_SERVICE);
final String tmDevice = "" + tm.getDeviceId();
final String tmSerial = "" + tm.getSimSerialNumber();
final String androidId = "" + Settings.Secure.getString(getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);

UUID deviceUuid = new UUID(androidId.hashCode(), ((long)tmDevice.hashCode() << 32) | tmSerial.hashCode());
String deviceId = deviceUuid.toString();

参照:java - Is there a unique Android device ID? - Stack Overflow

A Machine-learning Approach for Classifying and Categorizing Android Sources and Sinks を読みました

 FlowDroidというAndroidにおける静的テイント解析の中ではおそらく最先端の論文を読んでいたら,「FlowDroidはそのソースとシンクにSuSiプロジェクトで推測されたソースとシンクを用いている」との記載があったので読みました.自分の研究でも静的解析の際にソースとシンクのリストが必要だったのでとてもありがたいです.
 
 機械学習についてはまったく詳しくないどころかあまり興味もない分野なのですが,どのようにソースコードからソースとシンクを分類したのかが純粋に気になりました.なんとも優しいことに,教師あり学習の分かりやすい例について第4章のA項で丁寧に説明してくれるありがたい論文でした.分類器の訓練にはソース/シンクであるかどうかがアノテーションされた訓練データを使用する教師あり学習を使用しています.その分類には意味的・構文的な特徴とデータフロー特徴(粗い近似の静的テイント解析でソースからシンクへのデータフローがあったかどうか)が組み合わせて使用されます.評価の中で一番気になっていた,マルウェアで最も利用されているソースとシンクですが,そのうちの多くが研究当時の分析ツールにおいて検出できていないことが分かります(評価の項の図を参照).

 評価や機械学習の項は大分アバウトに纏めているので詳細については原文をお読み下さい.また,ソースとシンクのリストについてはGitHubで公開されています.
github.com

あらまし

 スマートフォンユーザがインストールする多くのアプリケーションは,センシティブな情報へのアクセスを行っており,開発者によって言及されていたとしても,その信頼性を判断するのは困難である.この問題に対して,研究者はより洗練された静的および動的解析ツールを研究開発することによってこの問題に対処してきた.しかしながら,これらのツールは信頼できないオブザーバにデータを漏洩する可能性のあるシンク,および,センシティブなデータのソースのリストを手動で構成しなければならなかった.ソースおよびシンクとなる可能性のある全てのAPIを手動で網羅することは現実的ではない.
 そこで,著者らは機械学習アプローチによってAndroidにおけるSourceとSinkを特定するSuSiを提案している.ソースおよびシンクであるかどうかが手動で注釈付けされたトレーニングセットを与えることで,SuSiはAPI全体のソースとシンクを自動的に特定する.また,SuSiはさらにソースとシンクを特定のカテゴリに分類している.
 Android4.2においてSuSiは数百ものソースとシンクを92%以上の精度で特定し,その多くが既存のテイント解析ツールでは見落とされているものであった.約11,000のマルウェア検体の評価により,これらのソースとシンクの多くが実際に使用されていることを確認している.また,SuSiがGoogle GlassやChromecast APIにおける未知のソースとシンクをも確実に分類できることを示している.

モチベーション

 ソースとシンクの包括的なリストを用意するのは難しく,既存研究ではソースやシンクとして非常によく知られているAndroid APIメソッドのみが含まれていると言うのが現状である.悪質なアプリケーション開発者は,そのような既存の分析ツールを回避するために,一般的によく知られていないソースやシンクを選択することが可能である.以下に,一般的ではないソースとシンクを利用してデータ漏洩を偽装しようとする例を示す.

void onCreate() {
  TelephonyManager tm; 
  GsmCellLocation loc;
  // 位置情報の取得
  tm = (TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE);
  loc = (GsmCellLocation) tm.getCellLocation();
  
  // ソース: セルID
  int cellID = loc.getCid();
  // ソース: エリアコード
  int lac = loc.getLac();
  boolean berlin = (lac == 20228 && cellID == 62253);

  String taint = "Berlin: " + berlin + " (" + cellID + " | " + lac + ")";
  String f = this.getFilesDir() + "/mytaintedFile.txt";

  // シンク
  FileUtils.stringToFile(f, taint);
  // ファイルを誰でもリード可能にする
  Runtime.getRuntime().exec("chmod 666 "+f);
}

 このシナリオでは,2つのソースメソッドが利用される.まず,getCid()を呼び出してセルIDを取得している.次に,getLac()を呼び出して,エリアコードを取得している.両方のピースを組み合わせることで,現在のGSMセルにサービスを提供する放送塔を特定することができる.これは,正確な場所ではないものの,ユーザのおおよその居場所を提供する.上記のコードでは,ドイツのベルリンでよく知られているセルタワーIDをチェックしている.実際の悪質なアプリは,より包括的なリストで位置検索を実行する.

 最後に,取得したデータを攻撃者が利用できるようにする必要がある.上記コードでは,パーミッションなしで他のアプリケーションからアクセスすることができるファイルを携帯端末の内部ストレージに作成する.Javaの通常のファイル書き込み関数を使用する代わりに,このコードは通常SDKから隠されているあまり知られていないAndroidシステムの関数を使用している.

 上記の攻撃は,著者らが実際に検査したマルウェアの代表的な例である.Fortify SCAやSCanDroid,IBM AppScanやTaintDroidなどの公に利用可能な静的および動的テイント解析ツールでこの攻撃例をテストしたところ,これらのツールのいずれも漏洩を検出しないことを確認している.これは,悪質な動作を検出するためのソースおよびシンクの包括的なリストを生成することが,いかに重要であるかを示している.SuSiはこの例で使用されるすべてのソースとシンクを発見して,適切に分類することが可能である.

ソースとシンクの定義

 ソースとシンクを推測する前に,まず「ソース」と「シンク」という用語の正確な定義が必要となる.いくつかのテイント/情報フロー解析の分野ではソースとシンクが議論されているが,これらの用語の正確な定義については開示されていない.トレーニングデータをより良いものにするためには正しい用語の定義が欠かせない.テイント解析ではプログラムを介してデータの流れを追跡する.ソースは,プログラムのどこで追跡するデータの入力が行われたかであり,シンクはデータがどこでプログラムから離れたかを示している.以下に,各用語の厳密な定義を示す.

データ

 データは値であるか,または値を参照するものである.

リソースメソッド

 リソースメソッドは,共有リソースから「データ」を取得するか,または,共有リソースに「データ」を書き込むメソッドである.

Androidソース

 ソースは,アプリケーションコード内に定数値ではない値を返す「リソースメソッド」への呼び出しである.

Androidシンク

 シンクは,新しい値が書き込まれているか,または,既存のリソースに上書きされた場合に,アプリケーションコードから少なくとも1つの非定数データ値をパラメータとして受け取っている「リソースメソッド」への呼び出しである.

 例えば,IMEI情報は「データ」の一部であり,IMEI情報を読みだすためのメソッドTelephonyManager::getDeviceId()はリソースメソッドである.そして,getDeviceId()メソッドAndroidソースである.これは,アプリケーション内に,すべての携帯端末において異なる値(すなわち非定数値)である値を返すリソースメソッドだからである.一方,SmsManager::sendTextMessage()メソッドは特定の電話番号にテキストメッセージを送信するリソースメソッドであり,そのリソースはGSMネットワークである.また,sendTextMessage()メソッドAndroidシンクであり,これは非定数値であるメッセージテキストと電話番号をパラメータとして受け取るリソースメソッドらかである.

分類アプローチ

f:id:i53:20160208214055p:plain
(Poster LearningSourceSinksより)

 上図は,SuSiの全体的な概要を示している.SuSiは学習において2つのラウンドを実行する.入力フェーズでは,Android APIメソッド(ラベル無しデータ)と,訓練された分類器,特徴データベースを用意する.第1ラウンドではソースか,シンクか,またはそれ以外であるかどうかを分類して,第2ラウンドでは第1ラウンドの結果,ソースとシンクに選ばれたものを特定のカテゴリに分類している.トレーニングデータは手動でソースおよびシンクであるかどうかが注釈付けされたラベルデータからランダムに選ばれたもので作成される.出力フェーズにおいて,ソースとシンクの分類リストを出力する.

 分類において最も重要となる特徴データベースであるが,著者らはAndroidメソッドを分類するために144の構文的および意味的な特徴のセットを用意している.単一の特徴だけでは,与えられたAndroidメソッドがソース,シンク,またはそのどちらでもないかを決定するために明らかに不十分である.しかしながら,すべての特徴を組み合わせることで,非常に正確に分類器を訓練することが可能となる.その主な理由は,Androidフレームワークの多くの開発者が実際には一定の規則的なコーディングスタイルに従うか,または新たなものを実装する際に既存のメソッドの実装の一部を複製するからである.これらソフトウェア開発の社会的側面が,コードベースにおける規則性と冗長性につながっており,著者らの機械学習アプローチに適していると考えられる.

 具体的にSuSiは以下の1st Runの分類における特徴クラスを使用している.例えば,「メソッド名がgetで始まる」特徴クラスなど.

また,2nd Runのカテゴリ分類における特徴は以下のようにグループ化されている.例えば,「Contacts」や「SmsManager」など特定の文字列を含んでいるかなど.

評価

f:id:i53:20160208222547p:plain
10分割の交差検証より,ソース/シンク/それ以外を約92%の精度で特定できることが示されている.また,訓練した分類器によってChromecast APIやGoogleGlass APIのソースとシンクを分類してマニュアルでその成否を検証したところ,Chromecast APIについては適合率・再現率ともに100%,Google GlassAPIについては98%の適合率と100%の再現率であった.

f:id:i53:20160208223031p:plain
上図は,約11,000のマルウェア検体で最も頻繁に使用されているソース(上段)とシンク(下段),および著名な解析ツールにおける検出結果の表であり,研究当時ではTaintDroidやSCanDroidといった著名なツールにおいても特定のソースとシンクについては検出できていないことが分かる.

リミテーション

 SuSiはその「ソース」の定義上,コールバックメソッドを発見することができない.すなわち,位置情報を取得するために利用されるonLocationChangedのようなコールバック関数にはSuSiは適用できない.しかしながら,Andoroid OSにおける,コールバックインタフェースの数は,マニュアルで検査するには十分に少ない数しかなく,すべてのコールバックメソッドを既知の小規模なデータセットとして定義することで,静的解析の際に検出可能となるだろう.

 また,Androidでは,XMLファイルを介してレイアウト制御を定義している.ソースコード内で,システムのfindViewByIdメソッドに渡されたIDによって,ラベルやボタン,パスワードフィールドへの参照を返すことになる.このように,IDに応じて,このメソッドはソースになるかどうかが変化するため,正確な分析のためにはAndroidのリソースシステムをモデル化しなければならない.UIソースがパスワードフィールドのみに制限されれば問題ないが,全ての入力フィールドをソースとして認識する場合には,多くのフォルスポジティブに繋がる可能性がある. 

ハッカソン初参加

自身のための備忘録です。

1月23日に福井情報システム工業会さん主催で開催された防災アプリハッカソンに参加してきました。(内定者合宿を除けば)初めてのハッカソンということで、期待と不安が入り混じるような感じで始まりました。

私のチームは全員がハッカソン初参加でした。自己紹介から始まり、お昼までにメンバーで1時間半をかけてアイデア出しをして、午後にアプリ実装と発表資料作りを分担して作業しました。が、最終的には自分が担当していた部分で「動くもの・見せられるもの」が出来上がらないまま時間切れとなってしまいました。

たくさん反省点はあるのですが、3点だけピックアップします。

1. 前日にアイデアを練ってはいけない

ハッカソンテーマは事前に分かっていたので、前日に一人でアイデアを練りに練ってのぞみました。

まず、既存の避難所アプリをいくつか見つけて来て機能の列挙や差別化されている点などをまとめました。例えば、「みたチョ」というアプリは普段からアプリ使いを行わせるために防災グッズと交換できるポイントを貯められる広告システムを備えています。

ハッカソンのテーマとして「避難アプリにゲーム性をもたせる」というのがありました。このテーマの元となっているのが、福井県オープンデータコンテストのアイデア部門で最優秀賞となった「街の防災はかせくん」というアイデアになります。

最近の避難所アプリは災害時の通信混雑・断絶を考慮してオフラインでも利用できることが求められます。ゲーム性を持たせることでアプリ利用を促進し、(一度でも使ってもらえれば)避難所情報やマップタイルのキャッシュを保持しておけるため、このアイデアは優れているなと個人的に感じました。

他にも、ゲーム性をもたせる場合はターゲットユーザが子どもか子供を持つ親になるだとか、お年寄りにはどうしようとか、GoogleのDirections APIでは最短の経路をナビすることはできるけれども、そこに本当に道があるのかとか、そこが安全な道であるかは考慮されていないんだとか、前日数時間かけてうんうん考えてきました。

で、個人的なアプリ案として自宅から最寄りの避難所までをトラッキングして、かかった時間やルートなどを保存して避難ランキングのようなものを作成する避難訓練アプリを考えてきました。最短避難経路情報を家族などで共有できるような用途を考えていました。災害時には保存してあった最短避難ルートを利用したり、小学生が自由研究(避難経路マップ作成など)にも利用できるよう考えていました。

このようなアイデアを前々から考えておくというのは「ハッカソン」を行う上では愚かな行為でした。ハッカソンは一人で行うものではないからです。他人のアイデアと自分のアイデアが不一致した時に軋轢を生みかねません。最悪、前日考えるにしても既存のアプリにどんなものがあるのかとか、使えるデータやAPIの情報をチーム内で共有する程度に留めた方が良いかなと思いました。

2. 時間の見積もりが甘かった

時間と作業の見積もりです。時間が限られているのに昼食に時間がかかりすぎてしまった、などです。お昼は近くのお蕎麦屋さんに行きました。てっきり他のチームもお蕎麦屋さんに来ているのではと思ったのですが、どうやら作業時間を考えて早く食べて出られるお店を選択していたようです。

f:id:i53:20160124230844j:plain
お昼に食べた亀蔵のかき揚げおろしそば、かき揚げの大きさに圧倒されました。かき揚げは思ったほど油っこくなくおろし汁を少しかけて崩しながら食べましたが、とても美味でした:)

蕎麦は美味しかったのですが、混んでいたため出てくるまでに少し時間がかかり、お昼休憩にかかった時間が移動込みで1時間、会場に戻ったところで発表の時間まで2時間半しかありませんでした。今回はWebアプリの開発ということだったのですが、僕はWebアプリ開発に関しては正直言って初級者です。とりあえず、発表までに動くレベルのものを目指して、福野さんの1日1創アプリのソースを眺めながら手を加えていきました。マップ上にルートを描画する機能とクイズの問題を生成する機能、クイズ座標と自座標の接近判定までは作成できましたが、クイズ座標に近づくとクイズがポップアップするという肝心要の機能までは作成できませんでした。

3. こだわってはいけない

ハッカソンは開発にかけられる時間が限られていました。今回の場合は特にそれが顕著(昼食込み5時間)でした。開発の途中でクイズの問題をポップアップするダイアログが作成できないという、壁にぶち当たりました。ネイティブアプリだったらカスタムビューやカスタムダイアログを利用できるのですがWebアプリで3択クイズをポップアップさせるのってどうすればいいの?とうんうん悩んでる間にただただ時間が過ぎて行きました。

ここでの最適解ですが、「ポップアップさせる」ということをさっさと諦めて、とりあえず地図の下にクイズの問題と選択する答えのリストを表示するだけでよかったのです…!ここで機転がきかなかったところが非常に悔やまれます。これさえできれば見せられるものが出来上がっていたのです。

他のチームでも実装が間に合わなかった部分は見せかけだけにしている部分が結構ありました。

終わりに

ここまで書いたのですが、なんだかんだいって自身の実力の無さが如実に現れた部分が大きいです。同期では僕より5歳年下なのにゴリゴリJSかける変態がいます。俺も負けてられない!!!俺、修論発表終わったらWebアプリ開発勉強するんだ・・・!

次回ハッカソンに参加する機会があれば、上記の点に気をつけつつ柔軟に取り組めるようにします。しましょう。絶対。

UPXにおけるIATのマニュアル再構築 【分析編】

i53.hatenablog.jp
 前回の記事でIATについて大雑把に勉強したので、その情報を元にIATのマニュアル再構築を試みます。

# 勉強したてホヤホヤなので間違いなどがあれば是非コメントにて指摘して頂けると助かります...!

続きを読む