案例研究 · Aegis驗證器

身份驗證器如何
生成登入程式碼?

六位驗證碼每 30 秒變化一次。用 REA 在 Android APK 中找出計算方法,再重建一個可調節時鐘的演示。

Aegis 3.4.3 · Android · 正式釋出 APK ·6.9MB

在GitHub上檢視Aegis

從 APK 還原可復現的驗證碼

  1. 01 · 定位功能3,077 個類 → 生成方法REA 搜尋包,追蹤顯示和複製驗證碼時使用的程式碼。
  2. 02 · 閱讀計算時間 + 賬戶金鑰 → 六位數字REA 返回方法與預設值,助手解釋它們如何配合。
  3. 03 · 重建並驗證調整時鐘,檢視驗證碼。新的瀏覽器演示覆現規則,再用公開對照用例檢查。

問問你的程式設計助手

該應用程式顯示更改的登入程式碼。 我們想找到 是什麼讓它改變 再現這種行為。

你的程式設計助手

用 REA 分析 aegis-v3.4.3.apk,找出六位登入驗證碼是怎麼產生的,解釋為什麼它每 30 秒變化一次,再做一個可以調整時間的小示範。

這是用於下載的 APK 的示例 prompt,需要先配置 REA 的 Android 分析後端。獲取 APK 和分析配置 ↓

試試程式碼生成器

應用把時間劃分為每塊 30 秒,再結合時間塊編號和賬戶金鑰生成驗證碼。同樣的金鑰和時間塊,會得到同樣的驗證碼。

將時鐘移動60秒

  1. 時間59 秒數我們的可調節示例時鐘
  2. 30秒區塊時間塊 1floor(59 / 30)
    30-59秒
  3. 生成的驗證碼287082帳戶金鑰+區塊→六位數字

在59秒: 287082. 在60秒: 359152. 在一個塊內移動會使程式碼保持不變。

金鑰是固定的,公開的 RFC6238測試資料. 該演示實現了從APK恢復的計算。

用REA查詢程式碼

  1. 將APK縮小到三個類

    程式設計助手→ REA
    inspect_android_package
    {"path": "aegis-v3.4.3.apk"}
    
    search_android_classes
    {"path": "aegis-v3.4.3.apk",
     "query": "Totp"}
    REA →程式設計助手 · 選定結果
    Package: com.beemdevelopment.aegis
    Version: 3.4.3
    Classes: 3,077
    
    Three matches:
      otp.TotpInfo
      ui.views.TotpProgressBar
      importers.TotpAuthenticatorImporter

    TotpInfo 是計算邏輯的候選方法;另外兩個涉及進度條和匯入的賬戶。TOTP 指基於時間的一次性密碼。

  2. 將生成器連線到應用程式的顯示器

    程式設計助手→ REA
    inspect_android_class
    {"path": "aegis-v3.4.3.apk",
     "class_name":
      "com.beemdevelopment.aegis.otp.TotpInfo"}
    
    trace_android_references
    {"path": "aegis-v3.4.3.apk",
     "class_name":
      "com.beemdevelopment.aegis.otp.OtpInfo",
     "method_name": "getOtp"}
    REA →程式設計助手·方法和呼叫者
    TotpInfo methods:
      getOtp()      · overload 0
      getOtp(long)  · overload 1
    
    OtpInfo.getOtp callers:
      ui.views.EntryHolder.getOtp
      ui.MainActivity.copyEntryCode

    REA 找到接受時間戳的方法過載,並定位基礎方法的呼叫方。繼續檢查 EntryHolder.getOtp,就能看到顯示邏輯呼叫了 TotpInfo.getOtp(timestamp)。

請求顯示縮短的輸入路徑。 結果類名省略常用 com.beemdevelopment.aegis 字首。

閱讀計算

REA 返回時間轉換、預設設定和生成方法。建構函式把間隔設為 30 秒、位數設為 6;接受時間戳的方法將秒數轉換為時間塊編號。

REA · 精選反編譯Java
// TotpInfo defaults and clock
setPeriod(30);
getOtp(System.currentTimeMillis() / 1000);

// OtpInfo default algorithm and digits
this(bArr, "SHA1", 6);

// Block passed to the generator
(long) Math.floor(j / ((double) this._period))

// generateOTP → getHash
byte[] hash = getHash(bArr, str, j);

// getHash: account key + encoded block
Mac mac = Mac.getInstance(str);
mac.init(secretKeySpec);
return mac.doFinal(bArrArray);

// OTP.toString, case 0
this._code % ((int) Math.pow(10.0d, i))

// Keep leading zeroes
while (sb.length() < i) {
    sb.insert(0, "0");
}
可讀摘要 · 程式設計助手解釋
// Group time into 30-second blocks
seconds = current_time_ms / 1000
block = floor(seconds / 30)

// Generate a number from the key and block
hash = HMAC_SHA1(account_key,
                 big_endian_8_bytes(block))
number = select_31_bits(hash)

// Format the default six-digit code
code = number % 1_000_000
code = pad_with_zeroes(code, 6)

時間選擇塊。 秒30到59都給塊1。 在60秒時,塊變為2。

金鑰也會影響結果。 生成函式把賬戶金鑰和時間塊組合起來。金鑰不同的賬戶,在同一時間也可能顯示不同驗證碼。

保留六位數字。 取除以 1,000,000 的餘數,位數不足時在前面補零,因此驗證碼也可以以 0 開頭。

這些節選來自多個檢查過的方法,為便於顯示增加了換行。右側是解釋性摘要。Aegis 原始碼採用 GPL-3.0 許可。

驗證碼生成函式內部

釋出的 APK 將 generateOTP 放在 kotlin.ExceptionsKt 中。REA 從 TotpInfo 追蹤呼叫,並返回這個函式體;原始原始碼把輔助函式命名為 HOTP。

REA · generateOTP 完整函式體
public static OTP generateOTP(byte[] bArr, String str,
        int i, long j)
        throws NoSuchAlgorithmException, InvalidKeyException {
    byte[] hash = getHash(bArr, str, j);
    int i2 = hash[hash.length - 1] & 15;
    return new OTP(
        (hash[i2 + 3] & 255)
        | ((hash[i2] & 127) << 24)
        | ((hash[i2 + 1] & 255) << 16)
        | ((hash[i2 + 2] & 255) << 8), i, 0);
}

雜湊的最後一個位元組決定讀取位置。從這個位置讀取四個位元組,得到正的 31 位數,再格式化為指定的位數。建構函式的最後一個引數選擇了編譯過程引入的驗證碼格式化分支。

與匹配的釋出源進行比較.

檢查重建

我們將選定的 REA 返回的 Java 方法放進小型測試程式。它們的輸出與獨立重建的實現一致,共驗證 133 個測試用例,包括時間塊邊界和以零開頭的驗證碼。

示例時間 時間塊 六位驗證碼
30秒 1 287082
59秒 1 287082
60秒 2 359152
1,111,111,109秒 37,037,036 081804

生成函式還符合 RFC 6238 中釋出的六個 SHA-1 對照用例。可以用這些用例檢查瀏覽器實現:

閱讀演示的計算

參考案例使用八位數字。 檢查也驗證他們的六位數的結果。

驗證執行提取的Java方法和新的演示。 對Android APK進行了靜態檢查。

親自檢查APK

先在 macOS 或 Linux 上設定 REA,再將這兩個檔案下載到同一資料夾。Windows 上可使用 WSL 等 Linux 環境。

Android分析需要完整的JDK17或更高版本。 選擇它與 JAVA_HOME 或 PATH. 本案例使用了JDK21。

讓 REA 使用分析後端配置檔案,再檢查 APK:

macOS/Linux
REA_JADX_MCP_JAR="$PWD/jadx-headless-mcp-0.7.1-all.jar" \
npx rea-agents@latest inspect-android-package \
  ./aegis-v3.4.3.apk --format json --full-output

助手可以透過 REA CLI 繼續使用上方的 prompt。如果使用 MCP,將 REA_JADX_MCP_JAR 加入 REA 服務的環境配置,再重新連線。

下一個問題: 當帳戶使用八位數字或不同的時間間隔時會發生什麼?

資料來源

使用 REA 6.1.0 於 2026 年 10 月 9 日檢查。反編譯節選歸屬 Aegis;圖示、可讀摘要和瀏覽器重建為新增教學材料。

頂部