Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 美團Android資源混淆保護的具體實踐

美團Android資源混淆保護的具體實踐

編輯:關於Android編程

原文章美團Android資源混淆保護實踐,但是該文章並沒有給出具體的混淆方案,只是放了一個函數,函數的實現過程需要自己去實現,本篇文章也並沒有實現該函數,只是對實現該函數有一個前期的准備。

在android 5.0的系統源碼中,要修改的代碼位於

/frameworks/base/tools/aapt/Resource.cpp

未修改前的代碼

& set,
                                  const char* resType)
{
    String8 type8(resType);
    String16 type16(resType);

    bool hasErrors = false;

    ResourceDirIterator it(set, String8(resType));
    ssize_t res;
    while ((res=it.next()) == NO_ERROR) {
        if (bundle->getVerbose()) {
            printf(    (new resource id %s from %s)
,
                   it.getBaseName().string(), it.getFile()->getPrintableSource().string());
        }
        String16 baseName(it.getBaseName());
        const char16_t* str = baseName.string();
        const char16_t* const end = str + baseName.size();
        while (str < end) {
            if (!((*str >= 'a' && *str <= 'z')
                    || (*str >= '0' && *str <= '9')
                    || *str == '_' || *str == '.')) {
                fprintf(stderr, %s: Invalid file name: must contain only [a-z0-9_.]
,
                        it.getPath().string());
                hasErrors = true;
            }
            str++;
        }
        String8 resPath = it.getPath();
        resPath.convertToResPath();


        table->addEntry(SourcePos(it.getPath(), 0), String16(assets->getPackage()),
                        type16,
                        baseName,
                        String16(resPath),
                        NULL,
                        &it.getParams());
        assets->addResource(it.getLeafName(), resPath, it.getFile(), type8);
    }

    return hasErrors ? STATUST(UNKNOWN_ERROR) : NO_ERROR;
} data-snippet-id=ext.8cebe8f81e0d5a08794b2195edc114f3 data-snippet-saved=false data-csrftoken=A3eZrNtf-uh85wfj0N23af0vOzZTUPCQG7nA data-codota-status=done>static status_t makeFileResources(Bundle* bundle, const sp& assets,
                                  ResourceTable* table,
                                  const sp& set,
                                  const char* resType)
{
    String8 type8(resType);
    String16 type16(resType);

    bool hasErrors = false;

    ResourceDirIterator it(set, String8(resType));
    ssize_t res;
    while ((res=it.next()) == NO_ERROR) {
        if (bundle->getVerbose()) {
            printf(    (new resource id %s from %s)
,
                   it.getBaseName().string(), it.getFile()->getPrintableSource().string());
        }
        String16 baseName(it.getBaseName());
        const char16_t* str = baseName.string();
        const char16_t* const end = str + baseName.size();
        while (str < end) {
            if (!((*str >= 'a' && *str <= 'z')
                    || (*str >= '0' && *str <= '9')
                    || *str == '_' || *str == '.')) {
                fprintf(stderr, %s: Invalid file name: must contain only [a-z0-9_.]
,
                        it.getPath().string());
                hasErrors = true;
            }
            str++;
        }
        String8 resPath = it.getPath();
        resPath.convertToResPath();


        table->addEntry(SourcePos(it.getPath(), 0), String16(assets->getPackage()),
                        type16,
                        baseName,
                        String16(resPath),
                        NULL,
                        &it.getParams());
        assets->addResource(it.getLeafName(), resPath, it.getFile(), type8);
    }

    return hasErrors ? STATUST(UNKNOWN_ERROR) : NO_ERROR;
}

美團給我們的差異代碼如下

String8 obfuscationName;
String8 obfuscationPath = getObfuscationName(resPath, obfuscationName);

table->addEntry(SourcePos(it.getPath(), 0), String16(assets->getPackage()),
        type16,
        baseName, // String16(obfuscationName),
        String16(obfuscationPath), // resPath
        NULL,
        &it.getParams());
assets->addResource(it.getLeafName(), obfuscationPath/*resPath*/, it.getFile(), type8);

只是調用了getObfuscationName函數進行混淆,返回值就是混淆後的路徑,然後在addEntry和addResource中將resPath替換為了obfuscationPath。

如果要我們自己實現這個混淆過程,首先我們得熟悉裡面的一些屬性的意義,比如getBaseName,getLeafName,getParams, convertToResPath等方法的意義。

getBaseName是獲得資源的名字,不包含後綴,如icon getLeafName是獲得資源的名字,包含後綴,如icon.png getParams是獲得限定符,如xxhdpi-v4,獲得的是一個對象,可以調用它的toString()方法將其轉換為字符串形式,也就是前面的xxhdpi-v4,注意不包含前綴- convertToResPath是將路徑中的\轉換為/,如res\drawable會被轉換為res/drawable,該方法位於String8這個類中 resType,這個是參數傳進來的,代表資源的類型,內部使用了 String8 type8(resType);轉換為了String8 類型,我們直接使用就可以了,但是這個值不包含限定符,如drawable

默認的打包過程,資源文件都是在res目錄下,現在我們通過一定的邏輯,將資源轉移到r目錄下。

首先獲得限定符

String8 params=it.getParams().toString();

由於該限定符可能為空,我們需要用if進行處理,後面再說。

再定義一個用於保存我們轉換後的目錄

String8 obfuscationPath();

如果資源限定符是空的,那麼我們直接將目錄進行拼接,別把限定符包含進去就可以了

                if(params.isEmpty()){
            obfuscationPath.append(r/);//我們放在r目錄下,所以最開始的是r/
            obfuscationPath.append(type8);//資源類型
            obfuscationPath.append(/);//添加/,因為是目錄
            obfuscationPath.append(it.getLeafName());//之後跟上全面,包含後綴的
        }

那麼假設限定符不為空呢,當然我們需要將其拼接上去

                if(params.isEmpty()){
            //......
        }else{
            obfuscationPath.append(r/);//我們放在r目錄下,所以最開始的是r/
            obfuscationPath.append(type8);//資源類型
            obfuscationPath.append(-);//增加資源限定符前綴-
            obfuscationPath.append(params);//將資源限定符添加上去
            obfuscationPath.append(/);//添加/,因為是目錄
            obfuscationPath.append(it.getLeafName());//之後跟上全面,包含後綴的
        }

然後後面打包資源的時候使用obfuscationPath代替resPath即可

addEntry(SourcePos(it.getPath(), 0), String16(assets->getPackage()),
                        type16,
                        baseName,
                        String16(obfuscationPath),
                        NULL,
                        &it.getParams());
        assets->addResource(it.getLeafName(), obfuscationPath, it.getFile(), type8); data-snippet-id=ext.055a61dd5a6e0e06973fbfff8bb91dbc data-snippet-saved=false data-csrftoken=K8bi3Ufd-VTXdHtvTccBK6ypOMRZNIf0iMQw data-codota-status=done>table->addEntry(SourcePos(it.getPath(), 0), String16(assets->getPackage()),
                        type16,
                        baseName,
                        String16(obfuscationPath),
                        NULL,
                        &it.getParams());
        assets->addResource(it.getLeafName(), obfuscationPath, it.getFile(), type8);

完整的函數如下

& set,
                                  const char* resType)
{
    String8 type8(resType);
    String16 type16(resType);

    bool hasErrors = false;

    ResourceDirIterator it(set, String8(resType));
    ssize_t res;
    while ((res=it.next()) == NO_ERROR) {
        if (bundle->getVerbose()) {
            printf(    (new resource id %s from %s)
,
                   it.getBaseName().string(), it.getFile()->getPrintableSource().string());
        }
        String16 baseName(it.getBaseName());
        const char16_t* str = baseName.string();
        const char16_t* const end = str + baseName.size();
        while (str < end) {
            if (!((*str >= 'a' && *str <= 'z')
                    || (*str >= '0' && *str <= '9')
                    || *str == '_' || *str == '.')) {
                fprintf(stderr, %s: Invalid file name: must contain only [a-z0-9_.]
,
                        it.getPath().string());
                hasErrors = true;
            }
            str++;
        }
        String8 resPath = it.getPath();
        resPath.convertToResPath();

        //String8 obfuscationPath = getObfuscationName(resPath, obfuscationName);

        String8 params=it.getParams().toString();
        String8 obfuscationPath();
        if(params.isEmpty()){
            obfuscationPath.append(r/);
            obfuscationPath.append(type8);
            obfuscationPath.append(/);
            obfuscationPath.append(it.getLeafName());
        }else{
            obfuscationPath.append(r/);
            obfuscationPath.append(type8);
            obfuscationPath.append(-);
            obfuscationPath.append(params);
            obfuscationPath.append(/);
            obfuscationPath.append(it.getLeafName());
        }
        fprintf(stderr, our Path:%s
,obfuscationPath.string());



        table->addEntry(SourcePos(it.getPath(), 0), String16(assets->getPackage()),
                        type16,
                        baseName,
                        String16(obfuscationPath),
                        NULL,
                        &it.getParams());
        assets->addResource(it.getLeafName(), obfuscationPath, it.getFile(), type8);
    }

    return hasErrors ? STATUST(UNKNOWN_ERROR) : NO_ERROR;
} data-snippet-id=ext.e9987aefeb2390d094769ac30ca644cc data-snippet-saved=false data-csrftoken=SdUZWE3g-4Be_rDkyYISJx2RRI82gvorFnv8 data-codota-status=done>static status_t makeFileResources(Bundle* bundle, const sp& assets,
                                  ResourceTable* table,
                                  const sp& set,
                                  const char* resType)
{
    String8 type8(resType);
    String16 type16(resType);

    bool hasErrors = false;

    ResourceDirIterator it(set, String8(resType));
    ssize_t res;
    while ((res=it.next()) == NO_ERROR) {
        if (bundle->getVerbose()) {
            printf(    (new resource id %s from %s)
,
                   it.getBaseName().string(), it.getFile()->getPrintableSource().string());
        }
        String16 baseName(it.getBaseName());
        const char16_t* str = baseName.string();
        const char16_t* const end = str + baseName.size();
        while (str < end) {
            if (!((*str >= 'a' && *str <= 'z')
                    || (*str >= '0' && *str <= '9')
                    || *str == '_' || *str == '.')) {
                fprintf(stderr, %s: Invalid file name: must contain only [a-z0-9_.]
,
                        it.getPath().string());
                hasErrors = true;
            }
            str++;
        }
        String8 resPath = it.getPath();
        resPath.convertToResPath();

        //String8 obfuscationPath = getObfuscationName(resPath, obfuscationName);

        String8 params=it.getParams().toString();
        String8 obfuscationPath();
        if(params.isEmpty()){
            obfuscationPath.append(r/);
            obfuscationPath.append(type8);
            obfuscationPath.append(/);
            obfuscationPath.append(it.getLeafName());
        }else{
            obfuscationPath.append(r/);
            obfuscationPath.append(type8);
            obfuscationPath.append(-);
            obfuscationPath.append(params);
            obfuscationPath.append(/);
            obfuscationPath.append(it.getLeafName());
        }
        fprintf(stderr, our Path:%s
,obfuscationPath.string());



        table->addEntry(SourcePos(it.getPath(), 0), String16(assets->getPackage()),
                        type16,
                        baseName,
                        String16(obfuscationPath),
                        NULL,
                        &it.getParams());
        assets->addResource(it.getLeafName(), obfuscationPath, it.getFile(), type8);
    }

    return hasErrors ? STATUST(UNKNOWN_ERROR) : NO_ERROR;
}

這樣進行編譯,編譯的步驟參考之前寫的博客http://blog.csdn.net/sbsujjbcy/article/details/47778879

替換我們的aapt進行編譯。

這裡寫圖片描述vc7Sw8fX1Ly6yuSz9rXExL/CvKOssrvU2srHcmVzxL/CvM/Co6y2+MrHcsS/wrzPwqOs1eLKsbryvau08rD8usO1xGFwa87EvP69+NDQt7Sx4NLroaPE47eiz9ZyZXPEv8K8z8KyosO709DO0sPH19S8utC0tcTXytS0zsS8/qOsyKvKx8+1zbPX1MnttcSjrMi7uvO24MHL0ru49nVua25vd27Ev8K8o6zA78PmsLTXxdStxL/CvMXFwdDXxc7Sw8e1xNfK1LTOxLz+PC9wPg0KPHA+PGltZyBhbHQ9"這裡寫圖片描述" src="/uploadfile/Collfiles/20151010/201510100843472.png" title="" />

很顯然,我們已經成功地將res中的文件轉移到了r文件夾中。那麼資源混淆也就變得簡單了。我們參考我們java中的類的混淆,我們的類會被混淆成a,b,c之類的符號,於是我們只要定義一個轉換函數,將原目錄映射到a,b,c等目錄,比如anim映射為a,color映射為b,….因此類推。然後對應目錄中的文件也依次重命名。a-z不夠用的可以使用aa-zz,甚至aaa-zzz。關鍵就是這麼一個轉換函數。

這個函數的實現其實應該不難,但是出於個人太懶,就沒去寫這個函數了,讀者有興趣可以在上面的代碼基礎上進行修改。

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved