編輯:關於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。關鍵就是這麼一個轉換函數。
這個函數的實現其實應該不難,但是出於個人太懶,就沒去寫這個函數了,讀者有興趣可以在上面的代碼基礎上進行修改。
360奇酷手機出自酷派和360合資公司,奇酷手機以及酷派手機都屬於安卓系統,那麼奇酷手機、酷派手機怎麼刷機呢?手機有毛病可以嘗試恢復手機出廠設置,操作方法如
主要的類: package de.hdodenhof.circleimageview; import edu.njupt.zhb.main.
在android開發中對圖片處理很是頻繁,其中對圖片的顏色處理就是很常見的一種。我們經常看到一些類似美圖秀秀,美顏相機的app,為什麼那麼黑的人拍出來是確實那麼地白呢?長
為了提高用戶體驗,我們肯定希望該Dialog能更加炫酷,讓用戶看著更舒服。那如何做呢,當然是我們自己定義一個ProgressDialog了。一、使用系統加載框mDialo