前言
因?yàn)閼?yīng)用市場審核的原因衣撬,馬甲包現(xiàn)在需要上線是越來越難了。目前也出現(xiàn)了很多繞過檢測的方法扮饶,比如修改主包路勁具练、添加垃圾代碼等。但是效果并不如人意甜无,特別是現(xiàn)在機(jī)器學(xué)習(xí)這么流行的情況下扛点,這種“小伎倆”還是很容易被識破的。所以最好是從源頭入手岂丘,徹底改變代碼結(jié)構(gòu)陵究,從源頭上解決問題。
那為什么要修改Bean的類名? 眾所周知的原因奥帘,Bean是沒辦法加入混淆的铜邮,且跟反射調(diào)用有著密切的關(guān)系,所以往往Bean對象都是“裸奔”的。在“裸奔”的情況下松蒜,如何避免相似度的檢測扔茅?如果是你,你如何檢測APK的相似度秸苗?
我能想到的且相對簡單的方法就是反編譯源代碼召娜,相互匹配類名(不考慮包路徑),類名相同的概率*權(quán)重就可以當(dāng)成這兩個應(yīng)用的相似度(當(dāng)然還需要其他檢測方法相互配合惊楼,類名只是其中一個因子而已)玖瘸。
實(shí)現(xiàn)思路
大致可將其分為幾步
- 查找Bean文件。(可以是配置的目錄或者通過名字正則匹配檀咙,例如:“**/**Bean.java”)
- 遍歷工程文件雅倒,替換使用到這個Bean的所有代碼。如果有使用DataBinding, 還需要遍歷layout xml文件攀芯。
編寫腳本
警告!!!!
此腳本會覆蓋你本地源代碼代碼屯断,請確保你的代碼有加入到版本管理(Git 或者 SVN) ,以便恢復(fù)侣诺。
開源地址: Gitee
子路徑: /tinyqiu/java-bean-rename-gradle
配置參數(shù)
首先定義需要用到的參數(shù)
ext {
//需要批量重命名的Bean路徑
renameBeanPath = "src/main/java/com/chockqiu/testpck/bean"
//Bean對象名字以什么字符串結(jié)尾, 默認(rèn)Bean, 例如設(shè)為Beax, 則所有Bean都會以Beax結(jié)尾, 如GoodsBeax.kt
beanNameSuffix = "Bear"
//Bean名字的前綴, 例如KoGoodsBean
beanPrefix = "Ko"
//Bean對象 Bean的前面加的字符串 KoGoodsFishBean
beanMidfix = "Fish"
//特殊的Bean比配
specialBeansMatcher = ["**/*Been.kt", "**/*Been.java"]
}
類名匹配
利用Gradle內(nèi)建函數(shù)FileTree可以輕松實(shí)現(xiàn)
FileTree beanTree = fileTree(renameBeanPath) {
include '**/*.java'
include '**/*.kt'
include specialBeansMatcher
}
//........
類名轉(zhuǎn)換
根據(jù)已有的類名殖演,增加前綴后綴等方式進(jìn)行轉(zhuǎn)換,這里可以根據(jù)具體需求靈活實(shí)現(xiàn)年鸳。
//遍歷匹配的類
beanTree.each { File beanFile ->
//println(beanFile.path + " Processing...")
def sname = beanFile.name
def fileEx = sname.substring(sname.lastIndexOf("."))
sname = sname.replace(fileEx, "")
def tName = ""
if (sname.endsWith("Bean")) {
tName = beanPrefix + sname.replace("Bean", beanMidfix + beanNameSuffix)
} else if (sname.endsWith("Bean")) {//兼容有些人把Bean寫成了Been
tName = beanPrefix + sname.replace("Bean", beanMidfix + beanNameSuffix)
} else {
tName = beanPrefix + sname + beanMidfix + beanNameSuffix
}
beanFile.renameTo(beanFile.parentFile.path + File.separator + tName + fileEx)
//..........
}
引用替換
替換所用使用到這個Bean的代碼
遍歷可能使用到的地方
主要是Kotlin和Java代碼趴久,如果有使用DataBinding,還有XML的Layout文件搔确。
FileTree processTree = fileTree("src") {
include '**/*.java'
include '**/*.kt'
include '**/layout/*.xml'
}
processTree.each { File f ->
ImportBeanReplacer(f.path, sname, tName)
}
字符串匹配規(guī)則
Bean的使用比較復(fù)雜彼棍,簡單的字符串替換是無法實(shí)現(xiàn)的,所以這里需要引入正則表達(dá)式進(jìn)行匹配膳算。
針對xml的匹配規(guī)則:
(?<![a-zA-Z0-9]+)(?<=[\\.]+)$sourceBeanName(?=[ \"\\./>]*)(?![a-zA-Z0-9]+)
針對Java/Kotlin的匹配規(guī)則
(?<![a-zA-Z0-9]+)(?<=[ \\.<:\\s\\,(]+)$sourceBeanName(?=[ \"\\.>\\?\\:\\(]*)(?![a-zA-Z0-9]+)
其中$sourceBeanName是需要被替換的類名字座硕。
正則表達(dá)式不熟的同學(xué)參考:https://www.runoob.com/regexp/regexp-metachar.html
正則表達(dá)式匹配規(guī)則是比較關(guān)鍵的,如果寫的不夠完整涕蜂,將導(dǎo)致輸出的代碼編譯無法通過华匾,所以需要不斷的進(jìn)行迭代更新,以適應(yīng)不同的情況机隙。