コース目次 / 第1章

標的を立てる — smaliソースから、練習用APKをビルドする

AndroidManifest.xmlとsmaliソースから、apktool単体でAPKをビルドし、jarsignerで自己署名します。Android SDK/Gradle不要のビルドパイプラインを実際に動かします。

第1章 / 全6章目安 約13分この章のゴール: smaliソースからAPKをビルドし、自己署名できるようになる

法と倫理ゲート

手を動かす前に

このコースは攻撃の技術に触れます。実習してよい相手は、次の3つだけです。

  • (a) 自分で作った練習用のやられ環境(このサイトが配る自作ターゲット)
  • (b) あなた自身の許可された環境(自分の Thousand SKY・secret-notes-ctf など)
  • (c) CTF 競技の中(規約の範囲で)

実在する第三者のシステムを許可なく触ることは、不正アクセス禁止法に触れます。 このゲートは、その線引きを毎回の入口で確かめるためのものです。詳しくは「セキュリティの法と倫理」へ。

プロジェクトの型 — apktool のソース構造

apktool は、APKを「逆コンパイルした形のフォルダ」から「再ビルド」できます。今回は、その逆コンパイルした形を、最初から手で用意します。フォルダ構成を作ります。

mkdir -p vulnnotes/smali/com/example/vulnnotes
cd vulnnotes

マニフェスト — アプリの設計図

AndroidManifest.xml は、アプリの構成を宣言する、いわば設計図です。わざと、いくつかの緩い設定を入れておきます(次章以降で1つずつ見ます)。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.vulnnotes">
    <uses-permission android:name="android.permission.INTERNET" />
    <application
        android:label="VulnNotes"
        android:allowBackup="true"
        android:usesCleartextTraffic="true">
        <activity android:name=".MainActivity" android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".AdminActivity" android:exported="true" />
    </application>
</manifest>

apktool.yml — ビルドの設定

!!brut.androlib.meta.MetaInfo
version: 2.7.0
apkFileName: base.apk
isFrameworkApk: false
usesFramework:
  ids:
  - 1
sdkInfo:
  minSdkVersion: '21'
  targetSdkVersion: '30'
packageInfo:
  forcedPackageId: '127'
versionInfo:
  versionCode: '1'
  versionName: '1.0'
compressionType: false
doNotCompress:
- resources.arsc

smali — アプリの中身

smali は、Android の実行バイトコード(DEX)を、人間が読み書きできる形にしたアセンブリ風の言語です(sec-asm で見た x86-64 アセンブリの、Android 版と考えてください)。smali/com/example/vulnnotes/MainActivity.smali として保存します。

.class public Lcom/example/vulnnotes/MainActivity;
.super Landroid/app/Activity;

.method public constructor <init>()V
    .locals 0
    invoke-direct {p0}, Landroid/app/Activity;-><init>()V
    return-void
.end method

smali/com/example/vulnnotes/AdminActivity.smali も、同じ形で作ります(クラス名だけ変えます)。

.class public Lcom/example/vulnnotes/AdminActivity;
.super Landroid/app/Activity;

.method public constructor <init>()V
    .locals 0
    invoke-direct {p0}, Landroid/app/Activity;-><init>()V
    return-void
.end method

ビルドする

フォルダ構成が vulnnotes/AndroidManifest.xml・vulnnotes/apktool.yml・vulnnotes/smali/... になっていることを確認し、ビルドします。

cd ..
apktool b vulnnotes -o vulnnotes.apk

Built apk into: vulnnotes.apk と出れば成功です。Android SDK も Gradle も、一切使っていません。apktool が内部で smali のアセンブルとリソースの梱包を行っています。

署名する

Android は、署名の無い APK を(通常は)インストールできません。JDK 標準の jarsigner/keytool で、自分用の鍵を作って署名します。

keytool -genkeypair -v -keystore debug.keystore -alias debugkey \
  -keyalg RSA -keysize 2048 -validity 10000 \
  -storepass android -keypass android -dname "CN=Practice,O=Learning,C=JP"

jarsigner -keystore debug.keystore -storepass android vulnnotes.apk debugkey

jadx で、逆コンパイルして確認する

jadx -d out vulnnotes.apk
cat out/sources/com/example/vulnnotes/MainActivity.java
package com.example.vulnnotes;
import android.app.Activity;
public class MainActivity extends Activity {
}

jadx が、DEX バイトコードから読みやすい Java のソースを復元しました。これで、標的の準備が整いました。次の章から、この練習用APKに意図的に仕込んだ穴を、静的解析で見つけていきます。

持ち帰る一言

apktool 単体で、APKは組み立てられる。 マニフェスト・apktool.yml・smaliの3点があれば、Android SDK無しでビルドでき、jarsignerで署名し、jadxで読み返せる。次の章で、この標的に仕込んだ最初の穴——ハードコードされた秘密——を見つけます。

こうなっていればOK

卒業まであと4章です。

この章はまだ完了していません。