动态

详情 返回 返回

APK 簽名驗證:不只是 apksigner,C++ 也能搞定 - 动态 详情

在 Android 開發和安全分析中,APK 簽名驗證是個高頻需求。很多人第一反應是用 apksignerkeytool,但如果你的系統環境受限、需要自動化批量處理,或者想深度集成到自己的產品裏,命令行工具就顯得捉襟見肘了。

今天我要分享的,是一套純 C++ 實現的 APK 簽名驗證方案,不依賴 Java、不調用外部工具,直接在你的程序裏完成從 APK 讀取到證書解析的全過程。


一、為什麼要自己解析 APK 簽名?

  • 跨平台需求:嵌入式系統、Linux 服務器、甚至 iOS 工具鏈,都可能需要驗證 Android APK 簽名
  • 性能要求高:批量掃描 APK 時,頻繁啓動外部進程開銷很大
  • 定製化分析:只需要證書指紋、公鑰或某個字段,而不是全部信息
  • 安全考慮:工具鏈可被替換或偽造,自研解析可控性更高

二、實現思路

APK 本質是 ZIP 文件,簽名信息存放在 META-INF 目錄下的 .RSA / .DSA / .EC 文件中,格式遵循 PKCS#7 標準。

所以整個流程可以分為:

  1. 打開 APK 並定位簽名文件
  2. 讀取簽名文件的二進制數據
  3. 用 OpenSSL 解析 PKCS#7 數據
  4. 提取證書鏈和指紋信息

三、核心代碼示例

1. 提取簽名文件數據

#include <zip.h>
#include <vector>
#include <string>

std::vector<uint8_t> extract_signature_file(const std::string& apk_path) {
    int err = 0;
    zip_t* z = zip_open(apk_path.c_str(), 0, &err);
    if (!z) return {};

    std::vector<uint8_t> data;
    zip_int64_t n = zip_get_num_entries(z, 0);

    for (zip_int64_t i = 0; i < n; ++i) {
        const char* name = zip_get_name(z, i, 0);
        if (!name) continue;

        std::string entry(name);
        if (entry.substr(0, 9) == "META-INF/" &&
            (entry.substr(entry.size() - 4) == ".RSA" ||
             entry.substr(entry.size() - 4) == ".DSA" ||
             entry.substr(entry.size() - 3) == ".EC")) {

            zip_stat_t st;
            zip_stat_index(z, i, 0, &st);
            zip_file_t* f = zip_fopen_index(z, i, 0);
            data.resize(st.size);
            zip_fread(f, data.data(), st.size);
            zip_fclose(f);
            break;
        }
    }

    zip_close(z);
    return data;
}

2. 解析 PKCS#7 獲取證書信息

#include <openssl/pkcs7.h>
#include <openssl/x509.h>
#include <openssl/bio.h>
#include <openssl/evp.h>

void parse_pkcs7(const std::vector<uint8_t>& p7_data) {
    if (p7_data.empty()) return;

    BIO* bio = BIO_new_mem_buf(p7_data.data(), p7_data.size());
    PKCS7* p7 = d2i_PKCS7_bio(bio, nullptr);
    BIO_free(bio);

    if (!p7) return;

    if (PKCS7_type_is_signed(p7)) {
        STACK_OF(X509)* certs = p7->d.sign->cert;
        for (int i = 0; i < sk_X509_num(certs); ++i) {
            X509* cert = sk_X509_value(certs, i);
            char subject[256];
            X509_NAME_oneline(X509_get_subject_name(cert), subject, sizeof(subject));
            printf("Subject: %s\n", subject);

            unsigned char md[EVP_MAX_MD_SIZE];
            unsigned int md_len;
            X509_digest(cert, EVP_sha256(), md, &md_len);
            // 輸出 SHA256 指紋...
        }
    }

    PKCS7_free(p7);
}

四、安全性建議

如果你打算把這個簽名驗證功能集成到商業產品中,尤其是在安全檢測、版權保護等場景,建議對核心解析代碼進行加固保護。
Virbox Protector 可以提供:

  • 代碼混淆
  • 虛擬機保護
  • 反調試
  • 反注入

這樣可以有效防止你的簽名驗證邏輯被逆向分析或繞過,保障業務安全。


五、總結

自己用 C++ 實現 APK 簽名解析,不僅能擺脱對 Java 環境和外部工具的依賴,還能獲得更高的性能和定製化能力。對於需要批量處理 APK 或深度安全分析的場景,這是一個值得投入的技術方案。


如果你願意,我可以幫你把這兩篇文章整合為一個系列教程,每篇都有不同的側重點,比如第一篇講提取,第二篇講驗證,第三篇講安全加固,這樣在自媒體平台的傳播效果會更好。
你要我幫你整理成系列嗎?

user avatar cloudace 头像 wangyiyunyidun 头像
点赞 2 用户, 点赞了这篇动态!
点赞

Add a new 评论

Some HTML is okay.