All Downloads are FREE. Search and download functionalities are using the official Maven repository.

main.com.xml.guard.model.DeclarationMapping.kt Maven / Gradle / Ivy

package com.xml.guard.model

import com.github.javaparser.JavaParser
import com.github.javaparser.ast.body.EnumDeclaration
import com.github.javaparser.ast.body.FieldDeclaration
import com.github.javaparser.ast.body.MethodDeclaration
import com.xml.guard.entensions.GuardExtension
import com.xml.guard.utils.generateNumbers
import com.xml.guard.utils.getClassPackage
import com.xml.guard.utils.getDirPath
import com.xml.guard.utils.inClassNameBlackList
import com.xml.guard.utils.inDeclarationBlackList
import com.xml.guard.utils.inPackageNameBlackList
import com.xml.guard.utils.isJava
import com.xml.guard.utils.isKt
import com.xml.guard.utils.javaDirs
import com.xml.guard.utils.lowercaseFirstChar
import com.xml.guard.utils.randomizeCase
import com.xml.guard.utils.replaceLast
import com.xml.guard.utils.to26Long
import com.xml.guard.utils.toLetterStr
import com.xml.guard.utils.toUpperLetterStr
import org.gradle.api.Project
import java.io.BufferedWriter
import java.io.File
import java.io.FileWriter
import java.util.regex.Pattern
import kotlin.math.pow
import kotlin.math.roundToInt
import kotlin.random.Random

class DeclarationMapping(private val guardExtension: GuardExtension) {
    private val constValPattern by lazy { "\\s*const\\s*val\\s*(\\w*)\\s*=" }

    // 白名单
    private val declarationWhiteList by lazy { guardExtension.declarationWhiteList }

    // 静态字段
    internal val staticFieldMapping by lazy { mutableMapOf() }

    // 非静态字段
    internal val nonStaticFieldMapping by lazy { mutableMapOf() }

    // 函数名称
    internal val methodNameMapping by lazy { mutableMapOf() }

    // 函数参数
    internal val methodParameterMapping by lazy { mutableMapOf() }

    // 枚举常量
    internal val enumConstantMapping by lazy { mutableMapOf() }

    // 混淆名索引
    internal var obfuscateIndex = -1L

    internal val allMappingMap by lazy { mutableMapOf() }

    // 寻找出所有静态字段、枚举常量名称
    fun findAllDeclaration(
        androidProjects: List,
        variantName: String
    ): Map {
        androidProjects.forEach { project ->
            project.files(project.javaDirs(variantName)).asFileTree.files.forEach asFileTree@{ file ->
                if (inClassWhiteList(project, file)) {
                    return@asFileTree
                }
                if (file.isJava) {
                    val cu = JavaParser().parse(file).result.get()
                    cu.findAll(FieldDeclaration::class.java).forEach findAll@{ declaration ->
                        declaration.variables.forEach variables@{ variable ->
                            val rawName = variable.nameAsString.trim()

                            // 白名单、已混淆
                            if (inWhiteList(rawName) || isObfuscated(rawName)) {
                                return@variables
                            }
                            if (declaration.isStatic) {
                                val newName =
                                    obfuscateName(staticFieldMapping, rawName, declaration.isFinal)
                                staticFieldMapping[rawName] = newName
                            } else {
                                val newName = obfuscateName(nonStaticFieldMapping, rawName)
                                nonStaticFieldMapping[rawName] = newName
                            }
                        }
                    }

                    cu.findAll(MethodDeclaration::class.java).forEach findAll@{ declaration ->
                        val rawMethodName = declaration.nameAsString.trim()

                        // 函数名称白名单
                        val isMethodNameWhiteList = inWhiteList(rawMethodName)
                        // 函数名称混淆
                        if (!isMethodNameWhiteList && !isObfuscated(rawMethodName)) {
                            val newMethodName = obfuscateName(methodNameMapping, rawMethodName)
                            methodNameMapping[rawMethodName] = newMethodName
                        }

                        declaration.parameters.forEach parameters@{ parameter ->
                            val rawParameterName = parameter.nameAsString.trim()

                            if (isMethodNameWhiteList) {
                                if (!declarationWhiteList.contains(rawParameterName)) {
                                    declarationWhiteList.add(rawParameterName)
                                }
                                return@parameters
                            }
                            // 白名单、已混淆
                            if (inWhiteList(rawParameterName) || isObfuscated(rawParameterName)) {
                                return@parameters
                            }
                            val newParameterName =
                                obfuscateName(methodParameterMapping, rawParameterName)
                            methodParameterMapping[rawParameterName] = newParameterName
                        }
                    }

                    cu.findAll(EnumDeclaration::class.java).forEach findAll@{ declaration ->
                        declaration.entries.forEach entries@{ enumConstant ->
                            val rawName = enumConstant.nameAsString.trim()

                            // 白名单、已混淆
                            if (inWhiteList(rawName) || isObfuscated(rawName)) {
                                return@entries
                            }
                            val newName =
                                obfuscateName(enumConstantMapping, rawName, isFinal = true)
                            enumConstantMapping[rawName] = newName
                        }
                    }
                    return@asFileTree
                }
                if (file.isKt) {
                    file.forEachLine { line ->
                        // 正则表达式匹配字符串
                        val pattern = Pattern.compile(constValPattern)
                        val matcher = pattern.matcher(line)

                        // 输出匹配到的字段名称
                        while (matcher.find()) {
                            val rawName = matcher.group(1)?.trim()

                            // 白名单、已混淆
                            if (rawName.isNullOrBlank()
                                || inWhiteList(rawName)
                                || isObfuscated(rawName)
                            ) {
                                continue
                            }
                            val newName = obfuscateName(staticFieldMapping, rawName, isFinal = true)
                            staticFieldMapping[rawName] = newName
                        }
                    }
                }
            }
        }

        return allMappingMap
    }

    fun writeMappingToFile(mappingFile: File) {
        val writer = BufferedWriter(FileWriter(mappingFile, false))

        writer.write("${MappingParser.STATIC_FIELD_MAPPING}\n")
        for ((key, value) in staticFieldMapping) {
            writer.write(String.format("\t%s -> %s\n", key, value))
        }
        writer.flush()

        writer.write("\n")
        writer.write("${MappingParser.NON_STATIC_FIELD_MAPPING}\n")
        for ((key, value) in nonStaticFieldMapping) {
            writer.write(String.format("\t%s -> %s\n", key, value))
        }
        writer.flush()

        writer.write("\n")
        writer.write("${MappingParser.METHOD_NAME_MAPPING}\n")
        for ((key, value) in methodNameMapping) {
            writer.write(String.format("\t%s -> %s\n", key, value))
        }
        writer.flush()

        writer.write("\n")
        writer.write("${MappingParser.METHOD_PARAMETER_MAPPING}\n")
        for ((key, value) in methodParameterMapping) {
            writer.write(String.format("\t%s -> %s\n", key, value))
        }
        writer.flush()

        writer.write("\n")
        writer.write("${MappingParser.ENUM_CONSTANT_MAPPING}\n")
        for ((key, value) in enumConstantMapping) {
            writer.write(String.format("\t%s -> %s\n", key, value))
        }
        writer.flush()

        writer.close()
    }

    // 白名单
    fun inClassWhiteList(project: Project, file: File): Boolean {
        val rawPackage = getClassPackage(project, file).trim()
        val rawClassPath = "${rawPackage}.${file.nameWithoutExtension}"
        return declarationWhiteList.any {
            (it == rawClassPath
                    || it == rawClassPath.getDirPath()
                    || (it.endsWith("*") && rawClassPath.startsWith(it.replaceLast("*", ""))))
        }
    }

    // 白名单
    fun inWhiteList(rawName: String): Boolean {
        if (rawName.inPackageNameBlackList()) {
            return true
        }
        if (rawName.inDeclarationBlackList()) {
            return true
        }
        return declarationWhiteList.any { it == rawName }
    }

    // 已混淆
    fun isObfuscated(rawName: String): Boolean {
        return allMappingMap.containsKey(rawName) || allMappingMap.containsValue(rawName)
    }

    private fun obfuscateName(
        mappingMap: MutableMap,
        rawName: String,
        isFinal: Boolean = false
    ): String {
        var obfuscateName = allMappingMap[rawName]
        if (obfuscateName == null) {
            obfuscateName = generateObfuscateName(isFinal)

            if (isFinal) {
                val len = (Random.nextDouble() * 3).roundToInt()
                for (i in 0 until len) {
                    val index = (generateNumbers().toDouble()
                        .pow(Random.nextDouble(1.0, 3.0))).toLong()
                    val randomName = index.toUpperLetterStr()
                    obfuscateName += "_${randomName}"
                }
            }
            allMappingMap[rawName] = obfuscateName
            mappingMap[rawName] = obfuscateName
        }
        return obfuscateName
    }

    private fun generateObfuscateName(isFinal: Boolean): String {
        while (true) {
            obfuscateIndex += (generateNumbers().toDouble()
                .pow(Random.nextDouble(1.0, 3.0))).toLong()
            val obfuscateFieldName =
                if (isFinal) obfuscateIndex.toUpperLetterStr()
                else obfuscateIndex.toLetterStr().randomizeCase().lowercaseFirstChar()
            if (obfuscateFieldName.length > 1 // 保证至少两位字母以上
                && !obfuscateFieldName.inClassNameBlackList()
                && !obfuscateFieldName.inPackageNameBlackList() // 过滤黑名单
            ) {
                val minimumValue = obfuscateFieldName.to26Long()
                obfuscateIndex = obfuscateIndex.coerceAtLeast(minimumValue)
                return obfuscateFieldName
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy