Tree Api+ClassScanner = identify the privacy permission of three parties and call | Android Lint

theme: smartblue

background

I introduced ClassScanner to you when I was doing privacy permission In fact, this has always been a small blind spot for me before, because there are few lint related documents. This time, I wrote it after referring to another ClassScanner.

Adhering to the principle that solo music is not as good as public music, I'd better pretend to force you.

Project address AndroidLint

text

As mentioned earlier, UastScanner is aimed at java and kt syntax trees, so we can check whether their syntax is reasonable when they are compiled into products. If it is unreasonable, Lint can be used to block it. As also described in previous articles.

It was said at the beginning of the article that the disk we want this time is ClassScanner. Our main scanning targets are third-party aar, jar and class products. These are actually Class file, because the process of javac has been skipped, there is no syntax tree.

Write it

class PrivacyClassDetector : Detector(), Detector.ClassScanner {

    override fun checkClass(context: ClassContext, classNode: ClassNode) {
        super.checkClass(context, classNode)
    }

    override fun checkCall(
        context: ClassContext,
        classNode: ClassNode,
        method: MethodNode,
        call: MethodInsnNode
    ) {
        super.checkCall(context, classNode, method, call)
    }

    override fun getApplicableAsmNodeTypes(): IntArray? {
        return intArrayOf(AbstractInsnNode.METHOD_INSN)
    }


    override fun checkInstruction(
        context: ClassContext,
        classNode: ClassNode,
        method: MethodNode,
        instruction: AbstractInsnNode
    ) {
        super.checkInstruction(context, classNode, method, instruction)
        if (instruction is MethodInsnNode) {
            if (instruction.isPrivacy() != null) {
                print("checkInstruction AbstractInsnNode:${instruction.opcode} \r\n")
                context.report(
                    ISSUE, context.getLocation(instruction),
                    "Outer ring q+Inner ring"
                )

            }
        }

    }

    private fun MethodInsnNode.isPrivacy(): PrivacyAsmEntity? {
        val pair = PrivacyHelper.privacyList.firstOrNull {
            val first = it
            first.owner == owner && first.code == opcode && first.name == name && first.desc == desc
        }
        return pair

    }

    companion object {
        val ISSUE = Issue.create(
            "ClassSampleDetector",  //Unique ID
            "Eh ",  //Simple description
            "I just want you to make a mistake",  //Detailed description
            Category.CORRECTNESS,  //Types of problems (correctness, safety, etc.)
            6, Severity.ERROR,  //Problem severity (ignore, warning, error)
            Implementation( //Implementation, including processing instance and scope
                PrivacyClassDetector::class.java,
                Scope.CLASS_FILE_SCOPE
            )
        )
    }
}

In fact, this part is very similar to the asm of privacy permission replacement I wrote, because it has been compiled into bytecode, and lint also uses the tree api. You can see many old acquaintances, such as ClassNode and MethodNode. Let's analyze it a little.

interface ClassScanner : FileScanner {

    // node type to check 
    fun getApplicableAsmNodeTypes(): IntArray?

    // function call
    fun checkInstruction(
        context: ClassContext,
        classNode: ClassNode,
        method: MethodNode,
        instruction: AbstractInsnNode
    )

    //   Similar to other lint APIs
    fun getApplicableCallNames(): List<String>?
    //   Similar to other lint APIs
    fun getApplicableCallOwners(): List<String>?

    // Match getApplicableCallNames
    fun checkCall(
        context: ClassContext,
        classNode: ClassNode,
        method: MethodNode,
        call: MethodInsnNode
    )

    // Match getApplicableCallOwners
    fun checkClass(context: ClassContext, classNode: ClassNode)
}

Let's start with this abstract interface. I made a simple method description on the function. This time, we need to judge the privacy api because there are many stack frame methods to judge, such as invokevirtual and invokestatic, so on getApplicableAsmNodeTypes, we get all the function calls. Invokevirtual and invokestatic are MethodInsnNode, so we just need to add abstractinsnnode in getApplicableAsmNodeTypes method METHOD_ Insn will do.

Then, what we need to do is also very simple, because our input type is only MethodInsnNode. Therefore, when checkInstruction is the stack frame, when the calling method is executed, directly convert the call into MethodInsnNode, and then judge the current stack to judge whether the current method is an operator, descriptor, owner, etc. all meet the definition of our privacy api, If so, just call lint repot.

ending

It can be regarded as the supplement of strange sexual skills. Interested leaders can learn. This article is so short. Of course, the premise of understanding the content of this article is that you must have a certain understanding of virtual machine code, and the understanding of asm will be integrated. It is the same whether transform or ClassScanner.

Added by mainewoods on Sun, 06 Mar 2022 04:44:21 +0200