上傳第三方市場的時(shí)候,經(jīng)常會(huì)碰到一些手機(jī)App市場會(huì)對一些代碼進(jìn)行掃描,比如廣告、"PM"命令等,如果出現(xiàn)此類代碼,會(huì)要求提供功能描述,看是否是合理功能,否者不予上架。本片就"PM"如何規(guī)避第三方市場來做一個(gè)簡單的分析。
概述
前幾天在工作中碰到過類似的問題,細(xì)節(jié)不方便說太多。在提交App的時(shí)候,被第三發(fā)市場以內(nèi)部包含"pm install"代碼的理由,要求提供代碼相關(guān)功能描述,或者刪除此代碼。
"pm install"的作用相信應(yīng)該都了解,不需要在這里重復(fù)講解。但是本著一個(gè)有職業(yè)操守的程序員,有"pm install"的代碼也只是本著讓用戶更方便的使用App,而非使用用一些不合規(guī)的手段謀利。
那么如何規(guī)避這樣的問題,把"pm install"能夠"合規(guī)"的放在項(xiàng)目中,而不讓軟件市場掃描到。
分析問題
第三方市場能準(zhǔn)確的找到是那個(gè)文件中,出現(xiàn)了違規(guī)的代碼塊??隙ㄊ菍⑵浣獍?,做了一個(gè)全路徑掃描,做字符串的匹配,有不合規(guī)的字符串就提示警告出來。
那么唯一要做的,就是對關(guān)鍵字符串的代碼進(jìn)行編碼,讓手機(jī)市場掃描不到。例如把"pm install"這個(gè)字符串用Base64編碼就是一個(gè)不錯(cuò)的手段,然后在需要使用的時(shí)候,再將編碼后的字符串進(jìn)行解碼,就是一個(gè)不錯(cuò)的方式。
實(shí)施方案
pm install
首先用工具把字符串轉(zhuǎn)換成Base64編碼。

得到一個(gè)字符串,然后在代碼中將其解碼即可。
private String getCommand0(){
return new String(Base64.decode("cG0gaW5zdGFsbA==", Base64.DEFAULT));
}
其實(shí)做到這一步,應(yīng)該就可以很簡單規(guī)避市場上架的問題(當(dāng)然我沒有試過)。
但是做事情要往深一步想想,如果只是一個(gè)簡單的一次Base64編碼,再解碼就可以解決問題了。那一定是因?yàn)槿绞袌鰶]有對這個(gè)地方做太嚴(yán)格的保護(hù),說白了,就是對其進(jìn)行放水了,增加一點(diǎn)門檻,又不讓門檻太高導(dǎo)致一部分App進(jìn)不來。那這個(gè)規(guī)則,市場如果想嚴(yán)格一點(diǎn)監(jiān)管,只需要把關(guān)鍵代碼串的一些常用編碼串,也加入到匹配列表中就可以了。如果規(guī)則改了,最后麻煩的還是我們。
所以再深一步,如果是我來寫這個(gè)全路徑文件內(nèi)容匹配的話,我會(huì)在apk解包之后,對所有的文件,進(jìn)行一行行的掃描,然后比對銘感代碼串。那么如果這個(gè)代碼串,不是一個(gè)連貫的,而是一個(gè)拼接的方式,又如何呢?所以我想到了一個(gè)解決方案,對getCommand0()進(jìn)行了改進(jìn),當(dāng)然是很簡單的改進(jìn),把他們拆分成多個(gè)字符串,拼接起來。
private String getCommand1(){
return new String(Base64.decode("cG0gaW5zdGFsbA"+"==", Base64.DEFAULT));
}
雖然從代碼上看,這樣是將字符串拆分開了。但是其實(shí)這樣是不生效的,因?yàn)樵诖虬倪^程中,編譯器會(huì)對代碼進(jìn)行優(yōu)化(當(dāng)然優(yōu)化的手段有很多),把一些不不要的代碼剔除,或者改進(jìn)現(xiàn)有的代碼塊的代碼,讓其運(yùn)行的更加高效。
如getCommand1(),在打包之后,反編譯出來看看。

從圖上可以看出來,編譯器會(huì)在變異的時(shí)候,自動(dòng)幫我們把一個(gè)拼接的字符串變成一個(gè)完整的字符串進(jìn)行賦值。
那么,如何預(yù)防這樣的問題呢?讓編譯器按照我們預(yù)想的,輸出兩個(gè)單獨(dú)的字符串,進(jìn)行拼接。這個(gè)時(shí)候,可以使用StringBuilder來處理字符串,就有了如下代碼。
private String getCommand() {
// pm install
return new String(Base64.decode(new StringBuilder("cG0gaW5zdGFsbA").append("==").toString(), Base64.DEFAULT));
}
然后我們再打包驗(yàn)證一下結(jié)果,發(fā)現(xiàn)確實(shí)是如我們預(yù)期的去做的。

總結(jié)
其實(shí)這種方案是一種比較簡單的方法,如果有心去預(yù)防,還是可以預(yù)防的,不過這種問題也沒必要做的太復(fù)雜。核心思想就是不要讓關(guān)鍵代碼完整的出現(xiàn)在一個(gè)地方。讓其有斷裂的,這樣機(jī)器很難通過靜態(tài)分析的方式去捕獲到此代碼。