Dexlib2 笔记1

4,759 阅读2分钟

最近在研究Dex文件的编辑,找到了dexlib2这个库,但是网上没有搜索到相关资料。所以在此记录一下。

1.导入Dexlib2

dexlib2截至目前最新版是2.4.0,可以在 dexlib2查看更新。

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"

    implementation  group: 'org.smali', name: 'dexlib2', version: '2.4.0'
}

2.创建DexBackedDexFile

我们可以通过 DexFileFactory 类来创建一个 DexBackedDexFile实例

val dexBackedDexFile = DexFileFactory.loadDexFile(File("classes.dex"), Opcodes.getDefault())

一个 DexBackedDexFile 实例代表一个dex文件,通过 DexBackedDexFile 我们可以访问到所有Class

//所有classes
    val classes = dexBackedDexFile.classes
    println(classes.size)

3.ClassDef

ClassDef 代表一个类,我们可以通过 DexBackedDexFile 实例来获取一个类,也可以自行创建一个类.

//从DexBackedDexFile获取ClassDef
val zzz = dexBackedDexFile.classes.find {
        //type 代表class name
        it.type == "Lcom.xxx.yyy.zzz;"
    }
    //父类
    println(zzz?.superclass)
val type = "Lcom.xxx.yyy.zzz;"
    val defClass = ImmutableClassDef(
        //类名
        type,
        AccessFlags.PUBLIC.value,
        //父类
        "Ljava/lang/Object;",
        //继承的接口
        null,
        //源文件
        null,
        //注解
        null,
        //静态成员变量
        listOf(
            ImmutableField(
                //所属类
                type,
                //成员名称
                "field1",
                //成员类型
                "I",
                AccessFlags.PRIVATE.value,
                //初始化值
                ImmutableIntEncodedValue(666),
                null,
                null
            )
        ),
        //成员变量
        null,
        //直系方法(自定义)
        null,
        //非直系(继承重载等)
        null
    )

3.修改某类的方法返回值

fun main() {

    val dexBackedDexFile = DexFileFactory.loadDexFile(File("classes.dex"), Opcodes.getDefault())

    val type = javaClassoType("com.uzmap.pkg.EntranceActivity")

    //定义一个DexRewriter
    val reWriter = DexRewriter(object : RewriterModule() {
        //修改方法
        override fun getMethodRewriter(rewriters: Rewriters): Rewriter<Method> = Rewriter {
            //判断类名和方法名
            if (it.definingClass == type && it.name == "isFromNativeSDK") {
                //返回修改后的方法
                return@Rewriter MethodWrapper(it).apply {
                    //修改方法的实现
                    methodImplementation = ImmutableMethodImplementation(
                        //寄存器个数
                        1, listOf(
                            ImmutableInstruction11n(
                                //指令
                                Opcode.CONST_4,
                                //寄存器
                                0,
                                //值
                                1),
                            //return p0
                            ImmutableInstruction11x(
                                Opcode.RETURN,
                                0
                            )
                        ), null, null
                    )
                }.build()
            }
            it
        }
    })

    val newDexFile = reWriter.dexFileRewriter.rewrite(dexBackedDexFile)
    DexFileFactory.writeDexFile("new.dex", newDexFile)
}

fun javaClassToType(clz: String): String = "L${clz.replace(".", "/")};"

上面我们修改了 isFromNativeSDK 方法使其返回true,这里有关于寄存器的知识:

当一个方法被调用的时候,方法的参数被置于最后N个寄存器中。如果一个方法有2个参数,5个寄存器(v0-v4),那么参数将置于最后2个寄存器——v3和v4。 非静态方法中的第一个参数总是调用该方法的对象。

这里指定了一个寄存器,就是第一个参数this——代表EntranceActivity实例。

修改后的smali代码:

# virtual methods
.method protected final isFromNativeSDK()Z
    .locals 0

    const/4 p0, 0x1

    return p0
.end method

​ 寄存器都是32位的,能够支持任何类型。64位类型(Long和Double型)用2个寄存器表示。 有两种方式指定一个方法中有多少寄存器是可用的。.registers指令指定了方法中寄存器的总数。.locals指令表明了方法中非参寄存器的数量。

MethodWrapper 类的定义:

import org.jf.dexlib2.iface.Method
import org.jf.dexlib2.immutable.ImmutableMethod

class MethodWrapper(method: Method) {

    var definingClass = method.definingClass
    var name = method.name
    var parameters = method.parameters
    var returnType = method.returnType
    var accessFlags = method.accessFlags
    var annotations = method.annotations
    var hiddenApiRestrictions = method.hiddenApiRestrictions
    var methodImplementation = method.implementation

    fun build(): ImmutableMethod = ImmutableMethod(
        definingClass,
        name,
        parameters,
        returnType,
        accessFlags,
        annotations,
        hiddenApiRestrictions,
        methodImplementation
    )
}